- Removed stupid idea to insert convertor nodes in Node Shaders, when a link is created by non-matching sockets. Now it works like Compositor, doing a default conversion. Works like this: 1 from 3 or 4 values: take average 3 from 1: copy to all 3 from 4: copy 3 4 from 1: copy to 3, set alpha to 1 4 from 3: copy 3, set alpha to 1 - Added select-linked in Nodes. Lkey or Shift+L. Also in pulldown menus
1187 lines
33 KiB
C
1187 lines
33 KiB
C
/**
|
|
* $Id$
|
|
*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2005 Blender Foundation.
|
|
* All rights reserved.
|
|
*
|
|
* The Original Code is: all of this file.
|
|
*
|
|
* Contributor(s): none yet.
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#include "DNA_ID.h"
|
|
#include "DNA_material_types.h"
|
|
#include "DNA_node_types.h"
|
|
#include "DNA_scene_types.h"
|
|
#include "DNA_texture_types.h"
|
|
|
|
#include "BKE_blender.h"
|
|
#include "BKE_colortools.h"
|
|
#include "BKE_node.h"
|
|
#include "BKE_material.h"
|
|
#include "BKE_texture.h"
|
|
#include "BKE_utildefines.h"
|
|
|
|
#include "BLI_arithb.h"
|
|
#include "BLI_blenlib.h"
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "RE_shader_ext.h" /* <- ShadeInput Shaderesult TexResult */
|
|
|
|
|
|
/* ********* exec data struct, remains internal *********** */
|
|
|
|
typedef struct ShaderCallData {
|
|
ShadeInput *shi; /* from render pipe */
|
|
ShadeResult *shr; /* from render pipe */
|
|
} ShaderCallData;
|
|
|
|
|
|
/* **************** call to switch lamploop for material node ************ */
|
|
|
|
static void (*node_shader_lamp_loop)(ShadeInput *, ShadeResult *);
|
|
|
|
void set_node_shader_lamp_loop(void (*lamp_loop_func)(ShadeInput *, ShadeResult *))
|
|
{
|
|
node_shader_lamp_loop= lamp_loop_func;
|
|
}
|
|
|
|
/* ****** */
|
|
|
|
static void nodestack_get_vec(float *in, short type_in, bNodeStack *ns)
|
|
{
|
|
float *from= ns->vec;
|
|
|
|
if(type_in==SOCK_VALUE) {
|
|
if(ns->sockettype==SOCK_VALUE)
|
|
*in= *from;
|
|
else
|
|
*in= 0.333333f*(from[0]+from[1]+from[2]);
|
|
}
|
|
else if(type_in==SOCK_VECTOR) {
|
|
if(ns->sockettype==SOCK_VALUE) {
|
|
in[0]= from[0];
|
|
in[1]= from[0];
|
|
in[2]= from[0];
|
|
}
|
|
else {
|
|
VECCOPY(in, from);
|
|
}
|
|
}
|
|
else { /* type_in==SOCK_RGBA */
|
|
if(ns->sockettype==SOCK_RGBA) {
|
|
QUATCOPY(in, from);
|
|
}
|
|
else if(ns->sockettype==SOCK_VALUE) {
|
|
in[0]= from[0];
|
|
in[1]= from[0];
|
|
in[2]= from[0];
|
|
in[3]= 1.0f;
|
|
}
|
|
else {
|
|
VECCOPY(in, from);
|
|
in[3]= 1.0f;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ******************************************************** */
|
|
/* ********* Shader Node type definitions ***************** */
|
|
/* ******************************************************** */
|
|
|
|
/* SocketType syntax:
|
|
socket type, max connections (0 is no limit), name, 4 values for default, 2 values for range */
|
|
|
|
/* Verification rule: If name changes, a saved socket and its links will be removed! Type changes are OK */
|
|
|
|
/* **************** OUTPUT ******************** */
|
|
static bNodeSocketType sh_node_output_in[]= {
|
|
{ SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ SOCK_VALUE, 1, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_output(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
if(data) {
|
|
ShadeInput *shi= ((ShaderCallData *)data)->shi;
|
|
float col[4];
|
|
|
|
/* stack order input sockets: col, alpha, normal */
|
|
nodestack_get_vec(col, SOCK_VECTOR, in[0]);
|
|
nodestack_get_vec(col+3, SOCK_VALUE, in[1]);
|
|
|
|
if(shi->do_preview) {
|
|
nodeAddToPreview(node, col, shi->xs, shi->ys);
|
|
node->lasty= shi->ys;
|
|
}
|
|
|
|
if(node->flag & NODE_DO_OUTPUT) {
|
|
ShadeResult *shr= ((ShaderCallData *)data)->shr;
|
|
|
|
QUATCOPY(shr->combined, col);
|
|
shr->alpha= col[3];
|
|
|
|
// VECCOPY(shr->nor, in[3]->vec);
|
|
}
|
|
}
|
|
}
|
|
|
|
static bNodeType sh_node_output= {
|
|
/* type code */ SH_NODE_OUTPUT,
|
|
/* name */ "Output",
|
|
/* width+range */ 80, 60, 200,
|
|
/* class+opts */ NODE_CLASS_OUTPUT, NODE_PREVIEW,
|
|
/* input sock */ sh_node_output_in,
|
|
/* output sock */ NULL,
|
|
/* storage */ "",
|
|
/* execfunc */ node_shader_exec_output
|
|
|
|
};
|
|
|
|
/* **************** GEOMETRY ******************** */
|
|
|
|
/* output socket defines */
|
|
#define GEOM_OUT_GLOB 0
|
|
#define GEOM_OUT_LOCAL 1
|
|
#define GEOM_OUT_VIEW 2
|
|
#define GEOM_OUT_ORCO 3
|
|
#define GEOM_OUT_UV 4
|
|
#define GEOM_OUT_NORMAL 5
|
|
|
|
/* output socket type definition */
|
|
static bNodeSocketType sh_node_geom_out[]= {
|
|
{ SOCK_VECTOR, 0, "Global", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, /* btw; uses no limit */
|
|
{ SOCK_VECTOR, 0, "Local", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ SOCK_VECTOR, 0, "View", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ SOCK_VECTOR, 0, "Orco", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ SOCK_VECTOR, 0, "UV", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
/* node execute callback */
|
|
static void node_shader_exec_geom(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
if(data) {
|
|
ShadeInput *shi= ((ShaderCallData *)data)->shi;
|
|
|
|
/* out: global, local, view, orco, uv, normal */
|
|
VECCOPY(out[GEOM_OUT_GLOB]->vec, shi->gl);
|
|
VECCOPY(out[GEOM_OUT_LOCAL]->vec, shi->co);
|
|
VECCOPY(out[GEOM_OUT_VIEW]->vec, shi->view);
|
|
VECCOPY(out[GEOM_OUT_ORCO]->vec, shi->lo);
|
|
VECCOPY(out[GEOM_OUT_UV]->vec, shi->uv);
|
|
VECCOPY(out[GEOM_OUT_NORMAL]->vec, shi->vno);
|
|
|
|
if(shi->osatex) {
|
|
out[GEOM_OUT_GLOB]->data= shi->dxgl;
|
|
out[GEOM_OUT_GLOB]->datatype= NS_OSA_VECTORS;
|
|
out[GEOM_OUT_LOCAL]->data= shi->dxco;
|
|
out[GEOM_OUT_LOCAL]->datatype= NS_OSA_VECTORS;
|
|
out[GEOM_OUT_VIEW]->data= &shi->dxview;
|
|
out[GEOM_OUT_VIEW]->datatype= NS_OSA_VALUES;
|
|
out[GEOM_OUT_ORCO]->data= shi->dxlo;
|
|
out[GEOM_OUT_ORCO]->datatype= NS_OSA_VECTORS;
|
|
out[GEOM_OUT_UV]->data= shi->dxuv;
|
|
out[GEOM_OUT_UV]->datatype= NS_OSA_VECTORS;
|
|
out[GEOM_OUT_NORMAL]->data= shi->dxno;
|
|
out[GEOM_OUT_NORMAL]->datatype= NS_OSA_VECTORS;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* node type definition */
|
|
static bNodeType sh_node_geom= {
|
|
/* type code */ SH_NODE_GEOMETRY,
|
|
/* name */ "Geometry",
|
|
/* width+range */ 90, 40, 100,
|
|
/* class+opts */ NODE_CLASS_INPUT, 0,
|
|
/* input sock */ NULL,
|
|
/* output sock */ sh_node_geom_out,
|
|
/* storage */ "",
|
|
/* execfunc */ node_shader_exec_geom
|
|
|
|
};
|
|
|
|
/* **************** MATERIAL ******************** */
|
|
|
|
/* input socket defines */
|
|
#define MAT_IN_COLOR 0
|
|
#define MAT_IN_SPEC 1
|
|
#define MAT_IN_REFL 2
|
|
#define MAT_IN_NORMAL 3
|
|
|
|
static bNodeSocketType sh_node_material_in[]= {
|
|
{ SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ SOCK_RGBA, 1, "Spec", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ SOCK_VALUE, 1, "Refl", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ SOCK_VECTOR, 1, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
/* output socket defines */
|
|
#define MAT_OUT_COLOR 0
|
|
#define MAT_OUT_ALPHA 1
|
|
#define MAT_OUT_NORMAL 2
|
|
|
|
static bNodeSocketType sh_node_material_out[]= {
|
|
{ SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ SOCK_VALUE, 0, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
|
|
{ SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_material(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
if(data && node->id) {
|
|
ShadeResult shrnode;
|
|
ShadeInput *shi;
|
|
ShaderCallData *shcd= data;
|
|
float col[4], *nor;
|
|
|
|
shi= shcd->shi;
|
|
shi->mat= (Material *)node->id;
|
|
|
|
/* copy all relevant material vars, note, keep this synced with render_types.h */
|
|
memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));
|
|
shi->har= shi->mat->har;
|
|
|
|
/* write values */
|
|
if(in[MAT_IN_COLOR]->hasinput)
|
|
nodestack_get_vec(&shi->r, SOCK_VECTOR, in[MAT_IN_COLOR]);
|
|
|
|
if(in[MAT_IN_SPEC]->hasinput)
|
|
nodestack_get_vec(&shi->specr, SOCK_VECTOR, in[MAT_IN_SPEC]);
|
|
|
|
if(in[MAT_IN_REFL]->hasinput)
|
|
nodestack_get_vec(&shi->refl, SOCK_VALUE, in[MAT_IN_REFL]);
|
|
|
|
/* retrieve normal */
|
|
if(in[MAT_IN_NORMAL]->hasinput) {
|
|
nodestack_get_vec(nor, SOCK_VECTOR, in[MAT_IN_NORMAL]);
|
|
Normalise(nor);
|
|
}
|
|
else
|
|
nor= shi->vno;
|
|
|
|
/* custom option to flip normal */
|
|
if(node->custom1 & SH_NODE_MAT_NEG) {
|
|
shi->vn[0]= -nor[0];
|
|
shi->vn[1]= -nor[1];
|
|
shi->vn[2]= -nor[2];
|
|
}
|
|
else {
|
|
VECCOPY(shi->vn, nor);
|
|
}
|
|
|
|
node_shader_lamp_loop(shi, &shrnode); /* clears shrnode */
|
|
|
|
/* write to outputs */
|
|
if(node->custom1 & SH_NODE_MAT_DIFF) {
|
|
VECCOPY(col, shrnode.combined);
|
|
if(!(node->custom1 & SH_NODE_MAT_SPEC)) {
|
|
VecSubf(col, col, shrnode.spec);
|
|
}
|
|
}
|
|
else if(node->custom1 & SH_NODE_MAT_SPEC) {
|
|
VECCOPY(col, shrnode.spec);
|
|
}
|
|
else
|
|
col[0]= col[1]= col[2]= 0.0f;
|
|
|
|
col[3]= shrnode.alpha;
|
|
|
|
if(shi->do_preview)
|
|
nodeAddToPreview(node, col, shi->xs, shi->ys);
|
|
|
|
VECCOPY(out[MAT_OUT_COLOR]->vec, col);
|
|
out[MAT_OUT_ALPHA]->vec[0]= shrnode.alpha;
|
|
|
|
if(node->custom1 & SH_NODE_MAT_NEG) {
|
|
shi->vn[0]= -shi->vn[0];
|
|
shi->vn[1]= -shi->vn[1];
|
|
shi->vn[2]= -shi->vn[2];
|
|
}
|
|
|
|
VECCOPY(out[MAT_OUT_NORMAL]->vec, shi->vn);
|
|
|
|
/* copy passes, now just active node */
|
|
if(node->flag & NODE_ACTIVE)
|
|
*(shcd->shr)= shrnode;
|
|
}
|
|
}
|
|
|
|
static bNodeType sh_node_material= {
|
|
/* type code */ SH_NODE_MATERIAL,
|
|
/* name */ "Material",
|
|
/* width+range */ 120, 80, 240,
|
|
/* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW,
|
|
/* input sock */ sh_node_material_in,
|
|
/* output sock */ sh_node_material_out,
|
|
/* storage */ "",
|
|
/* execfunc */ node_shader_exec_material
|
|
|
|
};
|
|
|
|
/* **************** TEXTURE ******************** */
|
|
static bNodeSocketType sh_node_texture_in[]= {
|
|
{ SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, /* no limit */
|
|
{ -1, 0, "" }
|
|
};
|
|
static bNodeSocketType sh_node_texture_out[]= {
|
|
{ SOCK_VALUE, 0, "Value", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ SOCK_RGBA , 0, "Color", 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
|
|
{ SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_texture(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
if(data && node->id) {
|
|
ShadeInput *shi= ((ShaderCallData *)data)->shi;
|
|
TexResult texres;
|
|
float vec[3], nor[3]={0.0f, 0.0f, 0.0f};
|
|
int retval;
|
|
|
|
/* out: value, color, normal */
|
|
|
|
/* we should find out if a normal as output is needed, for now we do all */
|
|
texres.nor= nor;
|
|
|
|
if(in[0]->hasinput) {
|
|
nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
|
|
|
|
if(in[0]->datatype==NS_OSA_VECTORS) {
|
|
float *fp= in[0]->data;
|
|
retval= multitex_ext((Tex *)node->id, vec, fp, fp+3, shi->osatex, &texres);
|
|
}
|
|
else if(in[0]->datatype==NS_OSA_VALUES) {
|
|
float *fp= in[0]->data;
|
|
float dxt[3], dyt[3];
|
|
|
|
dxt[0]= fp[0]; dxt[1]= dxt[2]= 0.0f;
|
|
dyt[0]= fp[1]; dyt[1]= dyt[2]= 0.0f;
|
|
retval= multitex_ext((Tex *)node->id, vec, dxt, dyt, shi->osatex, &texres);
|
|
}
|
|
else
|
|
retval= multitex_ext((Tex *)node->id, vec, NULL, NULL, 0, &texres);
|
|
}
|
|
else { /* only for previewrender, so we see stuff */
|
|
VECCOPY(vec, shi->lo);
|
|
retval= multitex_ext((Tex *)node->id, vec, NULL, NULL, 0, &texres);
|
|
}
|
|
|
|
/* stupid exception */
|
|
if( ((Tex *)node->id)->type==TEX_STUCCI) {
|
|
texres.tin= 0.5f + 0.7f*texres.nor[0];
|
|
CLAMP(texres.tin, 0.0f, 1.0f);
|
|
}
|
|
|
|
/* intensity and color need some handling */
|
|
if(texres.talpha)
|
|
out[0]->vec[0]= texres.ta;
|
|
else
|
|
out[0]->vec[0]= texres.tin;
|
|
|
|
if((retval & TEX_RGB)==0) {
|
|
out[1]->vec[0]= out[0]->vec[0];
|
|
out[1]->vec[1]= out[0]->vec[0];
|
|
out[1]->vec[2]= out[0]->vec[0];
|
|
out[1]->vec[3]= 1.0f;
|
|
}
|
|
else {
|
|
out[1]->vec[0]= texres.tr;
|
|
out[1]->vec[1]= texres.tg;
|
|
out[1]->vec[2]= texres.tb;
|
|
out[1]->vec[3]= 1.0f;
|
|
}
|
|
|
|
VECCOPY(out[2]->vec, nor);
|
|
|
|
if(shi->do_preview)
|
|
nodeAddToPreview(node, out[1]->vec, shi->xs, shi->ys);
|
|
|
|
}
|
|
}
|
|
|
|
static bNodeType sh_node_texture= {
|
|
/* type code */ SH_NODE_TEXTURE,
|
|
/* name */ "Texture",
|
|
/* width+range */ 120, 80, 240,
|
|
/* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW,
|
|
/* input sock */ sh_node_texture_in,
|
|
/* output sock */ sh_node_texture_out,
|
|
/* storage */ "",
|
|
/* execfunc */ node_shader_exec_texture
|
|
|
|
};
|
|
|
|
/* **************** MAPPING ******************** */
|
|
static bNodeSocketType sh_node_mapping_in[]= {
|
|
{ SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static bNodeSocketType sh_node_mapping_out[]= {
|
|
{ SOCK_VECTOR, 0, "Vector", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
/* do the regular mapping options for blender textures */
|
|
static void node_shader_exec_mapping(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
TexMapping *texmap= node->storage;
|
|
float *vec= out[0]->vec;
|
|
|
|
/* stack order input: vector */
|
|
/* stack order output: vector */
|
|
nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
|
|
Mat4MulVecfl(texmap->mat, vec);
|
|
|
|
if(texmap->flag & TEXMAP_CLIP_MIN) {
|
|
if(vec[0]<texmap->min[0]) vec[0]= texmap->min[0];
|
|
if(vec[1]<texmap->min[1]) vec[1]= texmap->min[1];
|
|
if(vec[2]<texmap->min[2]) vec[2]= texmap->min[2];
|
|
}
|
|
if(texmap->flag & TEXMAP_CLIP_MAX) {
|
|
if(vec[0]>texmap->max[0]) vec[0]= texmap->max[0];
|
|
if(vec[1]>texmap->max[1]) vec[1]= texmap->max[1];
|
|
if(vec[2]>texmap->max[2]) vec[2]= texmap->max[2];
|
|
}
|
|
}
|
|
|
|
static bNodeType sh_node_mapping= {
|
|
/* type code */ SH_NODE_MAPPING,
|
|
/* name */ "Mapping",
|
|
/* width+range */ 240, 160, 320,
|
|
/* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS,
|
|
/* input sock */ sh_node_mapping_in,
|
|
/* output sock */ sh_node_mapping_out,
|
|
/* storage */ "TexMapping",
|
|
/* execfunc */ node_shader_exec_mapping
|
|
|
|
};
|
|
|
|
/* **************** CAMERA INFO ******************** */
|
|
static bNodeSocketType sh_node_camera_out[]= {
|
|
{ SOCK_VECTOR, 0, "View Vector", 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f}, /* None of these actually */
|
|
{ SOCK_VALUE, 0, "View Z Depth", 0.f, 0.0f, 0.0f, 0.0f, 0.0f, 99999999999.0f}, /* have any limits on their */
|
|
{ SOCK_VALUE, 0, "View Distance", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 99999999999.0f}, /* values. */
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
|
|
static void node_shader_exec_camera(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
if(data) {
|
|
ShadeInput *shi= ((ShaderCallData *)data)->shi; /* Data we need for shading. */
|
|
|
|
VECCOPY(out[0]->vec, shi->co); /* get view vector */
|
|
out[1]->vec[0]= fabs(shi->co[2]); /* get view z-depth */
|
|
out[2]->vec[0]= Normalise(out[0]->vec); /* get view distance */
|
|
}
|
|
}
|
|
|
|
static bNodeType sh_node_camera= {
|
|
/* type code */ SH_NODE_CAMERA,
|
|
/* name */ "Camera Data",
|
|
/* width+range */ 95, 95, 120,
|
|
/* class+opts */ NODE_CLASS_INPUT, 0,
|
|
/* input sock */ NULL,
|
|
/* output sock */ sh_node_camera_out,
|
|
/* storage */ "node_camera",
|
|
/* execfunc */ node_shader_exec_camera
|
|
};
|
|
|
|
/* **************** SCALAR MATH ******************** */
|
|
static bNodeSocketType sh_node_math_in[]= {
|
|
{ SOCK_VALUE, 1, "Value", 0.5f, 0.5f, 0.5f, 1.0f, -100.0f, 100.0f},
|
|
{ SOCK_VALUE, 1, "Value", 0.5f, 0.5f, 0.5f, 1.0f, -100.0f, 100.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static bNodeSocketType sh_node_math_out[]= {
|
|
{ SOCK_VALUE, 0, "Value", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_math(void *data, bNode *node, bNodeStack **in,
|
|
bNodeStack **out)
|
|
{
|
|
switch(node->custom1){
|
|
|
|
case 0: /* Add */
|
|
out[0]->vec[0]= in[0]->vec[0] + in[1]->vec[0];
|
|
break;
|
|
case 1: /* Subtract */
|
|
out[0]->vec[0]= in[0]->vec[0] - in[1]->vec[0];
|
|
break;
|
|
case 2: /* Multiply */
|
|
out[0]->vec[0]= in[0]->vec[0] * in[1]->vec[0];
|
|
break;
|
|
case 3: /* Divide */
|
|
{
|
|
if(in[1]->vec[0]==0) /* We don't want to divide by zero. */
|
|
out[0]->vec[0]= 0.0;
|
|
else
|
|
out[0]->vec[0]= in[0]->vec[0] / in[1]->vec[0];
|
|
}
|
|
break;
|
|
case 4: /* Sine */
|
|
{
|
|
if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
|
|
out[0]->vec[0]= sin(in[0]->vec[0]);
|
|
else
|
|
out[0]->vec[0]= sin(in[1]->vec[0]);
|
|
}
|
|
break;
|
|
case 5: /* Cosine */
|
|
{
|
|
if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
|
|
out[0]->vec[0]= cos(in[0]->vec[0]);
|
|
else
|
|
out[0]->vec[0]= cos(in[1]->vec[0]);
|
|
}
|
|
break;
|
|
case 6: /* Tangent */
|
|
{
|
|
if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
|
|
out[0]->vec[0]= tan(in[0]->vec[0]);
|
|
else
|
|
out[0]->vec[0]= tan(in[1]->vec[0]);
|
|
}
|
|
break;
|
|
case 7: /* Arc-Sine */
|
|
{
|
|
if(in[0]->hasinput || !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */
|
|
/* Can't do the impossible... */
|
|
if( in[0]->vec[0] <= 1 && in[0]->vec[0] >= -1 )
|
|
out[0]->vec[0]= asin(in[0]->vec[0]);
|
|
else
|
|
out[0]->vec[0]= 0.0;
|
|
}
|
|
else {
|
|
/* Can't do the impossible... */
|
|
if( in[1]->vec[0] <= 1 && in[1]->vec[0] >= -1 )
|
|
out[0]->vec[0]= asin(in[1]->vec[0]);
|
|
else
|
|
out[0]->vec[0]= 0.0;
|
|
}
|
|
}
|
|
break;
|
|
case 8: /* Arc-Cosine */
|
|
{
|
|
if(in[0]->hasinput || !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */
|
|
/* Can't do the impossible... */
|
|
if( in[0]->vec[0] <= 1 && in[0]->vec[0] >= -1 )
|
|
out[0]->vec[0]= acos(in[0]->vec[0]);
|
|
else
|
|
out[0]->vec[0]= 0.0;
|
|
}
|
|
else {
|
|
/* Can't do the impossible... */
|
|
if( in[1]->vec[0] <= 1 && in[1]->vec[0] >= -1 )
|
|
out[0]->vec[0]= acos(in[1]->vec[0]);
|
|
else
|
|
out[0]->vec[0]= 0.0;
|
|
}
|
|
}
|
|
break;
|
|
case 9: /* Arc-Tangent */
|
|
{
|
|
if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
|
|
out[0]->vec[0]= atan(in[0]->vec[0]);
|
|
else
|
|
out[0]->vec[0]= atan(in[1]->vec[0]);
|
|
}
|
|
break;
|
|
case 10: /* Power */
|
|
{
|
|
/* Don't want any imaginary numbers... */
|
|
if( in[0]->vec[0] >= 0 )
|
|
out[0]->vec[0]= pow(in[0]->vec[0], in[1]->vec[0]);
|
|
else
|
|
out[0]->vec[0]= 0.0;
|
|
}
|
|
break;
|
|
case 11: /* Logarithm */
|
|
{
|
|
/* Don't want any imaginary numbers... */
|
|
if( in[0]->vec[0] > 0 && in[1]->vec[0] > 0 )
|
|
out[0]->vec[0]= log(in[0]->vec[0]) / log(in[1]->vec[0]);
|
|
else
|
|
out[0]->vec[0]= 0.0;
|
|
}
|
|
break;
|
|
case 12: /* Minimum */
|
|
{
|
|
if( in[0]->vec[0] < in[1]->vec[0] )
|
|
out[0]->vec[0]= in[1]->vec[0];
|
|
else
|
|
out[0]->vec[0]= in[0]->vec[0];
|
|
}
|
|
break;
|
|
case 13: /* Maximum */
|
|
{
|
|
if( in[0]->vec[0] > in[1]->vec[0] )
|
|
out[0]->vec[0]= in[1]->vec[0];
|
|
else
|
|
out[0]->vec[0]= in[0]->vec[0];
|
|
}
|
|
break;
|
|
case 14: /* Round */
|
|
{
|
|
if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
|
|
out[0]->vec[0]= (int)(in[0]->vec[0] + 0.5f);
|
|
else
|
|
out[0]->vec[0]= (int)(in[1]->vec[0] + 0.5f);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static bNodeType sh_node_math= {
|
|
/* type code */ SH_NODE_MATH,
|
|
/* name */ "Math",
|
|
/* width+range */ 120, 110, 160,
|
|
/* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
|
|
/* input sock */ sh_node_math_in,
|
|
/* output sock */ sh_node_math_out,
|
|
/* storage */ "node_math",
|
|
/* execfunc */ node_shader_exec_math
|
|
};
|
|
|
|
/* **************** VALUE SQUEEZE ******************** */
|
|
static bNodeSocketType sh_node_squeeze_in[]= {
|
|
{ SOCK_VALUE, 1, "Value", 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f},
|
|
{ SOCK_VALUE, 1, "Width", 1.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f},
|
|
{ SOCK_VALUE, 1, "Center", 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static bNodeSocketType sh_node_squeeze_out[]= {
|
|
{ SOCK_VALUE, 0, "Value", 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_squeeze(void *data, bNode *node, bNodeStack **in,
|
|
bNodeStack **out)
|
|
{
|
|
float vec[3];
|
|
|
|
nodestack_get_vec(vec, SOCK_VALUE, in[0]);
|
|
nodestack_get_vec(vec+1, SOCK_VALUE, in[1]);
|
|
nodestack_get_vec(vec+2, SOCK_VALUE, in[2]);
|
|
|
|
out[0]->vec[0] = 1.0f / (1.0f + pow(2.71828183,-((vec[0]-vec[2])*vec[1]))) ;
|
|
}
|
|
|
|
static bNodeType sh_node_squeeze= {
|
|
/* type code */ SH_NODE_SQUEEZE,
|
|
/* name */ "Squeeze Value",
|
|
/* width+range */ 120, 110, 160,
|
|
/* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
|
|
/* input sock */ sh_node_squeeze_in,
|
|
/* output sock */ sh_node_squeeze_out,
|
|
/* storage */ "node_squeeze",
|
|
/* execfunc */ node_shader_exec_squeeze
|
|
};
|
|
|
|
|
|
|
|
/* **************** VECTOR MATH ******************** */
|
|
static bNodeSocketType sh_node_vect_math_in[]= {
|
|
{ SOCK_VECTOR, 1, "Vector", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
|
|
{ SOCK_VECTOR, 1, "Vector", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static bNodeSocketType sh_node_vect_math_out[]= {
|
|
{ SOCK_VECTOR, 0, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ SOCK_VALUE, 0, "Value", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_vect_math(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
float vec1[3], vec2[3];
|
|
|
|
nodestack_get_vec(vec1, SOCK_VECTOR, in[0]);
|
|
nodestack_get_vec(vec1, SOCK_VECTOR, in[1]);
|
|
|
|
if(node->custom1 == 0) { /* Add */
|
|
out[0]->vec[0]= vec1[0] + vec2[0];
|
|
out[0]->vec[1]= vec1[1] + vec2[1];
|
|
out[0]->vec[2]= vec1[2] + vec2[2];
|
|
|
|
out[1]->vec[0]= (fabs(out[0]->vec[0]) + fabs(out[0]->vec[0]) + fabs(out[0]->vec[0])) / 3;
|
|
}
|
|
else if(node->custom1 == 1) { /* Subtract */
|
|
out[0]->vec[0]= vec1[0] - vec2[0];
|
|
out[0]->vec[1]= vec1[1] - vec2[1];
|
|
out[0]->vec[2]= vec1[2] - vec2[2];
|
|
|
|
out[1]->vec[0]= (fabs(out[0]->vec[0]) + fabs(out[0]->vec[0]) + fabs(out[0]->vec[0])) / 3;
|
|
}
|
|
else if(node->custom1 == 2) { /* Average */
|
|
out[0]->vec[0]= vec1[0] + vec2[0];
|
|
out[0]->vec[1]= vec1[1] + vec2[1];
|
|
out[0]->vec[2]= vec1[2] + vec2[2];
|
|
|
|
out[1]->vec[0] = Normalise( out[0]->vec );
|
|
}
|
|
else if(node->custom1 == 3) { /* Dot product */
|
|
out[1]->vec[0]= (vec1[0] * vec2[0]) + (vec1[1] * vec2[1]) + (vec1[2] * vec2[2]);
|
|
}
|
|
else if(node->custom1 == 4) { /* Cross product */
|
|
out[0]->vec[0]= (vec1[1] * vec2[2]) - (vec1[2] * vec2[1]);
|
|
out[0]->vec[1]= (vec1[2] * vec2[0]) - (vec1[0] * vec2[2]);
|
|
out[0]->vec[2]= (vec1[0] * vec2[1]) - (vec1[1] * vec2[0]);
|
|
|
|
out[1]->vec[0] = Normalise( out[0]->vec );
|
|
}
|
|
else if(node->custom1 == 5) { /* Normalize */
|
|
if(in[0]->hasinput || !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */
|
|
out[0]->vec[0]= vec1[0];
|
|
out[0]->vec[1]= vec1[1];
|
|
out[0]->vec[2]= vec1[2];
|
|
}
|
|
else {
|
|
out[0]->vec[0]= vec2[0];
|
|
out[0]->vec[1]= vec2[1];
|
|
out[0]->vec[2]= vec2[2];
|
|
}
|
|
|
|
out[1]->vec[0] = Normalise( out[0]->vec );
|
|
}
|
|
|
|
}
|
|
|
|
static bNodeType sh_node_vect_math= {
|
|
/* type code */ SH_NODE_VECT_MATH,
|
|
/* name */ "Vector Math",
|
|
/* width+range */ 80, 75, 140,
|
|
/* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
|
|
/* input sock */ sh_node_vect_math_in,
|
|
/* output sock */ sh_node_vect_math_out,
|
|
/* storage */ "node_vect_math",
|
|
/* execfunc */ node_shader_exec_vect_math
|
|
};
|
|
|
|
/* **************** NORMAL ******************** */
|
|
static bNodeSocketType sh_node_normal_in[]= {
|
|
{ SOCK_VECTOR, 1, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static bNodeSocketType sh_node_normal_out[]= {
|
|
{ SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
|
|
{ SOCK_VALUE, 0, "Dot", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
/* generates normal, does dot product */
|
|
static void node_shader_exec_normal(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
bNodeSocket *sock= node->outputs.first;
|
|
float vec[3];
|
|
|
|
/* stack order input: normal */
|
|
/* stack order output: normal, value */
|
|
|
|
nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
|
|
|
|
VECCOPY(out[0]->vec, sock->ns.vec);
|
|
/* render normals point inside... the widget points outside */
|
|
out[1]->vec[0]= -INPR(out[0]->vec, vec);
|
|
}
|
|
|
|
static bNodeType sh_node_normal= {
|
|
/* type code */ SH_NODE_NORMAL,
|
|
/* name */ "Normal",
|
|
/* width+range */ 100, 60, 200,
|
|
/* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS,
|
|
/* input sock */ sh_node_normal_in,
|
|
/* output sock */ sh_node_normal_out,
|
|
/* storage */ "",
|
|
/* execfunc */ node_shader_exec_normal
|
|
|
|
};
|
|
|
|
/* **************** CURVE VEC ******************** */
|
|
static bNodeSocketType sh_node_curve_vec_in[]= {
|
|
{ SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static bNodeSocketType sh_node_curve_vec_out[]= {
|
|
{ SOCK_VECTOR, 0, "Vector", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_curve_vec(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
float vec[3];
|
|
|
|
/* stack order input: vec */
|
|
/* stack order output: vec */
|
|
nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
|
|
curvemapping_evaluate3F(node->storage, out[0]->vec, vec);
|
|
}
|
|
|
|
static bNodeType sh_node_curve_vec= {
|
|
/* type code */ SH_NODE_CURVE_VEC,
|
|
/* name */ "Vector Curves",
|
|
/* width+range */ 200, 140, 320,
|
|
/* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS,
|
|
/* input sock */ sh_node_curve_vec_in,
|
|
/* output sock */ sh_node_curve_vec_out,
|
|
/* storage */ "CurveMapping",
|
|
/* execfunc */ node_shader_exec_curve_vec
|
|
|
|
};
|
|
|
|
/* **************** CURVE RGB ******************** */
|
|
static bNodeSocketType sh_node_curve_rgb_in[]= {
|
|
{ SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static bNodeSocketType sh_node_curve_rgb_out[]= {
|
|
{ SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_curve_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
float vec[3];
|
|
|
|
/* stack order input: vec */
|
|
/* stack order output: vec */
|
|
nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
|
|
curvemapping_evaluateRGBF(node->storage, out[0]->vec, vec);
|
|
}
|
|
|
|
static bNodeType sh_node_curve_rgb= {
|
|
/* type code */ SH_NODE_CURVE_RGB,
|
|
/* name */ "RGB Curves",
|
|
/* width+range */ 200, 140, 320,
|
|
/* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS,
|
|
/* input sock */ sh_node_curve_rgb_in,
|
|
/* output sock */ sh_node_curve_rgb_out,
|
|
/* storage */ "CurveMapping",
|
|
/* execfunc */ node_shader_exec_curve_rgb
|
|
|
|
};
|
|
|
|
/* **************** VALUE ******************** */
|
|
static bNodeSocketType sh_node_value_out[]= {
|
|
{ SOCK_VALUE, 0, "Value", 0.5f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_value(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
bNodeSocket *sock= node->outputs.first;
|
|
|
|
out[0]->vec[0]= sock->ns.vec[0];
|
|
}
|
|
|
|
static bNodeType sh_node_value= {
|
|
/* type code */ SH_NODE_VALUE,
|
|
/* name */ "Value",
|
|
/* width+range */ 80, 50, 120,
|
|
/* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS,
|
|
/* input sock */ NULL,
|
|
/* output sock */ sh_node_value_out,
|
|
/* storage */ "",
|
|
/* execfunc */ node_shader_exec_value
|
|
|
|
};
|
|
|
|
/* **************** RGB ******************** */
|
|
static bNodeSocketType sh_node_rgb_out[]= {
|
|
{ SOCK_RGBA, 0, "Color", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
bNodeSocket *sock= node->outputs.first;
|
|
|
|
VECCOPY(out[0]->vec, sock->ns.vec);
|
|
}
|
|
|
|
static bNodeType sh_node_rgb= {
|
|
/* type code */ SH_NODE_RGB,
|
|
/* name */ "RGB",
|
|
/* width+range */ 100, 60, 140,
|
|
/* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS,
|
|
/* input sock */ NULL,
|
|
/* output sock */ sh_node_rgb_out,
|
|
/* storage */ "",
|
|
/* execfunc */ node_shader_exec_rgb
|
|
|
|
};
|
|
|
|
/* **************** MIX RGB ******************** */
|
|
static bNodeSocketType sh_node_mix_rgb_in[]= {
|
|
{ SOCK_VALUE, 1, "Fac", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
|
|
{ SOCK_RGBA, 1, "Color1", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
|
|
{ SOCK_RGBA, 1, "Color2", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
static bNodeSocketType sh_node_mix_rgb_out[]= {
|
|
{ SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_mix_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
/* stack order in: fac, col1, col2 */
|
|
/* stack order out: col */
|
|
float col[3];
|
|
float fac;
|
|
float vec[3];
|
|
|
|
nodestack_get_vec(&fac, SOCK_VALUE, in[0]);
|
|
CLAMP(fac, 0.0f, 1.0f);
|
|
|
|
nodestack_get_vec(col, SOCK_VECTOR, in[1]);
|
|
nodestack_get_vec(vec, SOCK_VECTOR, in[2]);
|
|
|
|
ramp_blend(node->custom1, col, col+1, col+2, fac, vec);
|
|
VECCOPY(out[0]->vec, col);
|
|
}
|
|
|
|
static bNodeType sh_node_mix_rgb= {
|
|
/* type code */ SH_NODE_MIX_RGB,
|
|
/* name */ "Mix",
|
|
/* width+range */ 100, 60, 150,
|
|
/* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS,
|
|
/* input sock */ sh_node_mix_rgb_in,
|
|
/* output sock */ sh_node_mix_rgb_out,
|
|
/* storage */ "",
|
|
/* execfunc */ node_shader_exec_mix_rgb
|
|
|
|
};
|
|
|
|
|
|
/* **************** VALTORGB ******************** */
|
|
static bNodeSocketType sh_node_valtorgb_in[]= {
|
|
{ SOCK_VALUE, 1, "Fac", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
static bNodeSocketType sh_node_valtorgb_out[]= {
|
|
{ SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ SOCK_VALUE, 0, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
static void node_shader_exec_valtorgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
/* stack order in: fac */
|
|
/* stack order out: col, alpha */
|
|
|
|
if(node->storage) {
|
|
float fac;
|
|
nodestack_get_vec(&fac, SOCK_VALUE, in[0]);
|
|
|
|
do_colorband(node->storage, fac, out[0]->vec);
|
|
out[1]->vec[0]= out[0]->vec[3];
|
|
}
|
|
}
|
|
|
|
static bNodeType sh_node_valtorgb= {
|
|
/* type code */ SH_NODE_VALTORGB,
|
|
/* name */ "ColorRamp",
|
|
/* width+range */ 240, 200, 300,
|
|
/* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
|
|
/* input sock */ sh_node_valtorgb_in,
|
|
/* output sock */ sh_node_valtorgb_out,
|
|
/* storage */ "ColorBand",
|
|
/* execfunc */ node_shader_exec_valtorgb
|
|
|
|
};
|
|
|
|
|
|
/* **************** RGBTOBW ******************** */
|
|
static bNodeSocketType sh_node_rgbtobw_in[]= {
|
|
{ SOCK_RGBA, 1, "Color", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
static bNodeSocketType sh_node_rgbtobw_out[]= {
|
|
{ SOCK_VALUE, 0, "Val", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
|
{ -1, 0, "" }
|
|
};
|
|
|
|
|
|
static void node_shader_exec_rgbtobw(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
|
|
{
|
|
/* stack order out: bw */
|
|
/* stack order in: col */
|
|
|
|
out[0]->vec[0]= in[0]->vec[0]*0.35f + in[0]->vec[1]*0.45f + in[0]->vec[2]*0.2f;
|
|
}
|
|
|
|
static bNodeType sh_node_rgbtobw= {
|
|
/* type code */ SH_NODE_RGBTOBW,
|
|
/* name */ "RGB to BW",
|
|
/* width+range */ 80, 40, 120,
|
|
/* class+opts */ NODE_CLASS_CONVERTOR, 0,
|
|
/* input sock */ sh_node_rgbtobw_in,
|
|
/* output sock */ sh_node_rgbtobw_out,
|
|
/* storage */ "",
|
|
/* execfunc */ node_shader_exec_rgbtobw
|
|
|
|
};
|
|
|
|
|
|
/* ****************** types array for all shaders ****************** */
|
|
|
|
bNodeType *node_all_shaders[]= {
|
|
&node_group_typeinfo,
|
|
&sh_node_output,
|
|
&sh_node_material,
|
|
&sh_node_camera,
|
|
&sh_node_value,
|
|
&sh_node_rgb,
|
|
&sh_node_mix_rgb,
|
|
&sh_node_valtorgb,
|
|
&sh_node_rgbtobw,
|
|
&sh_node_texture,
|
|
&sh_node_normal,
|
|
&sh_node_geom,
|
|
&sh_node_mapping,
|
|
&sh_node_curve_vec,
|
|
&sh_node_curve_rgb,
|
|
&sh_node_math,
|
|
&sh_node_vect_math,
|
|
&sh_node_squeeze,
|
|
NULL
|
|
};
|
|
|
|
/* ******************* execute and parse ************ */
|
|
|
|
void ntreeShaderExecTree(bNodeTree *ntree, ShadeInput *shi, ShadeResult *shr)
|
|
{
|
|
ShaderCallData scd;
|
|
|
|
/* convert caller data to struct */
|
|
scd.shi= shi;
|
|
scd.shr= shr;
|
|
|
|
ntreeExecTree(ntree, &scd, shi->thread); /* threads */
|
|
|
|
/* better not allow negative for now */
|
|
if(shr->combined[0]<0.0f) shr->combined[0]= 0.0f;
|
|
if(shr->combined[1]<0.0f) shr->combined[1]= 0.0f;
|
|
if(shr->combined[2]<0.0f) shr->combined[2]= 0.0f;
|
|
|
|
}
|
|
|
|
/* go over all used Geometry and Texture nodes, and return a texco flag */
|
|
/* no group inside needed, this function is called for groups too */
|
|
int ntreeShaderGetTexco(bNodeTree *ntree, int r_mode)
|
|
{
|
|
bNode *node;
|
|
bNodeSocket *sock;
|
|
int texco= 0, a;
|
|
|
|
ntreeSocketUseFlags(ntree);
|
|
|
|
for(node= ntree->nodes.first; node; node= node->next) {
|
|
if(node->type==SH_NODE_TEXTURE) {
|
|
if((r_mode & R_OSA) && node->id) {
|
|
Tex *tex= (Tex *)node->id;
|
|
if ELEM3(tex->type, TEX_IMAGE, TEX_PLUGIN, TEX_ENVMAP)
|
|
texco |= TEXCO_OSA|NEED_UV;
|
|
}
|
|
}
|
|
else if(node->type==SH_NODE_GEOMETRY) {
|
|
/* note; sockets always exist for the given type! */
|
|
for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) {
|
|
if(sock->flag & SOCK_IN_USE) {
|
|
switch(a) {
|
|
case GEOM_OUT_GLOB:
|
|
texco |= TEXCO_GLOB|NEED_UV; break;
|
|
case GEOM_OUT_VIEW:
|
|
texco |= TEXCO_VIEW|NEED_UV; break;
|
|
case GEOM_OUT_ORCO:
|
|
texco |= TEXCO_ORCO|NEED_UV; break;
|
|
case GEOM_OUT_UV:
|
|
texco |= TEXCO_UV|NEED_UV; break;
|
|
case GEOM_OUT_NORMAL:
|
|
texco |= TEXCO_NORM|NEED_UV; break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return texco;
|
|
}
|
|
|
|
/* nodes that use ID data get synced with local data */
|
|
void nodeShaderSynchronizeID(bNode *node, int copyto)
|
|
{
|
|
if(node->id==NULL) return;
|
|
|
|
if(node->type==SH_NODE_MATERIAL) {
|
|
bNodeSocket *sock;
|
|
Material *ma= (Material *)node->id;
|
|
int a;
|
|
|
|
/* hrmf, case in loop isnt super fast, but we dont edit 100s of material at same time either! */
|
|
for(a=0, sock= node->inputs.first; sock; sock= sock->next, a++) {
|
|
if(!(sock->flag & SOCK_HIDDEN)) {
|
|
if(copyto) {
|
|
switch(a) {
|
|
case MAT_IN_COLOR:
|
|
VECCOPY(&ma->r, sock->ns.vec); break;
|
|
case MAT_IN_SPEC:
|
|
VECCOPY(&ma->specr, sock->ns.vec); break;
|
|
case MAT_IN_REFL:
|
|
ma->ref= sock->ns.vec[0]; break;
|
|
}
|
|
}
|
|
else {
|
|
switch(a) {
|
|
case MAT_IN_COLOR:
|
|
VECCOPY(sock->ns.vec, &ma->r); break;
|
|
case MAT_IN_SPEC:
|
|
VECCOPY(sock->ns.vec, &ma->specr); break;
|
|
case MAT_IN_REFL:
|
|
sock->ns.vec[0]= ma->ref; break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|