This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/blenkernel/intern/node_shaders.c
Ton Roosendaal 7f1e3874f9 Node editing usablity!
- 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
2006-12-08 21:20:36 +00:00

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;
}
}
}
}
}
}