c1e9d28bb4dc3ed4bed4c126cf99e7518747d657
[blender.git] / source / blender / nodes / composite / nodes / node_composite_image.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2006 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/nodes/composite/nodes/node_composite_image.c
29  *  \ingroup cmpnodes
30  */
31
32
33 #include "node_composite_util.h"
34
35
36 /* **************** IMAGE (and RenderResult, multilayer image) ******************** */
37
38 static bNodeSocketTemplate cmp_node_rlayers_out[]= {
39         {       SOCK_RGBA, 0, "Image",          0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
40         {       SOCK_FLOAT, 0, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
41         {       SOCK_FLOAT, 0, "Z",                     1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
42         {       SOCK_VECTOR, 0, "Normal",       0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
43         {       SOCK_VECTOR, 0, "UV",           1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
44         {       SOCK_VECTOR, 0, "Speed",        1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
45         {       SOCK_RGBA, 0, "Color",          0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
46         {       SOCK_RGBA, 0, "Diffuse",        0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
47         {       SOCK_RGBA, 0, "Specular",       0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
48         {       SOCK_RGBA, 0, "Shadow",         0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
49         {       SOCK_RGBA, 0, "AO",                     0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
50         {       SOCK_RGBA, 0, "Reflect",        0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
51         {       SOCK_RGBA, 0, "Refract",        0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
52         {       SOCK_RGBA, 0, "Indirect",       0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
53         {       SOCK_FLOAT, 0, "IndexOB",       0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
54         {       SOCK_FLOAT, 0, "IndexMA",       0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
55         {       SOCK_FLOAT, 0, "Mist",          0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
56         {       SOCK_RGBA, 0, "Emit",           0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
57         {       SOCK_RGBA, 0, "Environment",0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
58         {       -1, 0, ""       }
59 };
60
61
62 /* note: this function is used for multilayer too, to ensure uniform 
63    handling with BKE_image_get_ibuf() */
64 static CompBuf *node_composit_get_image(RenderData *rd, Image *ima, ImageUser *iuser)
65 {
66         ImBuf *ibuf;
67         CompBuf *stackbuf;
68         int type;
69
70         float *rect;
71         int alloc= FALSE;
72
73         ibuf= BKE_image_get_ibuf(ima, iuser);
74         if(ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL)) {
75                 return NULL;
76         }
77
78         if (ibuf->rect_float == NULL) {
79                 IMB_float_from_rect(ibuf);
80         }
81
82         /* now we need a float buffer from the image with matching color management */
83         /* XXX weak code, multilayer is excluded from this */
84         if(ibuf->channels == 4 && ima->rr==NULL) {
85                 if(rd->color_mgt_flag & R_COLOR_MANAGEMENT) {
86                         if(ibuf->profile != IB_PROFILE_NONE) {
87                                 rect= ibuf->rect_float;
88                         }
89                         else {
90                                 rect= MEM_mapallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, "node_composit_get_image");
91                                 srgb_to_linearrgb_rgba_rgba_buf(rect, ibuf->rect_float, ibuf->x * ibuf->y);
92                                 alloc= TRUE;
93                         }
94                 }
95                 else {
96                         if(ibuf->profile == IB_PROFILE_NONE) {
97                                 rect= ibuf->rect_float;
98                         }
99                         else {
100                                 rect= MEM_mapallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, "node_composit_get_image");
101                                 linearrgb_to_srgb_rgba_rgba_buf(rect, ibuf->rect_float, ibuf->x * ibuf->y);
102                                 alloc= TRUE;
103                         }
104                 }
105         }
106         else {
107                 /* non-rgba passes can't use color profiles */
108                 rect= ibuf->rect_float;
109         }
110         /* done coercing into the correct color management */
111
112
113         type= ibuf->channels;
114         
115         if(rd->scemode & R_COMP_CROP) {
116                 stackbuf= get_cropped_compbuf(&rd->disprect, rect, ibuf->x, ibuf->y, type);
117                 if(alloc)
118                         MEM_freeN(rect);
119         }
120         else {
121                 /* we put imbuf copy on stack, cbuf knows rect is from other ibuf when freed! */
122                 stackbuf= alloc_compbuf(ibuf->x, ibuf->y, type, FALSE);
123                 stackbuf->rect= rect;
124                 stackbuf->malloc= alloc;
125         }
126         
127         /*code to respect the premul flag of images; I'm
128           not sure if this is a good idea for multilayer images,
129           since it never worked before for them.
130         if (type==CB_RGBA && ima->flag & IMA_DO_PREMUL) {
131                 //premul the image
132                 int i;
133                 float *pixel = stackbuf->rect;
134                 
135                 for (i=0; i<stackbuf->x*stackbuf->y; i++, pixel += 4) {
136                         pixel[0] *= pixel[3];
137                         pixel[1] *= pixel[3];
138                         pixel[2] *= pixel[3];
139                 }
140         }
141         */
142         return stackbuf;
143 }
144
145 static CompBuf *node_composit_get_zimage(bNode *node, RenderData *rd)
146 {
147         ImBuf *ibuf= BKE_image_get_ibuf((Image *)node->id, node->storage);
148         CompBuf *zbuf= NULL;
149         
150         if(ibuf && ibuf->zbuf_float) {
151                 if(rd->scemode & R_COMP_CROP) {
152                         zbuf= get_cropped_compbuf(&rd->disprect, ibuf->zbuf_float, ibuf->x, ibuf->y, CB_VAL);
153                 }
154                 else {
155                         zbuf= alloc_compbuf(ibuf->x, ibuf->y, CB_VAL, 0);
156                         zbuf->rect= ibuf->zbuf_float;
157                 }
158         }
159         return zbuf;
160 }
161
162 /* check if layer is available, returns pass buffer */
163 static CompBuf *compbuf_multilayer_get(RenderData *rd, RenderLayer *rl, Image *ima, ImageUser *iuser, int passtype)
164 {
165         RenderPass *rpass;
166         short index;
167         
168         for(index=0, rpass= rl->passes.first; rpass; rpass= rpass->next, index++)
169                 if(rpass->passtype==passtype)
170                         break;
171         
172         if(rpass) {
173                 CompBuf *cbuf;
174                 
175                 iuser->pass= index;
176                 BKE_image_multilayer_index(ima->rr, iuser);
177                 cbuf= node_composit_get_image(rd, ima, iuser);
178                 
179                 return cbuf;
180         }
181         return NULL;
182 }
183
184 static void outputs_multilayer_get(RenderData *rd, RenderLayer *rl, bNodeStack **out, Image *ima, ImageUser *iuser)
185 {
186         if(out[RRES_OUT_Z]->hasoutput)
187                 out[RRES_OUT_Z]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_Z);
188         if(out[RRES_OUT_VEC]->hasoutput)
189                 out[RRES_OUT_VEC]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_VECTOR);
190         if(out[RRES_OUT_NORMAL]->hasoutput)
191                 out[RRES_OUT_NORMAL]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_NORMAL);
192         if(out[RRES_OUT_UV]->hasoutput)
193                 out[RRES_OUT_UV]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_UV);
194         
195         if(out[RRES_OUT_RGBA]->hasoutput)
196                 out[RRES_OUT_RGBA]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_RGBA);
197         if(out[RRES_OUT_DIFF]->hasoutput)
198                 out[RRES_OUT_DIFF]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_DIFFUSE);
199         if(out[RRES_OUT_SPEC]->hasoutput)
200                 out[RRES_OUT_SPEC]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_SPEC);
201         if(out[RRES_OUT_SHADOW]->hasoutput)
202                 out[RRES_OUT_SHADOW]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_SHADOW);
203         if(out[RRES_OUT_AO]->hasoutput)
204                 out[RRES_OUT_AO]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_AO);
205         if(out[RRES_OUT_REFLECT]->hasoutput)
206                 out[RRES_OUT_REFLECT]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_REFLECT);
207         if(out[RRES_OUT_REFRACT]->hasoutput)
208                 out[RRES_OUT_REFRACT]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_REFRACT);
209         if(out[RRES_OUT_INDIRECT]->hasoutput)
210                 out[RRES_OUT_INDIRECT]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_INDIRECT);
211         if(out[RRES_OUT_INDEXOB]->hasoutput)
212                 out[RRES_OUT_INDEXOB]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_INDEXOB);
213         if(out[RRES_OUT_INDEXMA]->hasoutput)
214                 out[RRES_OUT_INDEXMA]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_INDEXMA);
215         if(out[RRES_OUT_MIST]->hasoutput)
216                 out[RRES_OUT_MIST]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_MIST);
217         if(out[RRES_OUT_EMIT]->hasoutput)
218                 out[RRES_OUT_EMIT]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_EMIT);
219         if(out[RRES_OUT_ENV]->hasoutput)
220                 out[RRES_OUT_ENV]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_ENVIRONMENT);
221 }
222
223
224 static void node_composit_exec_image(void *data, bNode *node, bNodeStack **UNUSED(in), bNodeStack **out)
225 {
226         
227         /* image assigned to output */
228         /* stack order input sockets: col, alpha */
229         if(node->id) {
230                 RenderData *rd= data;
231                 Image *ima= (Image *)node->id;
232                 ImageUser *iuser= (ImageUser *)node->storage;
233                 CompBuf *stackbuf= NULL;
234                 
235                 /* first set the right frame number in iuser */
236                 BKE_image_user_calc_frame(iuser, rd->cfra, 0);
237                 
238                 /* force a load, we assume iuser index will be set OK anyway */
239                 if(ima->type==IMA_TYPE_MULTILAYER)
240                         BKE_image_get_ibuf(ima, iuser);
241                 
242                 if(ima->type==IMA_TYPE_MULTILAYER && ima->rr) {
243                         RenderLayer *rl= BLI_findlink(&ima->rr->layers, iuser->layer);
244                         
245                         if(rl) {
246                                 out[0]->data= stackbuf= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_COMBINED);
247                                 
248                                 /* go over all layers */
249                                 outputs_multilayer_get(rd, rl, out, ima, iuser);
250                         }
251                 }
252                 else {
253                         stackbuf= node_composit_get_image(rd, ima, iuser);
254
255                         if (stackbuf) {
256                                 /*respect image premul option*/
257                                 if (stackbuf->type==CB_RGBA && ima->flag & IMA_DO_PREMUL) {
258                                         int i;
259                                         float *pixel;
260                         
261                                         /*first duplicate stackbuf->rect, since it's just a pointer
262                                           to the source imbuf, and we don't want to change that.*/
263                                         stackbuf->rect = MEM_dupallocN(stackbuf->rect);
264                                         
265                                         /* since stackbuf now has allocated memory, rather than just a pointer,
266                                          * mark it as allocated so it can be freed properly */
267                                         stackbuf->malloc=1;
268                                         
269                                         /*premul the image*/
270                                         pixel = stackbuf->rect;
271                                         for (i=0; i<stackbuf->x*stackbuf->y; i++, pixel += 4) {
272                                                 pixel[0] *= pixel[3];
273                                                 pixel[1] *= pixel[3];
274                                                 pixel[2] *= pixel[3];
275                                         }
276                                 }
277                         
278                                 /* put image on stack */        
279                                 out[0]->data= stackbuf;
280                         
281                                 if(out[2]->hasoutput)
282                                         out[2]->data= node_composit_get_zimage(node, rd);
283                         }
284                 }
285                 
286                 /* alpha and preview for both types */
287                 if(stackbuf) {
288                         if(out[1]->hasoutput)
289                                 out[1]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A);
290
291                         generate_preview(data, node, stackbuf);
292                 }
293         }       
294 }
295
296 static void node_composit_init_image(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
297 {
298         ImageUser *iuser= MEM_callocN(sizeof(ImageUser), "node image user");
299         node->storage= iuser;
300         iuser->frames= 1;
301         iuser->sfra= 1;
302         iuser->fie_ima= 2;
303         iuser->ok= 1;
304 }
305
306 void register_node_type_cmp_image(ListBase *lb)
307 {
308         static bNodeType ntype;
309
310         node_type_base(&ntype, CMP_NODE_IMAGE, "Image", NODE_CLASS_INPUT, NODE_PREVIEW|NODE_OPTIONS);
311         node_type_socket_templates(&ntype, NULL, cmp_node_rlayers_out);
312         node_type_size(&ntype, 120, 80, 300);
313         node_type_init(&ntype, node_composit_init_image);
314         node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
315         node_type_exec(&ntype, node_composit_exec_image);
316
317         nodeRegisterType(lb, &ntype);
318 }
319
320
321 /* **************** RENDER RESULT ******************** */
322
323 static CompBuf *compbuf_from_pass(RenderData *rd, RenderLayer *rl, int rectx, int recty, int passcode)
324 {
325         float *fp= RE_RenderLayerGetPass(rl, passcode);
326         if(fp) {
327                 CompBuf *buf;
328                 int buftype= CB_VEC3;
329
330                 if(ELEM4(passcode, SCE_PASS_Z, SCE_PASS_INDEXOB, SCE_PASS_MIST, SCE_PASS_INDEXMA))
331                         buftype= CB_VAL;
332                 else if(passcode==SCE_PASS_VECTOR)
333                         buftype= CB_VEC4;
334                 else if(ELEM(passcode, SCE_PASS_COMBINED, SCE_PASS_RGBA))
335                         buftype= CB_RGBA;
336
337                 if(rd->scemode & R_COMP_CROP)
338                         buf= get_cropped_compbuf(&rd->disprect, fp, rectx, recty, buftype);
339                 else {
340                         buf= alloc_compbuf(rectx, recty, buftype, 0);
341                         buf->rect= fp;
342                 }
343                 return buf;
344         }
345         return NULL;
346 }
347
348 static void node_composit_rlayers_out(RenderData *rd, RenderLayer *rl, bNodeStack **out, int rectx, int recty)
349 {
350    if(out[RRES_OUT_Z]->hasoutput)
351           out[RRES_OUT_Z]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_Z);
352    if(out[RRES_OUT_VEC]->hasoutput)
353           out[RRES_OUT_VEC]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_VECTOR);
354    if(out[RRES_OUT_NORMAL]->hasoutput)
355           out[RRES_OUT_NORMAL]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_NORMAL);
356    if(out[RRES_OUT_UV]->hasoutput)
357           out[RRES_OUT_UV]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_UV);
358
359    if(out[RRES_OUT_RGBA]->hasoutput)
360           out[RRES_OUT_RGBA]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_RGBA);
361    if(out[RRES_OUT_DIFF]->hasoutput)
362           out[RRES_OUT_DIFF]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_DIFFUSE);
363    if(out[RRES_OUT_SPEC]->hasoutput)
364           out[RRES_OUT_SPEC]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_SPEC);
365    if(out[RRES_OUT_SHADOW]->hasoutput)
366           out[RRES_OUT_SHADOW]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_SHADOW);
367    if(out[RRES_OUT_AO]->hasoutput)
368           out[RRES_OUT_AO]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_AO);
369    if(out[RRES_OUT_REFLECT]->hasoutput)
370           out[RRES_OUT_REFLECT]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_REFLECT);
371    if(out[RRES_OUT_REFRACT]->hasoutput)
372           out[RRES_OUT_REFRACT]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_REFRACT);
373    if(out[RRES_OUT_INDIRECT]->hasoutput)
374           out[RRES_OUT_INDIRECT]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_INDIRECT);
375    if(out[RRES_OUT_INDEXOB]->hasoutput)
376            out[RRES_OUT_INDEXOB]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_INDEXOB);
377         if(out[RRES_OUT_INDEXMA]->hasoutput)
378                 out[RRES_OUT_INDEXMA]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_INDEXMA);
379    if(out[RRES_OUT_MIST]->hasoutput)
380            out[RRES_OUT_MIST]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_MIST);
381    if(out[RRES_OUT_EMIT]->hasoutput)
382            out[RRES_OUT_EMIT]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_EMIT);
383    if(out[RRES_OUT_ENV]->hasoutput)
384            out[RRES_OUT_ENV]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_ENVIRONMENT);
385 }
386
387 static void node_composit_exec_rlayers(void *data, bNode *node, bNodeStack **UNUSED(in), bNodeStack **out)
388 {
389         Scene *sce= (Scene *)node->id;
390         Render *re= (sce)? RE_GetRender(sce->id.name): NULL;
391         RenderData *rd= data;
392         RenderResult *rr= NULL;
393
394         if(re)
395                 rr= RE_AcquireResultRead(re);
396
397         if(rr) {
398                 SceneRenderLayer *srl= BLI_findlink(&sce->r.layers, node->custom1);
399                 if(srl) {
400                         RenderLayer *rl= RE_GetRenderLayer(rr, srl->name);
401                         if(rl && rl->rectf) {
402                                 CompBuf *stackbuf;
403
404                                 /* we put render rect on stack, cbuf knows rect is from other ibuf when freed! */
405                                 if(rd->scemode & R_COMP_CROP)
406                                         stackbuf= get_cropped_compbuf(&rd->disprect, rl->rectf, rr->rectx, rr->recty, CB_RGBA);
407                                 else {
408                                         stackbuf= alloc_compbuf(rr->rectx, rr->recty, CB_RGBA, 0);
409                                         stackbuf->rect= rl->rectf;
410                                 }
411                                 if(stackbuf==NULL) {
412                                         printf("Error; Preview Panel in UV Window returns zero sized image\n");
413                                 }
414                                 else {
415                                         stackbuf->xof= rr->xof;
416                                         stackbuf->yof= rr->yof;
417
418                                         /* put on stack */
419                                         out[RRES_OUT_IMAGE]->data= stackbuf;
420
421                                         if(out[RRES_OUT_ALPHA]->hasoutput)
422                                                 out[RRES_OUT_ALPHA]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A);
423
424                                         node_composit_rlayers_out(rd, rl, out, rr->rectx, rr->recty);
425
426                                         generate_preview(data, node, stackbuf);
427                                 }
428                         }
429                 }
430         }
431
432         if(re)
433                 RE_ReleaseResult(re);
434 }
435
436
437 void register_node_type_cmp_rlayers(ListBase *lb)
438 {
439         static bNodeType ntype;
440
441         node_type_base(&ntype, CMP_NODE_R_LAYERS, "Render Layers", NODE_CLASS_INPUT, NODE_PREVIEW|NODE_OPTIONS);
442         node_type_socket_templates(&ntype, NULL, cmp_node_rlayers_out);
443         node_type_size(&ntype, 150, 100, 300);
444         node_type_exec(&ntype, node_composit_exec_rlayers);
445
446         nodeRegisterType(lb, &ntype);
447 }
448
449
450