4 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
20 * The Original Code is Copyright (C) 2006 Blender Foundation.
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): none yet.
27 * ***** END GPL LICENSE BLOCK *****
30 #include "../CMP_util.h"
33 /* **************** IMAGE (and RenderResult, multilayer image) ******************** */
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},
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)
69 ibuf= BKE_image_get_ibuf(ima, iuser);
70 if(ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL)) {
74 if (ibuf->rect_float == NULL) {
75 IMB_float_from_rect(ibuf);
78 /* now we need a float buffer from the image
79 * with matching color management */
80 if(ibuf->channels == 4) {
81 if(rd->color_mgt_flag & R_COLOR_MANAGEMENT) {
82 if(ibuf->profile != IB_PROFILE_NONE) {
83 rect= ibuf->rect_float;
86 rect= MEM_mapallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, "node_composit_get_image");
87 srgb_to_linearrgb_rgba_rgba_buf(rect, ibuf->rect_float, ibuf->x * ibuf->y);
92 if(ibuf->profile == IB_PROFILE_NONE) {
93 rect= ibuf->rect_float;
96 rect= MEM_mapallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, "node_composit_get_image");
97 linearrgb_to_srgb_rgba_rgba_buf(rect, ibuf->rect_float, ibuf->x * ibuf->y);
103 /* non-rgba passes can't use color profiles */
104 rect= ibuf->rect_float;
106 /* done coercing into the correct color management */
109 type= ibuf->channels;
111 if(rd->scemode & R_COMP_CROP) {
112 stackbuf= get_cropped_compbuf(&rd->disprect, rect, ibuf->x, ibuf->y, type);
117 /* we put imbuf copy on stack, cbuf knows rect is from other ibuf when freed! */
118 stackbuf= alloc_compbuf(ibuf->x, ibuf->y, type, FALSE);
119 stackbuf->rect= rect;
120 stackbuf->malloc= alloc;
123 /*code to respect the premul flag of images; I'm
124 not sure if this is a good idea for multilayer images,
125 since it never worked before for them.
126 if (type==CB_RGBA && ima->flag & IMA_DO_PREMUL) {
129 float *pixel = stackbuf->rect;
131 for (i=0; i<stackbuf->x*stackbuf->y; i++, pixel += 4) {
132 pixel[0] *= pixel[3];
133 pixel[1] *= pixel[3];
134 pixel[2] *= pixel[3];
141 static CompBuf *node_composit_get_zimage(bNode *node, RenderData *rd)
143 ImBuf *ibuf= BKE_image_get_ibuf((Image *)node->id, node->storage);
146 if(ibuf && ibuf->zbuf_float) {
147 if(rd->scemode & R_COMP_CROP) {
148 zbuf= get_cropped_compbuf(&rd->disprect, ibuf->zbuf_float, ibuf->x, ibuf->y, CB_VAL);
151 zbuf= alloc_compbuf(ibuf->x, ibuf->y, CB_VAL, 0);
152 zbuf->rect= ibuf->zbuf_float;
158 /* check if layer is available, returns pass buffer */
159 static CompBuf *compbuf_multilayer_get(RenderData *rd, RenderLayer *rl, Image *ima, ImageUser *iuser, int passtype)
164 for(index=0, rpass= rl->passes.first; rpass; rpass= rpass->next, index++)
165 if(rpass->passtype==passtype)
172 BKE_image_multilayer_index(ima->rr, iuser);
173 cbuf= node_composit_get_image(rd, ima, iuser);
180 static void outputs_multilayer_get(RenderData *rd, RenderLayer *rl, bNodeStack **out, Image *ima, ImageUser *iuser)
182 if(out[RRES_OUT_Z]->hasoutput)
183 out[RRES_OUT_Z]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_Z);
184 if(out[RRES_OUT_VEC]->hasoutput)
185 out[RRES_OUT_VEC]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_VECTOR);
186 if(out[RRES_OUT_NORMAL]->hasoutput)
187 out[RRES_OUT_NORMAL]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_NORMAL);
188 if(out[RRES_OUT_UV]->hasoutput)
189 out[RRES_OUT_UV]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_UV);
191 if(out[RRES_OUT_RGBA]->hasoutput)
192 out[RRES_OUT_RGBA]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_RGBA);
193 if(out[RRES_OUT_DIFF]->hasoutput)
194 out[RRES_OUT_DIFF]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_DIFFUSE);
195 if(out[RRES_OUT_SPEC]->hasoutput)
196 out[RRES_OUT_SPEC]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_SPEC);
197 if(out[RRES_OUT_SHADOW]->hasoutput)
198 out[RRES_OUT_SHADOW]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_SHADOW);
199 if(out[RRES_OUT_AO]->hasoutput)
200 out[RRES_OUT_AO]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_AO);
201 if(out[RRES_OUT_REFLECT]->hasoutput)
202 out[RRES_OUT_REFLECT]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_REFLECT);
203 if(out[RRES_OUT_REFRACT]->hasoutput)
204 out[RRES_OUT_REFRACT]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_REFRACT);
205 if(out[RRES_OUT_INDIRECT]->hasoutput)
206 out[RRES_OUT_INDIRECT]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_INDIRECT);
207 if(out[RRES_OUT_INDEXOB]->hasoutput)
208 out[RRES_OUT_INDEXOB]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_INDEXOB);
209 if(out[RRES_OUT_MIST]->hasoutput)
210 out[RRES_OUT_MIST]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_MIST);
211 if(out[RRES_OUT_EMIT]->hasoutput)
212 out[RRES_OUT_EMIT]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_EMIT);
213 if(out[RRES_OUT_ENV]->hasoutput)
214 out[RRES_OUT_ENV]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_ENVIRONMENT);
218 static void node_composit_exec_image(void *data, bNode *node, bNodeStack **UNUSED(in), bNodeStack **out)
221 /* image assigned to output */
222 /* stack order input sockets: col, alpha */
224 RenderData *rd= data;
225 Image *ima= (Image *)node->id;
226 ImageUser *iuser= (ImageUser *)node->storage;
227 CompBuf *stackbuf= NULL;
229 /* first set the right frame number in iuser */
230 BKE_image_user_calc_frame(iuser, rd->cfra, 0);
232 /* force a load, we assume iuser index will be set OK anyway */
233 if(ima->type==IMA_TYPE_MULTILAYER)
234 BKE_image_get_ibuf(ima, iuser);
236 if(ima->type==IMA_TYPE_MULTILAYER && ima->rr) {
237 RenderLayer *rl= BLI_findlink(&ima->rr->layers, iuser->layer);
240 out[0]->data= stackbuf= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_COMBINED);
242 /* go over all layers */
243 outputs_multilayer_get(rd, rl, out, ima, iuser);
247 stackbuf= node_composit_get_image(rd, ima, iuser);
250 /*respect image premul option*/
251 if (stackbuf->type==CB_RGBA && ima->flag & IMA_DO_PREMUL) {
255 /*first duplicate stackbuf->rect, since it's just a pointer
256 to the source imbuf, and we don't want to change that.*/
257 stackbuf->rect = MEM_dupallocN(stackbuf->rect);
259 /* since stackbuf now has allocated memory, rather than just a pointer,
260 * mark it as allocated so it can be freed properly */
264 pixel = stackbuf->rect;
265 for (i=0; i<stackbuf->x*stackbuf->y; i++, pixel += 4) {
266 pixel[0] *= pixel[3];
267 pixel[1] *= pixel[3];
268 pixel[2] *= pixel[3];
272 /* put image on stack */
273 out[0]->data= stackbuf;
275 if(out[2]->hasoutput)
276 out[2]->data= node_composit_get_zimage(node, rd);
280 /* alpha and preview for both types */
282 if(out[1]->hasoutput)
283 out[1]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A);
285 generate_preview(data, node, stackbuf);
290 static void node_composit_init_image(bNode* node)
292 ImageUser *iuser= MEM_callocN(sizeof(ImageUser), "node image user");
293 node->storage= iuser;
300 void register_node_type_cmp_image(ListBase *lb)
302 static bNodeType ntype;
304 node_type_base(&ntype, CMP_NODE_IMAGE, "Image", NODE_CLASS_INPUT, NODE_PREVIEW|NODE_OPTIONS,
305 NULL, cmp_node_rlayers_out);
306 node_type_size(&ntype, 120, 80, 300);
307 node_type_init(&ntype, node_composit_init_image);
308 node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
309 node_type_exec(&ntype, node_composit_exec_image);
311 nodeRegisterType(lb, &ntype);
315 /* **************** RENDER RESULT ******************** */
317 static CompBuf *compbuf_from_pass(RenderData *rd, RenderLayer *rl, int rectx, int recty, int passcode)
319 float *fp= RE_RenderLayerGetPass(rl, passcode);
322 int buftype= CB_VEC3;
324 if(ELEM3(passcode, SCE_PASS_Z, SCE_PASS_INDEXOB, SCE_PASS_MIST))
326 else if(passcode==SCE_PASS_VECTOR)
328 else if(ELEM(passcode, SCE_PASS_COMBINED, SCE_PASS_RGBA))
331 if(rd->scemode & R_COMP_CROP)
332 buf= get_cropped_compbuf(&rd->disprect, fp, rectx, recty, buftype);
334 buf= alloc_compbuf(rectx, recty, buftype, 0);
342 static void node_composit_rlayers_out(RenderData *rd, RenderLayer *rl, bNodeStack **out, int rectx, int recty)
344 if(out[RRES_OUT_Z]->hasoutput)
345 out[RRES_OUT_Z]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_Z);
346 if(out[RRES_OUT_VEC]->hasoutput)
347 out[RRES_OUT_VEC]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_VECTOR);
348 if(out[RRES_OUT_NORMAL]->hasoutput)
349 out[RRES_OUT_NORMAL]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_NORMAL);
350 if(out[RRES_OUT_UV]->hasoutput)
351 out[RRES_OUT_UV]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_UV);
353 if(out[RRES_OUT_RGBA]->hasoutput)
354 out[RRES_OUT_RGBA]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_RGBA);
355 if(out[RRES_OUT_DIFF]->hasoutput)
356 out[RRES_OUT_DIFF]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_DIFFUSE);
357 if(out[RRES_OUT_SPEC]->hasoutput)
358 out[RRES_OUT_SPEC]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_SPEC);
359 if(out[RRES_OUT_SHADOW]->hasoutput)
360 out[RRES_OUT_SHADOW]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_SHADOW);
361 if(out[RRES_OUT_AO]->hasoutput)
362 out[RRES_OUT_AO]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_AO);
363 if(out[RRES_OUT_REFLECT]->hasoutput)
364 out[RRES_OUT_REFLECT]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_REFLECT);
365 if(out[RRES_OUT_REFRACT]->hasoutput)
366 out[RRES_OUT_REFRACT]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_REFRACT);
367 if(out[RRES_OUT_INDIRECT]->hasoutput)
368 out[RRES_OUT_INDIRECT]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_INDIRECT);
369 if(out[RRES_OUT_INDEXOB]->hasoutput)
370 out[RRES_OUT_INDEXOB]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_INDEXOB);
371 if(out[RRES_OUT_MIST]->hasoutput)
372 out[RRES_OUT_MIST]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_MIST);
373 if(out[RRES_OUT_EMIT]->hasoutput)
374 out[RRES_OUT_EMIT]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_EMIT);
375 if(out[RRES_OUT_ENV]->hasoutput)
376 out[RRES_OUT_ENV]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_ENVIRONMENT);
379 static void node_composit_exec_rlayers(void *data, bNode *node, bNodeStack **UNUSED(in), bNodeStack **out)
381 Scene *sce= (Scene *)node->id;
382 Render *re= (sce)? RE_GetRender(sce->id.name): NULL;
383 RenderData *rd= data;
384 RenderResult *rr= NULL;
387 rr= RE_AcquireResultRead(re);
390 SceneRenderLayer *srl= BLI_findlink(&sce->r.layers, node->custom1);
392 RenderLayer *rl= RE_GetRenderLayer(rr, srl->name);
393 if(rl && rl->rectf) {
396 /* we put render rect on stack, cbuf knows rect is from other ibuf when freed! */
397 if(rd->scemode & R_COMP_CROP)
398 stackbuf= get_cropped_compbuf(&rd->disprect, rl->rectf, rr->rectx, rr->recty, CB_RGBA);
400 stackbuf= alloc_compbuf(rr->rectx, rr->recty, CB_RGBA, 0);
401 stackbuf->rect= rl->rectf;
404 printf("Error; Preview Panel in UV Window returns zero sized image\n");
407 stackbuf->xof= rr->xof;
408 stackbuf->yof= rr->yof;
411 out[RRES_OUT_IMAGE]->data= stackbuf;
413 if(out[RRES_OUT_ALPHA]->hasoutput)
414 out[RRES_OUT_ALPHA]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A);
416 node_composit_rlayers_out(rd, rl, out, rr->rectx, rr->recty);
418 generate_preview(data, node, stackbuf);
425 RE_ReleaseResult(re);
429 void register_node_type_cmp_rlayers(ListBase *lb)
431 static bNodeType ntype;
433 node_type_base(&ntype, CMP_NODE_R_LAYERS, "Render Layers", NODE_CLASS_INPUT, NODE_PREVIEW|NODE_OPTIONS,
434 NULL, cmp_node_rlayers_out);
435 node_type_size(&ntype, 150, 100, 300);
436 node_type_exec(&ntype, node_composit_exec_rlayers);
438 nodeRegisterType(lb, &ntype);