More texnode preview fixes. Previews now have correct aspect ratio and are drawn...
[blender.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 int preview_flag = 0;
51
52 void tex_call_delegate(TexDelegate *dg, float *out, TexParams *params, short thread)
53 {
54         if(dg->node->need_exec)
55                 dg->fn(out, params, dg->node, dg->in, thread);
56 }
57
58 void tex_input(float *out, int sz, bNodeStack *in, TexParams *params, short thread)
59 {
60         TexDelegate *dg = in->data;
61         if(dg) {
62                 tex_call_delegate(dg, in->vec, params, thread);
63         
64                 if(in->hasoutput && in->sockettype == SOCK_VALUE)
65                         in->vec[1] = in->vec[2] = in->vec[0];
66         }
67         memcpy(out, in->vec, sz * sizeof(float));
68 }
69
70 void tex_input_vec(float *out, bNodeStack *in, TexParams *params, short thread)
71 {
72         tex_input(out, 3, in, params, thread);
73 }
74
75 void tex_input_rgba(float *out, bNodeStack *in, TexParams *params, short thread)
76 {
77         tex_input(out, 4, in, params, thread);
78         
79         if(in->hasoutput && in->sockettype == SOCK_VALUE)
80         {
81                 out[1] = out[2] = out[0];
82                 out[3] = 1;
83         }
84         
85         if(in->hasoutput && in->sockettype == SOCK_VECTOR) {
86                 out[0] = out[0] * .5f + .5f;
87                 out[1] = out[1] * .5f + .5f;
88                 out[2] = out[2] * .5f + .5f;
89                 out[3] = 1;
90         }
91 }
92
93 float tex_input_value(bNodeStack *in, TexParams *params, short thread)
94 {
95         float out[4];
96         tex_input_vec(out, in, params, thread);
97         return out[0];
98 }
99
100 static void init_preview(bNode *node)
101 {
102         int xsize = (int)(node->prvr.xmax - node->prvr.xmin);
103         int ysize = (int)(node->prvr.ymax - node->prvr.ymin);
104         
105         if(xsize == 0) {
106                 xsize = PREV_RES;
107                 ysize = PREV_RES;
108         }
109         
110         if(node->preview==NULL)
111                 node->preview= MEM_callocN(sizeof(bNodePreview), "node preview");
112         
113         if(node->preview->rect==NULL) {
114                 node->preview->rect= MEM_callocN(4*xsize + xsize*ysize*sizeof(float)*4, "node preview rect");
115                 node->preview->xsize= xsize;
116                 node->preview->ysize= ysize;
117         }
118 }
119
120 void params_from_cdata(TexParams *out, TexCallData *in)
121 {
122         out->coord = in->coord;
123         out->dxt = in->dxt;
124         out->dyt = in->dyt;
125         out->cfra = in->cfra;
126 }
127
128 void tex_do_preview(bNode *node, bNodeStack *ns, TexCallData *cdata)
129 {
130         int x, y;
131         float *result;
132         bNodePreview *preview;
133         float coord[3] = {0, 0, 0};
134         TexParams params;
135         int resolution;
136         int xsize, ysize;
137         
138         if(!cdata->do_preview)
139                 return;
140         
141         if(!(node->typeinfo->flag & NODE_PREVIEW))
142                 return;
143         
144         init_preview(node);
145         
146         preview = node->preview;
147         xsize = preview->xsize;
148         ysize = preview->ysize;
149         
150         params.dxt = 0;
151         params.dyt = 0;
152         params.cfra = cdata->cfra;
153         params.coord = coord;
154         
155         resolution = (xsize < ysize) ? xsize : ysize;
156         
157         for(x=0; x<xsize; x++)
158         for(y=0; y<ysize; y++)
159         {
160                 params.coord[0] = ((float) x / resolution) * 2 - 1;
161                 params.coord[1] = ((float) y / resolution) * 2 - 1;
162                 
163                 result = preview->rect + 4 * (xsize*y + x);
164                 
165                 tex_input_rgba(result, ns, &params, cdata->thread);
166         }
167 }
168
169 void tex_output(bNode *node, bNodeStack **in, bNodeStack *out, TexFn texfn)
170 {
171         TexDelegate *dg;
172         if(!out->data)
173                 /* Freed in tex_end_exec (node.c) */
174                 dg = out->data = MEM_mallocN(sizeof(TexDelegate), "tex delegate");
175         else
176                 dg = out->data;
177         
178         
179         dg->fn = texfn;
180         dg->node = node;
181         memcpy(dg->in, in, MAX_SOCKET * sizeof(bNodeStack*));
182         dg->type = out->sockettype;
183 }
184
185 void ntreeTexCheckCyclics(struct bNodeTree *ntree)
186 {
187         bNode *node;
188         for(node= ntree->nodes.first; node; node= node->next) {
189                 
190                 if(node->type == TEX_NODE_TEXTURE && node->id)
191                 {
192                         /* custom2 stops the node from rendering */
193                         if(node->custom1) {
194                                 node->custom2 = 1;
195                                 node->custom1 = 0;
196                         } else {
197                                 Tex *tex = (Tex *)node->id;
198                                 
199                                 node->custom2 = 0;
200                         
201                                 node->custom1 = 1;
202                                 if(tex->use_nodes && tex->nodetree) {
203                                         ntreeTexCheckCyclics(tex->nodetree);
204                                 }
205                                 node->custom1 = 0;
206                         }
207                 }
208
209         }
210 }
211
212 void ntreeTexExecTree(
213         bNodeTree *nodes,
214         TexResult *texres,
215         float *coord,
216         float *dxt, float *dyt,
217         short thread, 
218         Tex *tex, 
219         short which_output, 
220         int cfra
221 ){
222         TexResult dummy_texres;
223         TexCallData data;
224         
225         /* 0 means don't care, so just use first */
226         if(which_output == 0)
227                 which_output = 1;
228         
229         if(!texres) texres = &dummy_texres;
230         data.coord = coord;
231         data.dxt = dxt;
232         data.dyt = dyt;
233         data.target = texres;
234         data.do_preview = preview_flag;
235         data.thread = thread;
236         data.which_output = which_output;
237         data.cfra= cfra;
238         
239         preview_flag = 0;
240         
241         ntreeExecTree(nodes, &data, thread);
242 }
243
244 void ntreeTexSetPreviewFlag(int doit)
245 {
246         preview_flag = doit;
247 }
248
249 char* ntreeTexOutputMenu(bNodeTree *ntree)
250 {
251         bNode *node;
252         int len = 1;
253         char *str;
254         char ctrl[4];
255         int index = 0;
256         
257         for(node= ntree->nodes.first; node; node= node->next)
258                 if(node->type == TEX_NODE_OUTPUT) {
259                         len += strlen( 
260                                 ((TexNodeOutput*)node->storage)->name
261                         ) + strlen(" %xNNN|");
262                         index ++;
263                         
264                         if(node->custom1 > 999) {
265                                 printf("Error: too many outputs");
266                                 break;
267                         }
268                 }
269                         
270         str = malloc(len * sizeof(char));
271         *str = 0;
272
273         for(node= ntree->nodes.first; node; node= node->next)
274                 if(node->type == TEX_NODE_OUTPUT) {
275                         strcat(str, ((TexNodeOutput*)node->storage)->name);
276                         strcat(str, " %x");
277                         
278                         sprintf(ctrl, "%d", node->custom1);
279                         strcat(str, ctrl);
280                         
281                         if(--index)
282                                 strcat(str, "|");
283                         else
284                                 break;
285                 }
286         
287         return str;
288 }
289