diff options
-rw-r--r-- | source/blender/blenkernel/BKE_blender.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_node.h | 8 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/node.c | 14 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 86 | ||||
-rw-r--r-- | source/blender/blenloader/intern/writefile.c | 2 | ||||
-rw-r--r-- | source/blender/editors/space_node/drawnode.c | 213 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_edit.c | 42 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_intern.h | 4 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_ops.c | 4 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_node_types.h | 9 | ||||
-rw-r--r-- | source/blender/makesrna/RNA_access.h | 2 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_nodetree.c | 89 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_nodetree_types.h | 1 | ||||
-rw-r--r-- | source/blender/nodes/CMakeLists.txt | 4 | ||||
-rw-r--r-- | source/blender/nodes/NOD_composite.h | 1 | ||||
-rw-r--r-- | source/blender/nodes/composite/nodes/node_composite_outputFile.c | 314 |
16 files changed, 465 insertions, 330 deletions
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 1c661b3804f..392642b5305 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -42,7 +42,7 @@ extern "C" { * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ #define BLENDER_VERSION 262 -#define BLENDER_SUBVERSION 0 +#define BLENDER_SUBVERSION 1 #define BLENDER_MINVERSION 250 #define BLENDER_MINSUBVERSION 0 diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 753161d0788..cb161b26ee5 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -364,6 +364,7 @@ int nodeUpdateID(struct bNodeTree *ntree, struct ID *id); void nodeFreePreview(struct bNode *node); int nodeSocketIsHidden(struct bNodeSocket *sock); +void nodeSocketSetType(struct bNodeSocket *sock, int type); /* ************** NODE TYPE ACCESS *************** */ @@ -636,7 +637,7 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMaterial *mat); #define CMP_NODE_TRANSFORM 264 #define CMP_NODE_MOVIEDISTORTION 265 #define CMP_NODE_DOUBLEEDGEMASK 266 -#define CMP_NODE_OUTPUT_MULTI_FILE 267 +#define CMP_NODE_OUTPUT_MULTI_FILE__DEPRECATED 267 /* DEPRECATED multi file node has been merged into regular CMP_NODE_OUTPUT_FILE */ #define CMP_NODE_GLARE 301 #define CMP_NODE_TONEMAP 302 @@ -676,8 +677,9 @@ void ntreeCompositTagGenerators(struct bNodeTree *ntree); void ntreeCompositForceHidden(struct bNodeTree *ntree, struct Scene *scene); void ntreeCompositClearTags(struct bNodeTree *ntree); -void ntreeCompositOutputMultiFileAddSocket(struct bNodeTree *ntree, struct bNode *node, struct ImageFormatData *im_format); -int ntreeCompositOutputMultiFileRemoveActiveSocket(struct bNodeTree *ntree, struct bNode *node); +struct bNodeSocket *ntreeCompositOutputFileAddSocket(struct bNodeTree *ntree, struct bNode *node, + const char *name, struct ImageFormatData *im_format); +int ntreeCompositOutputFileRemoveActiveSocket(struct bNodeTree *ntree, struct bNode *node); /* ************** TEXTURE NODES *************** */ diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index c394a5354f1..99edd4bac8c 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1369,6 +1369,19 @@ int nodeSocketIsHidden(bNodeSocket *sock) return ((sock->flag & (SOCK_HIDDEN | SOCK_AUTO_HIDDEN | SOCK_UNAVAIL)) != 0); } +void nodeSocketSetType(bNodeSocket *sock, int type) +{ + int old_type = sock->type; + void *old_default_value = sock->default_value; + + sock->type = type; + + sock->default_value = node_socket_make_default_value(sock->type); + node_socket_init_default_value(type, sock->default_value); + node_socket_convert_default_value(sock->type, sock->default_value, old_type, old_default_value); + node_socket_free_default_value(old_type, old_default_value); +} + /* ************** dependency stuff *********** */ /* node is guaranteed to be not checked before */ @@ -1839,7 +1852,6 @@ static void registerCompositNodes(bNodeTreeType *ttype) register_node_type_cmp_viewer(ttype); register_node_type_cmp_splitviewer(ttype); register_node_type_cmp_output_file(ttype); - register_node_type_cmp_output_multi_file(ttype); register_node_type_cmp_view_levels(ttype); register_node_type_cmp_curve_rgb(ttype); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 180ccaddb0a..8abdc974488 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -7685,6 +7685,77 @@ static void do_versions_nodetree_socket_auto_hidden_flags_2_62(bNodeTree *ntree) } } +static void do_versions_nodetree_multi_file_output_format_2_62_1(Scene *sce, bNodeTree *ntree) +{ + bNode *node; + bNodeSocket *sock; + + for (node=ntree->nodes.first; node; node=node->next) { + if (node->type==CMP_NODE_OUTPUT_FILE) { + /* previous CMP_NODE_OUTPUT_FILE nodes get converted to multi-file outputs */ + NodeImageFile *old_data = node->storage; + NodeImageMultiFile *nimf= MEM_callocN(sizeof(NodeImageMultiFile), "node image multi file"); + bNodeSocket *old_image = BLI_findlink(&node->inputs, 0); + bNodeSocket *old_z = BLI_findlink(&node->inputs, 1); + bNodeSocket *sock; + + node->storage= nimf; + + BLI_strncpy(nimf->base_path, old_data->name, sizeof(nimf->base_path)); + nimf->format = old_data->im_format; + + /* if z buffer is saved, change the image type to multilayer exr. + * XXX this is slightly messy, Z buffer was ignored before for anything but EXR and IRIS ... + * i'm just assuming here that IRIZ means IRIS with z buffer ... + */ + if (ELEM(old_data->im_format.imtype, R_IMF_IMTYPE_IRIZ, R_IMF_IMTYPE_OPENEXR)) { + nimf->format.imtype = R_IMF_IMTYPE_MULTILAYER; + sock = ntreeCompositOutputFileAddSocket(ntree, node, old_image->name, &nimf->format); + if (old_image->link) { + old_image->link->tosock = sock; + sock->link = old_image->link; + } + sock = ntreeCompositOutputFileAddSocket(ntree, node, old_z->name, &nimf->format); + if (old_z->link) { + old_z->link->tosock = sock; + sock->link = old_z->link; + } + } + else { + /* saves directly to base path, which is the old image output path */ + sock = ntreeCompositOutputFileAddSocket(ntree, node, "", &nimf->format); + if (old_image->link) { + old_image->link->tosock = sock; + sock->link = old_image->link; + } + } + + nodeRemoveSocket(ntree, node, old_image); + nodeRemoveSocket(ntree, node, old_z); + MEM_freeN(old_data); + } + else if (node->type==CMP_NODE_OUTPUT_MULTI_FILE__DEPRECATED) { + NodeImageMultiFile *nimf = node->storage; + + /* CMP_NODE_OUTPUT_MULTI_FILE has been redeclared as CMP_NODE_OUTPUT_FILE */ + node->type = CMP_NODE_OUTPUT_FILE; + + /* initialize the node-wide image format from render data, if available */ + if (sce) + nimf->format = sce->r.im_format; + + /* transfer render format toggle to node format toggle */ + for (sock=node->inputs.first; sock; sock=sock->next) { + NodeImageMultiFileSocket *simf = sock->storage; + simf->use_node_format = simf->use_render_format; + } + + /* we do have preview now */ + node->flag |= NODE_PREVIEW; + } + } +} + static void do_versions(FileData *fd, Library *lib, Main *main) { /* WATCH IT!!!: pointers from libdata have not been converted */ @@ -13164,6 +13235,21 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } + if (main->versionfile < 262 || (main->versionfile == 262 && main->subversionfile < 1)) + { + /* update use flags for node sockets (was only temporary before) */ + Scene *sce; + bNodeTree *ntree; + + for (sce=main->scene.first; sce; sce=sce->id.next) + if (sce->nodetree) + do_versions_nodetree_multi_file_output_format_2_62_1(sce, sce->nodetree); + + /* XXX can't associate with scene for group nodes, image format will stay uninitialized */ + for (ntree=main->nodetree.first; ntree; ntree=ntree->id.next) + do_versions_nodetree_multi_file_output_format_2_62_1(NULL, ntree); + } + /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ /* WATCH IT 2!: Userdef struct init has to be in editors/interface/resources.c! */ diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index d5ed3096c79..b063a1656ab 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -727,7 +727,7 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree) writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage); } - if (node->type==CMP_NODE_OUTPUT_MULTI_FILE) { + if (node->type==CMP_NODE_OUTPUT_FILE) { /* inputs have own storage data */ for (sock=node->inputs.first; sock; sock=sock->next) writestruct(wd, DATA, "NodeImageMultiFileSocket", 1, sock->storage); diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index a58e03be237..bc22e668b5a 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -102,24 +102,71 @@ static void node_socket_button_label(const bContext *UNUSED(C), uiBlock *block, uiDefBut(block, LABEL, 0, sock->name, x, y, width, NODE_DY, NULL, 0, 0, 0, 0, ""); } +/* draw function for file output node sockets. + * XXX a bit ugly use atm, called from datatype button functions, + * since all node types and callbacks only use data type without struct_type. + */ +static void node_socket_button_output_file(const bContext *C, uiBlock *block, + bNodeTree *ntree, bNode *node, bNodeSocket *sock, + const char *UNUSED(name), int x, int y, int width) +{ + uiLayout *layout, *row; + PointerRNA nodeptr, sockptr, imfptr; + int imtype; + int rx, ry; + RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr); + RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &sockptr); + + layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, x, y+NODE_DY, width, 20, UI_GetStyle()); + row = uiLayoutRow(layout, 0); + + uiItemL(row, sock->name, 0); + + imfptr = RNA_pointer_get(&nodeptr, "format"); + imtype = RNA_enum_get(&imfptr, "file_format"); + /* in multilayer format all socket format details are ignored */ + if (imtype != R_IMF_IMTYPE_MULTILAYER) { + PropertyRNA *imtype_prop; + const char *imtype_name; + + if (!RNA_boolean_get(&sockptr, "use_node_format")) + imfptr = RNA_pointer_get(&sockptr, "format"); + + imtype_prop = RNA_struct_find_property(&imfptr, "file_format"); + RNA_property_enum_name((bContext*)C, &imfptr, imtype_prop, RNA_property_enum_get(&imfptr, imtype_prop), &imtype_name); + uiBlockSetEmboss(block, UI_EMBOSSP); + uiItemL(row, imtype_name, 0); + uiBlockSetEmboss(block, UI_EMBOSSN); + } + + uiBlockLayoutResolve(block, &rx, &ry); +} static void node_socket_button_default(const bContext *C, uiBlock *block, bNodeTree *ntree, bNode *node, bNodeSocket *sock, const char *name, int x, int y, int width) { - if (sock->link || (sock->flag & SOCK_HIDE_VALUE)) - node_socket_button_label(C, block, ntree, node, sock, name, x, y, width); - else { - PointerRNA ptr; - uiBut *bt; - - RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr); - - bt = uiDefButR(block, NUM, B_NODE_EXEC, name, - x, y+1, width, NODE_DY-2, - &ptr, "default_value", 0, 0, 0, -1, -1, NULL); - if (node) - uiButSetFunc(bt, node_sync_cb, CTX_wm_space_node(C), node); + switch (sock->struct_type) { + case SOCK_STRUCT_NONE: { + if (sock->link || (sock->flag & SOCK_HIDE_VALUE)) + node_socket_button_label(C, block, ntree, node, sock, name, x, y, width); + else { + PointerRNA ptr; + uiBut *bt; + + RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr); + + bt = uiDefButR(block, NUM, B_NODE_EXEC, name, + x, y+1, width, NODE_DY-2, + &ptr, "default_value", 0, 0, 0, -1, -1, NULL); + if (node) + uiButSetFunc(bt, node_sync_cb, CTX_wm_space_node(C), node); + } + break; + } + case SOCK_STRUCT_OUTPUT_FILE: + node_socket_button_output_file(C, block, ntree, node, sock, name, x, y, width); + break; } } @@ -149,25 +196,33 @@ static void node_socket_button_components(const bContext *C, uiBlock *block, bNodeTree *ntree, bNode *node, bNodeSocket *sock, const char *name, int x, int y, int width) { - if (sock->link || (sock->flag & SOCK_HIDE_VALUE)) - node_socket_button_label(C, block, ntree, node, sock, name, x, y, width); - else { - PointerRNA ptr; - SocketComponentMenuArgs *args; - - RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr); - - args= MEM_callocN(sizeof(SocketComponentMenuArgs), "SocketComponentMenuArgs"); - - args->ptr = ptr; - args->x = x; - args->y = y; - args->width = width; - args->cb = node_sync_cb; - args->arg1 = CTX_wm_space_node(C); - args->arg2 = node; - - uiDefBlockButN(block, socket_component_menu, args, name, x, y+1, width, NODE_DY-2, ""); + switch (sock->struct_type) { + case SOCK_STRUCT_NONE: { + if (sock->link || (sock->flag & SOCK_HIDE_VALUE)) + node_socket_button_label(C, block, ntree, node, sock, name, x, y, width); + else { + PointerRNA ptr; + SocketComponentMenuArgs *args; + + RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr); + + args= MEM_callocN(sizeof(SocketComponentMenuArgs), "SocketComponentMenuArgs"); + + args->ptr = ptr; + args->x = x; + args->y = y; + args->width = width; + args->cb = node_sync_cb; + args->arg1 = CTX_wm_space_node(C); + args->arg2 = node; + + uiDefBlockButN(block, socket_component_menu, args, name, x, y+1, width, NODE_DY-2, ""); + } + break; + } + case SOCK_STRUCT_OUTPUT_FILE: + node_socket_button_output_file(C, block, ntree, node, sock, name, x, y, width); + break; } } @@ -200,29 +255,10 @@ static void node_socket_button_color(const bContext *C, uiBlock *block, } break; } - case SOCK_STRUCT_OUTPUT_MULTI_FILE: { - uiLayout *layout, *row; - PointerRNA ptr, imfptr; - PropertyRNA *imtype_prop; - const char *imtype_name; - int rx, ry; - RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr); - imfptr = RNA_pointer_get(&ptr, "format"); - - layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, x, y+NODE_DY, width, 20, UI_GetStyle()); - row = uiLayoutRow(layout, 0); - - uiItemL(row, sock->name, 0); - imtype_prop = RNA_struct_find_property(&imfptr, "file_format"); - RNA_property_enum_name((bContext*)C, &imfptr, imtype_prop, RNA_property_enum_get(&imfptr, imtype_prop), &imtype_name); - uiBlockSetEmboss(block, UI_EMBOSSP); - uiItemL(row, imtype_name, 0); - uiBlockSetEmboss(block, UI_EMBOSSN); - - uiBlockLayoutResolve(block, &rx, &ry); + case SOCK_STRUCT_OUTPUT_FILE: + node_socket_button_output_file(C, block, ntree, node, sock, name, x, y, width); break; } - } } /* ****************** BASE DRAW FUNCTIONS FOR NEW OPERATOR NODES ***************** */ @@ -1699,56 +1735,54 @@ static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), Po static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - bNode *node= ptr->data; - NodeImageFile *nif= node->storage; - PointerRNA imfptr; - - uiLayout *row; - - uiItemR(layout, ptr, "filepath", 0, "", ICON_NONE); - - RNA_pointer_create(NULL, &RNA_ImageFormatSettings, &nif->im_format, &imfptr); - uiTemplateImageSettings(layout, &imfptr); - - row= uiLayoutRow(layout, 1); - uiItemR(row, ptr, "frame_start", 0, "Start", ICON_NONE); - uiItemR(row, ptr, "frame_end", 0, "End", ICON_NONE); -} - -static void node_composit_buts_multi_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemL(layout, "Base Path:", 0); + PointerRNA imfptr = RNA_pointer_get(ptr, "format"); + int multilayer = (RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER); + + if (multilayer) + uiItemL(layout, "Path:", 0); + else + uiItemL(layout, "Base Path:", 0); uiItemR(layout, ptr, "base_path", 0, "", ICON_NONE); } -static void node_composit_buts_multi_file_output_details(uiLayout *layout, bContext *C, PointerRNA *ptr) +static void node_composit_buts_file_output_details(uiLayout *layout, bContext *C, PointerRNA *ptr) { + PointerRNA imfptr = RNA_pointer_get(ptr, "format"); PointerRNA active_input_ptr = RNA_pointer_get(ptr, "active_input"); + int multilayer = (RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER); - node_composit_buts_multi_file_output(layout, C, ptr); + node_composit_buts_file_output(layout, C, ptr); + uiTemplateImageSettings(layout, &imfptr); + + uiItemS(layout); - uiItemO(layout, "Add Input", ICON_ZOOMIN, "NODE_OT_output_multi_file_add_socket"); + uiItemO(layout, "Add Input", ICON_ZOOMIN, "NODE_OT_output_file_add_socket"); uiTemplateList(layout, C, ptr, "inputs", ptr, "active_input_index", NULL, 0, 0, 0); if (active_input_ptr.data) { - PointerRNA imfptr = RNA_pointer_get(&active_input_ptr, "format"); uiLayout *row, *col; col = uiLayoutColumn(layout, 1); - uiItemL(col, "File Path:", 0); + if (multilayer) + uiItemL(col, "Layer Name:", 0); + else + uiItemL(col, "File Path:", 0); row = uiLayoutRow(col, 0); uiItemR(row, &active_input_ptr, "name", 0, "", 0); - uiItemFullO(row, "NODE_OT_output_multi_file_remove_active_socket", "", ICON_X, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_R_ICON_ONLY); - - uiItemS(layout); + uiItemFullO(row, "NODE_OT_output_file_remove_active_socket", "", ICON_X, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_R_ICON_ONLY); - col = uiLayoutColumn(layout, 1); - uiItemL(col, "Format:", 0); - uiItemR(col, &active_input_ptr, "use_render_format", 0, NULL, 0); - - col= uiLayoutColumn(layout, 0); - uiLayoutSetActive(col, RNA_boolean_get(&active_input_ptr, "use_render_format")==0); - uiTemplateImageSettings(col, &imfptr); + /* in multilayer format all socket format details are ignored */ + if (!multilayer) { + imfptr = RNA_pointer_get(&active_input_ptr, "format"); + + col = uiLayoutColumn(layout, 1); + uiItemL(col, "Format:", 0); + uiItemR(col, &active_input_ptr, "use_node_format", 0, NULL, 0); + + col= uiLayoutColumn(layout, 0); + uiLayoutSetActive(col, RNA_boolean_get(&active_input_ptr, "use_node_format")==0); + uiTemplateImageSettings(col, &imfptr); + } } } @@ -1986,10 +2020,7 @@ static void node_composit_set_butfunc(bNodeType *ntype) break; case CMP_NODE_OUTPUT_FILE: ntype->uifunc= node_composit_buts_file_output; - break; - case CMP_NODE_OUTPUT_MULTI_FILE: - ntype->uifunc= node_composit_buts_multi_file_output; - ntype->uifuncbut= node_composit_buts_multi_file_output_details; + ntype->uifuncbut= node_composit_buts_file_output_details; break; case CMP_NODE_DIFF_MATTE: ntype->uifunc=node_composit_buts_diff_matte; diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index c89e91724fb..a6d18b58cca 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -2254,6 +2254,8 @@ static void node_remove_extra_links(SpaceNode *snode, bNodeSocket *tsock, bNodeL } else nodeRemLink(snode->edittree, tlink); + + snode->edittree->update |= NTREE_UPDATE_LINKS; } } } @@ -3515,49 +3517,47 @@ void NODE_OT_new_node_tree(wmOperatorType *ot) RNA_def_string(ot->srna, "name", "NodeTree", MAX_ID_NAME-2, "Name", ""); } -/* ****************** Multi File Output Add Socket ******************* */ +/* ****************** File Output Add Socket ******************* */ -static int node_output_multi_file_add_socket_exec(bContext *C, wmOperator *UNUSED(op)) +static int node_output_file_add_socket_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); SpaceNode *snode= CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; bNode *node = nodeGetActive(ntree); + char file_path[MAX_NAME]; if (!node) return OPERATOR_CANCELLED; - ntreeCompositOutputMultiFileAddSocket(ntree, node, &scene->r.im_format); + RNA_string_get(op->ptr, "file_path", file_path); + ntreeCompositOutputFileAddSocket(ntree, node, file_path, &scene->r.im_format); snode_notify(C, snode); return OPERATOR_FINISHED; } -static int node_output_multi_file_add_socket_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) -{ - return node_output_multi_file_add_socket_exec(C, op); -} - -void NODE_OT_output_multi_file_add_socket(wmOperatorType *ot) +void NODE_OT_output_file_add_socket(wmOperatorType *ot) { /* identifiers */ - ot->name= "Add Multi File Node Socket"; - ot->description= "Add a new input to a multi file output node"; - ot->idname= "NODE_OT_output_multi_file_add_socket"; + ot->name= "Add File Node Socket"; + ot->description= "Add a new input to a file output node"; + ot->idname= "NODE_OT_output_file_add_socket"; /* callbacks */ - ot->exec= node_output_multi_file_add_socket_exec; - ot->invoke= node_output_multi_file_add_socket_invoke; + ot->exec= node_output_file_add_socket_exec; ot->poll= composite_node_active; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_string(ot->srna, "file_path", "Image", MAX_NAME, "File Path", "Sub-path of the output file"); } /* ****************** Multi File Output Remove Socket ******************* */ -static int node_output_multi_file_remove_active_socket_exec(bContext *C, wmOperator *UNUSED(op)) +static int node_output_file_remove_active_socket_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceNode *snode= CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; @@ -3566,7 +3566,7 @@ static int node_output_multi_file_remove_active_socket_exec(bContext *C, wmOpera if (!node) return OPERATOR_CANCELLED; - if (!ntreeCompositOutputMultiFileRemoveActiveSocket(ntree, node)) + if (!ntreeCompositOutputFileRemoveActiveSocket(ntree, node)) return OPERATOR_CANCELLED; snode_notify(C, snode); @@ -3574,15 +3574,15 @@ static int node_output_multi_file_remove_active_socket_exec(bContext *C, wmOpera return OPERATOR_FINISHED; } -void NODE_OT_output_multi_file_remove_active_socket(wmOperatorType *ot) +void NODE_OT_output_file_remove_active_socket(wmOperatorType *ot) { /* identifiers */ - ot->name= "Remove Multi File Node Socket"; - ot->description= "Remove active input from a multi file output node"; - ot->idname= "NODE_OT_output_multi_file_remove_active_socket"; + ot->name= "Remove File Node Socket"; + ot->description= "Remove active input from a file output node"; + ot->idname= "NODE_OT_output_file_remove_active_socket"; /* callbacks */ - ot->exec= node_output_multi_file_remove_active_socket_exec; + ot->exec= node_output_file_remove_active_socket_exec; ot->poll= composite_node_active; /* flags */ diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index f6d52aa9474..2524454d9c0 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -157,8 +157,8 @@ void NODE_OT_add_file(struct wmOperatorType *ot); void NODE_OT_new_node_tree(struct wmOperatorType *ot); -void NODE_OT_output_multi_file_add_socket(struct wmOperatorType *ot); -void NODE_OT_output_multi_file_remove_active_socket(struct wmOperatorType *ot); +void NODE_OT_output_file_add_socket(struct wmOperatorType *ot); +void NODE_OT_output_file_remove_active_socket(struct wmOperatorType *ot); extern const char *node_context_dir[]; diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index 608c6b51f70..d358556d36a 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -101,8 +101,8 @@ void node_operatortypes(void) WM_operatortype_append(NODE_OT_new_node_tree); - WM_operatortype_append(NODE_OT_output_multi_file_add_socket); - WM_operatortype_append(NODE_OT_output_multi_file_remove_active_socket); + WM_operatortype_append(NODE_OT_output_file_add_socket); + WM_operatortype_append(NODE_OT_output_file_remove_active_socket); } void ED_operatormacros_node(void) diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 93891a9edfa..ed9eaff4b92 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -114,7 +114,7 @@ typedef struct bNodeSocket { /* sock->struct_type */ #define SOCK_STRUCT_NONE 0 /* default, type is defined by sock->type only */ -#define SOCK_STRUCT_OUTPUT_MULTI_FILE 1 /* multi file output node socket */ +#define SOCK_STRUCT_OUTPUT_FILE 1 /* file output node socket */ /* socket side (input/output) */ #define SOCK_IN 1 @@ -352,7 +352,7 @@ typedef struct NodeHueSat { float hue, sat, val; } NodeHueSat; -typedef struct NodeImageFile { +typedef DNA_DEPRECATED struct NodeImageFile { char name[1024]; /* 1024 = FILE_MAX */ struct ImageFormatData im_format; int sfra, efra; @@ -362,10 +362,11 @@ typedef struct NodeImageMultiFile { char base_path[1024]; /* 1024 = FILE_MAX */ int active_input; /* selected input in details view list */ int pad; + ImageFormatData format; } NodeImageMultiFile; typedef struct NodeImageMultiFileSocket { - short use_render_format; /* use global render settings instead of own format */ - short pad1; + short use_render_format DNA_DEPRECATED; + short use_node_format; /* use overall node image format */ int pad2; ImageFormatData format; } NodeImageMultiFileSocket; diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 67d27af8b41..596e348e3f6 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -347,7 +347,7 @@ extern StructRNA RNA_NlaTrack; extern StructRNA RNA_Node; extern StructRNA RNA_NodeForLoop; extern StructRNA RNA_NodeGroup; -extern StructRNA RNA_NodeImageMultiFileSocket; +extern StructRNA RNA_NodeImageFileSocket; extern StructRNA RNA_NodeLink; extern StructRNA RNA_NodeSocket; extern StructRNA RNA_NodeSocketPanel; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index a6a8d9f9a35..01131709f3b 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -245,32 +245,28 @@ static StructRNA *rna_NodeSocket_refine(PointerRNA *ptr) return &RNA_NodeSocket##stypename##idname; \ } - if (sock->struct_type == SOCK_STRUCT_NONE) { + switch (sock->struct_type) { + case SOCK_STRUCT_NONE: switch (sock->type) { case SOCK_FLOAT: NODE_DEFINE_SUBTYPES_FLOAT - break; + break; case SOCK_INT: NODE_DEFINE_SUBTYPES_INT - break; + break; case SOCK_BOOLEAN: return &RNA_NodeSocketBoolean; - break; case SOCK_VECTOR: NODE_DEFINE_SUBTYPES_VECTOR - break; + break; case SOCK_RGBA: return &RNA_NodeSocketRGBA; - break; case SOCK_SHADER: return &RNA_NodeSocketShader; } - } - else { - switch (sock->struct_type) { - case SOCK_STRUCT_OUTPUT_MULTI_FILE: - return &RNA_NodeImageMultiFileSocket; - } + break; + case SOCK_STRUCT_OUTPUT_FILE: + return &RNA_NodeImageFileSocket; } #undef SUBTYPE @@ -332,24 +328,6 @@ static void rna_Matte_t2_set(PointerRNA *ptr, float value) chroma->t2 = value; } -static void rna_Image_start_frame_set(PointerRNA *ptr, int value) -{ - bNode *node= (bNode*)ptr->data; - NodeImageFile *image = node->storage; - - CLAMP(value, MINFRAME, image->efra); - image->sfra= value; -} - -static void rna_Image_end_frame_set(PointerRNA *ptr, int value) -{ - bNode *node= (bNode*)ptr->data; - NodeImageFile *image = node->storage; - - CLAMP(value, image->sfra, MAXFRAME); - image->efra= value; -} - static void rna_Node_scene_set(PointerRNA *ptr, PointerRNA value) { bNode *node= (bNode*)ptr->data; @@ -1770,61 +1748,29 @@ static void def_cmp_render_layers(StructRNA *srna) RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_Node_update"); } -static void def_cmp_output_file(StructRNA *srna) -{ - PropertyRNA *prop; - - RNA_def_struct_sdna_from(srna, "NodeImageFile", "storage"); - - prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); - RNA_def_property_string_sdna(prop, NULL, "name"); - RNA_def_property_ui_text(prop, "File Path", "Output path for the image, same functionality as render output"); - RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_Node_update"); - - prop= RNA_def_property(srna, "image_settings", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_NEVER_NULL); - RNA_def_property_pointer_sdna(prop, NULL, "im_format"); - RNA_def_property_struct_type(prop, "ImageFormatSettings"); - RNA_def_property_ui_text(prop, "Image Format", ""); - - prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "sfra"); - RNA_def_property_int_funcs(prop, NULL, "rna_Image_start_frame_set", NULL); - RNA_def_property_range(prop, MINFRAMEF, MAXFRAMEF); - RNA_def_property_ui_text(prop, "Start Frame", ""); - RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_Node_update"); - - prop = RNA_def_property(srna, "frame_end", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "efra"); - RNA_def_property_int_funcs(prop, NULL, "rna_Image_end_frame_set", NULL); - RNA_def_property_range(prop, MINFRAMEF, MAXFRAMEF); - RNA_def_property_ui_text(prop, "End Frame", ""); - RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_Node_update"); -} - -static void rna_def_cmp_output_multi_file_socket(BlenderRNA *brna) +static void rna_def_cmp_output_file_socket(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; - srna = RNA_def_struct(brna, "NodeImageMultiFileSocket", "NodeSocketRGBA"); + srna = RNA_def_struct(brna, "NodeImageFileSocket", "NodeSocketRGBA"); RNA_def_struct_sdna(srna, "bNodeSocket"); RNA_def_struct_path_func(srna, "rna_NodeSocket_path"); - RNA_def_struct_ui_text(srna, "Node Image Multi File Socket", "Socket data of multi file output node"); + RNA_def_struct_ui_text(srna, "Node Image File Socket", "Socket data of file output node"); RNA_def_struct_ui_icon(srna, ICON_PLUG); RNA_def_struct_sdna_from(srna, "bNodeSocket", NULL); RNA_def_struct_sdna_from(srna, "NodeImageMultiFileSocket", "storage"); - prop = RNA_def_property(srna, "use_render_format", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "use_render_format", 1); - RNA_def_property_ui_text(prop, "Use Render Format", ""); + prop = RNA_def_property(srna, "use_node_format", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "use_node_format", 1); + RNA_def_property_ui_text(prop, "Use Node Format", ""); RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_NodeSocket_update"); prop = RNA_def_property(srna, "format", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "ImageFormatSettings"); } -static void def_cmp_output_multi_file(StructRNA *srna) +static void def_cmp_output_file(StructRNA *srna) { PropertyRNA *prop; @@ -1845,6 +1791,9 @@ static void def_cmp_output_multi_file(StructRNA *srna) RNA_def_property_int_sdna(prop, NULL, "active_input"); RNA_def_property_ui_text(prop, "Active Input Index", "Active input index in details view list"); RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "format", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "ImageFormatSettings"); } static void def_cmp_dilate_erode(StructRNA *srna) @@ -3477,7 +3426,7 @@ void RNA_def_nodetree(BlenderRNA *brna) define_specific_node(brna, NODE_FRAME, def_frame); /* special socket types */ - rna_def_cmp_output_multi_file_socket(brna); + rna_def_cmp_output_file_socket(brna); } /* clean up macro definition */ diff --git a/source/blender/makesrna/intern/rna_nodetree_types.h b/source/blender/makesrna/intern/rna_nodetree_types.h index b336f864012..745a956d831 100644 --- a/source/blender/makesrna/intern/rna_nodetree_types.h +++ b/source/blender/makesrna/intern/rna_nodetree_types.h @@ -113,7 +113,6 @@ DefNode( CompositorNode, CMP_NODE_IMAGE, def_cmp_image, "IMAGE DefNode( CompositorNode, CMP_NODE_R_LAYERS, def_cmp_render_layers, "R_LAYERS", RLayers, "Render Layers", "" ) DefNode( CompositorNode, CMP_NODE_COMPOSITE, 0, "COMPOSITE", Composite, "Composite", "" ) DefNode( CompositorNode, CMP_NODE_OUTPUT_FILE, def_cmp_output_file, "OUTPUT_FILE", OutputFile, "Output File", "" ) -DefNode( CompositorNode, CMP_NODE_OUTPUT_MULTI_FILE, def_cmp_output_multi_file, "OUTPUT_MULTI_FILE", OutputMultiFile, "Output Multi File", "" ) DefNode( CompositorNode, CMP_NODE_TEXTURE, def_texture, "TEXTURE", Texture, "Texture", "" ) DefNode( CompositorNode, CMP_NODE_TRANSLATE, 0, "TRANSLATE", Translate, "Translate", "" ) DefNode( CompositorNode, CMP_NODE_ZCOMBINE, def_cmp_zcombine, "ZCOMBINE", Zcombine, "Z Combine", "" ) diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index b458ae3a77d..aabf13f3bb2 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -222,4 +222,8 @@ if(WITH_PYTHON) add_definitions(-DWITH_PYTHON) endif() +if(WITH_IMAGE_OPENEXR) + add_definitions(-DWITH_OPENEXR) +endif() + blender_add_lib(bf_nodes "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h index e2bbaea8c7f..284b89bc095 100644 --- a/source/blender/nodes/NOD_composite.h +++ b/source/blender/nodes/NOD_composite.h @@ -55,7 +55,6 @@ void register_node_type_cmp_composite(struct bNodeTreeType *ttype); void register_node_type_cmp_viewer(struct bNodeTreeType *ttype); void register_node_type_cmp_splitviewer(struct bNodeTreeType *ttype); void register_node_type_cmp_output_file(struct bNodeTreeType *ttype); -void register_node_type_cmp_output_multi_file(struct bNodeTreeType *ttype); void register_node_type_cmp_view_levels(struct bNodeTreeType *ttype); void register_node_type_cmp_curve_rgb(struct bNodeTreeType *ttype); diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.c b/source/blender/nodes/composite/nodes/node_composite_outputFile.c index 66075f1bba4..90aa03997c1 100644 --- a/source/blender/nodes/composite/nodes/node_composite_outputFile.c +++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.c @@ -37,107 +37,22 @@ #include "node_composite_util.h" -/* **************** OUTPUT FILE ******************** */ -static bNodeSocketTemplate cmp_node_output_file_in[]= { - { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f}, - { SOCK_FLOAT, 1, "Z", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, - { -1, 0, "" } -}; - -static void node_composit_exec_output_file(void *data, bNode *node, bNodeStack **in, bNodeStack **UNUSED(out)) -{ - /* image assigned to output */ - /* stack order input sockets: col, alpha */ - - if(in[0]->data) { - RenderData *rd= data; - NodeImageFile *nif= node->storage; - if(nif->sfra!=nif->efra && (rd->cfra<nif->sfra || rd->cfra>nif->efra)) { - return; /* BAIL OUT RETURN */ - } - else if (!G.rendering) { - /* only output files when rendering a sequence - - * otherwise, it overwrites the output files just - * scrubbing through the timeline when the compositor updates */ - return; - } else { - Main *bmain= G.main; /* TODO, have this passed along */ - CompBuf *cbuf= typecheck_compbuf(in[0]->data, CB_RGBA); - ImBuf *ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0); - char string[FILE_MAX]; - - ibuf->rect_float= cbuf->rect; - ibuf->dither= rd->dither_intensity; - - if (rd->color_mgt_flag & R_COLOR_MANAGEMENT) - ibuf->profile = IB_PROFILE_LINEAR_RGB; - - if(in[1]->data) { - CompBuf *zbuf= in[1]->data; - if(zbuf->type==CB_VAL && zbuf->x==cbuf->x && zbuf->y==cbuf->y) { - nif->im_format.flag |= R_IMF_FLAG_ZBUF; - ibuf->zbuf_float= zbuf->rect; - } - } - - BKE_makepicstring(string, nif->name, bmain->name, rd->cfra, nif->im_format.imtype, (rd->scemode & R_EXTENSION), TRUE); - - if(0 == BKE_write_ibuf(ibuf, string, &nif->im_format)) - printf("Cannot save Node File Output to %s\n", string); - else - printf("Saved: %s\n", string); - - IMB_freeImBuf(ibuf); - - generate_preview(data, node, cbuf); - - if(in[0]->data != cbuf) - free_compbuf(cbuf); - } - } -} +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" -static void node_composit_init_output_file(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *ntemp) -{ - RenderData *rd = &ntemp->scene->r; - NodeImageFile *nif= MEM_callocN(sizeof(NodeImageFile), "node image file"); - node->storage= nif; +#include "intern/openexr/openexr_multi.h" - BLI_strncpy(nif->name, rd->pic, sizeof(nif->name)); - nif->im_format= rd->im_format; - if (BKE_imtype_is_movie(nif->im_format.imtype)) { - nif->im_format.imtype= R_IMF_IMTYPE_OPENEXR; - } - nif->sfra= rd->sfra; - nif->efra= rd->efra; -} - -void register_node_type_cmp_output_file(bNodeTreeType *ttype) -{ - static bNodeType ntype; - - node_type_base(ttype, &ntype, CMP_NODE_OUTPUT_FILE, "File Output", NODE_CLASS_OUTPUT, NODE_PREVIEW|NODE_OPTIONS); - node_type_socket_templates(&ntype, cmp_node_output_file_in, NULL); - node_type_size(&ntype, 140, 80, 300); - node_type_init(&ntype, node_composit_init_output_file); - node_type_storage(&ntype, "NodeImageFile", node_free_standard_storage, node_copy_standard_storage); - node_type_exec(&ntype, node_composit_exec_output_file); - - nodeRegisterType(ttype, &ntype); -} - - -/* =============================================================================== */ +/* **************** OUTPUT FILE ******************** */ -void ntreeCompositOutputMultiFileAddSocket(bNodeTree *ntree, bNode *node, ImageFormatData *im_format) +bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree, bNode *node, const char *name, ImageFormatData *im_format) { - bNodeSocket *sock = nodeAddSocket(ntree, node, SOCK_IN, "", SOCK_RGBA); + bNodeSocket *sock = nodeAddSocket(ntree, node, SOCK_IN, name, SOCK_RGBA); /* create format data for the input socket */ NodeImageMultiFileSocket *sockdata = MEM_callocN(sizeof(NodeImageMultiFileSocket), "socket image format"); sock->storage = sockdata; - sock->struct_type = SOCK_STRUCT_OUTPUT_MULTI_FILE; + sock->struct_type = SOCK_STRUCT_OUTPUT_FILE; if(im_format) { sockdata->format= *im_format; @@ -145,11 +60,13 @@ void ntreeCompositOutputMultiFileAddSocket(bNodeTree *ntree, bNode *node, ImageF sockdata->format.imtype= R_IMF_IMTYPE_OPENEXR; } } - /* use render data format by default */ - sockdata->use_render_format = 1; + /* use node data format by default */ + sockdata->use_node_format = 1; + + return sock; } -int ntreeCompositOutputMultiFileRemoveActiveSocket(bNodeTree *ntree, bNode *node) +int ntreeCompositOutputFileRemoveActiveSocket(bNodeTree *ntree, bNode *node) { NodeImageMultiFile *nimf = node->storage; bNodeSocket *sock = BLI_findlink(&node->inputs, nimf->active_input); @@ -164,19 +81,20 @@ int ntreeCompositOutputMultiFileRemoveActiveSocket(bNodeTree *ntree, bNode *node return 1; } -static void init_output_multi_file(bNodeTree *ntree, bNode* node, bNodeTemplate *ntemp) +static void init_output_file(bNodeTree *ntree, bNode* node, bNodeTemplate *ntemp) { RenderData *rd = &ntemp->scene->r; NodeImageMultiFile *nimf= MEM_callocN(sizeof(NodeImageMultiFile), "node image multi file"); node->storage= nimf; BLI_strncpy(nimf->base_path, rd->pic, sizeof(nimf->base_path)); + nimf->format = rd->im_format; /* add one socket by default */ - ntreeCompositOutputMultiFileAddSocket(ntree, node, &rd->im_format); + ntreeCompositOutputFileAddSocket(ntree, node, "Image", &rd->im_format); } -void free_output_multi_file(bNode *node) +static void free_output_file(bNode *node) { bNodeSocket *sock; @@ -188,7 +106,7 @@ void free_output_multi_file(bNode *node) MEM_freeN(node->storage); } -void copy_output_multi_file(struct bNode *node, struct bNode *target) +static void copy_output_file(struct bNode *node, struct bNode *target) { bNodeSocket *sock, *newsock; @@ -200,52 +118,73 @@ void copy_output_multi_file(struct bNode *node, struct bNode *target) } } -static void exec_output_multi_file(void *data, bNode *node, bNodeStack **in, bNodeStack **UNUSED(out)) +static void update_output_file(bNodeTree *UNUSED(ntree), bNode *node) { - RenderData *rd= data; + bNodeSocket *sock; + + /* automatically update the socket type based on linked input */ + for (sock=node->inputs.first; sock; sock=sock->next) { + if (sock->link) { + int linktype = sock->link->fromsock->type; + if (linktype != sock->type) + nodeSocketSetType(sock, linktype); + } + } +} + +/* write input data into individual files */ +static void exec_output_file_singlelayer(RenderData *rd, bNode *node, bNodeStack **in) +{ + Main *bmain= G.main; /* TODO, have this passed along */ NodeImageMultiFile *nimf= node->storage; bNodeSocket *sock; int i; + int has_preview = 0; for (sock=node->inputs.first, i=0; sock; sock=sock->next, ++i) { - if (!in[i]->data) - continue; - - if (!G.rendering) { - /* only output files when rendering a sequence - - * otherwise, it overwrites the output files just - * scrubbing through the timeline when the compositor updates */ - return; - } else { - Main *bmain= G.main; /* TODO, have this passed along */ + if (in[i]->data) { NodeImageMultiFileSocket *sockdata = sock->storage; - CompBuf *cbuf= typecheck_compbuf(in[i]->data, CB_RGBA); - ImBuf *ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0); - ImageFormatData *format = (sockdata->use_render_format ? &rd->im_format : &sockdata->format); + ImageFormatData *format = (sockdata->use_node_format ? &nimf->format : &sockdata->format); char path[FILE_MAX]; - char string[FILE_MAX]; + char filename[FILE_MAX]; + CompBuf *cbuf; + ImBuf *ibuf; - ibuf->rect_float= cbuf->rect; - ibuf->dither= rd->dither_intensity; + switch (format->planes) { + case R_IMF_PLANES_BW: + cbuf = typecheck_compbuf(in[i]->data, CB_VAL); + break; + case R_IMF_PLANES_RGB: + cbuf = typecheck_compbuf(in[i]->data, CB_VEC3); + break; + case R_IMF_PLANES_RGBA: + cbuf = typecheck_compbuf(in[i]->data, CB_RGBA); + break; + } + + ibuf = IMB_allocImBuf(cbuf->x, cbuf->y, format->planes, 0); + ibuf->rect_float = cbuf->rect; + ibuf->dither = rd->dither_intensity; if (rd->color_mgt_flag & R_COLOR_MANAGEMENT) ibuf->profile = IB_PROFILE_LINEAR_RGB; /* get full path */ BLI_join_dirfile(path, FILE_MAX, nimf->base_path, sock->name); + BKE_makepicstring(filename, path, bmain->name, rd->cfra, format->imtype, (rd->scemode & R_EXTENSION), TRUE); - BKE_makepicstring(string, path, bmain->name, rd->cfra, format->imtype, (rd->scemode & R_EXTENSION), TRUE); - - if(0 == BKE_write_ibuf(ibuf, string, format)) - printf("Cannot save Node File Output to %s\n", string); + if(0 == BKE_write_ibuf(ibuf, filename, format)) + printf("Cannot save Node File Output to %s\n", filename); else - printf("Saved: %s\n", string); + printf("Saved: %s\n", filename); - IMB_freeImBuf(ibuf); + IMB_freeImBuf(ibuf); - #if 0 /* XXX not used yet */ - generate_preview(data, node, cbuf); - #endif + /* simply pick the first valid input for preview */ + if (!has_preview) { + generate_preview(rd, node, cbuf); + has_preview = 1; + } if(in[i]->data != cbuf) free_compbuf(cbuf); @@ -253,16 +192,129 @@ static void exec_output_multi_file(void *data, bNode *node, bNodeStack **in, bNo } } -void register_node_type_cmp_output_multi_file(bNodeTreeType *ttype) +/* write input data into layers */ +static void exec_output_file_multilayer(RenderData *rd, bNode *node, bNodeStack **in) +{ + Main *bmain= G.main; /* TODO, have this passed along */ + NodeImageMultiFile *nimf= node->storage; + void *exrhandle= IMB_exr_get_handle(); + char filename[FILE_MAX]; + bNodeSocket *sock; + int i; + /* Must have consistent pixel size for exr file, simply take the first valid input size. */ + int rectx = -1; + int recty = -1; + int has_preview = 0; + + BKE_makepicstring(filename, nimf->base_path, bmain->name, rd->cfra, R_IMF_IMTYPE_MULTILAYER, (rd->scemode & R_EXTENSION), TRUE); + BLI_make_existing_file(filename); + + for (sock=node->inputs.first, i=0; sock; sock=sock->next, ++i) { + if (in[i]->data) { + CompBuf *cbuf = in[i]->data; + char layname[EXR_LAY_MAXNAME]; + char channelname[EXR_PASS_MAXNAME]; + char *channelname_ext; + + if (cbuf->rect_procedural) { + printf("Error writing multilayer EXR: Procedural buffer not supported\n"); + continue; + } + if (rectx < 0) { + rectx = cbuf->x; + recty = cbuf->y; + } + else if (cbuf->x != rectx || cbuf->y != recty) { + printf("Error: Multilayer EXR output node %s expects same resolution for all input buffers. Layer %s skipped.\n", node->name, sock->name); + continue; + } + + BLI_strncpy(layname, sock->name, sizeof(layname)); + BLI_strncpy(channelname, sock->name, sizeof(channelname)-2); + channelname_ext = channelname + strlen(channelname); + + /* create channels */ + switch (cbuf->type) { + case CB_VAL: + strcpy(channelname_ext, ".V"); + IMB_exr_add_channel(exrhandle, layname, channelname, 1, rectx, cbuf->rect); + break; + case CB_VEC2: + strcpy(channelname_ext, ".X"); + IMB_exr_add_channel(exrhandle, layname, channelname, 2, 2*rectx, cbuf->rect); + strcpy(channelname_ext, ".Y"); + IMB_exr_add_channel(exrhandle, layname, channelname, 2, 2*rectx, cbuf->rect+1); + break; + case CB_VEC3: + strcpy(channelname_ext, ".X"); + IMB_exr_add_channel(exrhandle, layname, channelname, 3, 3*rectx, cbuf->rect); + strcpy(channelname_ext, ".Y"); + IMB_exr_add_channel(exrhandle, layname, channelname, 3, 3*rectx, cbuf->rect+1); + strcpy(channelname_ext, ".Z"); + IMB_exr_add_channel(exrhandle, layname, channelname, 3, 3*rectx, cbuf->rect+2); + break; + case CB_RGBA: + strcpy(channelname_ext, ".R"); + IMB_exr_add_channel(exrhandle, layname, channelname, 4, 4*rectx, cbuf->rect); + strcpy(channelname_ext, ".G"); + IMB_exr_add_channel(exrhandle, layname, channelname, 4, 4*rectx, cbuf->rect+1); + strcpy(channelname_ext, ".B"); + IMB_exr_add_channel(exrhandle, layname, channelname, 4, 4*rectx, cbuf->rect+2); + strcpy(channelname_ext, ".A"); + IMB_exr_add_channel(exrhandle, layname, channelname, 4, 4*rectx, cbuf->rect+3); + break; + } + + /* simply pick the first valid input for preview */ + if (!has_preview) { + generate_preview(rd, node, cbuf); + has_preview = 1; + } + } + } + + /* when the filename has no permissions, this can fail */ + if(IMB_exr_begin_write(exrhandle, filename, rectx, recty, nimf->format.compress)) { + IMB_exr_write_channels(exrhandle); + } + else { + /* TODO, get the error from openexr's exception */ + /* XXX nice way to do report? */ + printf("Error Writing Render Result, see console\n"); + } + + IMB_exr_close(exrhandle); +} + +static void exec_output_file(void *data, bNode *node, bNodeStack **in, bNodeStack **UNUSED(out)) +{ + RenderData *rd= data; + NodeImageMultiFile *nimf= node->storage; + + if (!G.rendering) { + /* only output files when rendering a sequence - + * otherwise, it overwrites the output files just + * scrubbing through the timeline when the compositor updates */ + return; + } + + if (nimf->format.imtype==R_IMF_IMTYPE_MULTILAYER) + exec_output_file_multilayer(rd, node, in); + else + exec_output_file_singlelayer(rd, node, in); +} + +void register_node_type_cmp_output_file(bNodeTreeType *ttype) { static bNodeType ntype; - node_type_base(ttype, &ntype, CMP_NODE_OUTPUT_MULTI_FILE, "Multi File Output", NODE_CLASS_OUTPUT, NODE_OPTIONS); + node_type_base(ttype, &ntype, CMP_NODE_OUTPUT_FILE, "File Output", NODE_CLASS_OUTPUT, NODE_OPTIONS|NODE_PREVIEW); node_type_socket_templates(&ntype, NULL, NULL); node_type_size(&ntype, 140, 80, 300); - node_type_init(&ntype, init_output_multi_file); - node_type_storage(&ntype, "NodeImageMultiFile", free_output_multi_file, copy_output_multi_file); - node_type_exec(&ntype, exec_output_multi_file); + node_type_init(&ntype, init_output_file); + node_type_storage(&ntype, "NodeImageMultiFile", free_output_file, copy_output_file); + node_type_update(&ntype, update_output_file, NULL); + node_type_exec(&ntype, exec_output_file); nodeRegisterType(ttype, &ntype); } |