2
* $Id: node_shaders.c,v 1.21 2007/02/01 20:38:37 sirdude Exp $
4
* ***** BEGIN GPL LICENSE BLOCK *****
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License
8
* as published by the Free Software Foundation; either version 2
9
* of the License, or (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software Foundation,
18
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
* The Original Code is Copyright (C) 2005 Blender Foundation.
21
* All rights reserved.
23
* The Original Code is: all of this file.
25
* Contributor(s): none yet.
27
* ***** END GPL LICENSE BLOCK *****
35
#include "DNA_material_types.h"
36
#include "DNA_node_types.h"
37
#include "DNA_scene_types.h"
38
#include "DNA_texture_types.h"
40
#include "BKE_blender.h"
41
#include "BKE_colortools.h"
43
#include "BKE_material.h"
44
#include "BKE_texture.h"
45
#include "BKE_utildefines.h"
47
#include "BLI_arithb.h"
48
#include "BLI_blenlib.h"
50
#include "MEM_guardedalloc.h"
52
#include "RE_shader_ext.h" /* <- ShadeInput Shaderesult TexResult */
55
/* ********* exec data struct, remains internal *********** */
57
typedef struct ShaderCallData {
58
ShadeInput *shi; /* from render pipe */
59
ShadeResult *shr; /* from render pipe */
63
/* **************** call to switch lamploop for material node ************ */
65
static void (*node_shader_lamp_loop)(ShadeInput *, ShadeResult *);
67
void set_node_shader_lamp_loop(void (*lamp_loop_func)(ShadeInput *, ShadeResult *))
69
node_shader_lamp_loop= lamp_loop_func;
74
static void nodestack_get_vec(float *in, short type_in, bNodeStack *ns)
78
if(type_in==SOCK_VALUE) {
79
if(ns->sockettype==SOCK_VALUE)
82
*in= 0.333333f*(from[0]+from[1]+from[2]);
84
else if(type_in==SOCK_VECTOR) {
85
if(ns->sockettype==SOCK_VALUE) {
94
else { /* type_in==SOCK_RGBA */
95
if(ns->sockettype==SOCK_RGBA) {
98
else if(ns->sockettype==SOCK_VALUE) {
111
/* ******************************************************** */
112
/* ********* Shader Node type definitions ***************** */
113
/* ******************************************************** */
115
/* SocketType syntax:
116
socket type, max connections (0 is no limit), name, 4 values for default, 2 values for range */
118
/* Verification rule: If name changes, a saved socket and its links will be removed! Type changes are OK */
120
/* **************** OUTPUT ******************** */
121
static bNodeSocketType sh_node_output_in[]= {
122
{ SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
123
{ SOCK_VALUE, 1, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
127
static void node_shader_exec_output(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
130
ShadeInput *shi= ((ShaderCallData *)data)->shi;
133
/* stack order input sockets: col, alpha, normal */
134
nodestack_get_vec(col, SOCK_VECTOR, in[0]);
135
nodestack_get_vec(col+3, SOCK_VALUE, in[1]);
137
if(shi->do_preview) {
138
nodeAddToPreview(node, col, shi->xs, shi->ys);
139
node->lasty= shi->ys;
142
if(node->flag & NODE_DO_OUTPUT) {
143
ShadeResult *shr= ((ShaderCallData *)data)->shr;
145
QUATCOPY(shr->combined, col);
148
// VECCOPY(shr->nor, in[3]->vec);
153
static bNodeType sh_node_output= {
154
/* type code */ SH_NODE_OUTPUT,
156
/* width+range */ 80, 60, 200,
157
/* class+opts */ NODE_CLASS_OUTPUT, NODE_PREVIEW,
158
/* input sock */ sh_node_output_in,
159
/* output sock */ NULL,
161
/* execfunc */ node_shader_exec_output
165
/* **************** GEOMETRY ******************** */
167
/* output socket defines */
168
#define GEOM_OUT_GLOB 0
169
#define GEOM_OUT_LOCAL 1
170
#define GEOM_OUT_VIEW 2
171
#define GEOM_OUT_ORCO 3
172
#define GEOM_OUT_UV 4
173
#define GEOM_OUT_NORMAL 5
174
#define GEOM_OUT_VCOL 6
176
/* output socket type definition */
177
static bNodeSocketType sh_node_geom_out[]= {
178
{ SOCK_VECTOR, 0, "Global", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, /* btw; uses no limit */
179
{ SOCK_VECTOR, 0, "Local", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
180
{ SOCK_VECTOR, 0, "View", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
181
{ SOCK_VECTOR, 0, "Orco", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
182
{ SOCK_VECTOR, 0, "UV", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
183
{ SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
184
{ SOCK_RGBA, 0, "Vertex Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
188
/* node execute callback */
189
static void node_shader_exec_geom(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
192
ShadeInput *shi= ((ShaderCallData *)data)->shi;
193
NodeGeometry *ngeo= (NodeGeometry*)node->storage;
194
ShadeInputUV *suv= &shi->uv[0];
195
static float defaultvcol[4] = {1.0f, 1.0f, 1.0f, 1.0f};
198
if(ngeo->uvname[0]) {
199
/* find uv layer by name */
200
for(i = 0; i < shi->totuv; i++) {
201
if(strcmp(shi->uv[i].name, ngeo->uvname)==0) {
208
/* out: global, local, view, orco, uv, normal, vertex color */
209
VECCOPY(out[GEOM_OUT_GLOB]->vec, shi->gl);
210
VECCOPY(out[GEOM_OUT_LOCAL]->vec, shi->co);
211
VECCOPY(out[GEOM_OUT_VIEW]->vec, shi->view);
212
VECCOPY(out[GEOM_OUT_ORCO]->vec, shi->lo);
213
VECCOPY(out[GEOM_OUT_UV]->vec, suv->uv);
214
VECCOPY(out[GEOM_OUT_NORMAL]->vec, shi->vno);
217
/* find vertex color layer by name */
218
ShadeInputCol *scol= &shi->col[0];
220
if(ngeo->colname[0]) {
221
for(i = 0; i < shi->totcol; i++) {
222
if(strcmp(shi->col[i].name, ngeo->colname)==0) {
229
VECCOPY(out[GEOM_OUT_VCOL]->vec, scol->col);
230
out[GEOM_OUT_VCOL]->vec[3]= 1.0f;
233
memcpy(out[GEOM_OUT_VCOL]->vec, defaultvcol, sizeof(defaultvcol));
236
out[GEOM_OUT_GLOB]->data= shi->dxgl;
237
out[GEOM_OUT_GLOB]->datatype= NS_OSA_VECTORS;
238
out[GEOM_OUT_LOCAL]->data= shi->dxco;
239
out[GEOM_OUT_LOCAL]->datatype= NS_OSA_VECTORS;
240
out[GEOM_OUT_VIEW]->data= &shi->dxview;
241
out[GEOM_OUT_VIEW]->datatype= NS_OSA_VALUES;
242
out[GEOM_OUT_ORCO]->data= shi->dxlo;
243
out[GEOM_OUT_ORCO]->datatype= NS_OSA_VECTORS;
244
out[GEOM_OUT_UV]->data= suv->dxuv;
245
out[GEOM_OUT_UV]->datatype= NS_OSA_VECTORS;
246
out[GEOM_OUT_NORMAL]->data= shi->dxno;
247
out[GEOM_OUT_NORMAL]->datatype= NS_OSA_VECTORS;
252
/* node type definition */
253
static bNodeType sh_node_geom= {
254
/* type code */ SH_NODE_GEOMETRY,
255
/* name */ "Geometry",
256
/* width+range */ 120, 80, 160,
257
/* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS,
258
/* input sock */ NULL,
259
/* output sock */ sh_node_geom_out,
260
/* storage */ "NodeGeometry",
261
/* execfunc */ node_shader_exec_geom
265
/* **************** MATERIAL ******************** */
267
/* input socket defines */
268
#define MAT_IN_COLOR 0
269
#define MAT_IN_SPEC 1
270
#define MAT_IN_REFL 2
271
#define MAT_IN_NORMAL 3
273
static bNodeSocketType sh_node_material_in[]= {
274
{ SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
275
{ SOCK_RGBA, 1, "Spec", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
276
{ SOCK_VALUE, 1, "Refl", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
277
{ SOCK_VECTOR, 1, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
281
/* output socket defines */
282
#define MAT_OUT_COLOR 0
283
#define MAT_OUT_ALPHA 1
284
#define MAT_OUT_NORMAL 2
286
static bNodeSocketType sh_node_material_out[]= {
287
{ SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
288
{ SOCK_VALUE, 0, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
289
{ SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
293
static void node_shader_exec_material(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
295
if(data && node->id) {
298
ShaderCallData *shcd= data;
302
shi->mat= (Material *)node->id;
304
/* copy all relevant material vars, note, keep this synced with render_types.h */
305
memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));
306
shi->har= shi->mat->har;
309
if(in[MAT_IN_COLOR]->hasinput)
310
nodestack_get_vec(&shi->r, SOCK_VECTOR, in[MAT_IN_COLOR]);
312
if(in[MAT_IN_SPEC]->hasinput)
313
nodestack_get_vec(&shi->specr, SOCK_VECTOR, in[MAT_IN_SPEC]);
315
if(in[MAT_IN_REFL]->hasinput)
316
nodestack_get_vec(&shi->refl, SOCK_VALUE, in[MAT_IN_REFL]);
318
/* retrieve normal */
319
if(in[MAT_IN_NORMAL]->hasinput) {
320
nodestack_get_vec(shi->vn, SOCK_VECTOR, in[MAT_IN_NORMAL]);
324
VECCOPY(shi->vn, shi->vno);
326
/* custom option to flip normal */
327
if(node->custom1 & SH_NODE_MAT_NEG) {
328
shi->vn[0]= -shi->vn[0];
329
shi->vn[1]= -shi->vn[1];
330
shi->vn[2]= -shi->vn[2];
333
node_shader_lamp_loop(shi, &shrnode); /* clears shrnode */
335
/* write to outputs */
336
if(node->custom1 & SH_NODE_MAT_DIFF) {
337
VECCOPY(col, shrnode.combined);
338
if(!(node->custom1 & SH_NODE_MAT_SPEC)) {
339
VecSubf(col, col, shrnode.spec);
342
else if(node->custom1 & SH_NODE_MAT_SPEC) {
343
VECCOPY(col, shrnode.spec);
346
col[0]= col[1]= col[2]= 0.0f;
348
col[3]= shrnode.alpha;
351
nodeAddToPreview(node, col, shi->xs, shi->ys);
353
VECCOPY(out[MAT_OUT_COLOR]->vec, col);
354
out[MAT_OUT_ALPHA]->vec[0]= shrnode.alpha;
356
if(node->custom1 & SH_NODE_MAT_NEG) {
357
shi->vn[0]= -shi->vn[0];
358
shi->vn[1]= -shi->vn[1];
359
shi->vn[2]= -shi->vn[2];
362
VECCOPY(out[MAT_OUT_NORMAL]->vec, shi->vn);
364
/* copy passes, now just active node */
365
if(node->flag & NODE_ACTIVE_ID)
366
*(shcd->shr)= shrnode;
370
static bNodeType sh_node_material= {
371
/* type code */ SH_NODE_MATERIAL,
372
/* name */ "Material",
373
/* width+range */ 120, 80, 240,
374
/* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW,
375
/* input sock */ sh_node_material_in,
376
/* output sock */ sh_node_material_out,
378
/* execfunc */ node_shader_exec_material
382
/* **************** TEXTURE ******************** */
383
static bNodeSocketType sh_node_texture_in[]= {
384
{ SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, /* no limit */
387
static bNodeSocketType sh_node_texture_out[]= {
388
{ SOCK_VALUE, 0, "Value", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
389
{ SOCK_RGBA , 0, "Color", 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
390
{ SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
394
static void node_shader_exec_texture(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
396
if(data && node->id) {
397
ShadeInput *shi= ((ShaderCallData *)data)->shi;
399
float vec[3], nor[3]={0.0f, 0.0f, 0.0f};
402
/* out: value, color, normal */
404
/* we should find out if a normal as output is needed, for now we do all */
407
if(in[0]->hasinput) {
408
nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
410
if(in[0]->datatype==NS_OSA_VECTORS) {
411
float *fp= in[0]->data;
412
retval= multitex_ext((Tex *)node->id, vec, fp, fp+3, shi->osatex, &texres);
414
else if(in[0]->datatype==NS_OSA_VALUES) {
415
float *fp= in[0]->data;
416
float dxt[3], dyt[3];
418
dxt[0]= fp[0]; dxt[1]= dxt[2]= 0.0f;
419
dyt[0]= fp[1]; dyt[1]= dyt[2]= 0.0f;
420
retval= multitex_ext((Tex *)node->id, vec, dxt, dyt, shi->osatex, &texres);
423
retval= multitex_ext((Tex *)node->id, vec, NULL, NULL, 0, &texres);
425
else { /* only for previewrender, so we see stuff */
426
VECCOPY(vec, shi->lo);
427
retval= multitex_ext((Tex *)node->id, vec, NULL, NULL, 0, &texres);
430
/* stupid exception */
431
if( ((Tex *)node->id)->type==TEX_STUCCI) {
432
texres.tin= 0.5f + 0.7f*texres.nor[0];
433
CLAMP(texres.tin, 0.0f, 1.0f);
436
/* intensity and color need some handling */
438
out[0]->vec[0]= texres.ta;
440
out[0]->vec[0]= texres.tin;
442
if((retval & TEX_RGB)==0) {
443
out[1]->vec[0]= out[0]->vec[0];
444
out[1]->vec[1]= out[0]->vec[0];
445
out[1]->vec[2]= out[0]->vec[0];
446
out[1]->vec[3]= 1.0f;
449
out[1]->vec[0]= texres.tr;
450
out[1]->vec[1]= texres.tg;
451
out[1]->vec[2]= texres.tb;
452
out[1]->vec[3]= 1.0f;
455
VECCOPY(out[2]->vec, nor);
458
nodeAddToPreview(node, out[1]->vec, shi->xs, shi->ys);
463
static bNodeType sh_node_texture= {
464
/* type code */ SH_NODE_TEXTURE,
465
/* name */ "Texture",
466
/* width+range */ 120, 80, 240,
467
/* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW,
468
/* input sock */ sh_node_texture_in,
469
/* output sock */ sh_node_texture_out,
471
/* execfunc */ node_shader_exec_texture
475
/* **************** MAPPING ******************** */
476
static bNodeSocketType sh_node_mapping_in[]= {
477
{ SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
481
static bNodeSocketType sh_node_mapping_out[]= {
482
{ SOCK_VECTOR, 0, "Vector", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
486
/* do the regular mapping options for blender textures */
487
static void node_shader_exec_mapping(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
489
TexMapping *texmap= node->storage;
490
float *vec= out[0]->vec;
492
/* stack order input: vector */
493
/* stack order output: vector */
494
nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
495
Mat4MulVecfl(texmap->mat, vec);
497
if(texmap->flag & TEXMAP_CLIP_MIN) {
498
if(vec[0]<texmap->min[0]) vec[0]= texmap->min[0];
499
if(vec[1]<texmap->min[1]) vec[1]= texmap->min[1];
500
if(vec[2]<texmap->min[2]) vec[2]= texmap->min[2];
502
if(texmap->flag & TEXMAP_CLIP_MAX) {
503
if(vec[0]>texmap->max[0]) vec[0]= texmap->max[0];
504
if(vec[1]>texmap->max[1]) vec[1]= texmap->max[1];
505
if(vec[2]>texmap->max[2]) vec[2]= texmap->max[2];
509
static bNodeType sh_node_mapping= {
510
/* type code */ SH_NODE_MAPPING,
511
/* name */ "Mapping",
512
/* width+range */ 240, 160, 320,
513
/* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS,
514
/* input sock */ sh_node_mapping_in,
515
/* output sock */ sh_node_mapping_out,
516
/* storage */ "TexMapping",
517
/* execfunc */ node_shader_exec_mapping
521
/* **************** CAMERA INFO ******************** */
522
static bNodeSocketType sh_node_camera_out[]= {
523
{ SOCK_VECTOR, 0, "View Vector", 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f}, /* None of these actually */
524
{ SOCK_VALUE, 0, "View Z Depth", 0.f, 0.0f, 0.0f, 0.0f, 0.0f, 99999999999.0f}, /* have any limits on their */
525
{ SOCK_VALUE, 0, "View Distance", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 99999999999.0f}, /* values. */
530
static void node_shader_exec_camera(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
533
ShadeInput *shi= ((ShaderCallData *)data)->shi; /* Data we need for shading. */
535
VECCOPY(out[0]->vec, shi->co); /* get view vector */
536
out[1]->vec[0]= fabs(shi->co[2]); /* get view z-depth */
537
out[2]->vec[0]= Normalise(out[0]->vec); /* get view distance */
541
static bNodeType sh_node_camera= {
542
/* type code */ SH_NODE_CAMERA,
543
/* name */ "Camera Data",
544
/* width+range */ 95, 95, 120,
545
/* class+opts */ NODE_CLASS_INPUT, 0,
546
/* input sock */ NULL,
547
/* output sock */ sh_node_camera_out,
548
/* storage */ "node_camera",
549
/* execfunc */ node_shader_exec_camera
552
/* **************** SCALAR MATH ******************** */
553
static bNodeSocketType sh_node_math_in[]= {
554
{ SOCK_VALUE, 1, "Value", 0.5f, 0.5f, 0.5f, 1.0f, -100.0f, 100.0f},
555
{ SOCK_VALUE, 1, "Value", 0.5f, 0.5f, 0.5f, 1.0f, -100.0f, 100.0f},
559
static bNodeSocketType sh_node_math_out[]= {
560
{ SOCK_VALUE, 0, "Value", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
564
static void node_shader_exec_math(void *data, bNode *node, bNodeStack **in,
567
switch(node->custom1){
570
out[0]->vec[0]= in[0]->vec[0] + in[1]->vec[0];
572
case 1: /* Subtract */
573
out[0]->vec[0]= in[0]->vec[0] - in[1]->vec[0];
575
case 2: /* Multiply */
576
out[0]->vec[0]= in[0]->vec[0] * in[1]->vec[0];
580
if(in[1]->vec[0]==0) /* We don't want to divide by zero. */
583
out[0]->vec[0]= in[0]->vec[0] / in[1]->vec[0];
588
if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
589
out[0]->vec[0]= sin(in[0]->vec[0]);
591
out[0]->vec[0]= sin(in[1]->vec[0]);
596
if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
597
out[0]->vec[0]= cos(in[0]->vec[0]);
599
out[0]->vec[0]= cos(in[1]->vec[0]);
602
case 6: /* Tangent */
604
if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
605
out[0]->vec[0]= tan(in[0]->vec[0]);
607
out[0]->vec[0]= tan(in[1]->vec[0]);
610
case 7: /* Arc-Sine */
612
if(in[0]->hasinput || !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */
613
/* Can't do the impossible... */
614
if( in[0]->vec[0] <= 1 && in[0]->vec[0] >= -1 )
615
out[0]->vec[0]= asin(in[0]->vec[0]);
620
/* Can't do the impossible... */
621
if( in[1]->vec[0] <= 1 && in[1]->vec[0] >= -1 )
622
out[0]->vec[0]= asin(in[1]->vec[0]);
628
case 8: /* Arc-Cosine */
630
if(in[0]->hasinput || !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */
631
/* Can't do the impossible... */
632
if( in[0]->vec[0] <= 1 && in[0]->vec[0] >= -1 )
633
out[0]->vec[0]= acos(in[0]->vec[0]);
638
/* Can't do the impossible... */
639
if( in[1]->vec[0] <= 1 && in[1]->vec[0] >= -1 )
640
out[0]->vec[0]= acos(in[1]->vec[0]);
646
case 9: /* Arc-Tangent */
648
if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
649
out[0]->vec[0]= atan(in[0]->vec[0]);
651
out[0]->vec[0]= atan(in[1]->vec[0]);
656
/* Don't want any imaginary numbers... */
657
if( in[0]->vec[0] >= 0 )
658
out[0]->vec[0]= pow(in[0]->vec[0], in[1]->vec[0]);
663
case 11: /* Logarithm */
665
/* Don't want any imaginary numbers... */
666
if( in[0]->vec[0] > 0 && in[1]->vec[0] > 0 )
667
out[0]->vec[0]= log(in[0]->vec[0]) / log(in[1]->vec[0]);
672
case 12: /* Minimum */
674
if( in[0]->vec[0] < in[1]->vec[0] )
675
out[0]->vec[0]= in[0]->vec[0];
677
out[0]->vec[0]= in[1]->vec[0];
680
case 13: /* Maximum */
682
if( in[0]->vec[0] > in[1]->vec[0] )
683
out[0]->vec[0]= in[0]->vec[0];
685
out[0]->vec[0]= in[1]->vec[0];
690
if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
691
out[0]->vec[0]= (int)(in[0]->vec[0] + 0.5f);
693
out[0]->vec[0]= (int)(in[1]->vec[0] + 0.5f);
699
static bNodeType sh_node_math= {
700
/* type code */ SH_NODE_MATH,
702
/* width+range */ 120, 110, 160,
703
/* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
704
/* input sock */ sh_node_math_in,
705
/* output sock */ sh_node_math_out,
706
/* storage */ "node_math",
707
/* execfunc */ node_shader_exec_math
710
/* **************** VALUE SQUEEZE ******************** */
711
static bNodeSocketType sh_node_squeeze_in[]= {
712
{ SOCK_VALUE, 1, "Value", 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f},
713
{ SOCK_VALUE, 1, "Width", 1.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f},
714
{ SOCK_VALUE, 1, "Center", 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f},
718
static bNodeSocketType sh_node_squeeze_out[]= {
719
{ SOCK_VALUE, 0, "Value", 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
723
static void node_shader_exec_squeeze(void *data, bNode *node, bNodeStack **in,
728
nodestack_get_vec(vec, SOCK_VALUE, in[0]);
729
nodestack_get_vec(vec+1, SOCK_VALUE, in[1]);
730
nodestack_get_vec(vec+2, SOCK_VALUE, in[2]);
732
out[0]->vec[0] = 1.0f / (1.0f + pow(2.71828183,-((vec[0]-vec[2])*vec[1]))) ;
735
static bNodeType sh_node_squeeze= {
736
/* type code */ SH_NODE_SQUEEZE,
737
/* name */ "Squeeze Value",
738
/* width+range */ 120, 110, 160,
739
/* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
740
/* input sock */ sh_node_squeeze_in,
741
/* output sock */ sh_node_squeeze_out,
742
/* storage */ "node_squeeze",
743
/* execfunc */ node_shader_exec_squeeze
748
/* **************** VECTOR MATH ******************** */
749
static bNodeSocketType sh_node_vect_math_in[]= {
750
{ SOCK_VECTOR, 1, "Vector", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
751
{ SOCK_VECTOR, 1, "Vector", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
755
static bNodeSocketType sh_node_vect_math_out[]= {
756
{ SOCK_VECTOR, 0, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
757
{ SOCK_VALUE, 0, "Value", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
761
static void node_shader_exec_vect_math(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
763
float vec1[3], vec2[3];
765
nodestack_get_vec(vec1, SOCK_VECTOR, in[0]);
766
nodestack_get_vec(vec2, SOCK_VECTOR, in[1]);
768
if(node->custom1 == 0) { /* Add */
769
out[0]->vec[0]= vec1[0] + vec2[0];
770
out[0]->vec[1]= vec1[1] + vec2[1];
771
out[0]->vec[2]= vec1[2] + vec2[2];
773
out[1]->vec[0]= (fabs(out[0]->vec[0]) + fabs(out[0]->vec[0]) + fabs(out[0]->vec[0])) / 3;
775
else if(node->custom1 == 1) { /* Subtract */
776
out[0]->vec[0]= vec1[0] - vec2[0];
777
out[0]->vec[1]= vec1[1] - vec2[1];
778
out[0]->vec[2]= vec1[2] - vec2[2];
780
out[1]->vec[0]= (fabs(out[0]->vec[0]) + fabs(out[0]->vec[0]) + fabs(out[0]->vec[0])) / 3;
782
else if(node->custom1 == 2) { /* Average */
783
out[0]->vec[0]= vec1[0] + vec2[0];
784
out[0]->vec[1]= vec1[1] + vec2[1];
785
out[0]->vec[2]= vec1[2] + vec2[2];
787
out[1]->vec[0] = Normalise( out[0]->vec );
789
else if(node->custom1 == 3) { /* Dot product */
790
out[1]->vec[0]= (vec1[0] * vec2[0]) + (vec1[1] * vec2[1]) + (vec1[2] * vec2[2]);
792
else if(node->custom1 == 4) { /* Cross product */
793
out[0]->vec[0]= (vec1[1] * vec2[2]) - (vec1[2] * vec2[1]);
794
out[0]->vec[1]= (vec1[2] * vec2[0]) - (vec1[0] * vec2[2]);
795
out[0]->vec[2]= (vec1[0] * vec2[1]) - (vec1[1] * vec2[0]);
797
out[1]->vec[0] = Normalise( out[0]->vec );
799
else if(node->custom1 == 5) { /* Normalize */
800
if(in[0]->hasinput || !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */
801
out[0]->vec[0]= vec1[0];
802
out[0]->vec[1]= vec1[1];
803
out[0]->vec[2]= vec1[2];
806
out[0]->vec[0]= vec2[0];
807
out[0]->vec[1]= vec2[1];
808
out[0]->vec[2]= vec2[2];
811
out[1]->vec[0] = Normalise( out[0]->vec );
816
static bNodeType sh_node_vect_math= {
817
/* type code */ SH_NODE_VECT_MATH,
818
/* name */ "Vector Math",
819
/* width+range */ 80, 75, 140,
820
/* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
821
/* input sock */ sh_node_vect_math_in,
822
/* output sock */ sh_node_vect_math_out,
823
/* storage */ "node_vect_math",
824
/* execfunc */ node_shader_exec_vect_math
827
/* **************** NORMAL ******************** */
828
static bNodeSocketType sh_node_normal_in[]= {
829
{ SOCK_VECTOR, 1, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
833
static bNodeSocketType sh_node_normal_out[]= {
834
{ SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
835
{ SOCK_VALUE, 0, "Dot", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
839
/* generates normal, does dot product */
840
static void node_shader_exec_normal(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
842
bNodeSocket *sock= node->outputs.first;
845
/* stack order input: normal */
846
/* stack order output: normal, value */
848
nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
850
VECCOPY(out[0]->vec, sock->ns.vec);
851
/* render normals point inside... the widget points outside */
852
out[1]->vec[0]= -INPR(out[0]->vec, vec);
855
static bNodeType sh_node_normal= {
856
/* type code */ SH_NODE_NORMAL,
858
/* width+range */ 100, 60, 200,
859
/* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS,
860
/* input sock */ sh_node_normal_in,
861
/* output sock */ sh_node_normal_out,
863
/* execfunc */ node_shader_exec_normal
867
/* **************** CURVE VEC ******************** */
868
static bNodeSocketType sh_node_curve_vec_in[]= {
869
{ SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
873
static bNodeSocketType sh_node_curve_vec_out[]= {
874
{ SOCK_VECTOR, 0, "Vector", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
878
static void node_shader_exec_curve_vec(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
882
/* stack order input: vec */
883
/* stack order output: vec */
884
nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
885
curvemapping_evaluate3F(node->storage, out[0]->vec, vec);
888
static bNodeType sh_node_curve_vec= {
889
/* type code */ SH_NODE_CURVE_VEC,
890
/* name */ "Vector Curves",
891
/* width+range */ 200, 140, 320,
892
/* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS,
893
/* input sock */ sh_node_curve_vec_in,
894
/* output sock */ sh_node_curve_vec_out,
895
/* storage */ "CurveMapping",
896
/* execfunc */ node_shader_exec_curve_vec
900
/* **************** CURVE RGB ******************** */
901
static bNodeSocketType sh_node_curve_rgb_in[]= {
902
{ SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
906
static bNodeSocketType sh_node_curve_rgb_out[]= {
907
{ SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
911
static void node_shader_exec_curve_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
915
/* stack order input: vec */
916
/* stack order output: vec */
917
nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
918
curvemapping_evaluateRGBF(node->storage, out[0]->vec, vec);
921
static bNodeType sh_node_curve_rgb= {
922
/* type code */ SH_NODE_CURVE_RGB,
923
/* name */ "RGB Curves",
924
/* width+range */ 200, 140, 320,
925
/* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS,
926
/* input sock */ sh_node_curve_rgb_in,
927
/* output sock */ sh_node_curve_rgb_out,
928
/* storage */ "CurveMapping",
929
/* execfunc */ node_shader_exec_curve_rgb
933
/* **************** VALUE ******************** */
934
static bNodeSocketType sh_node_value_out[]= {
935
{ SOCK_VALUE, 0, "Value", 0.5f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f},
939
static void node_shader_exec_value(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
941
bNodeSocket *sock= node->outputs.first;
943
out[0]->vec[0]= sock->ns.vec[0];
946
static bNodeType sh_node_value= {
947
/* type code */ SH_NODE_VALUE,
949
/* width+range */ 80, 50, 120,
950
/* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS,
951
/* input sock */ NULL,
952
/* output sock */ sh_node_value_out,
954
/* execfunc */ node_shader_exec_value
958
/* **************** RGB ******************** */
959
static bNodeSocketType sh_node_rgb_out[]= {
960
{ SOCK_RGBA, 0, "Color", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
964
static void node_shader_exec_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
966
bNodeSocket *sock= node->outputs.first;
968
VECCOPY(out[0]->vec, sock->ns.vec);
971
static bNodeType sh_node_rgb= {
972
/* type code */ SH_NODE_RGB,
974
/* width+range */ 100, 60, 140,
975
/* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS,
976
/* input sock */ NULL,
977
/* output sock */ sh_node_rgb_out,
979
/* execfunc */ node_shader_exec_rgb
983
/* **************** MIX RGB ******************** */
984
static bNodeSocketType sh_node_mix_rgb_in[]= {
985
{ SOCK_VALUE, 1, "Fac", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
986
{ SOCK_RGBA, 1, "Color1", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
987
{ SOCK_RGBA, 1, "Color2", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
990
static bNodeSocketType sh_node_mix_rgb_out[]= {
991
{ SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
995
static void node_shader_exec_mix_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
997
/* stack order in: fac, col1, col2 */
998
/* stack order out: col */
1003
nodestack_get_vec(&fac, SOCK_VALUE, in[0]);
1004
CLAMP(fac, 0.0f, 1.0f);
1006
nodestack_get_vec(col, SOCK_VECTOR, in[1]);
1007
nodestack_get_vec(vec, SOCK_VECTOR, in[2]);
1009
ramp_blend(node->custom1, col, col+1, col+2, fac, vec);
1010
VECCOPY(out[0]->vec, col);
1013
static bNodeType sh_node_mix_rgb= {
1014
/* type code */ SH_NODE_MIX_RGB,
1016
/* width+range */ 100, 60, 150,
1017
/* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS,
1018
/* input sock */ sh_node_mix_rgb_in,
1019
/* output sock */ sh_node_mix_rgb_out,
1021
/* execfunc */ node_shader_exec_mix_rgb
1026
/* **************** VALTORGB ******************** */
1027
static bNodeSocketType sh_node_valtorgb_in[]= {
1028
{ SOCK_VALUE, 1, "Fac", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1031
static bNodeSocketType sh_node_valtorgb_out[]= {
1032
{ SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1033
{ SOCK_VALUE, 0, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
1037
static void node_shader_exec_valtorgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1039
/* stack order in: fac */
1040
/* stack order out: col, alpha */
1044
nodestack_get_vec(&fac, SOCK_VALUE, in[0]);
1046
do_colorband(node->storage, fac, out[0]->vec);
1047
out[1]->vec[0]= out[0]->vec[3];
1051
static bNodeType sh_node_valtorgb= {
1052
/* type code */ SH_NODE_VALTORGB,
1053
/* name */ "ColorRamp",
1054
/* width+range */ 240, 200, 300,
1055
/* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
1056
/* input sock */ sh_node_valtorgb_in,
1057
/* output sock */ sh_node_valtorgb_out,
1058
/* storage */ "ColorBand",
1059
/* execfunc */ node_shader_exec_valtorgb
1064
/* **************** RGBTOBW ******************** */
1065
static bNodeSocketType sh_node_rgbtobw_in[]= {
1066
{ SOCK_RGBA, 1, "Color", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
1069
static bNodeSocketType sh_node_rgbtobw_out[]= {
1070
{ SOCK_VALUE, 0, "Val", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
1075
static void node_shader_exec_rgbtobw(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
1077
/* stack order out: bw */
1078
/* stack order in: col */
1080
out[0]->vec[0]= in[0]->vec[0]*0.35f + in[0]->vec[1]*0.45f + in[0]->vec[2]*0.2f;
1083
static bNodeType sh_node_rgbtobw= {
1084
/* type code */ SH_NODE_RGBTOBW,
1085
/* name */ "RGB to BW",
1086
/* width+range */ 80, 40, 120,
1087
/* class+opts */ NODE_CLASS_CONVERTOR, 0,
1088
/* input sock */ sh_node_rgbtobw_in,
1089
/* output sock */ sh_node_rgbtobw_out,
1091
/* execfunc */ node_shader_exec_rgbtobw
1095
/* ****************** types array for all shaders ****************** */
1097
bNodeType *node_all_shaders[]= {
1098
&node_group_typeinfo,
1119
/* ******************* execute and parse ************ */
1121
void ntreeShaderExecTree(bNodeTree *ntree, ShadeInput *shi, ShadeResult *shr)
1125
/* convert caller data to struct */
1128
/* each material node has own local shaderesult, with optional copying */
1129
memset(shr, 0, sizeof(ShadeResult));
1131
ntreeExecTree(ntree, &scd, shi->thread); /* threads */
1133
/* better not allow negative for now */
1134
if(shr->combined[0]<0.0f) shr->combined[0]= 0.0f;
1135
if(shr->combined[1]<0.0f) shr->combined[1]= 0.0f;
1136
if(shr->combined[2]<0.0f) shr->combined[2]= 0.0f;
1140
/* go over all used Geometry and Texture nodes, and return a texco flag */
1141
/* no group inside needed, this function is called for groups too */
1142
void ntreeShaderGetTexcoMode(bNodeTree *ntree, int r_mode, short *texco, int *mode)
1148
ntreeSocketUseFlags(ntree);
1150
for(node= ntree->nodes.first; node; node= node->next) {
1151
if(node->type==SH_NODE_TEXTURE) {
1152
if((r_mode & R_OSA) && node->id) {
1153
Tex *tex= (Tex *)node->id;
1154
if ELEM3(tex->type, TEX_IMAGE, TEX_PLUGIN, TEX_ENVMAP)
1155
*texco |= TEXCO_OSA|NEED_UV;
1157
/* usability exception... without input we still give the node orcos */
1158
sock= node->inputs.first;
1159
if(sock==NULL || sock->link==NULL)
1160
*texco |= TEXCO_ORCO|NEED_UV;
1162
else if(node->type==SH_NODE_GEOMETRY) {
1163
/* note; sockets always exist for the given type! */
1164
for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) {
1165
if(sock->flag & SOCK_IN_USE) {
1168
*texco |= TEXCO_GLOB|NEED_UV; break;
1170
*texco |= TEXCO_VIEW|NEED_UV; break;
1172
*texco |= TEXCO_ORCO|NEED_UV; break;
1174
*texco |= TEXCO_UV|NEED_UV; break;
1175
case GEOM_OUT_NORMAL:
1176
*texco |= TEXCO_NORM|NEED_UV; break;
1178
*texco |= NEED_UV; *mode |= MA_VERTEXCOL; break;
1186
/* nodes that use ID data get synced with local data */
1187
void nodeShaderSynchronizeID(bNode *node, int copyto)
1189
if(node->id==NULL) return;
1191
if(node->type==SH_NODE_MATERIAL) {
1193
Material *ma= (Material *)node->id;
1196
/* hrmf, case in loop isnt super fast, but we dont edit 100s of material at same time either! */
1197
for(a=0, sock= node->inputs.first; sock; sock= sock->next, a++) {
1198
if(!(sock->flag & SOCK_HIDDEN)) {
1202
VECCOPY(&ma->r, sock->ns.vec); break;
1204
VECCOPY(&ma->specr, sock->ns.vec); break;
1206
ma->ref= sock->ns.vec[0]; break;
1212
VECCOPY(sock->ns.vec, &ma->r); break;
1214
VECCOPY(sock->ns.vec, &ma->specr); break;
1216
sock->ns.vec[0]= ma->ref; break;