UI: Refactor timecode functions into BLI_timecode
[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 int sh_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
41 {
42         return STREQ(ntree->idname, "ShaderNodeTree");
43 }
44
45 void sh_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass, short flag)
46 {
47         node_type_base(ntype, type, name, nclass, flag);
48         
49         ntype->poll = sh_node_poll_default;
50         ntype->update_internal_links = node_update_internal_links_default;
51 }
52
53 /* ****** */
54
55 void nodestack_get_vec(float *in, short type_in, bNodeStack *ns)
56 {
57         float *from = ns->vec;
58                 
59         if (type_in == SOCK_FLOAT) {
60                 if (ns->sockettype == SOCK_FLOAT)
61                         *in = *from;
62                 else 
63                         *in = (from[0] + from[1] + from[2]) / 3.0f;
64         }
65         else if (type_in == SOCK_VECTOR) {
66                 if (ns->sockettype == SOCK_FLOAT) {
67                         in[0] = from[0];
68                         in[1] = from[0];
69                         in[2] = from[0];
70                 }
71                 else {
72                         copy_v3_v3(in, from);
73                 }
74         }
75         else { /* type_in==SOCK_RGBA */
76                 if (ns->sockettype == SOCK_RGBA) {
77                         copy_v4_v4(in, from);
78                 }
79                 else if (ns->sockettype == SOCK_FLOAT) {
80                         in[0] = from[0];
81                         in[1] = from[0];
82                         in[2] = from[0];
83                         in[3] = 1.0f;
84                 }
85                 else {
86                         copy_v3_v3(in, from);
87                         in[3] = 1.0f;
88                 }
89         }
90 }
91
92
93 /* go over all used Geometry and Texture nodes, and return a texco flag */
94 /* no group inside needed, this function is called for groups too */
95 void ntreeShaderGetTexcoMode(bNodeTree *ntree, int r_mode, short *texco, int *mode)
96 {
97         bNode *node;
98         bNodeSocket *sock;
99         int a;
100         
101         for (node = ntree->nodes.first; node; node = node->next) {
102                 if (node->type == SH_NODE_TEXTURE) {
103                         if ((r_mode & R_OSA) && node->id) {
104                                 Tex *tex = (Tex *)node->id;
105                                 if (ELEM(tex->type, TEX_IMAGE, TEX_ENVMAP)) {
106                                         *texco |= TEXCO_OSA | NEED_UV;
107                                 }
108                         }
109                         /* usability exception... without input we still give the node orcos */
110                         sock = node->inputs.first;
111                         if (sock == NULL || sock->link == NULL)
112                                 *texco |= TEXCO_ORCO | NEED_UV;
113                 }
114                 else if (node->type == SH_NODE_GEOMETRY) {
115                         /* note; sockets always exist for the given type! */
116                         for (a = 0, sock = node->outputs.first; sock; sock = sock->next, a++) {
117                                 if (sock->flag & SOCK_IN_USE) {
118                                         switch (a) {
119                                                 case GEOM_OUT_GLOB: 
120                                                         *texco |= TEXCO_GLOB | NEED_UV; break;
121                                                 case GEOM_OUT_VIEW: 
122                                                         *texco |= TEXCO_VIEW | NEED_UV; break;
123                                                 case GEOM_OUT_ORCO: 
124                                                         *texco |= TEXCO_ORCO | NEED_UV; break;
125                                                 case GEOM_OUT_UV: 
126                                                         *texco |= TEXCO_UV | NEED_UV; break;
127                                                 case GEOM_OUT_NORMAL: 
128                                                         *texco |= TEXCO_NORM | NEED_UV; break;
129                                                 case GEOM_OUT_VCOL:
130                                                         *texco |= NEED_UV; *mode |= MA_VERTEXCOL; break;
131                                                 case GEOM_OUT_VCOL_ALPHA:
132                                                         *texco |= NEED_UV; *mode |= MA_VERTEXCOL; break;
133                                         }
134                                 }
135                         }
136                 }
137         }
138 }
139
140 void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
141 {
142         memset(gs, 0, sizeof(*gs));
143         
144         copy_v4_v4(gs->vec, ns->vec);
145         gs->link = ns->data;
146         
147         if (type == SOCK_FLOAT)
148                 gs->type = GPU_FLOAT;
149         else if (type == SOCK_VECTOR)
150                 gs->type = GPU_VEC3;
151         else if (type == SOCK_RGBA)
152                 gs->type = GPU_VEC4;
153         else if (type == SOCK_SHADER)
154                 gs->type = GPU_VEC4;
155         else
156                 gs->type = GPU_NONE;
157         
158         gs->name = "";
159         gs->hasinput = ns->hasinput && ns->data;
160         /* XXX Commented out the ns->data check here, as it seems it's not always set,
161          *     even though there *is* a valid connection/output... But that might need
162          *     further investigation.
163          */
164         gs->hasoutput = ns->hasoutput /*&& ns->data*/;
165         gs->sockettype = ns->sockettype;
166 }
167
168 void node_data_from_gpu_stack(bNodeStack *ns, GPUNodeStack *gs)
169 {
170         copy_v4_v4(ns->vec, gs->vec);
171         ns->data = gs->link;
172         ns->sockettype = gs->sockettype;
173 }
174
175 static void gpu_stack_from_data_list(GPUNodeStack *gs, ListBase *sockets, bNodeStack **ns)
176 {
177         bNodeSocket *sock;
178         int i;
179         
180         for (sock = sockets->first, i = 0; sock; sock = sock->next, i++)
181                 node_gpu_stack_from_data(&gs[i], sock->type, ns[i]);
182         
183         gs[i].type = GPU_NONE;
184 }
185
186 static void data_from_gpu_stack_list(ListBase *sockets, bNodeStack **ns, GPUNodeStack *gs)
187 {
188         bNodeSocket *sock;
189         int i;
190
191         for (sock = sockets->first, i = 0; sock; sock = sock->next, i++)
192                 node_data_from_gpu_stack(ns[i], &gs[i]);
193 }
194
195 bNode *nodeGetActiveTexture(bNodeTree *ntree)
196 {
197         /* this is the node we texture paint and draw in textured draw */
198         bNode *node, *tnode, *inactivenode = NULL;
199
200         if (!ntree)
201                 return NULL;
202
203         for (node = ntree->nodes.first; node; node = node->next) {
204                 if (node->flag & NODE_ACTIVE_TEXTURE)
205                         return node;
206                 else if (!inactivenode && node->typeinfo->nclass == NODE_CLASS_TEXTURE)
207                         inactivenode = node;
208         }
209         
210         /* node active texture node in this tree, look inside groups */
211         for (node = ntree->nodes.first; node; node = node->next) {
212                 if (node->type == NODE_GROUP) {
213                         tnode = nodeGetActiveTexture((bNodeTree *)node->id);
214                         if (tnode && ((tnode->flag & NODE_ACTIVE_TEXTURE) || !inactivenode))
215                                 return tnode;
216                 }
217         }
218         
219         return inactivenode;
220 }
221
222 void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, int do_outputs)
223 {
224         bNodeExec *nodeexec;
225         bNode *node;
226         int n;
227         bNodeStack *stack;
228         bNodeStack *nsin[MAX_SOCKET];   /* arbitrary... watch this */
229         bNodeStack *nsout[MAX_SOCKET];  /* arbitrary... watch this */
230         GPUNodeStack gpuin[MAX_SOCKET + 1], gpuout[MAX_SOCKET + 1];
231         int do_it;
232
233         stack = exec->stack;
234
235         for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
236                 node = nodeexec->node;
237                 
238                 do_it = FALSE;
239                 /* for groups, only execute outputs for edited group */
240                 if (node->typeinfo->nclass == NODE_CLASS_OUTPUT) {
241                         if (do_outputs && (node->flag & NODE_DO_OUTPUT))
242                                 do_it = TRUE;
243                 }
244                 else
245                         do_it = TRUE;
246
247                 if (do_it) {
248                         if (node->typeinfo->gpufunc) {
249                                 node_get_stack(node, stack, nsin, nsout);
250                                 gpu_stack_from_data_list(gpuin, &node->inputs, nsin);
251                                 gpu_stack_from_data_list(gpuout, &node->outputs, nsout);
252                                 if (node->typeinfo->gpufunc(mat, node, &nodeexec->data, gpuin, gpuout))
253                                         data_from_gpu_stack_list(&node->outputs, nsout, gpuout);
254                         }
255                 }
256         }
257 }
258
259 void node_shader_gpu_tex_mapping(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *UNUSED(out))
260 {
261         NodeTexBase *base = node->storage;
262         TexMapping *texmap = &base->tex_mapping;
263         float domin = (texmap->flag & TEXMAP_CLIP_MIN) != 0;
264         float domax = (texmap->flag & TEXMAP_CLIP_MAX) != 0;
265
266         if (domin || domax || !(texmap->flag & TEXMAP_UNIT_MATRIX)) {
267                 GPUNodeLink *tmat = GPU_uniform((float *)texmap->mat);
268                 GPUNodeLink *tmin = GPU_uniform(texmap->min);
269                 GPUNodeLink *tmax = GPU_uniform(texmap->max);
270                 GPUNodeLink *tdomin = GPU_uniform(&domin);
271                 GPUNodeLink *tdomax = GPU_uniform(&domax);
272
273                 GPU_link(mat, "mapping", in[0].link, tmat, tmin, tmax, tdomin, tdomax, &in[0].link);
274
275                 if (texmap->type == TEXMAP_TYPE_NORMAL)
276                         GPU_link(mat, "texco_norm", in[0].link, &in[0].link);
277         }
278 }
279