fix for using uninitialized value in gpu_shader_material
[blender.git] / source / blender / nodes / intern / SHD_nodes / SHD_material.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 /** \file blender/nodes/intern/SHD_nodes/SHD_material.c
31  *  \ingroup shdnodes
32  */
33
34
35 #include "../SHD_util.h"
36
37 /* **************** MATERIAL ******************** */
38
39 static bNodeSocketType sh_node_material_in[]= {
40         {       SOCK_RGBA, 1, "Color",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
41         {       SOCK_RGBA, 1, "Spec",           0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
42         {       SOCK_VALUE, 1, "Refl",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
43         {       SOCK_VECTOR, 1, "Normal",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
44         {       -1, 0, ""       }
45 };
46
47 static bNodeSocketType sh_node_material_out[]= {
48         {       SOCK_RGBA, 0, "Color",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
49         {       SOCK_VALUE, 0, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
50         {       SOCK_VECTOR, 0, "Normal",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
51         {       -1, 0, ""       }
52 };
53
54 /* **************** EXTENDED MATERIAL ******************** */
55
56 static bNodeSocketType sh_node_material_ext_in[]= {
57         {       SOCK_RGBA, 1, "Color",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
58         {       SOCK_RGBA, 1, "Spec",           0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
59         {       SOCK_VALUE, 1, "Refl",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
60         {       SOCK_VECTOR, 1, "Normal",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
61         {       SOCK_RGBA, 1, "Mirror",         0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
62         {       SOCK_VALUE, 1, "Ambient",       0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
63         {       SOCK_VALUE, 1, "Emit",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
64         {       SOCK_VALUE, 1, "SpecTra",       0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
65         {       SOCK_VALUE, 1, "Ray Mirror",    0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
66         {       SOCK_VALUE, 1, "Alpha",         0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
67         {       SOCK_VALUE, 1, "Translucency",  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
68         {       -1, 0, ""       }
69 };
70
71 static bNodeSocketType sh_node_material_ext_out[]= {
72         {       SOCK_RGBA, 0, "Color",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
73         {       SOCK_VALUE, 0, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
74         {       SOCK_VECTOR, 0, "Normal",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
75         {       SOCK_RGBA, 0, "Diffuse",                0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
76         {       SOCK_RGBA, 0, "Spec",           0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
77         {       SOCK_RGBA, 0, "AO",             0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
78         {       -1, 0, ""       }
79 };
80
81 static void node_shader_exec_material(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
82 {
83         if(data && node->id) {
84                 ShadeResult shrnode;
85                 ShadeInput *shi;
86                 ShaderCallData *shcd= data;
87                 float col[4];
88                 bNodeSocket *sock;
89                 char hasinput[NUM_MAT_IN]= {'\0'};
90                 int i;
91                 
92                 /* note: cannot use the in[]->hasinput flags directly, as these are not necessarily
93                  * the constant input stack values (e.g. in case material node is inside a group).
94                  * we just want to know if a node input uses external data or the material setting.
95                  * this is an ugly hack, but so is this node as a whole.
96                  */
97                 for (sock=node->inputs.first, i=0; sock; sock=sock->next, ++i)
98                         hasinput[i] = (sock->link != NULL);
99                 
100                 shi= shcd->shi;
101                 shi->mat= (Material *)node->id;
102                 
103                 /* copy all relevant material vars, note, keep this synced with render_types.h */
104                 memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));
105                 shi->har= shi->mat->har;
106                 
107                 /* write values */
108                 if(hasinput[MAT_IN_COLOR])
109                         nodestack_get_vec(&shi->r, SOCK_VECTOR, in[MAT_IN_COLOR]);
110                 
111                 if(hasinput[MAT_IN_SPEC])
112                         nodestack_get_vec(&shi->specr, SOCK_VECTOR, in[MAT_IN_SPEC]);
113                 
114                 if(hasinput[MAT_IN_REFL])
115                         nodestack_get_vec(&shi->refl, SOCK_VALUE, in[MAT_IN_REFL]);
116                 
117                 /* retrieve normal */
118                 if(hasinput[MAT_IN_NORMAL]) {
119                         nodestack_get_vec(shi->vn, SOCK_VECTOR, in[MAT_IN_NORMAL]);
120                         normalize_v3(shi->vn);
121                 }
122                 else
123                         VECCOPY(shi->vn, shi->vno);
124                 
125                 /* custom option to flip normal */
126                 if(node->custom1 & SH_NODE_MAT_NEG) {
127                         shi->vn[0]= -shi->vn[0];
128                         shi->vn[1]= -shi->vn[1];
129                         shi->vn[2]= -shi->vn[2];
130                 }
131                 
132                 if (node->type == SH_NODE_MATERIAL_EXT) {
133                         if(hasinput[MAT_IN_MIR])
134                                 nodestack_get_vec(&shi->mirr, SOCK_VECTOR, in[MAT_IN_MIR]);
135                         if(hasinput[MAT_IN_AMB])
136                                 nodestack_get_vec(&shi->amb, SOCK_VALUE, in[MAT_IN_AMB]);
137                         if(hasinput[MAT_IN_EMIT])
138                                 nodestack_get_vec(&shi->emit, SOCK_VALUE, in[MAT_IN_EMIT]);
139                         if(hasinput[MAT_IN_SPECTRA])
140                                 nodestack_get_vec(&shi->spectra, SOCK_VALUE, in[MAT_IN_SPECTRA]);
141                         if(hasinput[MAT_IN_RAY_MIRROR])
142                                 nodestack_get_vec(&shi->ray_mirror, SOCK_VALUE, in[MAT_IN_RAY_MIRROR]);
143                         if(hasinput[MAT_IN_ALPHA])
144                                 nodestack_get_vec(&shi->alpha, SOCK_VALUE, in[MAT_IN_ALPHA]);
145                         if(hasinput[MAT_IN_TRANSLUCENCY])
146                                 nodestack_get_vec(&shi->translucency, SOCK_VALUE, in[MAT_IN_TRANSLUCENCY]);                     
147                 }
148                 
149                 shi->nodes= 1; /* temp hack to prevent trashadow recursion */
150                 node_shader_lamp_loop(shi, &shrnode);   /* clears shrnode */
151                 shi->nodes= 0;
152                 
153                 /* write to outputs */
154                 if(node->custom1 & SH_NODE_MAT_DIFF) {
155                         VECCOPY(col, shrnode.combined);
156                         if(!(node->custom1 & SH_NODE_MAT_SPEC)) {
157                                 sub_v3_v3(col, shrnode.spec);
158                         }
159                 }
160                 else if(node->custom1 & SH_NODE_MAT_SPEC) {
161                         VECCOPY(col, shrnode.spec);
162                 }
163                 else
164                         col[0]= col[1]= col[2]= 0.0f;
165                 
166                 col[3]= shrnode.alpha;
167                 
168                 if(shi->do_preview)
169                         nodeAddToPreview(node, col, shi->xs, shi->ys, shi->do_manage);
170                 
171                 VECCOPY(out[MAT_OUT_COLOR]->vec, col);
172                 out[MAT_OUT_ALPHA]->vec[0]= shrnode.alpha;
173                 
174                 if(node->custom1 & SH_NODE_MAT_NEG) {
175                         shi->vn[0]= -shi->vn[0];
176                         shi->vn[1]= -shi->vn[1];
177                         shi->vn[2]= -shi->vn[2];
178                 }
179                 
180                 VECCOPY(out[MAT_OUT_NORMAL]->vec, shi->vn);
181                 
182                 /* Extended material options */
183                 if (node->type == SH_NODE_MATERIAL_EXT) {
184                         /* Shadow, Reflect, Refract, Radiosity, Speed seem to cause problems inside
185                          * a node tree :( */
186                         VECCOPY(out[MAT_OUT_DIFFUSE]->vec, shrnode.diff);
187                         VECCOPY(out[MAT_OUT_SPEC]->vec, shrnode.spec);
188                         VECCOPY(out[MAT_OUT_AO]->vec, shrnode.ao);
189                 }
190                 
191                 /* copy passes, now just active node */
192                 if(node->flag & NODE_ACTIVE_ID) {
193                         float combined[4], alpha;
194
195                         copy_v4_v4(combined, shcd->shr->combined);
196                         alpha= shcd->shr->alpha;
197
198                         *(shcd->shr)= shrnode;
199
200                         copy_v4_v4(shcd->shr->combined, combined);
201                         shcd->shr->alpha= alpha;
202                 }
203         }
204 }
205
206
207 static void node_shader_init_material(bNode* node)
208 {
209         node->custom1= SH_NODE_MAT_DIFF|SH_NODE_MAT_SPEC;
210 }
211
212 /* XXX this is also done as a local static function in gpu_codegen.c,
213  * but we need this to hack around the crappy material node.
214  */
215 static GPUNodeLink *gpu_get_input_link(GPUNodeStack *in)
216 {
217         if (in->link)
218                 return in->link;
219         else
220                 return GPU_uniform(in->vec);
221 }
222
223 static int gpu_shader_material(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out)
224 {
225         if(node->id) {
226                 GPUShadeInput shi;
227                 GPUShadeResult shr;
228                 bNodeSocket *sock;
229                 char hasinput[NUM_MAT_IN]= {'\0'};
230                 int i;
231                 
232                 /* note: cannot use the in[]->hasinput flags directly, as these are not necessarily
233                  * the constant input stack values (e.g. in case material node is inside a group).
234                  * we just want to know if a node input uses external data or the material setting.
235                  */
236                 for (sock=node->inputs.first, i=0; sock; sock=sock->next, ++i)
237                         hasinput[i] = (sock->link != NULL);
238
239                 GPU_shadeinput_set(mat, (Material*)node->id, &shi);
240
241                 /* write values */
242                 if(hasinput[MAT_IN_COLOR])
243                         shi.rgb = gpu_get_input_link(&in[MAT_IN_COLOR]);
244                 
245                 if(hasinput[MAT_IN_SPEC])
246                         shi.specrgb = gpu_get_input_link(&in[MAT_IN_SPEC]);
247                 
248                 if(hasinput[MAT_IN_REFL])
249                         shi.refl = gpu_get_input_link(&in[MAT_IN_REFL]);
250                 
251                 /* retrieve normal */
252                 if(hasinput[MAT_IN_NORMAL]) {
253                         GPUNodeLink *tmp;
254                         shi.vn = gpu_get_input_link(&in[MAT_IN_NORMAL]);
255                         GPU_link(mat, "vec_math_normalize", shi.vn, &shi.vn, &tmp);
256                 }
257                 
258                 /* custom option to flip normal */
259                 if(node->custom1 & SH_NODE_MAT_NEG)
260                         GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn);
261
262                 if (node->type == SH_NODE_MATERIAL_EXT) {
263                         if(hasinput[MAT_IN_AMB])
264                                 shi.amb= gpu_get_input_link(&in[MAT_IN_AMB]);
265                         if(hasinput[MAT_IN_EMIT])
266                                 shi.emit= gpu_get_input_link(&in[MAT_IN_EMIT]);
267                         if(hasinput[MAT_IN_ALPHA])
268                                 shi.alpha= gpu_get_input_link(&in[MAT_IN_ALPHA]);
269                 }
270
271                 GPU_shaderesult_set(&shi, &shr); /* clears shr */
272                 
273                 /* write to outputs */
274                 if(node->custom1 & SH_NODE_MAT_DIFF) {
275                         out[MAT_OUT_COLOR].link= shr.combined;
276
277                         if(!(node->custom1 & SH_NODE_MAT_SPEC)) {
278                                 GPUNodeLink *link;
279                                 GPU_link(mat, "vec_math_sub", shr.combined, shr.spec, &out[MAT_OUT_COLOR].link, &link);
280                         }
281                 }
282                 else if(node->custom1 & SH_NODE_MAT_SPEC) {
283                         out[MAT_OUT_COLOR].link= shr.spec;
284                 }
285                 else
286                         GPU_link(mat, "set_rgb_zero", &out[MAT_OUT_COLOR].link);
287
288                 GPU_link(mat, "mtex_alpha_to_col", out[MAT_OUT_COLOR].link, shr.alpha, &out[MAT_OUT_COLOR].link);
289
290                 out[MAT_OUT_ALPHA].link = shr.alpha; //
291                 
292                 if(node->custom1 & SH_NODE_MAT_NEG)
293                         GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn);
294                 out[MAT_OUT_NORMAL].link = shi.vn;
295
296                 if (node->type == SH_NODE_MATERIAL_EXT) {
297                         out[MAT_OUT_DIFFUSE].link = shr.diff;
298                         out[MAT_OUT_SPEC].link = shr.spec;
299                 }
300
301                 return 1;
302         }
303
304         return 0;
305 }
306
307 void register_node_type_sh_material(ListBase *lb)
308 {
309         static bNodeType ntype;
310
311         node_type_base(&ntype, SH_NODE_MATERIAL, "Material", NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW,
312                 sh_node_material_in, sh_node_material_out);
313         node_type_size(&ntype, 120, 80, 240);
314         node_type_init(&ntype, node_shader_init_material);
315         node_type_exec(&ntype, node_shader_exec_material);
316         node_type_gpu(&ntype, gpu_shader_material);
317
318         nodeRegisterType(lb, &ntype);
319 }
320
321
322 void register_node_type_sh_material_ext(ListBase *lb)
323 {
324         static bNodeType ntype;
325
326         node_type_base(&ntype, SH_NODE_MATERIAL_EXT, "Extended Material", NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW,
327                 sh_node_material_ext_in, sh_node_material_ext_out);
328         node_type_size(&ntype, 120, 80, 240);
329         node_type_init(&ntype, node_shader_init_material);
330         node_type_exec(&ntype, node_shader_exec_material);
331         node_type_gpu(&ntype, gpu_shader_material);
332
333         nodeRegisterType(lb, &ntype);
334 }
335
336