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