Final merge of HEAD (bf-blender) into the orange branch.
[blender.git] / source / blender / blenkernel / intern / node_shaders.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
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. 
10  *
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.
15  *
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.
19  *
20  * The Original Code is Copyright (C) 2005 Blender Foundation.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "DNA_ID.h"
34 #include "DNA_material_types.h"
35 #include "DNA_node_types.h"
36 #include "DNA_texture_types.h"
37
38 #include "BKE_blender.h"
39 #include "BKE_colortools.h"
40 #include "BKE_node.h"
41 #include "BKE_material.h"
42 #include "BKE_texture.h"
43 #include "BKE_utildefines.h"
44
45 #include "BLI_arithb.h"
46 #include "BLI_blenlib.h"
47
48 #include "MEM_guardedalloc.h"
49
50 #include "RE_shader_ext.h"              /* <- ShadeInput Shaderesult TexResult */
51
52
53 /* ********* exec data struct, remains internal *********** */
54
55 typedef struct ShaderCallData {
56         ShadeInput *shi;
57         ShadeResult *shr;
58 } ShaderCallData;
59
60
61 /* **************** call to switch lamploop for material node ************ */
62
63 static void (*node_shader_lamp_loop)(ShadeInput *, ShadeResult *);
64                                                                          
65 void set_node_shader_lamp_loop(void (*lamp_loop_func)(ShadeInput *, ShadeResult *))
66 {
67         node_shader_lamp_loop= lamp_loop_func;
68 }
69
70
71 /* ******************************************************** */
72 /* ********* Shader Node type definitions ***************** */
73 /* ******************************************************** */
74
75 /* SocketType syntax: 
76    socket type, max connections (0 is no limit), name, 4 values for default, 2 values for range */
77
78 /* Verification rule: If name changes, a saved socket and its links will be removed! Type changes are OK */
79
80 /* **************** OUTPUT ******************** */
81 static bNodeSocketType sh_node_output_in[]= {
82         {       SOCK_RGBA, 1, "Color",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
83         {       SOCK_VALUE, 1, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
84         {       -1, 0, ""       }
85 };
86
87 static void node_shader_exec_output(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
88 {
89         if(data) {
90                 ShadeInput *shi= ((ShaderCallData *)data)->shi;
91                 float col[4];
92                 
93                 /* stack order input sockets: col, alpha, normal */
94                 VECCOPY(col, in[0]->vec);
95                 col[3]= in[1]->vec[0];
96                 
97                 if(shi->do_preview) {
98                         nodeAddToPreview(node, col, shi->xs, shi->ys);
99                         node->lasty= shi->ys;
100                 }
101                 
102                 if(node->flag & NODE_DO_OUTPUT) {
103                         ShadeResult *shr= ((ShaderCallData *)data)->shr;
104                         
105                         VECCOPY(shr->diff, col);
106                         col[0]= col[1]= col[2]= 0.0f;
107                         VECCOPY(shr->spec, col);
108                         shr->alpha= col[3];
109                         
110                         //      VECCOPY(shr->nor, in[3]->vec);
111                 }
112         }       
113 }
114
115 static bNodeType sh_node_output= {
116         /* type code   */       SH_NODE_OUTPUT,
117         /* name        */       "Output",
118         /* width+range */       80, 60, 200,
119         /* class+opts  */       NODE_CLASS_OUTPUT, NODE_PREVIEW,
120         /* input sock  */       sh_node_output_in,
121         /* output sock */       NULL,
122         /* storage     */       "",
123         /* execfunc    */       node_shader_exec_output
124         
125 };
126
127 /* **************** GEOMETRY  ******************** */
128
129 /* output socket defines */
130 #define GEOM_OUT_GLOB   0
131 #define GEOM_OUT_LOCAL  1
132 #define GEOM_OUT_VIEW   2
133 #define GEOM_OUT_ORCO   3
134 #define GEOM_OUT_UV             4
135 #define GEOM_OUT_NORMAL 5
136
137 /* output socket type definition */
138 static bNodeSocketType sh_node_geom_out[]= {
139         {       SOCK_VECTOR, 0, "Global",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},   /* btw; uses no limit */
140         {       SOCK_VECTOR, 0, "Local",        0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
141         {       SOCK_VECTOR, 0, "View", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
142         {       SOCK_VECTOR, 0, "Orco", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
143         {       SOCK_VECTOR, 0, "UV",   0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
144         {       SOCK_VECTOR, 0, "Normal",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
145         {       -1, 0, ""       }
146 };
147
148 /* node execute callback */
149 static void node_shader_exec_geom(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
150 {
151         if(data) {
152                 ShadeInput *shi= ((ShaderCallData *)data)->shi;
153                 
154                 /* out: global, local, view, orco, uv, normal */
155                 VECCOPY(out[GEOM_OUT_GLOB]->vec, shi->gl);
156                 VECCOPY(out[GEOM_OUT_LOCAL]->vec, shi->co);
157                 VECCOPY(out[GEOM_OUT_VIEW]->vec, shi->view);
158                 VECCOPY(out[GEOM_OUT_ORCO]->vec, shi->lo);
159                 VECCOPY(out[GEOM_OUT_UV]->vec, shi->uv);
160                 VECCOPY(out[GEOM_OUT_NORMAL]->vec, shi->vno);
161                 
162                 if(shi->osatex) {
163                         out[GEOM_OUT_GLOB]->data= shi->dxgl;
164                         out[GEOM_OUT_GLOB]->datatype= NS_OSA_VECTORS;
165                         out[GEOM_OUT_LOCAL]->data= shi->dxco;
166                         out[GEOM_OUT_LOCAL]->datatype= NS_OSA_VECTORS;
167                         out[GEOM_OUT_VIEW]->data= &shi->dxview;
168                         out[GEOM_OUT_VIEW]->datatype= NS_OSA_VALUES;
169                         out[GEOM_OUT_ORCO]->data= shi->dxlo;
170                         out[GEOM_OUT_ORCO]->datatype= NS_OSA_VECTORS;
171                         out[GEOM_OUT_UV]->data= shi->dxuv;
172                         out[GEOM_OUT_UV]->datatype= NS_OSA_VECTORS;
173                         out[GEOM_OUT_NORMAL]->data= shi->dxno;
174                         out[GEOM_OUT_NORMAL]->datatype= NS_OSA_VECTORS;
175                 }
176         }
177 }
178
179 /* node type definition */
180 static bNodeType sh_node_geom= {
181         /* type code   */       SH_NODE_GEOMETRY,
182         /* name        */       "Geometry",
183         /* width+range */       60, 40, 100,
184         /* class+opts  */       NODE_CLASS_INPUT, 0,
185         /* input sock  */       NULL,
186         /* output sock */       sh_node_geom_out,
187         /* storage     */       "",
188         /* execfunc    */       node_shader_exec_geom
189         
190 };
191
192 /* **************** MATERIAL ******************** */
193
194 /* input socket defines */
195 #define MAT_IN_COLOR    0
196 #define MAT_IN_SPEC             1
197 #define MAT_IN_REFL             2
198 #define MAT_IN_NORMAL   3
199
200 static bNodeSocketType sh_node_material_in[]= {
201         {       SOCK_RGBA, 1, "Color",          0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
202         {       SOCK_RGBA, 1, "Spec",           0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
203         {       SOCK_VALUE, 1, "Refl",          0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
204         {       SOCK_VECTOR, 1, "Normal",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
205         {       -1, 0, ""       }
206 };
207
208 /* output socket defines */
209 #define MAT_OUT_COLOR   0
210 #define MAT_OUT_ALPHA   1
211 #define MAT_OUT_NORMAL  2
212
213 static bNodeSocketType sh_node_material_out[]= {
214         {       SOCK_RGBA, 0, "Color",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
215         {       SOCK_VALUE, 0, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
216         {       SOCK_VECTOR, 0, "Normal",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
217         {       -1, 0, ""       }
218 };
219
220 static void node_shader_exec_material(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
221 {
222         if(data && node->id) {
223                 ShadeResult shrnode;
224                 ShadeInput *shi;
225                 float col[4], *nor;
226                 
227                 shi= ((ShaderCallData *)data)->shi;
228                 shi->mat= (Material *)node->id;
229                 
230                 /* copy all relevant material vars, note, keep this synced with render_types.h */
231                 memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));
232                 shi->har= shi->mat->har;
233                 
234                 /* write values */
235                 if(in[MAT_IN_COLOR]->hasinput)
236                         VECCOPY(&shi->r,  in[MAT_IN_COLOR]->vec);
237                 
238                 if(in[MAT_IN_SPEC]->hasinput)
239                         VECCOPY(&shi->specr,  in[MAT_IN_SPEC]->vec);
240                 
241                 if(in[MAT_IN_REFL]->hasinput)
242                         shi->mat->ref= in[MAT_IN_REFL]->vec[0]; 
243                 
244                 /* retrieve normal */
245                 if(in[MAT_IN_NORMAL]->hasinput) {
246                         nor= in[MAT_IN_NORMAL]->vec;
247                         Normalise(nor);
248                 }
249                 else
250                         nor= shi->vno;
251                 
252                 /* custom option to flip normal */
253                 if(node->custom1 & SH_NODE_MAT_NEG) {
254                         shi->vn[0]= -nor[0];
255                         shi->vn[1]= -nor[1];
256                         shi->vn[2]= -nor[2];
257                 }
258                 else {
259                         VECCOPY(shi->vn, nor);
260                 }
261                 
262                 node_shader_lamp_loop(shi, &shrnode);
263                 
264                 /* write to outputs */
265                 if(node->custom1 & SH_NODE_MAT_DIFF) {
266                         VECCOPY(col, shrnode.diff);
267                         if(node->custom1 & SH_NODE_MAT_SPEC) {
268                                 VecAddf(col, col, shrnode.spec);
269                         }
270                 }
271                 else if(node->custom1 & SH_NODE_MAT_SPEC) {
272                         VECCOPY(col, shrnode.spec);
273                 }
274                 else
275                         col[0]= col[1]= col[2]= 0.0f;
276                 
277                 col[3]= shrnode.alpha;
278                 
279                 if(shi->do_preview)
280                         nodeAddToPreview(node, col, shi->xs, shi->ys);
281                 
282                 VECCOPY(out[MAT_OUT_COLOR]->vec, col);
283                 out[MAT_OUT_ALPHA]->vec[0]= shrnode.alpha;
284                 
285                 if(node->custom1 & SH_NODE_MAT_NEG) {
286                         shi->vn[0]= -shi->vn[0];
287                         shi->vn[1]= -shi->vn[1];
288                         shi->vn[2]= -shi->vn[2];
289                 }
290                 
291                 VECCOPY(out[MAT_OUT_NORMAL]->vec, shi->vn);
292                 
293         }
294 }
295
296 static bNodeType sh_node_material= {
297         /* type code   */       SH_NODE_MATERIAL,
298         /* name        */       "Material",
299         /* width+range */       120, 80, 240,
300         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_OPTIONS|NODE_PREVIEW,
301         /* input sock  */       sh_node_material_in,
302         /* output sock */       sh_node_material_out,
303         /* storage     */       "",
304         /* execfunc    */       node_shader_exec_material
305         
306 };
307
308 /* **************** TEXTURE ******************** */
309 static bNodeSocketType sh_node_texture_in[]= {
310         {       SOCK_VECTOR, 1, "Vector",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},   /* no limit */
311         {       -1, 0, ""       }
312 };
313 static bNodeSocketType sh_node_texture_out[]= {
314         {       SOCK_VALUE, 0, "Value",         1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
315         {       SOCK_RGBA , 0, "Color",         1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
316         {       SOCK_VECTOR, 0, "Normal",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
317         {       -1, 0, ""       }
318 };
319
320 static void node_shader_exec_texture(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
321 {
322         if(data && node->id) {
323                 ShadeInput *shi= ((ShaderCallData *)data)->shi;
324                 TexResult texres;
325                 float *vec, nor[3]={0.0f, 0.0f, 0.0f};
326                 int retval;
327                 
328                 /* out: value, color, normal */
329                 
330                 /* we should find out if a normal as output is needed, for now we do all */
331                 texres.nor= nor;
332                 
333                 if(in[0]->hasinput) {
334                         vec= in[0]->vec;
335                         
336                         if(in[0]->datatype==NS_OSA_VECTORS) {
337                                 float *fp= in[0]->data;
338                                 retval= multitex((Tex *)node->id, vec, fp, fp+3, shi->osatex, &texres);
339                         }
340                         else if(in[0]->datatype==NS_OSA_VALUES) {
341                                 float *fp= in[0]->data;
342                                 float dxt[3], dyt[3];
343                                 
344                                 dxt[0]= fp[0]; dxt[1]= dxt[2]= 0.0f;
345                                 dyt[0]= fp[1]; dyt[1]= dyt[2]= 0.0f;
346                                 retval= multitex((Tex *)node->id, vec, dxt, dyt, shi->osatex, &texres);
347                         }
348                         else
349                                 retval= multitex((Tex *)node->id, vec, NULL, NULL, 0, &texres);
350                 }
351                 else {  /* only for previewrender, so we see stuff */
352                         vec= shi->lo;
353                         retval= multitex((Tex *)node->id, vec, NULL, NULL, 0, &texres);
354                 }
355                 
356                 /* stupid exception */
357                 if( ((Tex *)node->id)->type==TEX_STUCCI) {
358                         texres.tin= 0.5f + 0.7f*texres.nor[0];
359                         CLAMP(texres.tin, 0.0f, 1.0f);
360                 }
361                 
362                 /* intensity and color need some handling */
363                 if(texres.talpha)
364                         out[0]->vec[0]= texres.ta;
365                 else
366                         out[0]->vec[0]= texres.tin;
367                 
368                 if((retval & TEX_RGB)==0) {
369                         out[1]->vec[0]= out[0]->vec[0];
370                         out[1]->vec[1]= out[0]->vec[0];
371                         out[1]->vec[2]= out[0]->vec[0];
372                         out[1]->vec[3]= 1.0f;
373                 }
374                 else {
375                         out[1]->vec[0]= texres.tr;
376                         out[1]->vec[1]= texres.tg;
377                         out[1]->vec[2]= texres.tb;
378                         out[1]->vec[3]= 1.0f;
379                 }
380                 
381                 VECCOPY(out[2]->vec, nor);
382                 
383                 if(shi->do_preview)
384                         nodeAddToPreview(node, out[1]->vec, shi->xs, shi->ys);
385                 
386         }
387 }
388
389 static bNodeType sh_node_texture= {
390         /* type code   */       SH_NODE_TEXTURE,
391         /* name        */       "Texture",
392         /* width+range */       120, 80, 240,
393         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_OPTIONS|NODE_PREVIEW,
394         /* input sock  */       sh_node_texture_in,
395         /* output sock */       sh_node_texture_out,
396         /* storage     */       "",
397         /* execfunc    */       node_shader_exec_texture
398         
399 };
400
401 /* **************** MAPPING  ******************** */
402 static bNodeSocketType sh_node_mapping_in[]= {
403         {       SOCK_VECTOR, 1, "Vector",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
404         {       -1, 0, ""       }
405 };
406
407 static bNodeSocketType sh_node_mapping_out[]= {
408         {       SOCK_VECTOR, 0, "Vector",       0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
409         {       -1, 0, ""       }
410 };
411
412 /* do the regular mapping options for blender textures */
413 static void node_shader_exec_mapping(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
414 {
415         TexMapping *texmap= node->storage;
416         float *vec= out[0]->vec;
417         
418         /* stack order input:  vector */
419         /* stack order output: vector */
420         VECCOPY(vec, in[0]->vec);
421         Mat4MulVecfl(texmap->mat, vec);
422         
423         if(texmap->flag & TEXMAP_CLIP_MIN) {
424                 if(vec[0]<texmap->min[0]) vec[0]= texmap->min[0];
425                 if(vec[1]<texmap->min[1]) vec[1]= texmap->min[1];
426                 if(vec[2]<texmap->min[2]) vec[2]= texmap->min[2];
427         }
428         if(texmap->flag & TEXMAP_CLIP_MAX) {
429                 if(vec[0]>texmap->max[0]) vec[0]= texmap->max[0];
430                 if(vec[1]>texmap->max[1]) vec[1]= texmap->max[1];
431                 if(vec[2]>texmap->max[2]) vec[2]= texmap->max[2];
432         }
433 }
434
435 static bNodeType sh_node_mapping= {
436         /* type code   */       SH_NODE_MAPPING,
437         /* name        */       "Mapping",
438         /* width+range */       240, 160, 320,
439         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
440         /* input sock  */       sh_node_mapping_in,
441         /* output sock */       sh_node_mapping_out,
442         /* storage     */       "TexMapping",
443         /* execfunc    */       node_shader_exec_mapping
444         
445 };
446
447 /* **************** NORMAL  ******************** */
448 static bNodeSocketType sh_node_normal_in[]= {
449         {       SOCK_VECTOR, 1, "Normal",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
450         {       -1, 0, ""       }
451 };
452
453 static bNodeSocketType sh_node_normal_out[]= {
454         {       SOCK_VECTOR, 0, "Normal",       0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
455         {       SOCK_VALUE, 0, "Dot",           1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
456         {       -1, 0, ""       }
457 };
458
459 /* generates normal, does dot product */
460 static void node_shader_exec_normal(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
461 {
462         bNodeSocket *sock= node->outputs.first;
463         /* stack order input:  normal */
464         /* stack order output: normal, value */
465         
466         VECCOPY(out[0]->vec, sock->ns.vec);
467         /* render normals point inside... the widget points outside */
468         out[1]->vec[0]= -INPR(out[0]->vec, in[0]->vec);
469 }
470
471 static bNodeType sh_node_normal= {
472         /* type code   */       SH_NODE_NORMAL,
473         /* name        */       "Normal",
474         /* width+range */       100, 60, 200,
475         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
476         /* input sock  */       sh_node_normal_in,
477         /* output sock */       sh_node_normal_out,
478         /* storage     */       "",
479         /* execfunc    */       node_shader_exec_normal
480         
481 };
482
483 /* **************** CURVE VEC  ******************** */
484 static bNodeSocketType sh_node_curve_vec_in[]= {
485         {       SOCK_VECTOR, 1, "Vector",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
486         {       -1, 0, ""       }
487 };
488
489 static bNodeSocketType sh_node_curve_vec_out[]= {
490         {       SOCK_VECTOR, 0, "Vector",       0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
491         {       -1, 0, ""       }
492 };
493
494 static void node_shader_exec_curve_vec(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
495 {
496         /* stack order input:  vec */
497         /* stack order output: vec */
498         
499         curvemapping_evaluate3F(node->storage, out[0]->vec, in[0]->vec);
500 }
501
502 static bNodeType sh_node_curve_vec= {
503         /* type code   */       SH_NODE_CURVE_VEC,
504         /* name        */       "Vector Curves",
505         /* width+range */       200, 140, 320,
506         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
507         /* input sock  */       sh_node_curve_vec_in,
508         /* output sock */       sh_node_curve_vec_out,
509         /* storage     */       "CurveMapping",
510         /* execfunc    */       node_shader_exec_curve_vec
511         
512 };
513
514 /* **************** CURVE RGB  ******************** */
515 static bNodeSocketType sh_node_curve_rgb_in[]= {
516         {       SOCK_RGBA, 1, "Color",  0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
517         {       -1, 0, ""       }
518 };
519
520 static bNodeSocketType sh_node_curve_rgb_out[]= {
521         {       SOCK_RGBA, 0, "Color",  0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
522         {       -1, 0, ""       }
523 };
524
525 static void node_shader_exec_curve_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
526 {
527         /* stack order input:  vec */
528         /* stack order output: vec */
529         
530         curvemapping_evaluateRGBF(node->storage, out[0]->vec, in[0]->vec);
531 }
532
533 static bNodeType sh_node_curve_rgb= {
534         /* type code   */       SH_NODE_CURVE_RGB,
535         /* name        */       "RGB Curves",
536         /* width+range */       200, 140, 320,
537         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
538         /* input sock  */       sh_node_curve_rgb_in,
539         /* output sock */       sh_node_curve_rgb_out,
540         /* storage     */       "CurveMapping",
541         /* execfunc    */       node_shader_exec_curve_rgb
542         
543 };
544
545 /* **************** VALUE ******************** */
546 static bNodeSocketType sh_node_value_out[]= {
547         {       SOCK_VALUE, 0, "Value",         0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
548         {       -1, 0, ""       }
549 };
550
551 static void node_shader_exec_value(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
552 {
553         bNodeSocket *sock= node->outputs.first;
554         
555         out[0]->vec[0]= sock->ns.vec[0];
556 }
557
558 static bNodeType sh_node_value= {
559         /* type code   */       SH_NODE_VALUE,
560         /* name        */       "Value",
561         /* width+range */       80, 40, 120,
562         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_OPTIONS,
563         /* input sock  */       NULL,
564         /* output sock */       sh_node_value_out,
565         /* storage     */       "", 
566         /* execfunc    */       node_shader_exec_value
567         
568 };
569
570 /* **************** RGB ******************** */
571 static bNodeSocketType sh_node_rgb_out[]= {
572         {       SOCK_RGBA, 0, "Color",                  0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
573         {       -1, 0, ""       }
574 };
575
576 static void node_shader_exec_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
577 {
578         bNodeSocket *sock= node->outputs.first;
579         
580         VECCOPY(out[0]->vec, sock->ns.vec);
581 }
582
583 static bNodeType sh_node_rgb= {
584         /* type code   */       SH_NODE_RGB,
585         /* name        */       "RGB",
586         /* width+range */       100, 60, 140,
587         /* class+opts  */       NODE_CLASS_GENERATOR, NODE_OPTIONS,
588         /* input sock  */       NULL,
589         /* output sock */       sh_node_rgb_out,
590         /* storage     */       "",
591         /* execfunc    */       node_shader_exec_rgb
592         
593 };
594
595 /* **************** MIX RGB ******************** */
596 static bNodeSocketType sh_node_mix_rgb_in[]= {
597         {       SOCK_VALUE, 1, "Fac",                   0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
598         {       SOCK_RGBA, 1, "Color1",                 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
599         {       SOCK_RGBA, 1, "Color2",                 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
600         {       -1, 0, ""       }
601 };
602 static bNodeSocketType sh_node_mix_rgb_out[]= {
603         {       SOCK_RGBA, 0, "Color",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
604         {       -1, 0, ""       }
605 };
606
607 static void node_shader_exec_mix_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
608 {
609         /* stack order in: fac, col1, col2 */
610         /* stack order out: col */
611         float col[3];
612         float fac= in[0]->vec[0];
613         
614         CLAMP(fac, 0.0f, 1.0f);
615         
616         VECCOPY(col, in[1]->vec);
617         ramp_blend(node->custom1, col, col+1, col+2, fac, in[2]->vec);
618         VECCOPY(out[0]->vec, col);
619 }
620
621 static bNodeType sh_node_mix_rgb= {
622         /* type code   */       SH_NODE_MIX_RGB,
623         /* name        */       "Mix",
624         /* width+range */       80, 40, 120,
625         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
626         /* input sock  */       sh_node_mix_rgb_in,
627         /* output sock */       sh_node_mix_rgb_out,
628         /* storage     */       "", 
629         /* execfunc    */       node_shader_exec_mix_rgb
630         
631 };
632
633
634 /* **************** VALTORGB ******************** */
635 static bNodeSocketType sh_node_valtorgb_in[]= {
636         {       SOCK_VALUE, 1, "Fac",                   0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
637         {       -1, 0, ""       }
638 };
639 static bNodeSocketType sh_node_valtorgb_out[]= {
640         {       SOCK_RGBA, 0, "Color",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
641         {       SOCK_VALUE, 0, "Alpha",                 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
642         {       -1, 0, ""       }
643 };
644
645 static void node_shader_exec_valtorgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
646 {
647         /* stack order in: fac */
648         /* stack order out: col, alpha */
649         
650         if(node->storage) {
651                 do_colorband(node->storage, in[0]->vec[0], out[0]->vec);
652                 out[1]->vec[0]= out[0]->vec[3];
653         }
654 }
655
656 static bNodeType sh_node_valtorgb= {
657         /* type code   */       SH_NODE_VALTORGB,
658         /* name        */       "ColorRamp",
659         /* width+range */       240, 200, 300,
660         /* class+opts  */       NODE_CLASS_OPERATOR, NODE_OPTIONS,
661         /* input sock  */       sh_node_valtorgb_in,
662         /* output sock */       sh_node_valtorgb_out,
663         /* storage     */       "ColorBand",
664         /* execfunc    */       node_shader_exec_valtorgb
665         
666 };
667
668
669 /* **************** RGBTOBW ******************** */
670 static bNodeSocketType sh_node_rgbtobw_in[]= {
671         {       SOCK_RGBA, 1, "Color",                  0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
672         {       -1, 0, ""       }
673 };
674 static bNodeSocketType sh_node_rgbtobw_out[]= {
675         {       SOCK_VALUE, 0, "Val",                   0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
676         {       -1, 0, ""       }
677 };
678
679
680 static void node_shader_exec_rgbtobw(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
681 {
682         /* stack order out: bw */
683         /* stack order in: col */
684         
685         out[0]->vec[0]= in[0]->vec[0]*0.35f + in[0]->vec[1]*0.45f + in[0]->vec[2]*0.2f;
686 }
687
688 static bNodeType sh_node_rgbtobw= {
689         /* type code   */       SH_NODE_RGBTOBW,
690         /* name        */       "RGB to BW",
691         /* width+range */       80, 40, 120,
692         /* class+opts  */       NODE_CLASS_OPERATOR, 0,
693         /* input sock  */       sh_node_rgbtobw_in,
694         /* output sock */       sh_node_rgbtobw_out,
695         /* storage     */       "",
696         /* execfunc    */       node_shader_exec_rgbtobw
697         
698 };
699
700
701 /* ****************** types array for all shaders ****************** */
702
703 bNodeType *node_all_shaders[]= {
704         &node_group_typeinfo,
705         &sh_node_output,
706         &sh_node_material,
707         &sh_node_value,
708         &sh_node_rgb,
709         &sh_node_mix_rgb,
710         &sh_node_valtorgb,
711         &sh_node_rgbtobw,
712         &sh_node_texture,
713         &sh_node_normal,
714         &sh_node_geom,
715         &sh_node_mapping,
716         &sh_node_curve_vec,
717         &sh_node_curve_rgb,
718         NULL
719 };
720
721 /* ******************* execute and parse ************ */
722
723 void ntreeShaderExecTree(bNodeTree *ntree, ShadeInput *shi, ShadeResult *shr)
724 {
725         ShaderCallData scd;
726         
727         /* convert caller data to struct */
728         scd.shi= shi;
729         scd.shr= shr;
730         
731         ntreeExecTree(ntree, &scd, shi->thread);        /* threads */
732 }
733
734 /* go over all used Geometry and Texture nodes, and return a texco flag */
735 int ntreeShaderGetTexco(bNodeTree *ntree, int osa)
736 {
737         bNode *node;
738         bNodeSocket *sock;
739         int texco= 0, a;
740         
741         ntreeSocketUseFlags(ntree);
742         
743         for(node= ntree->nodes.first; node; node= node->next) {
744                 if(node->type==SH_NODE_TEXTURE) {
745                         if(osa && node->id) {
746                                 Tex *tex= (Tex *)node->id;
747                                 if ELEM3(tex->type, TEX_IMAGE, TEX_PLUGIN, TEX_ENVMAP) texco |= TEXCO_OSA;
748                         }
749                 }
750                 else if(node->type==SH_NODE_GEOMETRY) {
751                         /* note; sockets always exist for the given type! */
752                         for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) {
753                                 if(sock->flag & SOCK_IN_USE) {
754                                         switch(a) {
755                                                 case GEOM_OUT_GLOB: 
756                                                         texco |= TEXCO_GLOB; break;
757                                                 case GEOM_OUT_VIEW: 
758                                                         texco |= TEXCO_VIEW; break;
759                                                 case GEOM_OUT_ORCO: 
760                                                         texco |= TEXCO_ORCO; break;
761                                                 case GEOM_OUT_UV: 
762                                                         texco |= TEXCO_UV; break;
763                                                 case GEOM_OUT_NORMAL: 
764                                                         texco |= TEXCO_NORM; break;
765                                         }
766                                 }
767                         }
768                 }
769         }
770         
771         return texco;
772 }
773
774 /* nodes that use ID data get synced with local data */
775 void nodeShaderSynchronizeID(bNode *node, int copyto)
776 {
777         if(node->id==NULL) return;
778         
779         if(node->type==SH_NODE_MATERIAL) {
780                 bNodeSocket *sock;
781                 Material *ma= (Material *)node->id;
782                 int a;
783                 
784                 /* hrmf, case in loop isnt super fast, but we dont edit 100s of material at same time either! */
785                 for(a=0, sock= node->inputs.first; sock; sock= sock->next, a++) {
786                         if(!(sock->flag & SOCK_HIDDEN)) {
787                                 if(copyto) {
788                                         switch(a) {
789                                                 case MAT_IN_COLOR:
790                                                         VECCOPY(&ma->r, sock->ns.vec); break;
791                                                 case MAT_IN_SPEC:
792                                                         VECCOPY(&ma->specr, sock->ns.vec); break;
793                                                 case MAT_IN_REFL:
794                                                         ma->ref= sock->ns.vec[0]; break;
795                                         }
796                                 }
797                                 else {
798                                         switch(a) {
799                                                 case MAT_IN_COLOR:
800                                                         VECCOPY(sock->ns.vec, &ma->r); break;
801                                                 case MAT_IN_SPEC:
802                                                         VECCOPY(sock->ns.vec, &ma->specr); break;
803                                                 case MAT_IN_REFL:
804                                                         sock->ns.vec[0]= ma->ref; break;
805                                         }
806                                 }
807                         }
808                 }
809         }
810         
811 }