Merge with trunk r40782
[blender.git] / source / blender / nodes / shader / node_shader_util.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/shader/node_shader_util.c
31  *  \ingroup nodes
32  */
33
34
35 #include "DNA_node_types.h"
36
37 #include "node_shader_util.h"
38
39 #include "node_exec.h"
40
41 /* ****** */
42
43 void nodestack_get_vec(float *in, short type_in, bNodeStack *ns)
44 {
45         float *from= ns->vec;
46                 
47         if(type_in==SOCK_FLOAT) {
48                 if(ns->sockettype==SOCK_FLOAT)
49                         *in= *from;
50                 else 
51                         *in= 0.333333f*(from[0]+from[1]+from[2]);
52         }
53         else if(type_in==SOCK_VECTOR) {
54                 if(ns->sockettype==SOCK_FLOAT) {
55                         in[0]= from[0];
56                         in[1]= from[0];
57                         in[2]= from[0];
58                 }
59                 else {
60                         VECCOPY(in, from);
61                 }
62         }
63         else { /* type_in==SOCK_RGBA */
64                 if(ns->sockettype==SOCK_RGBA) {
65                         QUATCOPY(in, from);
66                 }
67                 else if(ns->sockettype==SOCK_FLOAT) {
68                         in[0]= from[0];
69                         in[1]= from[0];
70                         in[2]= from[0];
71                         in[3]= 1.0f;
72                 }
73                 else {
74                         VECCOPY(in, from);
75                         in[3]= 1.0f;
76                 }
77         }
78 }
79
80
81 /* ******************* execute and parse ************ */
82
83 /* go over all used Geometry and Texture nodes, and return a texco flag */
84 /* no group inside needed, this function is called for groups too */
85 void ntreeShaderGetTexcoMode(bNodeTree *ntree, int r_mode, short *texco, int *mode)
86 {
87         bNode *node;
88         bNodeSocket *sock;
89         int a;
90         
91         ntreeSocketUseFlags(ntree);
92
93         for(node= ntree->nodes.first; node; node= node->next) {
94                 if(node->type==SH_NODE_TEXTURE) {
95                         if((r_mode & R_OSA) && node->id) {
96                                 Tex *tex= (Tex *)node->id;
97                                 if ELEM3(tex->type, TEX_IMAGE, TEX_PLUGIN, TEX_ENVMAP) 
98                                         *texco |= TEXCO_OSA|NEED_UV;
99                         }
100                         /* usability exception... without input we still give the node orcos */
101                         sock= node->inputs.first;
102                         if(sock==NULL || sock->link==NULL)
103                                 *texco |= TEXCO_ORCO|NEED_UV;
104                 }
105                 else if(node->type==SH_NODE_GEOMETRY) {
106                         /* note; sockets always exist for the given type! */
107                         for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) {
108                                 if(sock->flag & SOCK_IN_USE) {
109                                         switch(a) {
110                                                 case GEOM_OUT_GLOB: 
111                                                         *texco |= TEXCO_GLOB|NEED_UV; break;
112                                                 case GEOM_OUT_VIEW: 
113                                                         *texco |= TEXCO_VIEW|NEED_UV; break;
114                                                 case GEOM_OUT_ORCO: 
115                                                         *texco |= TEXCO_ORCO|NEED_UV; break;
116                                                 case GEOM_OUT_UV: 
117                                                         *texco |= TEXCO_UV|NEED_UV; break;
118                                                 case GEOM_OUT_NORMAL: 
119                                                         *texco |= TEXCO_NORM|NEED_UV; break;
120                                                 case GEOM_OUT_VCOL:
121                                                         *texco |= NEED_UV; *mode |= MA_VERTEXCOL; break;
122                                                 case GEOM_OUT_VCOL_ALPHA:
123                                                         *texco |= NEED_UV; *mode |= MA_VERTEXCOL; break;
124                                         }
125                                 }
126                         }
127                 }
128         }
129 }
130
131 /* nodes that use ID data get synced with local data */
132 void nodeShaderSynchronizeID(bNode *node, int copyto)
133 {
134         if(node->id==NULL) return;
135         
136         if(ELEM(node->type, SH_NODE_MATERIAL, SH_NODE_MATERIAL_EXT)) {
137                 bNodeSocket *sock;
138                 Material *ma= (Material *)node->id;
139                 int a;
140                 
141                 /* hrmf, case in loop isnt super fast, but we dont edit 100s of material at same time either! */
142                 for(a=0, sock= node->inputs.first; sock; sock= sock->next, a++) {
143                         if(!(sock->flag & SOCK_HIDDEN)) {
144                                 if(copyto) {
145                                         switch(a) {
146                                                 case MAT_IN_COLOR:
147                                                         VECCOPY(&ma->r, ((bNodeSocketValueRGBA*)sock->default_value)->value); break;
148                                                 case MAT_IN_SPEC:
149                                                         VECCOPY(&ma->specr, ((bNodeSocketValueRGBA*)sock->default_value)->value); break;
150                                                 case MAT_IN_REFL:
151                                                         ma->ref= ((bNodeSocketValueFloat*)sock->default_value)->value; break;
152                                                 case MAT_IN_MIR:
153                                                         VECCOPY(&ma->mirr, ((bNodeSocketValueRGBA*)sock->default_value)->value); break;
154                                                 case MAT_IN_AMB:
155                                                         ma->amb= ((bNodeSocketValueFloat*)sock->default_value)->value; break;
156                                                 case MAT_IN_EMIT:
157                                                         ma->emit= ((bNodeSocketValueFloat*)sock->default_value)->value; break;
158                                                 case MAT_IN_SPECTRA:
159                                                         ma->spectra= ((bNodeSocketValueFloat*)sock->default_value)->value; break;
160                                                 case MAT_IN_RAY_MIRROR:
161                                                         ma->ray_mirror= ((bNodeSocketValueFloat*)sock->default_value)->value; break;
162                                                 case MAT_IN_ALPHA:
163                                                         ma->alpha= ((bNodeSocketValueFloat*)sock->default_value)->value; break;
164                                                 case MAT_IN_TRANSLUCENCY:
165                                                         ma->translucency= ((bNodeSocketValueFloat*)sock->default_value)->value; break;
166                                         }
167                                 }
168                                 else {
169                                         switch(a) {
170                                                 case MAT_IN_COLOR:
171                                                         VECCOPY(((bNodeSocketValueRGBA*)sock->default_value)->value, &ma->r); break;
172                                                 case MAT_IN_SPEC:
173                                                         VECCOPY(((bNodeSocketValueRGBA*)sock->default_value)->value, &ma->specr); break;
174                                                 case MAT_IN_REFL:
175                                                         ((bNodeSocketValueFloat*)sock->default_value)->value= ma->ref; break;
176                                                 case MAT_IN_MIR:
177                                                         VECCOPY(((bNodeSocketValueRGBA*)sock->default_value)->value, &ma->mirr); break;
178                                                 case MAT_IN_AMB:
179                                                         ((bNodeSocketValueFloat*)sock->default_value)->value= ma->amb; break;
180                                                 case MAT_IN_EMIT:
181                                                         ((bNodeSocketValueFloat*)sock->default_value)->value= ma->emit; break;
182                                                 case MAT_IN_SPECTRA:
183                                                         ((bNodeSocketValueFloat*)sock->default_value)->value= ma->spectra; break;
184                                                 case MAT_IN_RAY_MIRROR:
185                                                         ((bNodeSocketValueFloat*)sock->default_value)->value= ma->ray_mirror; break;
186                                                 case MAT_IN_ALPHA:
187                                                         ((bNodeSocketValueFloat*)sock->default_value)->value= ma->alpha; break;
188                                                 case MAT_IN_TRANSLUCENCY:
189                                                         ((bNodeSocketValueFloat*)sock->default_value)->value= ma->translucency; break;
190                                         }
191                                 }
192                         }
193                 }
194         }
195         
196 }
197
198
199 void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
200 {
201         memset(gs, 0, sizeof(*gs));
202         
203         QUATCOPY(gs->vec, ns->vec);
204         gs->link= ns->data;
205         
206         if (type == SOCK_FLOAT)
207                 gs->type= GPU_FLOAT;
208         else if (type == SOCK_VECTOR)
209                 gs->type= GPU_VEC3;
210         else if (type == SOCK_RGBA)
211                 gs->type= GPU_VEC4;
212         else
213                 gs->type= GPU_NONE;
214         
215         gs->name = "";
216         gs->hasinput= ns->hasinput && ns->data;
217         gs->hasoutput= ns->hasoutput && ns->data;
218         gs->sockettype= ns->sockettype;
219 }
220
221 void node_data_from_gpu_stack(bNodeStack *ns, GPUNodeStack *gs)
222 {
223         ns->data= gs->link;
224         ns->sockettype= gs->sockettype;
225 }
226
227 static void gpu_stack_from_data_list(GPUNodeStack *gs, ListBase *sockets, bNodeStack **ns)
228 {
229         bNodeSocket *sock;
230         int i;
231         
232         for (sock=sockets->first, i=0; sock; sock=sock->next, i++)
233                 node_gpu_stack_from_data(&gs[i], sock->type, ns[i]);
234         
235         gs[i].type= GPU_NONE;
236 }
237
238 static void data_from_gpu_stack_list(ListBase *sockets, bNodeStack **ns, GPUNodeStack *gs)
239 {
240         bNodeSocket *sock;
241         int i;
242
243         for (sock=sockets->first, i=0; sock; sock=sock->next, i++)
244                 node_data_from_gpu_stack(ns[i], &gs[i]);
245 }
246
247 void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, int do_outputs)
248 {
249         bNodeExec *nodeexec;
250         bNode *node;
251         int n;
252         bNodeStack *stack;
253         bNodeStack *nsin[MAX_SOCKET];   /* arbitrary... watch this */
254         bNodeStack *nsout[MAX_SOCKET];  /* arbitrary... watch this */
255         GPUNodeStack gpuin[MAX_SOCKET+1], gpuout[MAX_SOCKET+1];
256         int doit;
257
258         stack= exec->stack;
259
260         for(n=0, nodeexec= exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
261                 node = nodeexec->node;
262                 
263                 doit = 0;
264                 /* for groups, only execute outputs for edited group */
265                 if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
266                         if(do_outputs && (node->flag & NODE_DO_OUTPUT))
267                                 doit = 1;
268                 }
269                 else
270                         doit = 1;
271
272                 if (doit) {
273                         if(node->typeinfo->gpufunc) {
274                                 node_get_stack(node, stack, nsin, nsout);
275                                 gpu_stack_from_data_list(gpuin, &node->inputs, nsin);
276                                 gpu_stack_from_data_list(gpuout, &node->outputs, nsout);
277                                 if(node->typeinfo->gpufunc(mat, node, gpuin, gpuout))
278                                         data_from_gpu_stack_list(&node->outputs, nsout, gpuout);
279                         }
280                         else if(node->typeinfo->gpuextfunc) {
281                                 node_get_stack(node, stack, nsin, nsout);
282                                 gpu_stack_from_data_list(gpuin, &node->inputs, nsin);
283                                 gpu_stack_from_data_list(gpuout, &node->outputs, nsout);
284                                 if(node->typeinfo->gpuextfunc(mat, node, nodeexec->data, gpuin, gpuout))
285                                         data_from_gpu_stack_list(&node->outputs, nsout, gpuout);
286                         }
287                 }
288         }
289 }