Fix T56799: Custom render passes missing when using Save Buffers
[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 #include "node_composite_util.h"
33
34 #include "BLI_utildefines.h"
35 #include "BLI_linklist.h"
36
37 #include "DNA_scene_types.h"
38
39 #include "RE_engine.h"
40
41 #include "BKE_context.h"
42 #include "BKE_global.h"
43 #include "BKE_main.h"
44
45 /* **************** IMAGE (and RenderResult, multilayer image) ******************** */
46
47 static bNodeSocketTemplate cmp_node_rlayers_out[] = {
48         {       SOCK_RGBA,   0, N_("Image"),                                                    0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
49         {       SOCK_FLOAT,  0, N_("Alpha"),                                                    1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
50         {       SOCK_FLOAT,  0, N_(RE_PASSNAME_Z),                                              1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
51         {       SOCK_VECTOR, 0, N_(RE_PASSNAME_NORMAL),                                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
52         {       SOCK_VECTOR, 0, N_(RE_PASSNAME_UV),                                             1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
53         {       SOCK_VECTOR, 0, N_(RE_PASSNAME_VECTOR),                                 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
54         {       SOCK_RGBA,   0, N_(RE_PASSNAME_RGBA),                                   0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
55         {       SOCK_RGBA,   0, N_(RE_PASSNAME_DIFFUSE),                                0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
56         {       SOCK_RGBA,   0, N_(RE_PASSNAME_SPEC),                                   0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
57         {       SOCK_RGBA,   0, N_(RE_PASSNAME_SHADOW),                                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
58         {       SOCK_RGBA,   0, N_(RE_PASSNAME_AO),                                             0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
59         {       SOCK_RGBA,   0, N_(RE_PASSNAME_REFLECT),                                0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
60         {       SOCK_RGBA,   0, N_(RE_PASSNAME_REFRACT),                                0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
61         {       SOCK_RGBA,   0, N_(RE_PASSNAME_INDIRECT),                               0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
62         {       SOCK_FLOAT,  0, N_(RE_PASSNAME_INDEXOB),                                0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
63         {       SOCK_FLOAT,  0, N_(RE_PASSNAME_INDEXMA),                                0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
64         {       SOCK_FLOAT,  0, N_(RE_PASSNAME_MIST),                                   0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
65         {       SOCK_RGBA,   0, N_(RE_PASSNAME_EMIT),                                   0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
66         {       SOCK_RGBA,   0, N_(RE_PASSNAME_ENVIRONMENT),                    0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
67         {       SOCK_RGBA,   0, N_(RE_PASSNAME_DIFFUSE_DIRECT),                 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
68         {       SOCK_RGBA,   0, N_(RE_PASSNAME_DIFFUSE_INDIRECT),               0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
69         {       SOCK_RGBA,   0, N_(RE_PASSNAME_DIFFUSE_COLOR),                  0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
70         {       SOCK_RGBA,   0, N_(RE_PASSNAME_GLOSSY_DIRECT),                  0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
71         {       SOCK_RGBA,   0, N_(RE_PASSNAME_GLOSSY_INDIRECT),                0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
72         {       SOCK_RGBA,   0, N_(RE_PASSNAME_GLOSSY_COLOR),                   0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
73         {       SOCK_RGBA,   0, N_(RE_PASSNAME_TRANSM_DIRECT),                  0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
74         {       SOCK_RGBA,   0, N_(RE_PASSNAME_TRANSM_INDIRECT),                0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
75         {       SOCK_RGBA,   0, N_(RE_PASSNAME_TRANSM_COLOR),                   0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
76         {       SOCK_RGBA,   0, N_(RE_PASSNAME_SUBSURFACE_DIRECT),              0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
77         {       SOCK_RGBA,   0, N_(RE_PASSNAME_SUBSURFACE_INDIRECT),    0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
78         {       SOCK_RGBA,   0, N_(RE_PASSNAME_SUBSURFACE_COLOR),               0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
79         {       -1, 0, ""       }
80 };
81
82 static void cmp_node_image_add_pass_output(bNodeTree *ntree, bNode *node,
83                                            const char *name, const char *passname,
84                                            int rres_index, int type, int is_rlayers,
85                                            LinkNodePair *available_sockets, int *prev_index)
86 {
87         bNodeSocket *sock;
88         int sock_index = BLI_findstringindex(&node->outputs, name, offsetof(bNodeSocket, name));
89
90         if (sock_index < 0) {
91                 /* The first 31 sockets always are the legacy hardcoded sockets.
92                  * Any dynamically allocated sockets follow afterwards, and are sorted in the order in which they were stored in the RenderResult.
93                  * Therefore, we remember the index of the last matched socket. New sockets are placed behind the previously traversed one, but always after the first 31. */
94                 int after_index = *prev_index;
95                 if (is_rlayers && after_index < 30)
96                         after_index = 30;
97
98                 if (rres_index >= 0) {
99                         sock = node_add_socket_from_template(ntree, node, &cmp_node_rlayers_out[rres_index], SOCK_OUT);
100                 }
101                 else {
102                         sock = nodeAddStaticSocket(ntree, node, SOCK_OUT, type, PROP_NONE, name, name);
103                 }
104                 /* extra socket info */
105                 NodeImageLayer *sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer");
106                 sock->storage = sockdata;
107
108                 BLI_strncpy(sockdata->pass_name, passname, sizeof(sockdata->pass_name));
109
110                 sock_index = BLI_listbase_count(&node->outputs) - 1;
111                 if (sock_index != after_index + 1) {
112                         bNodeSocket *after_sock = BLI_findlink(&node->outputs, after_index);
113                         BLI_remlink(&node->outputs, sock);
114                         BLI_insertlinkafter(&node->outputs, after_sock, sock);
115                 }
116         }
117         else {
118                 sock = BLI_findlink(&node->outputs, sock_index);
119                 NodeImageLayer *sockdata = sock->storage;
120                 if (sockdata) {
121                         BLI_strncpy(sockdata->pass_name, passname, sizeof(sockdata->pass_name));
122                 }
123         }
124
125         BLI_linklist_append(available_sockets, sock);
126         *prev_index = sock_index;
127 }
128
129 static void cmp_node_image_create_outputs(bNodeTree *ntree, bNode *node, LinkNodePair *available_sockets)
130 {
131         Image *ima = (Image *)node->id;
132         ImBuf *ibuf;
133         int prev_index = -1;
134         if (ima) {
135                 ImageUser *iuser = node->storage;
136                 ImageUser load_iuser = {NULL};
137                 int offset = BKE_image_sequence_guess_offset(ima);
138
139                 /* It is possible that image user in this node is not
140                  * properly updated yet. In this case loading image will
141                  * fail and sockets detection will go wrong.
142                  *
143                  * So we manually construct image user to be sure first
144                  * image from sequence (that one which is set as filename
145                  * for image datablock) is used for sockets detection
146                  */
147                 load_iuser.ok = 1;
148                 load_iuser.framenr = offset;
149
150                 /* make sure ima->type is correct */
151                 ibuf = BKE_image_acquire_ibuf(ima, &load_iuser, NULL);
152
153                 if (ima->rr) {
154                         RenderLayer *rl = BLI_findlink(&ima->rr->layers, iuser->layer);
155
156                         if (rl) {
157                                 RenderPass *rpass;
158                                 for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
159                                         int type;
160                                         if (rpass->channels == 1)
161                                                 type = SOCK_FLOAT;
162                                         else
163                                                 type = SOCK_RGBA;
164
165                                         cmp_node_image_add_pass_output(ntree, node, rpass->name, rpass->name, -1, type, false, available_sockets, &prev_index);
166                                         /* Special handling for the Combined pass to ensure compatibility. */
167                                         if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) {
168                                                 cmp_node_image_add_pass_output(ntree, node, "Alpha", rpass->name, -1, SOCK_FLOAT, false, available_sockets, &prev_index);
169                                         }
170                                 }
171                                 BKE_image_release_ibuf(ima, ibuf, NULL);
172                                 return;
173                         }
174                 }
175         }
176
177         cmp_node_image_add_pass_output(ntree, node, "Image", RE_PASSNAME_COMBINED, -1, SOCK_RGBA, false, available_sockets, &prev_index);
178         cmp_node_image_add_pass_output(ntree, node, "Alpha", RE_PASSNAME_COMBINED, -1, SOCK_FLOAT, false, available_sockets, &prev_index);
179
180         if (ima) {
181                 if (!ima->rr) {
182                         cmp_node_image_add_pass_output(ntree, node, RE_PASSNAME_Z, RE_PASSNAME_Z, -1, SOCK_FLOAT, false, available_sockets, &prev_index);
183                 }
184                 BKE_image_release_ibuf(ima, ibuf, NULL);
185         }
186 }
187
188 typedef struct RLayerUpdateData {
189         LinkNodePair *available_sockets;
190         int prev_index;
191 } RLayerUpdateData;
192
193 void node_cmp_rlayers_register_pass(bNodeTree *ntree, bNode *node, Scene *scene, SceneRenderLayer *srl, const char *name, int type)
194 {
195         RLayerUpdateData *data = node->storage;
196
197         if (scene == NULL || srl == NULL || data == NULL || node->id != (ID *)scene) {
198                 return;
199         }
200
201         SceneRenderLayer *node_srl = BLI_findlink(&scene->r.layers, node->custom1);
202         if (node_srl != srl) {
203                 return;
204         }
205
206         /* Special handling for the Combined pass to ensure compatibility. */
207         if (STREQ(name, RE_PASSNAME_COMBINED)) {
208                 cmp_node_image_add_pass_output(ntree, node, "Image", name, -1, type, true, data->available_sockets, &data->prev_index);
209                 cmp_node_image_add_pass_output(ntree, node, "Alpha", name, -1, SOCK_FLOAT, true, data->available_sockets, &data->prev_index);
210         }
211         else {
212                 cmp_node_image_add_pass_output(ntree, node, name, name, -1, type, true, data->available_sockets, &data->prev_index);
213         }
214 }
215
216 static void cmp_node_rlayer_create_outputs_cb(RenderEngine *UNUSED(engine), Scene *scene, SceneRenderLayer *srl,
217                                               const char *name, int UNUSED(channels), const char *UNUSED(chanid), int type)
218 {
219         /* Register the pass in all scenes that have a render layer node for this layer.
220          * Since multiple scenes can be used in the compositor, the code must loop over all scenes
221          * and check whether their nodetree has a node that needs to be updated. */
222         /* NOTE: using G_MAIN seems valid here,
223          * unless we want to register that for every other temp Main we could generate??? */
224         for (Scene *sce = G_MAIN->scene.first; sce; sce = sce->id.next) {
225                 if (sce->nodetree) {
226                         ntreeCompositRegisterPass(sce->nodetree, scene, srl, name, type);
227                 }
228         }
229 }
230
231 static void cmp_node_rlayer_create_outputs(bNodeTree *ntree, bNode *node, LinkNodePair *available_sockets)
232 {
233         Scene *scene = (Scene *)node->id;
234
235         if (scene) {
236                 RenderEngineType *engine_type = RE_engines_find(scene->r.engine);
237                 if (engine_type && engine_type->update_render_passes) {
238                         SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, node->custom1);
239                         if (srl) {
240                                 RLayerUpdateData *data = MEM_mallocN(sizeof(RLayerUpdateData), "render layer update data");
241                                 data->available_sockets = available_sockets;
242                                 data->prev_index = -1;
243                                 node->storage = data;
244
245                                 RenderEngine *engine = RE_engine_create(engine_type);
246                                 RE_engine_update_render_passes(engine, scene, srl, cmp_node_rlayer_create_outputs_cb);
247                                 RE_engine_free(engine);
248
249                                 MEM_freeN(data);
250                                 node->storage = NULL;
251
252                                 return;
253                         }
254                 }
255         }
256
257         int prev_index = -1;
258         cmp_node_image_add_pass_output(ntree, node, "Image", RE_PASSNAME_COMBINED, RRES_OUT_IMAGE, SOCK_RGBA, true, available_sockets, &prev_index);
259         cmp_node_image_add_pass_output(ntree, node, "Alpha", RE_PASSNAME_COMBINED, RRES_OUT_ALPHA, SOCK_FLOAT, true, available_sockets, &prev_index);
260 }
261
262 /* XXX make this into a generic socket verification function for dynamic socket replacement (multilayer, groups, static templates) */
263 static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rlayer)
264 {
265         bNodeSocket *sock, *sock_next;
266         LinkNodePair available_sockets = {NULL, NULL};
267         int sock_index;
268
269         /* XXX make callback */
270         if (rlayer)
271                 cmp_node_rlayer_create_outputs(ntree, node, &available_sockets);
272         else
273                 cmp_node_image_create_outputs(ntree, node, &available_sockets);
274
275         /* Get rid of sockets whose passes are not available in the image.
276          * If sockets that are not available would be deleted, the connections to them would be lost
277          * when e.g. opening a file (since there's no render at all yet).
278          * Therefore, sockets with connected links will just be set as unavailable.
279          *
280          * Another important detail comes from compatibility with the older socket model, where there
281          * was a fixed socket per pass type that was just hidden or not. Therefore, older versions expect
282          * the first 31 passes to belong to a specific pass type.
283          * So, we keep those 31 always allocated before the others as well, even if they have no links attached. */
284         sock_index = 0;
285         for (sock = node->outputs.first; sock; sock = sock_next, sock_index++) {
286                 sock_next = sock->next;
287                 if (BLI_linklist_index(available_sockets.list, sock) >= 0) {
288                         sock->flag &= ~(SOCK_UNAVAIL | SOCK_HIDDEN);
289                 }
290                 else {
291                         bNodeLink *link;
292                         for (link = ntree->links.first; link; link = link->next) {
293                                 if (link->fromsock == sock) break;
294                         }
295                         if (!link && (!rlayer || sock_index > 30)) {
296                                 MEM_freeN(sock->storage);
297                                 nodeRemoveSocket(ntree, node, sock);
298                         }
299                         else {
300                                 sock->flag |= SOCK_UNAVAIL;
301                         }
302                 }
303         }
304
305         BLI_linklist_free(available_sockets.list, NULL);
306 }
307
308 static void cmp_node_image_update(bNodeTree *ntree, bNode *node)
309 {
310         /* avoid unnecessary updates, only changes to the image/image user data are of interest */
311         if (node->update & NODE_UPDATE_ID)
312                 cmp_node_image_verify_outputs(ntree, node, false);
313
314         cmp_node_update_default(ntree, node);
315 }
316
317 static void node_composit_init_image(bNodeTree *ntree, bNode *node)
318 {
319         ImageUser *iuser = MEM_callocN(sizeof(ImageUser), "node image user");
320         node->storage = iuser;
321         iuser->frames = 1;
322         iuser->sfra = 1;
323         iuser->fie_ima = 2;
324         iuser->ok = 1;
325
326         /* setup initial outputs */
327         cmp_node_image_verify_outputs(ntree, node, false);
328 }
329
330 static void node_composit_free_image(bNode *node)
331 {
332         bNodeSocket *sock;
333
334         /* free extra socket info */
335         for (sock = node->outputs.first; sock; sock = sock->next)
336                 MEM_freeN(sock->storage);
337
338         MEM_freeN(node->storage);
339 }
340
341 static void node_composit_copy_image(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, bNode *src_node)
342 {
343         bNodeSocket *sock;
344
345         dest_node->storage = MEM_dupallocN(src_node->storage);
346
347         /* copy extra socket info */
348         for (sock = src_node->outputs.first; sock; sock = sock->next)
349                 sock->new_sock->storage = MEM_dupallocN(sock->storage);
350 }
351
352 void register_node_type_cmp_image(void)
353 {
354         static bNodeType ntype;
355
356         cmp_node_type_base(&ntype, CMP_NODE_IMAGE, "Image", NODE_CLASS_INPUT, NODE_PREVIEW);
357         node_type_init(&ntype, node_composit_init_image);
358         node_type_storage(&ntype, "ImageUser", node_composit_free_image, node_composit_copy_image);
359         node_type_update(&ntype, cmp_node_image_update, NULL);
360         node_type_label(&ntype, node_image_label);
361
362         nodeRegisterType(&ntype);
363 }
364
365
366 /* **************** RENDER RESULT ******************** */
367
368 void node_cmp_rlayers_outputs(bNodeTree *ntree, bNode *node)
369 {
370         cmp_node_image_verify_outputs(ntree, node, true);
371 }
372
373 const char *node_cmp_rlayers_sock_to_pass(int sock_index)
374 {
375         const char *sock_to_passname[] = {
376                 RE_PASSNAME_COMBINED, RE_PASSNAME_COMBINED,
377                 RE_PASSNAME_Z, RE_PASSNAME_NORMAL, RE_PASSNAME_UV, RE_PASSNAME_VECTOR, RE_PASSNAME_RGBA,
378                 RE_PASSNAME_DIFFUSE, RE_PASSNAME_SPEC, RE_PASSNAME_SHADOW, RE_PASSNAME_AO,
379                 RE_PASSNAME_REFLECT, RE_PASSNAME_REFRACT, RE_PASSNAME_INDIRECT,
380                 RE_PASSNAME_INDEXOB, RE_PASSNAME_INDEXMA, RE_PASSNAME_MIST, RE_PASSNAME_EMIT, RE_PASSNAME_ENVIRONMENT,
381                 RE_PASSNAME_DIFFUSE_DIRECT, RE_PASSNAME_DIFFUSE_INDIRECT, RE_PASSNAME_DIFFUSE_COLOR,
382                 RE_PASSNAME_GLOSSY_DIRECT, RE_PASSNAME_GLOSSY_INDIRECT, RE_PASSNAME_GLOSSY_COLOR,
383                 RE_PASSNAME_TRANSM_DIRECT, RE_PASSNAME_TRANSM_INDIRECT, RE_PASSNAME_TRANSM_COLOR,
384                 RE_PASSNAME_SUBSURFACE_DIRECT, RE_PASSNAME_SUBSURFACE_INDIRECT, RE_PASSNAME_SUBSURFACE_COLOR
385         };
386         if (sock_index > 30) {
387                 return NULL;
388         }
389         return sock_to_passname[sock_index];
390 }
391
392 static void node_composit_init_rlayers(const bContext *C, PointerRNA *ptr)
393 {
394         Scene *scene = CTX_data_scene(C);
395         bNode *node = ptr->data;
396         int sock_index = 0;
397
398         node->id = &scene->id;
399
400         for (bNodeSocket *sock = node->outputs.first; sock; sock = sock->next, sock_index++) {
401                 NodeImageLayer *sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer");
402                 sock->storage = sockdata;
403
404                 BLI_strncpy(sockdata->pass_name, node_cmp_rlayers_sock_to_pass(sock_index), sizeof(sockdata->pass_name));
405         }
406 }
407
408 static bool node_composit_poll_rlayers(bNodeType *UNUSED(ntype), bNodeTree *ntree)
409 {
410         if (STREQ(ntree->idname, "CompositorNodeTree")) {
411                 Scene *scene;
412
413                 /* XXX ugly: check if ntree is a local scene node tree.
414                  * Render layers node can only be used in local scene->nodetree,
415                  * since it directly links to the scene.
416                  */
417                 for (scene = G.main->scene.first; scene; scene = scene->id.next)
418                         if (scene->nodetree == ntree)
419                                 break;
420
421                 return (scene != NULL);
422         }
423         return false;
424 }
425
426 static void node_composit_free_rlayers(bNode *node)
427 {
428         bNodeSocket *sock;
429
430         /* free extra socket info */
431         for (sock = node->outputs.first; sock; sock = sock->next)
432                 MEM_freeN(sock->storage);
433 }
434
435 static void node_composit_copy_rlayers(bNodeTree *UNUSED(dest_ntree), bNode *UNUSED(dest_node), bNode *src_node)
436 {
437         bNodeSocket *sock;
438
439         /* copy extra socket info */
440         for (sock = src_node->outputs.first; sock; sock = sock->next)
441                 sock->new_sock->storage = MEM_dupallocN(sock->storage);
442 }
443
444 static void cmp_node_rlayers_update(bNodeTree *ntree, bNode *node)
445 {
446         cmp_node_image_verify_outputs(ntree, node, true);
447
448         cmp_node_update_default(ntree, node);
449 }
450
451 void register_node_type_cmp_rlayers(void)
452 {
453         static bNodeType ntype;
454
455         cmp_node_type_base(&ntype, CMP_NODE_R_LAYERS, "Render Layers", NODE_CLASS_INPUT, NODE_PREVIEW);
456         node_type_socket_templates(&ntype, NULL, cmp_node_rlayers_out);
457         ntype.initfunc_api = node_composit_init_rlayers;
458         ntype.poll = node_composit_poll_rlayers;
459         node_type_storage(&ntype, NULL, node_composit_free_rlayers, node_composit_copy_rlayers);
460         node_type_update(&ntype, cmp_node_rlayers_update, NULL);
461         node_type_init(&ntype, node_cmp_rlayers_outputs);
462
463         nodeRegisterType(&ntype);
464 }