style cleanup
[blender.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 /* go over all used Geometry and Texture nodes, and return a texco flag */
80 /* no group inside needed, this function is called for groups too */
81 void ntreeShaderGetTexcoMode(bNodeTree *ntree, int r_mode, short *texco, int *mode)
82 {
83         bNode *node;
84         bNodeSocket *sock;
85         int a;
86         
87         for (node= ntree->nodes.first; node; node= node->next) {
88                 if (node->type==SH_NODE_TEXTURE) {
89                         if ((r_mode & R_OSA) && node->id) {
90                                 Tex *tex= (Tex *)node->id;
91                                 if (ELEM(tex->type, TEX_IMAGE, TEX_ENVMAP)) {
92                                         *texco |= TEXCO_OSA|NEED_UV;
93                                 }
94                         }
95                         /* usability exception... without input we still give the node orcos */
96                         sock= node->inputs.first;
97                         if (sock==NULL || sock->link==NULL)
98                                 *texco |= TEXCO_ORCO|NEED_UV;
99                 }
100                 else if (node->type==SH_NODE_GEOMETRY) {
101                         /* note; sockets always exist for the given type! */
102                         for (a=0, sock= node->outputs.first; sock; sock= sock->next, a++) {
103                                 if (sock->flag & SOCK_IN_USE) {
104                                         switch (a) {
105                                                 case GEOM_OUT_GLOB: 
106                                                         *texco |= TEXCO_GLOB|NEED_UV; break;
107                                                 case GEOM_OUT_VIEW: 
108                                                         *texco |= TEXCO_VIEW|NEED_UV; break;
109                                                 case GEOM_OUT_ORCO: 
110                                                         *texco |= TEXCO_ORCO|NEED_UV; break;
111                                                 case GEOM_OUT_UV: 
112                                                         *texco |= TEXCO_UV|NEED_UV; break;
113                                                 case GEOM_OUT_NORMAL: 
114                                                         *texco |= TEXCO_NORM|NEED_UV; break;
115                                                 case GEOM_OUT_VCOL:
116                                                         *texco |= NEED_UV; *mode |= MA_VERTEXCOL; break;
117                                                 case GEOM_OUT_VCOL_ALPHA:
118                                                         *texco |= NEED_UV; *mode |= MA_VERTEXCOL; break;
119                                         }
120                                 }
121                         }
122                 }
123         }
124 }
125
126 /* nodes that use ID data get synced with local data */
127 void nodeShaderSynchronizeID(bNode *node, int copyto)
128 {
129         if (node->id==NULL) return;
130         
131         if (ELEM(node->type, SH_NODE_MATERIAL, SH_NODE_MATERIAL_EXT)) {
132                 bNodeSocket *sock;
133                 Material *ma= (Material *)node->id;
134                 int a;
135                 
136                 /* hrmf, case in loop isn't super fast, but we don't edit 100s of material at same time either! */
137                 for (a=0, sock= node->inputs.first; sock; sock= sock->next, a++) {
138                         if (!nodeSocketIsHidden(sock)) {
139                                 if (copyto) {
140                                         switch (a) {
141                                                 case MAT_IN_COLOR:
142                                                         copy_v3_v3(&ma->r, ((bNodeSocketValueRGBA *)sock->default_value)->value); break;
143                                                 case MAT_IN_SPEC:
144                                                         copy_v3_v3(&ma->specr, ((bNodeSocketValueRGBA *)sock->default_value)->value); break;
145                                                 case MAT_IN_REFL:
146                                                         ma->ref= ((bNodeSocketValueFloat *)sock->default_value)->value; break;
147                                                 case MAT_IN_MIR:
148                                                         copy_v3_v3(&ma->mirr, ((bNodeSocketValueRGBA *)sock->default_value)->value); break;
149                                                 case MAT_IN_AMB:
150                                                         ma->amb = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
151                                                 case MAT_IN_EMIT:
152                                                         ma->emit = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
153                                                 case MAT_IN_SPECTRA:
154                                                         ma->spectra = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
155                                                 case MAT_IN_RAY_MIRROR:
156                                                         ma->ray_mirror = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
157                                                 case MAT_IN_ALPHA:
158                                                         ma->alpha = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
159                                                 case MAT_IN_TRANSLUCENCY:
160                                                         ma->translucency = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
161                                         }
162                                 }
163                                 else {
164                                         switch (a) {
165                                                 case MAT_IN_COLOR:
166                                                         copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->r); break;
167                                                 case MAT_IN_SPEC:
168                                                         copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->specr); break;
169                                                 case MAT_IN_REFL:
170                                                         ((bNodeSocketValueFloat *)sock->default_value)->value= ma->ref; break;
171                                                 case MAT_IN_MIR:
172                                                         copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->mirr); break;
173                                                 case MAT_IN_AMB:
174                                                         ((bNodeSocketValueFloat *)sock->default_value)->value = ma->amb; break;
175                                                 case MAT_IN_EMIT:
176                                                         ((bNodeSocketValueFloat *)sock->default_value)->value = ma->emit; break;
177                                                 case MAT_IN_SPECTRA:
178                                                         ((bNodeSocketValueFloat *)sock->default_value)->value = ma->spectra; break;
179                                                 case MAT_IN_RAY_MIRROR:
180                                                         ((bNodeSocketValueFloat *)sock->default_value)->value = ma->ray_mirror; break;
181                                                 case MAT_IN_ALPHA:
182                                                         ((bNodeSocketValueFloat *)sock->default_value)->value = ma->alpha; break;
183                                                 case MAT_IN_TRANSLUCENCY:
184                                                         ((bNodeSocketValueFloat *)sock->default_value)->value = ma->translucency; break;
185                                         }
186                                 }
187                         }
188                 }
189         }
190         
191 }
192
193
194 void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
195 {
196         memset(gs, 0, sizeof(*gs));
197         
198         copy_v4_v4(gs->vec, ns->vec);
199         gs->link= ns->data;
200         
201         if (type == SOCK_FLOAT)
202                 gs->type= GPU_FLOAT;
203         else if (type == SOCK_VECTOR)
204                 gs->type= GPU_VEC3;
205         else if (type == SOCK_RGBA)
206                 gs->type= GPU_VEC4;
207         else if (type == SOCK_SHADER)
208                 gs->type= GPU_VEC4;
209         else
210                 gs->type= GPU_NONE;
211         
212         gs->name = "";
213         gs->hasinput= ns->hasinput && ns->data;
214         /* XXX Commented out the ns->data check here, as it seems it's not always set,
215          *     even though there *is* a valid connection/output... But that might need
216          *     further investigation.
217          */
218         gs->hasoutput= ns->hasoutput /*&& ns->data*/;
219         gs->sockettype= ns->sockettype;
220 }
221
222 void node_data_from_gpu_stack(bNodeStack *ns, GPUNodeStack *gs)
223 {
224         ns->data= gs->link;
225         ns->sockettype= gs->sockettype;
226 }
227
228 static void gpu_stack_from_data_list(GPUNodeStack *gs, ListBase *sockets, bNodeStack **ns)
229 {
230         bNodeSocket *sock;
231         int i;
232         
233         for (sock=sockets->first, i=0; sock; sock=sock->next, i++)
234                 node_gpu_stack_from_data(&gs[i], sock->type, ns[i]);
235         
236         gs[i].type= GPU_NONE;
237 }
238
239 static void data_from_gpu_stack_list(ListBase *sockets, bNodeStack **ns, GPUNodeStack *gs)
240 {
241         bNodeSocket *sock;
242         int i;
243
244         for (sock=sockets->first, i=0; sock; sock=sock->next, i++)
245                 node_data_from_gpu_stack(ns[i], &gs[i]);
246 }
247
248 bNode *nodeGetActiveTexture(bNodeTree *ntree)
249 {
250         /* this is the node we texture paint and draw in textured draw */
251         bNode *node;
252
253         if (!ntree)
254                 return NULL;
255
256         /* check for group edit */
257         for (node= ntree->nodes.first; node; node= node->next)
258                 if (node->flag & NODE_GROUP_EDIT)
259                         break;
260
261         if (node)
262                 ntree = (bNodeTree *)node->id;
263
264         for (node= ntree->nodes.first; node; node= node->next)
265                 if (node->flag & NODE_ACTIVE_TEXTURE)
266                         return node;
267         
268         return NULL;
269 }
270
271 void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, int do_outputs)
272 {
273         bNodeExec *nodeexec;
274         bNode *node;
275         int n;
276         bNodeStack *stack;
277         bNodeStack *nsin[MAX_SOCKET];   /* arbitrary... watch this */
278         bNodeStack *nsout[MAX_SOCKET];  /* arbitrary... watch this */
279         GPUNodeStack gpuin[MAX_SOCKET+1], gpuout[MAX_SOCKET+1];
280         int do_it;
281
282         stack= exec->stack;
283
284         for (n=0, nodeexec= exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
285                 node = nodeexec->node;
286                 
287                 do_it = FALSE;
288                 /* for groups, only execute outputs for edited group */
289                 if (node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
290                         if (do_outputs && (node->flag & NODE_DO_OUTPUT))
291                                 do_it = TRUE;
292                 }
293                 else
294                         do_it = TRUE;
295
296                 if (do_it) {
297                         if (node->typeinfo->gpufunc) {
298                                 node_get_stack(node, stack, nsin, nsout);
299                                 gpu_stack_from_data_list(gpuin, &node->inputs, nsin);
300                                 gpu_stack_from_data_list(gpuout, &node->outputs, nsout);
301                                 if (node->typeinfo->gpufunc(mat, node, gpuin, gpuout))
302                                         data_from_gpu_stack_list(&node->outputs, nsout, gpuout);
303                         }
304                         else if (node->typeinfo->gpuextfunc) {
305                                 node_get_stack(node, stack, nsin, nsout);
306                                 gpu_stack_from_data_list(gpuin, &node->inputs, nsin);
307                                 gpu_stack_from_data_list(gpuout, &node->outputs, nsout);
308                                 if (node->typeinfo->gpuextfunc(mat, node, nodeexec->data, gpuin, gpuout))
309                                         data_from_gpu_stack_list(&node->outputs, nsout, gpuout);
310                         }
311                 }
312         }
313 }
314
315 void node_shader_gpu_tex_mapping(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *UNUSED(out))
316 {
317         NodeTexBase *base= node->storage;
318         TexMapping *texmap= &base->tex_mapping;
319         float domin= (texmap->flag & TEXMAP_CLIP_MIN) != 0;
320         float domax= (texmap->flag & TEXMAP_CLIP_MAX) != 0;
321
322         if (domin || domax || !(texmap->flag & TEXMAP_UNIT_MATRIX)) {
323                 GPUNodeLink *tmat = GPU_uniform((float *)texmap->mat);
324                 GPUNodeLink *tmin = GPU_uniform(texmap->min);
325                 GPUNodeLink *tmax = GPU_uniform(texmap->max);
326                 GPUNodeLink *tdomin = GPU_uniform(&domin);
327                 GPUNodeLink *tdomax = GPU_uniform(&domax);
328
329                 GPU_link(mat, "mapping", in[0].link, tmat, tmin, tmax, tdomin, tdomax, &in[0].link);
330         }
331 }
332