stupid me! if you move var declarations sometimes you have to add
[blender-staging.git] / source / blender / nodes / intern / CMP_nodes / CMP_image.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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2006 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 #include "../CMP_util.h"
31
32
33 /* **************** IMAGE (and RenderResult, multilayer image) ******************** */
34
35 static bNodeSocketType cmp_node_rlayers_out[]= {
36         {       SOCK_RGBA, 0, "Image",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
37         {       SOCK_VALUE, 0, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
38         {       SOCK_VALUE, 0, "Z",                     1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
39         {       SOCK_VECTOR, 0, "Normal",       0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
40         {       SOCK_VECTOR, 0, "UV",           1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
41         {       SOCK_VECTOR, 0, "Speed",        1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
42         {       SOCK_RGBA, 0, "Color",          0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
43         {       SOCK_RGBA, 0, "Diffuse",        0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
44         {       SOCK_RGBA, 0, "Specular",       0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
45         {       SOCK_RGBA, 0, "Shadow",         0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
46         {       SOCK_RGBA, 0, "AO",                     0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
47         {       SOCK_RGBA, 0, "Reflect",        0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
48         {       SOCK_RGBA, 0, "Refract",        0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
49         {       SOCK_RGBA, 0, "Radio",          0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
50         {       SOCK_VALUE, 0, "IndexOB",       0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
51         {       SOCK_VALUE, 0, "Mist",          0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
52         {       -1, 0, ""       }
53 };
54
55
56 /* note: this function is used for multilayer too, to ensure uniform 
57    handling with BKE_image_get_ibuf() */
58 static CompBuf *node_composit_get_image(RenderData *rd, Image *ima, ImageUser *iuser)
59 {
60         ImBuf *ibuf;
61         CompBuf *stackbuf;
62         int type;
63         
64         ibuf= BKE_image_get_ibuf(ima, iuser);
65         if(ibuf==NULL)
66                 return NULL;
67         
68         if(ibuf->rect_float==NULL)
69                 IMB_float_from_rect(ibuf);
70         
71         type= ibuf->channels;
72         
73         if(rd->scemode & R_COMP_CROP) {
74                 stackbuf= get_cropped_compbuf(&rd->disprect, ibuf->rect_float, ibuf->x, ibuf->y, type);
75         }
76         else {
77                 /* we put imbuf copy on stack, cbuf knows rect is from other ibuf when freed! */
78                 stackbuf= alloc_compbuf(ibuf->x, ibuf->y, type, 0);
79                 stackbuf->rect= ibuf->rect_float;
80         }
81         
82         /*code to respect the premul flag of images; I'm
83           not sure if this is a good idea for multilayer images,
84           since it never worked before for them.
85         if (type==CB_RGBA && ima->flag & IMA_DO_PREMUL) {
86                 //premul the image
87                 int i;
88                 float *pixel = stackbuf->rect;
89                 
90                 for (i=0; i<stackbuf->x*stackbuf->y; i++, pixel += 4) {
91                         pixel[0] *= pixel[3];
92                         pixel[1] *= pixel[3];
93                         pixel[2] *= pixel[3];
94                 }
95         }
96         */
97         return stackbuf;
98 };
99
100 static CompBuf *node_composit_get_zimage(bNode *node, RenderData *rd)
101 {
102         ImBuf *ibuf= BKE_image_get_ibuf((Image *)node->id, node->storage);
103         CompBuf *zbuf= NULL;
104         
105         if(ibuf && ibuf->zbuf_float) {
106                 if(rd->scemode & R_COMP_CROP) {
107                         zbuf= get_cropped_compbuf(&rd->disprect, ibuf->zbuf_float, ibuf->x, ibuf->y, CB_VAL);
108                 }
109                 else {
110                         zbuf= alloc_compbuf(ibuf->x, ibuf->y, CB_VAL, 0);
111                         zbuf->rect= ibuf->zbuf_float;
112                 }
113         }
114         return zbuf;
115 };
116
117 /* check if layer is available, returns pass buffer */
118 static CompBuf *compbuf_multilayer_get(RenderData *rd, RenderLayer *rl, Image *ima, ImageUser *iuser, int passtype)
119 {
120         RenderPass *rpass;
121         short index;
122         
123         for(index=0, rpass= rl->passes.first; rpass; rpass= rpass->next, index++)
124                 if(rpass->passtype==passtype)
125                         break;
126         
127         if(rpass) {
128                 CompBuf *cbuf;
129                 
130                 iuser->pass= index;
131                 BKE_image_multilayer_index(ima->rr, iuser);
132                 cbuf= node_composit_get_image(rd, ima, iuser);
133                 
134                 return cbuf;
135         }
136         return NULL;
137 };
138
139 void outputs_multilayer_get(RenderData *rd, RenderLayer *rl, bNodeStack **out, Image *ima, ImageUser *iuser)
140 {
141         if(out[RRES_OUT_Z]->hasoutput)
142                 out[RRES_OUT_Z]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_Z);
143         if(out[RRES_OUT_VEC]->hasoutput)
144                 out[RRES_OUT_VEC]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_VECTOR);
145         if(out[RRES_OUT_NORMAL]->hasoutput)
146                 out[RRES_OUT_NORMAL]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_NORMAL);
147         if(out[RRES_OUT_UV]->hasoutput)
148                 out[RRES_OUT_UV]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_UV);
149         
150         if(out[RRES_OUT_RGBA]->hasoutput)
151                 out[RRES_OUT_RGBA]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_RGBA);
152         if(out[RRES_OUT_DIFF]->hasoutput)
153                 out[RRES_OUT_DIFF]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_DIFFUSE);
154         if(out[RRES_OUT_SPEC]->hasoutput)
155                 out[RRES_OUT_SPEC]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_SPEC);
156         if(out[RRES_OUT_SHADOW]->hasoutput)
157                 out[RRES_OUT_SHADOW]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_SHADOW);
158         if(out[RRES_OUT_AO]->hasoutput)
159                 out[RRES_OUT_AO]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_AO);
160         if(out[RRES_OUT_REFLECT]->hasoutput)
161                 out[RRES_OUT_REFLECT]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_REFLECT);
162         if(out[RRES_OUT_REFRACT]->hasoutput)
163                 out[RRES_OUT_REFRACT]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_REFRACT);
164         if(out[RRES_OUT_RADIO]->hasoutput)
165                 out[RRES_OUT_RADIO]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_RADIO);
166         if(out[RRES_OUT_INDEXOB]->hasoutput)
167                 out[RRES_OUT_INDEXOB]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_INDEXOB);
168         if(out[RRES_OUT_MIST]->hasoutput)
169                 out[RRES_OUT_MIST]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_MIST);
170         
171 };
172
173
174 static void node_composit_exec_image(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
175 {
176         
177         /* image assigned to output */
178         /* stack order input sockets: col, alpha */
179         if(node->id) {
180                 RenderData *rd= data;
181                 Image *ima= (Image *)node->id;
182                 ImageUser *iuser= (ImageUser *)node->storage;
183                 CompBuf *stackbuf= NULL;
184                 
185                 /* first set the right frame number in iuser */
186                 BKE_image_user_calc_imanr(iuser, rd->cfra, 0);
187                 
188                 /* force a load, we assume iuser index will be set OK anyway */
189                 if(ima->type==IMA_TYPE_MULTILAYER)
190                         BKE_image_get_ibuf(ima, iuser);
191                 
192                 if(ima->type==IMA_TYPE_MULTILAYER && ima->rr) {
193                         RenderLayer *rl= BLI_findlink(&ima->rr->layers, iuser->layer);
194                         
195                         if(rl) {
196                                 out[0]->data= stackbuf= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_COMBINED);
197                                 
198                                 /* go over all layers */
199                                 outputs_multilayer_get(rd, rl, out, ima, iuser);
200                         }
201                 }
202                 else {
203                         stackbuf= node_composit_get_image(rd, ima, iuser);
204                         
205                         /*respect image premul option*/
206                         if (stackbuf->type==CB_RGBA && ima->flag & IMA_DO_PREMUL) {
207                                 int i;
208                                 float *pixel;
209                         
210                                 /*first duplicate stackbuf->rect, since it's just a pointer
211                                   to the source imbuf, and we don't want to change that.*/
212                                 stackbuf->rect = MEM_dupallocN(stackbuf->rect);
213                                 
214                                 /*premul the image*/
215                                 
216                                 pixel = stackbuf->rect;
217                                 for (i=0; i<stackbuf->x*stackbuf->y; i++, pixel += 4) {
218                                         pixel[0] *= pixel[3];
219                                         pixel[1] *= pixel[3];
220                                         pixel[2] *= pixel[3];
221                                 }
222                         }
223                         
224                         /* put image on stack */        
225                         out[0]->data= stackbuf;
226                         
227                         if(out[2]->hasoutput)
228                                 out[2]->data= node_composit_get_zimage(node, rd);
229                 }
230                 
231                 /* alpha and preview for both types */
232                 if(stackbuf) {
233                         if(out[1]->hasoutput)
234                                 out[1]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A);
235
236                         generate_preview(node, stackbuf);
237                 }
238         }       
239 };
240
241 static void node_composit_init_image(bNode* node)
242 {
243    ImageUser *iuser= MEM_callocN(sizeof(ImageUser), "node image user");
244    node->storage= iuser;
245    iuser->sfra= 1;
246    iuser->fie_ima= 2;
247    iuser->ok= 1;
248 }
249
250 bNodeType cmp_node_image= {
251         /* *next,*prev */       NULL, NULL,
252         /* type code   */       CMP_NODE_IMAGE,
253         /* name        */       "Image",
254         /* width+range */       120, 80, 300,
255         /* class+opts  */       NODE_CLASS_INPUT, NODE_PREVIEW|NODE_OPTIONS,
256         /* input sock  */       NULL,
257         /* output sock */       cmp_node_rlayers_out,
258         /* storage     */       "ImageUser",
259         /* execfunc    */       node_composit_exec_image,
260         /* butfunc     */       NULL,
261         /* initfunc    */       node_composit_init_image,
262         /* freestoragefunc    */        node_free_standard_storage,
263         /* copystoragefunc    */        node_copy_standard_storage,
264         /* id          */       NULL
265 };
266
267 /* **************** RENDER RESULT ******************** */
268
269 static CompBuf *compbuf_from_pass(RenderData *rd, RenderLayer *rl, int rectx, int recty, int passcode)
270 {
271    float *fp= RE_RenderLayerGetPass(rl, passcode);
272    if(fp) {
273       CompBuf *buf;
274       int buftype= CB_VEC3;
275
276       if(ELEM3(passcode, SCE_PASS_Z, SCE_PASS_INDEXOB, SCE_PASS_MIST))
277          buftype= CB_VAL;
278       else if(passcode==SCE_PASS_VECTOR)
279          buftype= CB_VEC4;
280       else if(ELEM(passcode, SCE_PASS_COMBINED, SCE_PASS_RGBA))
281          buftype= CB_RGBA;
282
283       if(rd->scemode & R_COMP_CROP)
284          buf= get_cropped_compbuf(&rd->disprect, fp, rectx, recty, buftype);
285       else {
286          buf= alloc_compbuf(rectx, recty, buftype, 0);
287          buf->rect= fp;
288       }
289       return buf;
290    }
291    return NULL;
292 };
293
294 void node_composit_rlayers_out(RenderData *rd, RenderLayer *rl, bNodeStack **out, int rectx, int recty)
295 {
296    if(out[RRES_OUT_Z]->hasoutput)
297       out[RRES_OUT_Z]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_Z);
298    if(out[RRES_OUT_VEC]->hasoutput)
299       out[RRES_OUT_VEC]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_VECTOR);
300    if(out[RRES_OUT_NORMAL]->hasoutput)
301       out[RRES_OUT_NORMAL]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_NORMAL);
302    if(out[RRES_OUT_UV]->hasoutput)
303       out[RRES_OUT_UV]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_UV);
304
305    if(out[RRES_OUT_RGBA]->hasoutput)
306       out[RRES_OUT_RGBA]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_RGBA);
307    if(out[RRES_OUT_DIFF]->hasoutput)
308       out[RRES_OUT_DIFF]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_DIFFUSE);
309    if(out[RRES_OUT_SPEC]->hasoutput)
310       out[RRES_OUT_SPEC]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_SPEC);
311    if(out[RRES_OUT_SHADOW]->hasoutput)
312       out[RRES_OUT_SHADOW]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_SHADOW);
313    if(out[RRES_OUT_AO]->hasoutput)
314       out[RRES_OUT_AO]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_AO);
315    if(out[RRES_OUT_REFLECT]->hasoutput)
316       out[RRES_OUT_REFLECT]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_REFLECT);
317    if(out[RRES_OUT_REFRACT]->hasoutput)
318       out[RRES_OUT_REFRACT]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_REFRACT);
319    if(out[RRES_OUT_RADIO]->hasoutput)
320       out[RRES_OUT_RADIO]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_RADIO);
321    if(out[RRES_OUT_INDEXOB]->hasoutput)
322            out[RRES_OUT_INDEXOB]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_INDEXOB);
323    if(out[RRES_OUT_MIST]->hasoutput)
324            out[RRES_OUT_MIST]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_MIST);
325
326 };
327
328 static void node_composit_exec_rlayers(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
329 {
330    Scene *sce= node->id?(Scene *)node->id:G.scene; /* G.scene is WEAK! */
331    RenderData *rd= data;
332    RenderResult *rr;
333
334    rr= RE_GetResult(RE_GetRender(sce->id.name));
335
336    if(rr) {
337       SceneRenderLayer *srl= BLI_findlink(&sce->r.layers, node->custom1);
338       if(srl) {
339          RenderLayer *rl= RE_GetRenderLayer(rr, srl->name);
340          if(rl && rl->rectf) {
341             CompBuf *stackbuf;
342
343             /* we put render rect on stack, cbuf knows rect is from other ibuf when freed! */
344             if(rd->scemode & R_COMP_CROP)
345                stackbuf= get_cropped_compbuf(&rd->disprect, rl->rectf, rr->rectx, rr->recty, CB_RGBA);
346             else {
347                stackbuf= alloc_compbuf(rr->rectx, rr->recty, CB_RGBA, 0);
348                stackbuf->rect= rl->rectf;
349             }
350             if(stackbuf==NULL) {
351                printf("Error; Preview Panel in UV Window returns zero sized image\n");
352             }
353             else {
354                stackbuf->xof= rr->xof;
355                stackbuf->yof= rr->yof;
356
357                /* put on stack */       
358                out[RRES_OUT_IMAGE]->data= stackbuf;
359
360                if(out[RRES_OUT_ALPHA]->hasoutput)
361                   out[RRES_OUT_ALPHA]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A);
362
363                node_composit_rlayers_out(rd, rl, out, rr->rectx, rr->recty);
364
365                generate_preview(node, stackbuf);
366             }
367          }
368       }
369    }    
370 };
371
372
373 bNodeType cmp_node_rlayers= {
374         /* *next,*prev */       NULL, NULL,
375         /* type code   */       CMP_NODE_R_LAYERS,
376         /* name        */       "Render Layers",
377         /* width+range */       150, 100, 300,
378         /* class+opts  */       NODE_CLASS_INPUT, NODE_PREVIEW|NODE_OPTIONS,
379         /* input sock  */       NULL,
380         /* output sock */       cmp_node_rlayers_out,
381         /* storage     */       "",
382         /* execfunc    */       node_composit_exec_rlayers,
383         /* butfunc     */       NULL,
384         /* initfunc    */       NULL,
385         /* freestoragefunc    */        NULL,
386         /* copystoragefunc    */        NULL,
387         /* id          */       NULL
388
389 };
390
391