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