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