Fix build error on Windows 32 bit.
[blender-staging.git] / source / blender / nodes / shader / nodes / node_shader_material.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2005 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/nodes/shader/nodes/node_shader_material.c
29  *  \ingroup shdnodes
30  */
31
32 #include "node_shader_util.h"
33
34 /* **************** MATERIAL ******************** */
35
36 static bNodeSocketTemplate sh_node_material_in[] = {
37         {       SOCK_RGBA, 1, N_("Color"),              0.0f, 0.0f, 0.0f, 1.0f},
38         {       SOCK_RGBA, 1, N_("Spec"),               0.0f, 0.0f, 0.0f, 1.0f},
39         {       SOCK_FLOAT, 1, N_("DiffuseIntensity"),          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
40         {       SOCK_VECTOR, 1, N_("Normal"),   0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_DIRECTION},
41         {       -1, 0, ""       }
42 };
43
44 static bNodeSocketTemplate sh_node_material_out[] = {
45         {       SOCK_RGBA, 0, N_("Color")},
46         {       SOCK_FLOAT, 0, N_("Alpha")},
47         {       SOCK_VECTOR, 0, N_("Normal")},
48         {       -1, 0, ""       }
49 };
50
51 /* **************** EXTENDED MATERIAL ******************** */
52
53 static bNodeSocketTemplate sh_node_material_ext_in[] = {
54         {       SOCK_RGBA, 1, N_("Color"),              0.0f, 0.0f, 0.0f, 1.0f},
55         {       SOCK_RGBA, 1, N_("Spec"),               0.0f, 0.0f, 0.0f, 1.0f},
56         {       SOCK_FLOAT, 1, N_("DiffuseIntensity"),          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
57         {       SOCK_VECTOR, 1, N_("Normal"),   0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_DIRECTION},
58         {       SOCK_RGBA, 1, N_("Mirror"),             0.0f, 0.0f, 0.0f, 1.0f},
59         {       SOCK_FLOAT, 1, N_("Ambient"),   0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
60         {       SOCK_FLOAT, 1, N_("Emit"),              0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_UNSIGNED},
61         {       SOCK_FLOAT, 1, N_("SpecTra"),   0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
62         {       SOCK_FLOAT, 1, N_("Reflectivity"),      0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
63         {       SOCK_FLOAT, 1, N_("Alpha"),             0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_UNSIGNED},
64         {       SOCK_FLOAT, 1, N_("Translucency"),      0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
65         {       -1, 0, ""       }
66 };
67
68 static bNodeSocketTemplate sh_node_material_ext_out[] = {
69         {       SOCK_RGBA, 0, N_("Color")},
70         {       SOCK_FLOAT, 0, N_("Alpha")},
71         {       SOCK_VECTOR, 0, N_("Normal")},
72         {       SOCK_RGBA, 0, N_("Diffuse")},
73         {       SOCK_RGBA, 0, N_("Spec")},
74         {       SOCK_RGBA, 0, N_("AO")},
75         {       -1, 0, ""       }
76 };
77
78 static void node_shader_exec_material(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out)
79 {
80         if (data && node->id) {
81                 ShadeResult shrnode;
82                 ShadeInput *shi;
83                 ShaderCallData *shcd = data;
84                 float col[4];
85                 bNodeSocket *sock;
86                 char hasinput[NUM_MAT_IN] = {'\0'};
87                 int i, mode;
88                 
89                 /* note: cannot use the in[]->hasinput flags directly, as these are not necessarily
90                  * the constant input stack values (e.g. in case material node is inside a group).
91                  * we just want to know if a node input uses external data or the material setting.
92                  * this is an ugly hack, but so is this node as a whole.
93                  */
94                 for (sock = node->inputs.first, i = 0; sock; sock = sock->next, ++i)
95                         hasinput[i] = (sock->link != NULL);
96                 
97                 shi = shcd->shi;
98                 shi->mat = (Material *)node->id;
99                 
100                 /* copy all relevant material vars, note, keep this synced with render_types.h */
101                 memcpy(&shi->r, &shi->mat->r, 23 * sizeof(float));
102                 shi->har = shi->mat->har;
103                 
104                 /* write values */
105                 if (hasinput[MAT_IN_COLOR])
106                         nodestack_get_vec(&shi->r, SOCK_VECTOR, in[MAT_IN_COLOR]);
107                 
108                 if (hasinput[MAT_IN_SPEC])
109                         nodestack_get_vec(&shi->specr, SOCK_VECTOR, in[MAT_IN_SPEC]);
110                 
111                 if (hasinput[MAT_IN_REFL])
112                         nodestack_get_vec(&shi->refl, SOCK_FLOAT, in[MAT_IN_REFL]);
113                 
114                 /* retrieve normal */
115                 if (hasinput[MAT_IN_NORMAL]) {
116                         nodestack_get_vec(shi->vn, SOCK_VECTOR, in[MAT_IN_NORMAL]);
117                         if (shi->use_world_space_shading) {
118                                 negate_v3(shi->vn);
119                                 mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), shi->vn);
120                         }
121                         normalize_v3(shi->vn);
122                 }
123                 else
124                         copy_v3_v3(shi->vn, shi->vno);
125                 
126                 /* custom option to flip normal */
127                 if (node->custom1 & SH_NODE_MAT_NEG) {
128                         negate_v3(shi->vn);
129                 }
130                 
131                 if (node->type == SH_NODE_MATERIAL_EXT) {
132                         if (hasinput[MAT_IN_MIR])
133                                 nodestack_get_vec(&shi->mirr, SOCK_VECTOR, in[MAT_IN_MIR]);
134                         if (hasinput[MAT_IN_AMB])
135                                 nodestack_get_vec(&shi->amb, SOCK_FLOAT, in[MAT_IN_AMB]);
136                         if (hasinput[MAT_IN_EMIT])
137                                 nodestack_get_vec(&shi->emit, SOCK_FLOAT, in[MAT_IN_EMIT]);
138                         if (hasinput[MAT_IN_SPECTRA])
139                                 nodestack_get_vec(&shi->spectra, SOCK_FLOAT, in[MAT_IN_SPECTRA]);
140                         if (hasinput[MAT_IN_RAY_MIRROR])
141                                 nodestack_get_vec(&shi->ray_mirror, SOCK_FLOAT, in[MAT_IN_RAY_MIRROR]);
142                         if (hasinput[MAT_IN_ALPHA])
143                                 nodestack_get_vec(&shi->alpha, SOCK_FLOAT, in[MAT_IN_ALPHA]);
144                         if (hasinput[MAT_IN_TRANSLUCENCY])
145                                 nodestack_get_vec(&shi->translucency, SOCK_FLOAT, in[MAT_IN_TRANSLUCENCY]);
146                 }
147                 
148                 /* make alpha output give results even if transparency is only enabled on
149                  * the material linked in this not and not on the parent material */
150                 mode = shi->mode;
151                 if (shi->mat->mode & MA_TRANSP)
152                         shi->mode |= MA_TRANSP;
153
154                 shi->nodes = 1; /* temp hack to prevent trashadow recursion */
155                 node_shader_lamp_loop(shi, &shrnode);   /* clears shrnode */
156                 shi->nodes = 0;
157                 
158                 shi->mode = mode;
159
160                 /* write to outputs */
161                 if (node->custom1 & SH_NODE_MAT_DIFF) {
162                         copy_v3_v3(col, shrnode.combined);
163                         if (!(node->custom1 & SH_NODE_MAT_SPEC)) {
164                                 sub_v3_v3(col, shrnode.spec);
165                         }
166                 }
167                 else if (node->custom1 & SH_NODE_MAT_SPEC) {
168                         copy_v3_v3(col, shrnode.spec);
169                 }
170                 else
171                         col[0] = col[1] = col[2] = 0.0f;
172                 
173                 col[3] = shrnode.alpha;
174                 
175                 if (shi->do_preview)
176                         BKE_node_preview_set_pixel(execdata->preview, col, shi->xs, shi->ys, shi->do_manage);
177                 
178                 copy_v3_v3(out[MAT_OUT_COLOR]->vec, col);
179                 out[MAT_OUT_ALPHA]->vec[0] = shrnode.alpha;
180                 
181                 if (node->custom1 & SH_NODE_MAT_NEG) {
182                         shi->vn[0] = -shi->vn[0];
183                         shi->vn[1] = -shi->vn[1];
184                         shi->vn[2] = -shi->vn[2];
185                 }
186                 
187                 copy_v3_v3(out[MAT_OUT_NORMAL]->vec, shi->vn);
188
189                 if (shi->use_world_space_shading) {
190                         negate_v3(out[MAT_OUT_NORMAL]->vec);
191                         mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[MAT_OUT_NORMAL]->vec);
192                 }
193                 /* Extended material options */
194                 if (node->type == SH_NODE_MATERIAL_EXT) {
195                         /* Shadow, Reflect, Refract, Radiosity, Speed seem to cause problems inside
196                          * a node tree :( */
197                         copy_v3_v3(out[MAT_OUT_DIFFUSE]->vec, shrnode.diffshad);
198                         copy_v3_v3(out[MAT_OUT_SPEC]->vec, shrnode.spec);
199                         copy_v3_v3(out[MAT_OUT_AO]->vec, shrnode.ao);
200                 }
201                 
202                 /* copy passes, now just active node */
203                 if (node->flag & NODE_ACTIVE_ID) {
204                         float combined[4], alpha;
205
206                         copy_v4_v4(combined, shcd->shr->combined);
207                         alpha = shcd->shr->alpha;
208
209                         *(shcd->shr) = shrnode;
210
211                         copy_v4_v4(shcd->shr->combined, combined);
212                         shcd->shr->alpha = alpha;
213                 }
214         }
215 }
216
217
218 static void node_shader_init_material(bNodeTree *UNUSED(ntree), bNode *node)
219 {
220         node->custom1 = SH_NODE_MAT_DIFF | SH_NODE_MAT_SPEC;
221 }
222
223 /* XXX this is also done as a local static function in gpu_codegen.c,
224  * but we need this to hack around the crappy material node.
225  */
226 static GPUNodeLink *gpu_get_input_link(GPUMaterial *mat, GPUNodeStack *in)
227 {
228         if (in->link) {
229                 return in->link;
230         }
231         else {
232                 GPUNodeLink *result = NULL;
233
234                 /* note GPU_uniform() is only intended to be used as a parameter to
235                  * GPU_link(), returning it directly results in leaks or double frees */
236                 if (in->type == GPU_FLOAT)
237                         GPU_link(mat, "set_value", GPU_uniform(in->vec), &result);
238                 else if (in->type == GPU_VEC3)
239                         GPU_link(mat, "set_rgb", GPU_uniform(in->vec), &result);
240                 else if (in->type == GPU_VEC4)
241                         GPU_link(mat, "set_rgba", GPU_uniform(in->vec), &result);
242                 else
243                         BLI_assert(0);
244
245                 return result;
246         }
247 }
248
249 static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
250 {
251         if (node->id) {
252                 GPUShadeInput shi;
253                 GPUShadeResult shr;
254                 bNodeSocket *sock;
255                 char hasinput[NUM_MAT_IN] = {'\0'};
256                 int i;
257                 
258                 /* note: cannot use the in[]->hasinput flags directly, as these are not necessarily
259                  * the constant input stack values (e.g. in case material node is inside a group).
260                  * we just want to know if a node input uses external data or the material setting.
261                  */
262                 for (sock = node->inputs.first, i = 0; sock; sock = sock->next, ++i)
263                         hasinput[i] = (sock->link != NULL);
264
265                 GPU_shadeinput_set(mat, (Material *)node->id, &shi);
266
267                 /* write values */
268                 if (hasinput[MAT_IN_COLOR])
269                         shi.rgb = gpu_get_input_link(mat, &in[MAT_IN_COLOR]);
270                 
271                 if (hasinput[MAT_IN_SPEC])
272                         shi.specrgb = gpu_get_input_link(mat, &in[MAT_IN_SPEC]);
273                 
274                 if (hasinput[MAT_IN_REFL])
275                         shi.refl = gpu_get_input_link(mat, &in[MAT_IN_REFL]);
276                 
277                 /* retrieve normal */
278                 if (hasinput[MAT_IN_NORMAL]) {
279                         GPUNodeLink *tmp;
280                         shi.vn = gpu_get_input_link(mat, &in[MAT_IN_NORMAL]);
281                         if (GPU_material_use_world_space_shading(mat)) {
282                                 GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn);
283                                 GPU_link(mat, "direction_transform_m4v3", shi.vn, GPU_builtin(GPU_VIEW_MATRIX), &shi.vn);
284                         }
285                         GPU_link(mat, "vec_math_normalize", shi.vn, &shi.vn, &tmp);
286                 }
287                 
288                 /* custom option to flip normal */
289                 if (node->custom1 & SH_NODE_MAT_NEG)
290                         GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn);
291
292                 if (node->type == SH_NODE_MATERIAL_EXT) {
293                         if (hasinput[MAT_IN_MIR])
294                                 shi.mir = gpu_get_input_link(mat, &in[MAT_IN_MIR]);
295                         if (hasinput[MAT_IN_AMB])
296                                 shi.amb = gpu_get_input_link(mat, &in[MAT_IN_AMB]);
297                         if (hasinput[MAT_IN_EMIT])
298                                 shi.emit = gpu_get_input_link(mat, &in[MAT_IN_EMIT]);
299                         if (hasinput[MAT_IN_SPECTRA])
300                                 shi.spectra = gpu_get_input_link(mat, &in[MAT_IN_SPECTRA]);
301                         if (hasinput[MAT_IN_ALPHA])
302                                 shi.alpha = gpu_get_input_link(mat, &in[MAT_IN_ALPHA]);
303                 }
304
305                 GPU_shaderesult_set(&shi, &shr); /* clears shr */
306                 
307                 /* write to outputs */
308                 if (node->custom1 & SH_NODE_MAT_DIFF) {
309                         out[MAT_OUT_COLOR].link = shr.combined;
310
311                         if (!(node->custom1 & SH_NODE_MAT_SPEC)) {
312                                 GPUNodeLink *link;
313                                 GPU_link(mat, "vec_math_sub", shr.combined, shr.spec, &out[MAT_OUT_COLOR].link, &link);
314                         }
315                 }
316                 else if (node->custom1 & SH_NODE_MAT_SPEC) {
317                         out[MAT_OUT_COLOR].link = shr.spec;
318                 }
319                 else
320                         GPU_link(mat, "set_rgb_zero", &out[MAT_OUT_COLOR].link);
321
322                 GPU_link(mat, "mtex_alpha_to_col", out[MAT_OUT_COLOR].link, shr.alpha, &out[MAT_OUT_COLOR].link);
323
324                 out[MAT_OUT_ALPHA].link = shr.alpha; //
325                 
326                 if (node->custom1 & SH_NODE_MAT_NEG)
327                         GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn);
328                 out[MAT_OUT_NORMAL].link = shi.vn;
329                 if (GPU_material_use_world_space_shading(mat)) {
330                         GPU_link(mat, "vec_math_negate", out[MAT_OUT_NORMAL].link, &out[MAT_OUT_NORMAL].link);
331                         GPU_link(mat, "direction_transform_m4v3", out[MAT_OUT_NORMAL].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[MAT_OUT_NORMAL].link);
332                 }
333
334                 if (node->type == SH_NODE_MATERIAL_EXT) {
335                         out[MAT_OUT_DIFFUSE].link = shr.diff;
336                         out[MAT_OUT_SPEC].link = shr.spec;
337                         GPU_link(mat, "set_rgb_one", &out[MAT_OUT_AO].link);
338                 }
339
340                 return 1;
341         }
342
343         return 0;
344 }
345
346 void register_node_type_sh_material(void)
347 {
348         static bNodeType ntype;
349
350         sh_node_type_base(&ntype, SH_NODE_MATERIAL, "Material", NODE_CLASS_INPUT, NODE_PREVIEW);
351         node_type_compatibility(&ntype, NODE_OLD_SHADING);
352         node_type_socket_templates(&ntype, sh_node_material_in, sh_node_material_out);
353         node_type_init(&ntype, node_shader_init_material);
354         node_type_exec(&ntype, NULL, NULL, node_shader_exec_material);
355         node_type_gpu(&ntype, gpu_shader_material);
356
357         nodeRegisterType(&ntype);
358 }
359
360
361 void register_node_type_sh_material_ext(void)
362 {
363         static bNodeType ntype;
364
365         sh_node_type_base(&ntype, SH_NODE_MATERIAL_EXT, "Extended Material", NODE_CLASS_INPUT, NODE_PREVIEW);
366         node_type_compatibility(&ntype, NODE_OLD_SHADING);
367         node_type_socket_templates(&ntype, sh_node_material_ext_in, sh_node_material_ext_out);
368         node_type_init(&ntype, node_shader_init_material);
369         node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
370         node_type_exec(&ntype, NULL, NULL, node_shader_exec_material);
371         node_type_gpu(&ntype, gpu_shader_material);
372
373         nodeRegisterType(&ntype);
374 }