1bfb986fdde9a3723f90bb32366b3d5c977dfe61
[blender-staging.git] / source / blender / nodes / shader / node_shader_util.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/node_shader_util.c
29  *  \ingroup nodes
30  */
31
32
33 #include "DNA_node_types.h"
34
35 #include "node_shader_util.h"
36
37 #include "node_exec.h"
38
39 /* ****** */
40
41 void nodestack_get_vec(float *in, short type_in, bNodeStack *ns)
42 {
43         float *from= ns->vec;
44                 
45         if(type_in==SOCK_FLOAT) {
46                 if(ns->sockettype==SOCK_FLOAT)
47                         *in= *from;
48                 else 
49                         *in= 0.333333f*(from[0]+from[1]+from[2]);
50         }
51         else if(type_in==SOCK_VECTOR) {
52                 if(ns->sockettype==SOCK_FLOAT) {
53                         in[0]= from[0];
54                         in[1]= from[0];
55                         in[2]= from[0];
56                 }
57                 else {
58                         copy_v3_v3(in, from);
59                 }
60         }
61         else { /* type_in==SOCK_RGBA */
62                 if(ns->sockettype==SOCK_RGBA) {
63                         copy_v4_v4(in, from);
64                 }
65                 else if(ns->sockettype==SOCK_FLOAT) {
66                         in[0]= from[0];
67                         in[1]= from[0];
68                         in[2]= from[0];
69                         in[3]= 1.0f;
70                 }
71                 else {
72                         copy_v3_v3(in, from);
73                         in[3]= 1.0f;
74                 }
75         }
76 }
77
78
79 /* ******************* execute and parse ************ */
80
81 /* Used for muted nodes, just copy the vec data from input to output… */
82 void node_shader_pass_on(void *UNUSED(data), int UNUSED(thread), struct bNode *node, void *UNUSED(nodedata),
83                          struct bNodeStack **in, struct bNodeStack **out)
84 {
85         ListBase links;
86         LinkInOutsMuteNode *lnk;
87         int i;
88
89         if(node->typeinfo->mutelinksfunc == NULL)
90                 return;
91
92         /* Get default muting links (as bNodeStack pointers). */
93         links = node->typeinfo->mutelinksfunc(NULL, node, in, out, NULL, NULL);
94
95         for(lnk = links.first; lnk; lnk = lnk->next) {
96                 for(i = 0; i < lnk->num_outs; i++) {
97                         copy_v4_v4((((bNodeStack*)(lnk->outs))+i)->vec, ((bNodeStack*)(lnk->in))->vec);
98                 }
99                 /* If num_outs > 1, lnk->outs was an allocated table of pointers... */
100                 if(i > 1)
101                         MEM_freeN(lnk->outs);
102         }
103         BLI_freelistN(&links);
104 }
105
106 int gpu_shader_pass_on(struct GPUMaterial *mat, struct bNode *node, void *UNUSED(nodedata),
107                        struct GPUNodeStack *in, struct GPUNodeStack *out)
108 {
109         ListBase links;
110         LinkInOutsMuteNode *lnk;
111
112         if(node->typeinfo->mutelinksfunc == NULL)
113                 return 0;
114
115         /* Get default muting links (as GPUNodeStack pointers). */
116         links = node->typeinfo->mutelinksfunc(NULL, node, NULL, NULL, in, out);
117
118         for(lnk = links.first; lnk; lnk = lnk->next) {
119                 GPU_stack_link_mute(mat, "copy_raw", lnk);
120                 /* If num_outs > 1, lnk->outs was an allocated table of pointers... */
121                 if(lnk->num_outs > 1)
122                         MEM_freeN(lnk->outs);
123         }
124
125         BLI_freelistN(&links);
126         return 1;
127 }
128
129 /* go over all used Geometry and Texture nodes, and return a texco flag */
130 /* no group inside needed, this function is called for groups too */
131 void ntreeShaderGetTexcoMode(bNodeTree *ntree, int r_mode, short *texco, int *mode)
132 {
133         bNode *node;
134         bNodeSocket *sock;
135         int a;
136         
137         for(node= ntree->nodes.first; node; node= node->next) {
138                 if(node->type==SH_NODE_TEXTURE) {
139                         if((r_mode & R_OSA) && node->id) {
140                                 Tex *tex= (Tex *)node->id;
141                                 if ELEM3(tex->type, TEX_IMAGE, TEX_PLUGIN, TEX_ENVMAP) 
142                                         *texco |= TEXCO_OSA|NEED_UV;
143                         }
144                         /* usability exception... without input we still give the node orcos */
145                         sock= node->inputs.first;
146                         if(sock==NULL || sock->link==NULL)
147                                 *texco |= TEXCO_ORCO|NEED_UV;
148                 }
149                 else if(node->type==SH_NODE_GEOMETRY) {
150                         /* note; sockets always exist for the given type! */
151                         for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) {
152                                 if(sock->flag & SOCK_IN_USE) {
153                                         switch(a) {
154                                                 case GEOM_OUT_GLOB: 
155                                                         *texco |= TEXCO_GLOB|NEED_UV; break;
156                                                 case GEOM_OUT_VIEW: 
157                                                         *texco |= TEXCO_VIEW|NEED_UV; break;
158                                                 case GEOM_OUT_ORCO: 
159                                                         *texco |= TEXCO_ORCO|NEED_UV; break;
160                                                 case GEOM_OUT_UV: 
161                                                         *texco |= TEXCO_UV|NEED_UV; break;
162                                                 case GEOM_OUT_NORMAL: 
163                                                         *texco |= TEXCO_NORM|NEED_UV; break;
164                                                 case GEOM_OUT_VCOL:
165                                                         *texco |= NEED_UV; *mode |= MA_VERTEXCOL; break;
166                                                 case GEOM_OUT_VCOL_ALPHA:
167                                                         *texco |= NEED_UV; *mode |= MA_VERTEXCOL; break;
168                                         }
169                                 }
170                         }
171                 }
172         }
173 }
174
175 /* nodes that use ID data get synced with local data */
176 void nodeShaderSynchronizeID(bNode *node, int copyto)
177 {
178         if(node->id==NULL) return;
179         
180         if(ELEM(node->type, SH_NODE_MATERIAL, SH_NODE_MATERIAL_EXT)) {
181                 bNodeSocket *sock;
182                 Material *ma= (Material *)node->id;
183                 int a;
184                 
185                 /* hrmf, case in loop isnt super fast, but we dont edit 100s of material at same time either! */
186                 for(a=0, sock= node->inputs.first; sock; sock= sock->next, a++) {
187                         if(!nodeSocketIsHidden(sock)) {
188                                 if(copyto) {
189                                         switch(a) {
190                                                 case MAT_IN_COLOR:
191                                                         copy_v3_v3(&ma->r, ((bNodeSocketValueRGBA*)sock->default_value)->value); break;
192                                                 case MAT_IN_SPEC:
193                                                         copy_v3_v3(&ma->specr, ((bNodeSocketValueRGBA*)sock->default_value)->value); break;
194                                                 case MAT_IN_REFL:
195                                                         ma->ref= ((bNodeSocketValueFloat*)sock->default_value)->value; break;
196                                                 case MAT_IN_MIR:
197                                                         copy_v3_v3(&ma->mirr, ((bNodeSocketValueRGBA*)sock->default_value)->value); break;
198                                                 case MAT_IN_AMB:
199                                                         ma->amb= ((bNodeSocketValueFloat*)sock->default_value)->value; break;
200                                                 case MAT_IN_EMIT:
201                                                         ma->emit= ((bNodeSocketValueFloat*)sock->default_value)->value; break;
202                                                 case MAT_IN_SPECTRA:
203                                                         ma->spectra= ((bNodeSocketValueFloat*)sock->default_value)->value; break;
204                                                 case MAT_IN_RAY_MIRROR:
205                                                         ma->ray_mirror= ((bNodeSocketValueFloat*)sock->default_value)->value; break;
206                                                 case MAT_IN_ALPHA:
207                                                         ma->alpha= ((bNodeSocketValueFloat*)sock->default_value)->value; break;
208                                                 case MAT_IN_TRANSLUCENCY:
209                                                         ma->translucency= ((bNodeSocketValueFloat*)sock->default_value)->value; break;
210                                         }
211                                 }
212                                 else {
213                                         switch(a) {
214                                                 case MAT_IN_COLOR:
215                                                         copy_v3_v3(((bNodeSocketValueRGBA*)sock->default_value)->value, &ma->r); break;
216                                                 case MAT_IN_SPEC:
217                                                         copy_v3_v3(((bNodeSocketValueRGBA*)sock->default_value)->value, &ma->specr); break;
218                                                 case MAT_IN_REFL:
219                                                         ((bNodeSocketValueFloat*)sock->default_value)->value= ma->ref; break;
220                                                 case MAT_IN_MIR:
221                                                         copy_v3_v3(((bNodeSocketValueRGBA*)sock->default_value)->value, &ma->mirr); break;
222                                                 case MAT_IN_AMB:
223                                                         ((bNodeSocketValueFloat*)sock->default_value)->value= ma->amb; break;
224                                                 case MAT_IN_EMIT:
225                                                         ((bNodeSocketValueFloat*)sock->default_value)->value= ma->emit; break;
226                                                 case MAT_IN_SPECTRA:
227                                                         ((bNodeSocketValueFloat*)sock->default_value)->value= ma->spectra; break;
228                                                 case MAT_IN_RAY_MIRROR:
229                                                         ((bNodeSocketValueFloat*)sock->default_value)->value= ma->ray_mirror; break;
230                                                 case MAT_IN_ALPHA:
231                                                         ((bNodeSocketValueFloat*)sock->default_value)->value= ma->alpha; break;
232                                                 case MAT_IN_TRANSLUCENCY:
233                                                         ((bNodeSocketValueFloat*)sock->default_value)->value= ma->translucency; break;
234                                         }
235                                 }
236                         }
237                 }
238         }
239         
240 }
241
242
243 void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
244 {
245         memset(gs, 0, sizeof(*gs));
246         
247         copy_v4_v4(gs->vec, ns->vec);
248         gs->link= ns->data;
249         
250         if (type == SOCK_FLOAT)
251                 gs->type= GPU_FLOAT;
252         else if (type == SOCK_VECTOR)
253                 gs->type= GPU_VEC3;
254         else if (type == SOCK_RGBA)
255                 gs->type= GPU_VEC4;
256         else if (type == SOCK_SHADER)
257                 gs->type= GPU_VEC4;
258         else
259                 gs->type= GPU_NONE;
260         
261         gs->name = "";
262         gs->hasinput= ns->hasinput && ns->data;
263         /* XXX Commented out the ns->data check here, as it seems it’s not alwas set,
264          *     even though there *is* a valid connection/output... But that might need
265          *     further investigation.
266          */
267         gs->hasoutput= ns->hasoutput /*&& ns->data*/;
268         gs->sockettype= ns->sockettype;
269 }
270
271 void node_data_from_gpu_stack(bNodeStack *ns, GPUNodeStack *gs)
272 {
273         ns->data= gs->link;
274         ns->sockettype= gs->sockettype;
275 }
276
277 static void gpu_stack_from_data_list(GPUNodeStack *gs, ListBase *sockets, bNodeStack **ns)
278 {
279         bNodeSocket *sock;
280         int i;
281         
282         for (sock=sockets->first, i=0; sock; sock=sock->next, i++)
283                 node_gpu_stack_from_data(&gs[i], sock->type, ns[i]);
284         
285         gs[i].type= GPU_NONE;
286 }
287
288 static void data_from_gpu_stack_list(ListBase *sockets, bNodeStack **ns, GPUNodeStack *gs)
289 {
290         bNodeSocket *sock;
291         int i;
292
293         for (sock=sockets->first, i=0; sock; sock=sock->next, i++)
294                 node_data_from_gpu_stack(ns[i], &gs[i]);
295 }
296
297 bNode *nodeGetActiveTexture(bNodeTree *ntree)
298 {
299         /* this is the node we texture paint and draw in textured draw */
300         bNode *node;
301
302         if(!ntree)
303                 return NULL;
304
305         /* check for group edit */
306         for(node= ntree->nodes.first; node; node= node->next)
307                 if(node->flag & NODE_GROUP_EDIT)
308                         break;
309
310         if(node)
311                 ntree= (bNodeTree*)node->id;
312
313         for(node= ntree->nodes.first; node; node= node->next)
314                 if(node->flag & NODE_ACTIVE_TEXTURE)
315                         return node;
316         
317         return NULL;
318 }
319
320 void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, int do_outputs)
321 {
322         bNodeExec *nodeexec;
323         bNode *node;
324         int n;
325         bNodeStack *stack;
326         bNodeStack *nsin[MAX_SOCKET];   /* arbitrary... watch this */
327         bNodeStack *nsout[MAX_SOCKET];  /* arbitrary... watch this */
328         GPUNodeStack gpuin[MAX_SOCKET+1], gpuout[MAX_SOCKET+1];
329         int doit;
330
331         stack= exec->stack;
332
333         for(n=0, nodeexec= exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
334                 node = nodeexec->node;
335                 
336                 doit = 0;
337                 /* for groups, only execute outputs for edited group */
338                 if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
339                         if(do_outputs && (node->flag & NODE_DO_OUTPUT))
340                                 doit = 1;
341                 }
342                 else
343                         doit = 1;
344
345                 if (doit) {
346                         if((node->flag & NODE_MUTED) && node->typeinfo->gpumutefunc) {
347                                 node_get_stack(node, stack, nsin, nsout);
348                                 gpu_stack_from_data_list(gpuin, &node->inputs, nsin);
349                                 gpu_stack_from_data_list(gpuout, &node->outputs, nsout);
350                                 if(node->typeinfo->gpumutefunc(mat, node, nodeexec->data, gpuin, gpuout))
351                                         data_from_gpu_stack_list(&node->outputs, nsout, gpuout);
352                         }
353                         else if(node->typeinfo->gpufunc) {
354                                 node_get_stack(node, stack, nsin, nsout);
355                                 gpu_stack_from_data_list(gpuin, &node->inputs, nsin);
356                                 gpu_stack_from_data_list(gpuout, &node->outputs, nsout);
357                                 if(node->typeinfo->gpufunc(mat, node, gpuin, gpuout))
358                                         data_from_gpu_stack_list(&node->outputs, nsout, gpuout);
359                         }
360                         else if(node->typeinfo->gpuextfunc) {
361                                 node_get_stack(node, stack, nsin, nsout);
362                                 gpu_stack_from_data_list(gpuin, &node->inputs, nsin);
363                                 gpu_stack_from_data_list(gpuout, &node->outputs, nsout);
364                                 if(node->typeinfo->gpuextfunc(mat, node, nodeexec->data, gpuin, gpuout))
365                                         data_from_gpu_stack_list(&node->outputs, nsout, gpuout);
366                         }
367                 }
368         }
369 }
370
371 void node_shader_gpu_tex_mapping(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *UNUSED(out))
372 {
373         NodeTexBase *base= node->storage;
374         TexMapping *texmap= &base->tex_mapping;
375         float domin= (texmap->flag & TEXMAP_CLIP_MIN) != 0;
376         float domax= (texmap->flag & TEXMAP_CLIP_MAX) != 0;
377
378         if(domin || domax || !(texmap->flag & TEXMAP_UNIT_MATRIX)) {
379                 GPUNodeLink *tmat = GPU_uniform((float*)texmap->mat);
380                 GPUNodeLink *tmin = GPU_uniform(texmap->min);
381                 GPUNodeLink *tmax = GPU_uniform(texmap->max);
382                 GPUNodeLink *tdomin = GPU_uniform(&domin);
383                 GPUNodeLink *tdomax = GPU_uniform(&domax);
384
385                 GPU_link(mat, "mapping", in[0].link, tmat, tmin, tmax, tdomin, tdomax, &in[0].link);
386         }
387 }
388