diff options
-rw-r--r-- | source/blender/blenkernel/BKE_node.h | 8 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/node.c | 1 | ||||
-rw-r--r-- | source/blender/blenloader/intern/writefile.c | 6 | ||||
-rw-r--r-- | source/blender/editors/space_node/drawnode.c | 160 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_draw.c | 10 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_edit.c | 74 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_header.c | 18 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_intern.h | 3 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_ops.c | 3 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_node_types.h | 18 | ||||
-rw-r--r-- | source/blender/makesrna/RNA_access.h | 1 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_nodetree.c | 107 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_nodetree_types.h | 1 | ||||
-rw-r--r-- | source/blender/nodes/NOD_composite.h | 1 | ||||
-rw-r--r-- | source/blender/nodes/composite/nodes/node_composite_outputFile.c | 182 |
15 files changed, 514 insertions, 79 deletions
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index ae2f9305894..fe914a8c5ba 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -112,8 +112,9 @@ typedef struct bNodeSocketType { typedef struct bNodeTemplate { int type; - /* group tree */ - struct bNodeTree *ngroup; + struct Main *main; + struct Scene *scene; + struct bNodeTree *ngroup; /* group tree */ } bNodeTemplate; /** Defines a node type. @@ -653,6 +654,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_GLARE 301 #define CMP_NODE_TONEMAP 302 @@ -692,6 +694,8 @@ 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); /* ************** TEXTURE NODES *************** */ diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index b72abcd79f4..cf2cbaed8f1 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1804,6 +1804,7 @@ 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/writefile.c b/source/blender/blenloader/intern/writefile.c index a6a61286fb1..8ea5427b1ed 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -725,6 +725,12 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree) else writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage); } + + if (node->type==CMP_NODE_OUTPUT_MULTI_FILE) { + /* inputs have own storage data */ + for (sock=node->inputs.first; sock; sock=sock->next) + writestruct(wd, DATA, "NodeImageMultiFileSocket", 1, sock->storage); + } } for(link= ntree->links.first; link; link= link->next) diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 143173da5bc..63eead6780f 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -107,16 +107,20 @@ 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) { - 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); + 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); + } } typedef struct SocketComponentMenuArgs { @@ -145,42 +149,80 @@ 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) { - 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, ""); + 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, ""); + } } static void node_socket_button_color(const bContext *C, uiBlock *block, bNodeTree *ntree, bNode *node, bNodeSocket *sock, const char *name, int x, int y, int width) { - PointerRNA ptr; - uiBut *bt; - int labelw= width - 40; - - RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr); - - bt=uiDefButR(block, COL, B_NODE_EXEC, "", - x, y+2, (labelw>0 ? 40 : 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); + /* XXX would be nicer to have draw function based on sock->struct_type as well, + * but currently socket types are completely identified by data type only. + */ - if (name[0]!='\0' && labelw>0) - uiDefBut(block, LABEL, 0, name, x + 40, y+2, labelw, NODE_DY-2, NULL, 0, 0, 0, 0, ""); + 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; + int labelw= width - 40; + RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr); + + bt=uiDefButR(block, COL, B_NODE_EXEC, "", + x, y+2, (labelw>0 ? 40 : 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); + + if (name[0]!='\0' && labelw>0) + uiDefBut(block, LABEL, 0, name, x + 40, y+2, labelw, NODE_DY-2, NULL, 0, 0, 0, 0, ""); + } + 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); + break; + } + } } /* ****************** BASE DRAW FUNCTIONS FOR NEW OPERATOR NODES ***************** */ @@ -1673,6 +1715,42 @@ static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C) 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); + uiItemR(layout, ptr, "base_path", 0, "", ICON_NONE); +} +static void node_composit_buts_multi_file_output_details(uiLayout *layout, bContext *C, PointerRNA *ptr) +{ + PointerRNA active_input_ptr = RNA_pointer_get(ptr, "active_input"); + + node_composit_buts_multi_file_output(layout, C, ptr); + + uiItemO(layout, "Add Input", ICON_ZOOMIN, "NODE_OT_output_multi_file_add_socket"); + + uiTemplateList(layout, C, ptr, "inputs", ptr, "active_input_index", NULL, 0, 0, 0); + + if (active_input_ptr.data) { + uiLayout *row, *col; + + uiItemS(layout); + + col = uiLayoutColumn(layout, 1); + 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); + uiItemL(layout, "Format:", 0); + uiItemR(layout, &active_input_ptr, "use_render_format", 0, NULL, 0); + if (!RNA_boolean_get(&active_input_ptr, "use_render_format")) { + PointerRNA imfptr = RNA_pointer_get(&active_input_ptr, "format"); + uiTemplateImageSettings(layout, &imfptr); + } + } +} + static void node_composit_buts_scale(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "space", 0, "", ICON_NONE); @@ -1908,6 +1986,10 @@ static void node_composit_set_butfunc(bNodeType *ntype) 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; + break; case CMP_NODE_DIFF_MATTE: ntype->uifunc=node_composit_buts_diff_matte; break; diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index a82ea9e9046..0913c3fb9eb 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -718,14 +718,8 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN node_socket_circle_draw(ntree, sock, NODE_SOCKSIZE); - if (sock->link || (sock->flag & SOCK_HIDE_VALUE)) { - uiDefBut(node->block, LABEL, 0, sock->name, sock->locx+NODE_DYS, sock->locy-NODE_DYS, node->width-NODE_DY, NODE_DY, - NULL, 0, 0, 0, 0, ""); - } - else { - if (stype->buttonfunc) - stype->buttonfunc(C, node->block, ntree, node, sock, sock->name, sock->locx+NODE_DYS, sock->locy-NODE_DYS, node->width-NODE_DY); - } + if (stype->buttonfunc) + stype->buttonfunc(C, node->block, ntree, node, sock, sock->name, sock->locx+NODE_DYS, sock->locy-NODE_DYS, node->width-NODE_DY); } /* socket outputs */ diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 906b5d01e32..d92bdc42958 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -3587,3 +3587,77 @@ void NODE_OT_new_node_tree(wmOperatorType *ot) RNA_def_enum(ot->srna, "type", nodetree_type_items, NTREE_COMPOSIT, "Tree Type", ""); RNA_def_string(ot->srna, "name", "NodeTree", MAX_ID_NAME-2, "Name", ""); } + +/* ****************** Multi File Output Add Socket ******************* */ + +static int node_output_multi_file_add_socket_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Scene *scene= CTX_data_scene(C); + SpaceNode *snode= CTX_wm_space_node(C); + bNodeTree *ntree = snode->edittree; + bNode *node = nodeGetActive(ntree); + + if (!node) + return OPERATOR_CANCELLED; + + ntreeCompositOutputMultiFileAddSocket(ntree, node, &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) +{ + /* 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"; + + /* callbacks */ + ot->exec= node_output_multi_file_add_socket_exec; + ot->invoke= node_output_multi_file_add_socket_invoke; + ot->poll= composite_node_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* ****************** Multi File Output Remove Socket ******************* */ + +static int node_output_multi_file_remove_active_socket_exec(bContext *C, wmOperator *UNUSED(op)) +{ + SpaceNode *snode= CTX_wm_space_node(C); + bNodeTree *ntree = snode->edittree; + bNode *node = nodeGetActive(ntree); + + if (!node) + return OPERATOR_CANCELLED; + + if (!ntreeCompositOutputMultiFileRemoveActiveSocket(ntree, node)) + return OPERATOR_CANCELLED; + + snode_notify(C, snode); + + return OPERATOR_FINISHED; +} + +void NODE_OT_output_multi_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"; + + /* callbacks */ + ot->exec= node_output_multi_file_remove_active_socket_exec; + ot->poll= composite_node_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} diff --git a/source/blender/editors/space_node/node_header.c b/source/blender/editors/space_node/node_header.c index 6dd5eeba832..df83afc143e 100644 --- a/source/blender/editors/space_node/node_header.c +++ b/source/blender/editors/space_node/node_header.c @@ -110,14 +110,22 @@ static void do_node_add(bContext *C, bNodeTemplate *ntemp) static void do_node_add_static(bContext *C, void *UNUSED(arg), int event) { + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); bNodeTemplate ntemp; + ntemp.type = event; + ntemp.main = bmain; + ntemp.scene = scene; + do_node_add(C, &ntemp); } static void do_node_add_group(bContext *C, void *UNUSED(arg), int event) { SpaceNode *snode= CTX_wm_space_node(C); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); bNodeTemplate ntemp; if (event>=0) { @@ -143,14 +151,24 @@ static void do_node_add_group(bContext *C, void *UNUSED(arg), int event) if (!ntemp.ngroup) return; + ntemp.main = bmain; + ntemp.scene = scene; + do_node_add(C, &ntemp); } #if 0 /* disabled */ static void do_node_add_dynamic(bContext *C, void *UNUSED(arg), int event) { + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); bNodeTemplate ntemp; + ntemp.type = NODE_DYNAMIC; + + ntemp.main = bmain; + ntemp.scene = scene; + do_node_add(C, &ntemp); } #endif diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index 48501079e60..4bfb62023b5 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -159,6 +159,9 @@ 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); + extern const char *node_context_dir[]; // XXXXXX diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index 508021540b5..493f4747387 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -99,6 +99,9 @@ void node_operatortypes(void) WM_operatortype_append(NODE_OT_add_file); 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); } void ED_operatormacros_node(void) diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 361aca4a572..05a469916a6 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -77,7 +77,7 @@ typedef struct bNodeSocket { short type, flag; short limit; /* max. number of links */ - short pad1; + short struct_type; /* optional identifier for RNA struct subtype */ float locx, locy; @@ -112,6 +112,10 @@ typedef struct bNodeSocket { #define SOCK_INT 6 #define NUM_SOCKET_TYPES 7 /* must be last! */ +/* 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 */ + /* socket side (input/output) */ #define SOCK_IN 1 #define SOCK_OUT 2 @@ -354,6 +358,18 @@ typedef struct NodeImageFile { int sfra, efra; } NodeImageFile; +typedef struct NodeImageMultiFile { + char base_path[1024]; /* 1024 = FILE_MAX */ + int active_input; /* selected input in details view list */ + int pad; +} NodeImageMultiFile; +typedef struct NodeImageMultiFileSocket { + short use_render_format; /* use global render settings instead of own format */ + short pad1; + int pad2; + ImageFormatData format; +} NodeImageMultiFileSocket; + typedef struct NodeChroma { float t1,t2,t3; float fsize,fstrength,falpha; diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 1aecbc223b5..67d27af8b41 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -347,6 +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_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 989202f785c..42668c6080c 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -35,6 +35,8 @@ #include "rna_internal.h" #include "rna_internal_types.h" +#include "BLI_listbase.h" + #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_node_types.h" @@ -243,24 +245,32 @@ static StructRNA *rna_NodeSocket_refine(PointerRNA *ptr) return &RNA_NodeSocket##stypename##idname; \ } - switch (sock->type) { - case SOCK_FLOAT: - NODE_DEFINE_SUBTYPES_FLOAT - break; - case SOCK_INT: - NODE_DEFINE_SUBTYPES_INT - break; - case SOCK_BOOLEAN: - return &RNA_NodeSocketBoolean; - break; - case SOCK_VECTOR: - NODE_DEFINE_SUBTYPES_VECTOR - break; - case SOCK_RGBA: - return &RNA_NodeSocketRGBA; - break; - case SOCK_SHADER: - return &RNA_NodeSocketShader; + if (sock->struct_type == SOCK_STRUCT_NONE) { + switch (sock->type) { + case SOCK_FLOAT: + NODE_DEFINE_SUBTYPES_FLOAT + break; + case SOCK_INT: + NODE_DEFINE_SUBTYPES_INT + break; + case SOCK_BOOLEAN: + return &RNA_NodeSocketBoolean; + break; + case SOCK_VECTOR: + NODE_DEFINE_SUBTYPES_VECTOR + 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; + } } #undef SUBTYPE @@ -824,6 +834,16 @@ static void rna_Mapping_Node_update(Main *bmain, Scene *scene, PointerRNA *ptr) rna_Node_update(bmain, scene, ptr); } +static PointerRNA rna_CompositNodeOutputMultiFile_active_input_get(PointerRNA *ptr) +{ + bNode *node = ptr->data; + NodeImageMultiFile *nimf = node->storage; + bNodeSocket *sock = BLI_findlink(&node->inputs, nimf->active_input); + PointerRNA sock_ptr; + RNA_pointer_create((ID*)ptr->id.data, &RNA_NodeSocket, sock, &sock_ptr); + return sock_ptr; +} + #else static EnumPropertyItem prop_image_layer_items[] = { @@ -1782,6 +1802,51 @@ static void def_cmp_output_file(StructRNA *srna) RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_Node_update"); } +static void rna_def_cmp_output_multi_file_socket(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "NodeImageMultiFileSocket", "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_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", ""); + 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) +{ + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeImageMultiFile", "storage"); + + prop = RNA_def_property(srna, "base_path", PROP_STRING, PROP_FILEPATH); + RNA_def_property_string_sdna(prop, NULL, "base_path"); + RNA_def_property_ui_text(prop, "Base Path", "Base output path for the image"); + RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "active_input", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_funcs(prop, "rna_CompositNodeOutputMultiFile_active_input_get", NULL, NULL, NULL); + RNA_def_property_struct_type(prop, "NodeSocket"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Active Input", "Active input in details view list"); + + prop = RNA_def_property(srna, "active_input_index", PROP_INT, PROP_NONE); + 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"); +} + static void def_cmp_dilate_erode(StructRNA *srna) { PropertyRNA *prop; @@ -3144,6 +3209,9 @@ static void rna_def_node_socket_subtype(BlenderRNA *brna, int type, int subtype, RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_NodeSocket_update"); break; } + + /* XXX need to reset the from-type here, so subtype subclasses cast correctly! (RNA bug) */ + RNA_def_struct_sdna_from(srna, "bNodeSocket", NULL); } static void rna_def_node(BlenderRNA *brna) @@ -3407,6 +3475,9 @@ void RNA_def_nodetree(BlenderRNA *brna) define_specific_node(brna, NODE_FORLOOP, def_forloop); define_specific_node(brna, NODE_WHILELOOP, def_whileloop); define_specific_node(brna, NODE_FRAME, def_frame); + + /* special socket types */ + rna_def_cmp_output_multi_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 745a956d831..b336f864012 100644 --- a/source/blender/makesrna/intern/rna_nodetree_types.h +++ b/source/blender/makesrna/intern/rna_nodetree_types.h @@ -113,6 +113,7 @@ 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/NOD_composite.h b/source/blender/nodes/NOD_composite.h index 284b89bc095..e2bbaea8c7f 100644 --- a/source/blender/nodes/NOD_composite.h +++ b/source/blender/nodes/NOD_composite.h @@ -55,6 +55,7 @@ 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 50a196deb07..02df603f494 100644 --- a/source/blender/nodes/composite/nodes/node_composite_outputFile.c +++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.c @@ -30,6 +30,11 @@ */ +#include <string.h> +#include "BLI_path_util.h" + +#include "BKE_utildefines.h" + #include "node_composite_util.h" /* **************** OUTPUT FILE ******************** */ @@ -59,7 +64,7 @@ static void node_composit_exec_output_file(void *data, bNode *node, bNodeStack * 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[256]; + char string[FILE_MAX]; ibuf->rect_float= cbuf->rect; ibuf->dither= rd->dither_intensity; @@ -92,21 +97,26 @@ static void node_composit_exec_output_file(void *data, bNode *node, bNodeStack * } } -static void node_composit_init_output_file(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp)) +static void node_composit_mute_output_file(void *UNUSED(data), int UNUSED(thread), + struct bNode *UNUSED(node), void *UNUSED(nodedata), + struct bNodeStack **UNUSED(in), struct bNodeStack **UNUSED(out)) +{ + /* nothing to do here */ +} + +static void node_composit_init_output_file(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *ntemp) { - Scene *scene= (Scene *)node->id; + RenderData *rd = &ntemp->scene->r; NodeImageFile *nif= MEM_callocN(sizeof(NodeImageFile), "node image file"); node->storage= nif; - if(scene) { - BLI_strncpy(nif->name, scene->r.pic, sizeof(nif->name)); - nif->im_format= scene->r.im_format; - if (BKE_imtype_is_movie(nif->im_format.imtype)) { - nif->im_format.imtype= R_IMF_IMTYPE_OPENEXR; - } - nif->sfra= scene->r.sfra; - nif->efra= scene->r.efra; + 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) @@ -119,6 +129,156 @@ void register_node_type_cmp_output_file(bNodeTreeType *ttype) 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); + node_type_mute(&ntype, node_composit_mute_output_file, NULL); + + nodeRegisterType(ttype, &ntype); +} + + +/* =============================================================================== */ + + +void ntreeCompositOutputMultiFileAddSocket(bNodeTree *ntree, bNode *node, ImageFormatData *im_format) +{ + bNodeSocket *sock = nodeAddSocket(ntree, node, SOCK_IN, "", 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; + + if(im_format) { + sockdata->format= *im_format; + if (BKE_imtype_is_movie(sockdata->format.imtype)) { + sockdata->format.imtype= R_IMF_IMTYPE_OPENEXR; + } + } + /* use render data format by default */ + sockdata->use_render_format = 1; +} + +int ntreeCompositOutputMultiFileRemoveActiveSocket(bNodeTree *ntree, bNode *node) +{ + NodeImageMultiFile *nimf = node->storage; + bNodeSocket *sock = BLI_findlink(&node->inputs, nimf->active_input); + + if (!sock) + return 0; + + /* free format data */ + MEM_freeN(sock->storage); + + nodeRemoveSocket(ntree, node, sock); + return 1; +} + +static void init_output_multi_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)); + + /* add one socket by default */ + ntreeCompositOutputMultiFileAddSocket(ntree, node, &rd->im_format); +} + +void free_output_multi_file(bNode *node) +{ + bNodeSocket *sock; + + /* free storage data in sockets */ + for (sock=node->inputs.first; sock; sock=sock->next) { + MEM_freeN(sock->storage); + } + + MEM_freeN(node->storage); +} + +void copy_output_multi_file(struct bNode *node, struct bNode *target) +{ + bNodeSocket *sock, *newsock; + + target->storage = MEM_dupallocN(node->storage); + + /* duplicate storage data in sockets */ + for (sock=node->inputs.first, newsock=target->inputs.first; sock && newsock; sock=sock->next, newsock=newsock->next) { + newsock->storage = MEM_dupallocN(sock->storage); + } +} + +static void exec_output_multi_file(void *data, bNode *node, bNodeStack **in, bNodeStack **UNUSED(out)) +{ + RenderData *rd= data; + NodeImageMultiFile *nimf= node->storage; + bNodeSocket *sock; + int i; + + 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 */ + 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); + char path[FILE_MAX]; + 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; + + /* get full path */ + BLI_join_dirfile(path, FILE_MAX, nimf->base_path, sock->name); + + 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); + else + printf("Saved: %s\n", string); + + IMB_freeImBuf(ibuf); + + #if 0 /* XXX not used yet */ + generate_preview(data, node, cbuf); + #endif + + if(in[i]->data != cbuf) + free_compbuf(cbuf); + } + } +} + +static void mute_output_multi_file(void *UNUSED(data), int UNUSED(thread), + struct bNode *UNUSED(node), void *UNUSED(nodedata), + struct bNodeStack **UNUSED(in), struct bNodeStack **UNUSED(out)) +{ + /* nothing to do here */ +} + +void register_node_type_cmp_output_multi_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_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_mute(&ntype, mute_output_multi_file, NULL); nodeRegisterType(ttype, &ntype); } |