Implemented multisampling for texture nodes.
[blender-staging.git] / source / blender / nodes / intern / TEX_util.c
1 /**
2  *
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version. 
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2005 Blender Foundation.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s): none yet.
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28  
29 /*
30         HOW TEXTURE NODES WORK
31
32         In contrast to Shader nodes, which place a colour into the output
33         stack when executed, Texture nodes place a TexDelegate* there. To
34         obtain a colour value from this, a node further up the chain reads
35         the TexDelegate* from its input stack, and uses tex_call_delegate to
36         retrieve the colour from the delegate.
37  
38     comments: (ton)
39     
40     This system needs recode, a node system should rely on the stack, and 
41         callbacks for nodes only should evaluate own node, not recursively go
42     over other previous ones.
43 */
44
45 #include <assert.h>
46 #include "TEX_util.h"
47
48 #define PREV_RES 128 /* default preview resolution */
49
50 void tex_call_delegate(TexDelegate *dg, float *out, TexParams *params, short thread)
51 {
52         if(dg->node->need_exec)
53                 dg->fn(out, params, dg->node, dg->in, thread);
54 }
55
56 void tex_input(float *out, int sz, bNodeStack *in, TexParams *params, short thread)
57 {
58         TexDelegate *dg = in->data;
59         if(dg) {
60                 tex_call_delegate(dg, in->vec, params, thread);
61         
62                 if(in->hasoutput && in->sockettype == SOCK_VALUE)
63                         in->vec[1] = in->vec[2] = in->vec[0];
64         }
65         memcpy(out, in->vec, sz * sizeof(float));
66 }
67
68 void tex_input_vec(float *out, bNodeStack *in, TexParams *params, short thread)
69 {
70         tex_input(out, 3, in, params, thread);
71 }
72
73 void tex_input_rgba(float *out, bNodeStack *in, TexParams *params, short thread)
74 {
75         tex_input(out, 4, in, params, thread);
76         
77         if(in->hasoutput && in->sockettype == SOCK_VALUE)
78         {
79                 out[1] = out[2] = out[0];
80                 out[3] = 1;
81         }
82         
83         if(in->hasoutput && in->sockettype == SOCK_VECTOR) {
84                 out[0] = out[0] * .5f + .5f;
85                 out[1] = out[1] * .5f + .5f;
86                 out[2] = out[2] * .5f + .5f;
87                 out[3] = 1;
88         }
89 }
90
91 float tex_input_value(bNodeStack *in, TexParams *params, short thread)
92 {
93         float out[4];
94         tex_input_vec(out, in, params, thread);
95         return out[0];
96 }
97
98 static void init_preview(bNode *node)
99 {
100         int xsize = (int)(node->prvr.xmax - node->prvr.xmin);
101         int ysize = (int)(node->prvr.ymax - node->prvr.ymin);
102         
103         if(xsize == 0) {
104                 xsize = PREV_RES;
105                 ysize = PREV_RES;
106         }
107         
108         if(node->preview==NULL)
109                 node->preview= MEM_callocN(sizeof(bNodePreview), "node preview");
110         
111         if(node->preview->rect)
112                 if(node->preview->xsize!=xsize && node->preview->ysize!=ysize) {
113                         MEM_freeN(node->preview->rect);
114                         node->preview->rect= NULL;
115                 }
116         
117         if(node->preview->rect==NULL) {
118                 node->preview->rect= MEM_callocN(4*xsize + xsize*ysize*sizeof(float)*4, "node preview rect");
119                 node->preview->xsize= xsize;
120                 node->preview->ysize= ysize;
121         }
122 }
123
124 void params_from_cdata(TexParams *out, TexCallData *in)
125 {
126         out->coord = in->coord;
127         out->dxt = in->dxt;
128         out->dyt = in->dyt;
129         out->cfra = in->cfra;
130 }
131
132 void tex_do_preview(bNode *node, bNodeStack *ns, TexCallData *cdata)
133 {
134         int x, y;
135         float *result;
136         bNodePreview *preview;
137         float coord[3] = {0, 0, 0};
138         TexParams params;
139         
140         if(!cdata->do_preview)
141                 return;
142         
143         if(!(node->typeinfo->flag & NODE_PREVIEW))
144                 return;
145         
146         init_preview(node);
147         
148         preview = node->preview;
149         
150         params.dxt = 0;
151         params.dyt = 0;
152         params.cfra = cdata->cfra;
153         params.coord = coord;
154         
155         for(x=0; x<preview->xsize; x++)
156         for(y=0; y<preview->ysize; y++)
157         {
158                 params.coord[0] = ((float) x / preview->xsize) * 2 - 1;
159                 params.coord[1] = ((float) y / preview->ysize) * 2 - 1;
160                 
161                 result = preview->rect + 4 * (preview->xsize*y + x);
162                 
163                 tex_input_rgba(result, ns, &params, cdata->thread);
164         }
165 }
166
167 void tex_output(bNode *node, bNodeStack **in, bNodeStack *out, TexFn texfn)
168 {
169         TexDelegate *dg;
170         if(!out->data)
171                 /* Freed in tex_end_exec (node.c) */
172                 dg = out->data = MEM_mallocN(sizeof(TexDelegate), "tex delegate");
173         else
174                 dg = out->data;
175         
176         
177         dg->fn = texfn;
178         dg->node = node;
179         memcpy(dg->in, in, MAX_SOCKET * sizeof(bNodeStack*));
180         dg->type = out->sockettype;
181 }
182
183 void ntreeTexCheckCyclics(struct bNodeTree *ntree)
184 {
185         bNode *node;
186         for(node= ntree->nodes.first; node; node= node->next) {
187                 
188                 if(node->type == TEX_NODE_TEXTURE && node->id)
189                 {
190                         /* custom2 stops the node from rendering */
191                         if(node->custom1) {
192                                 node->custom2 = 1;
193                                 node->custom1 = 0;
194                         } else {
195                                 Tex *tex = (Tex *)node->id;
196                                 
197                                 node->custom2 = 0;
198                         
199                                 node->custom1 = 1;
200                                 if(tex->use_nodes && tex->nodetree) {
201                                         ntreeTexCheckCyclics(tex->nodetree);
202                                 }
203                                 node->custom1 = 0;
204                         }
205                 }
206
207         }
208 }
209
210 void ntreeTexExecTree(
211         bNodeTree *nodes,
212         TexResult *texres,
213         float *coord,
214         float *dxt, float *dyt,
215         char do_preview, 
216         short thread, 
217         Tex *tex, 
218         short which_output, 
219         int cfra
220 ){
221         TexResult dummy_texres;
222         TexCallData data;
223         
224         /* 0 means don't care, so just use first */
225         if(which_output == 0)
226                 which_output = 1;
227         
228         if(!texres) texres = &dummy_texres;
229         data.coord = coord;
230         data.dxt = dxt;
231         data.dyt = dyt;
232         data.target = texres;
233         data.do_preview = do_preview;
234         data.thread = thread;
235         data.which_output = which_output;
236         data.cfra= cfra;
237         
238         ntreeExecTree(nodes, &data, thread);
239 }
240
241 void ntreeTexUpdatePreviews(bNodeTree* nodetree)
242 {
243         Tex *tex;
244         float coord[] = {0,0,0};
245         TexResult dummy_texres;
246         
247         for(tex= G.main->tex.first; tex; tex= tex->id.next)
248                 if(tex->nodetree == nodetree) break;
249         if(!tex) return;
250         
251         dummy_texres.nor = 0;
252         
253         ntreeBeginExecTree(nodetree);
254         ntreeTexExecTree(nodetree, &dummy_texres, coord, 0, 0, 1, 0, tex, 0, 0);
255         ntreeEndExecTree(nodetree);
256         
257 }
258
259 char* ntreeTexOutputMenu(bNodeTree *ntree)
260 {
261         bNode *node;
262         int len = 1;
263         char *str;
264         char ctrl[4];
265         int index = 0;
266         
267         for(node= ntree->nodes.first; node; node= node->next)
268                 if(node->type == TEX_NODE_OUTPUT) {
269                         len += strlen( 
270                                 ((TexNodeOutput*)node->storage)->name
271                         ) + strlen(" %xNNN|");
272                         index ++;
273                         
274                         if(node->custom1 > 999) {
275                                 printf("Error: too many outputs");
276                                 break;
277                         }
278                 }
279                         
280         str = malloc(len * sizeof(char));
281         *str = 0;
282
283         for(node= ntree->nodes.first; node; node= node->next)
284                 if(node->type == TEX_NODE_OUTPUT) {
285                         strcat(str, ((TexNodeOutput*)node->storage)->name);
286                         strcat(str, " %x");
287                         
288                         sprintf(ctrl, "%d", node->custom1);
289                         strcat(str, ctrl);
290                         
291                         if(--index)
292                                 strcat(str, "|");
293                         else
294                                 break;
295                 }
296         
297         return str;
298 }
299
300 void ntreeTexAssignIndex(struct bNodeTree *ntree, struct bNode *node)
301 {
302         bNode *tnode;
303         int index = 1;
304         
305         if(ntree) 
306                 tnode = ntree->nodes.first;
307         else {
308                 tnode = node;
309                 while(tnode->prev) tnode = tnode->prev;
310         }
311         
312         check_index:
313         for(; tnode; tnode= tnode->next)
314                 if(tnode->type == TEX_NODE_OUTPUT && tnode != node)
315                         if(tnode->custom1 == index) {
316                                 index ++;
317                                 goto check_index;
318                         }
319                         
320         node->custom1 = index;
321 }
322