diff options
-rw-r--r-- | source/blender/blenkernel/BKE_blender.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_node.h | 5 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 66 | ||||
-rw-r--r-- | source/blender/blenloader/intern/writefile.c | 5 | ||||
-rw-r--r-- | source/blender/editors/space_node/drawnode.c | 66 | ||||
-rw-r--r-- | source/blender/imbuf/intern/openexr/openexr_api.cpp | 62 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_node_types.h | 17 | ||||
-rw-r--r-- | source/blender/makesrna/RNA_access.h | 4 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_nodetree.c | 148 | ||||
-rw-r--r-- | source/blender/nodes/composite/nodes/node_composite_image.c | 129 | ||||
-rw-r--r-- | source/blender/nodes/composite/nodes/node_composite_outputFile.c | 103 |
11 files changed, 442 insertions, 165 deletions
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 62f1dbc5867..29e02562be3 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 263 -#define BLENDER_SUBVERSION 4 +#define BLENDER_SUBVERSION 5 #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 fcb56bf8027..68b3e01b9ff 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -684,6 +684,11 @@ void ntreeCompositClearTags(struct bNodeTree *ntree); struct bNodeSocket *ntreeCompositOutputFileAddSocket(struct bNodeTree *ntree, struct bNode *node, const char *name, struct ImageFormatData *im_format); int ntreeCompositOutputFileRemoveActiveSocket(struct bNodeTree *ntree, struct bNode *node); +void ntreeCompositOutputFileSetPath(struct bNode *node, struct bNodeSocket *sock, const char *name); +void ntreeCompositOutputFileSetLayer(struct bNode *node, struct bNodeSocket *sock, const char *name); +/* needed in do_versions */ +void ntreeCompositOutputFileUniquePath(struct ListBase *list, struct bNodeSocket *sock, const char defname[], char delim); +void ntreeCompositOutputFileUniqueLayer(struct ListBase *list, struct bNodeSocket *sock, const char defname[], char delim); /* ************** TEXTURE NODES *************** */ diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 5bf2c8e53e2..c76261418f8 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -6840,6 +6840,52 @@ static void do_versions_nodetree_multi_file_output_path_2_64_0(bNodeTree *ntree) } } +static void do_versions_nodetree_file_output_layers_2_64_5(bNodeTree *ntree) +{ + bNode *node; + + for (node=ntree->nodes.first; node; node=node->next) { + if (node->type==CMP_NODE_OUTPUT_FILE) { + bNodeSocket *sock; + for (sock=node->inputs.first; sock; sock=sock->next) { + NodeImageMultiFileSocket *input = sock->storage; + + /* multilayer names are stored as separate strings now, + * used the path string before, so copy it over. + */ + BLI_strncpy(input->layer, input->path, sizeof(input->layer)); + + /* paths/layer names also have to be unique now, initial check */ + ntreeCompositOutputFileUniquePath(&node->inputs, sock, input->path, '_'); + ntreeCompositOutputFileUniqueLayer(&node->inputs, sock, input->layer, '_'); + } + } + } +} + +static void do_versions_nodetree_image_layer_2_64_5(bNodeTree *ntree) +{ + bNode *node; + + for (node=ntree->nodes.first; node; node=node->next) { + if (node->type==CMP_NODE_IMAGE) { + ImageUser *iuser= (ImageUser *)node->storage; + bNodeSocket *sock; + for (sock=node->outputs.first; sock; sock=sock->next) { + NodeImageLayer *output = MEM_callocN(sizeof(NodeImageLayer), "node image layer"); + + /* take layer index from image user (this is ignored from now on) */ + output->layer_index = iuser->layer; + /* take pass index both from current storage ptr (actually an int) */ + output->pass_index = GET_INT_FROM_POINTER(sock->storage); + + /* replace socket data pointer */ + sock->storage = output; + } + } + } +} + static void do_versions(FileData *fd, Library *lib, Main *main) { /* WATCH IT!!!: pointers from libdata have not been converted */ @@ -7456,6 +7502,26 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } + if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 5)) + { + { + /* file output node paths are now stored in the file info struct instead socket name */ + Scene *sce; + bNodeTree *ntree; + + for (sce = main->scene.first; sce; sce=sce->id.next) { + if (sce->nodetree) { + do_versions_nodetree_file_output_layers_2_64_5(sce->nodetree); + do_versions_nodetree_image_layer_2_64_5(sce->nodetree); + } + } + for (ntree = main->nodetree.first; ntree; ntree=ntree->id.next) { + do_versions_nodetree_file_output_layers_2_64_5(ntree); + do_versions_nodetree_image_layer_2_64_5(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 27ecf25fa91..f065ae238a6 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -734,6 +734,11 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree) for (sock=node->inputs.first; sock; sock=sock->next) writestruct(wd, DATA, "NodeImageMultiFileSocket", 1, sock->storage); } + if (node->type==CMP_NODE_IMAGE) { + /* write extra socket info */ + for (sock=node->outputs.first; sock; sock=sock->next) + writestruct(wd, DATA, "NodeImageLayer", 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 c2b7a1d6a7f..205202a0658 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1262,9 +1262,6 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA * } col= uiLayoutColumn(layout, 0); - - if (RNA_enum_get(&imaptr, "type")== IMA_TYPE_MULTILAYER) - uiItemR(col, ptr, "layer", 0, NULL, ICON_NONE); } static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -1709,25 +1706,30 @@ static void node_draw_input_file_output(const bContext *C, uiBlock *block, bNodeTree *ntree, bNode *node, bNodeSocket *sock, const char *UNUSED(name), int x, int y, int width) { - NodeImageMultiFileSocket *input = sock->storage; uiLayout *layout, *row; PointerRNA nodeptr, inputptr, imfptr; int imtype; int rx, ry; RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr); - RNA_pointer_create(&ntree->id, &RNA_NodeImageFileSocket, input, &inputptr); layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, x, y+NODE_DY, width, 20, UI_GetStyle()); - row = uiLayoutRow(layout, 0); - - uiItemL(row, input->path, 0); + row = uiLayoutRow(layout, 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) { + if (imtype == R_IMF_IMTYPE_MULTILAYER) { + NodeImageMultiFileSocket *input = sock->storage; + RNA_pointer_create(&ntree->id, &RNA_NodeOutputFileSlotLayer, input, &inputptr); + + uiItemL(row, input->layer, 0); + } + else { + NodeImageMultiFileSocket *input = sock->storage; PropertyRNA *imtype_prop; const char *imtype_name; + RNA_pointer_create(&ntree->id, &RNA_NodeOutputFileSlotFile, input, &inputptr); + + uiItemL(row, input->path, 0); if (!RNA_boolean_get(&inputptr, "use_node_format")) imfptr = RNA_pointer_get(&inputptr, "format"); @@ -1767,10 +1769,18 @@ static void node_composit_buts_file_output_details(uiLayout *layout, bContext *C uiItemO(layout, "Add Input", ICON_ZOOMIN, "NODE_OT_output_file_add_socket"); - uiTemplateList(layout, C, ptr, "file_inputs", ptr, "active_input_index", NULL, 0, 0, 0); - active_index = RNA_int_get(ptr, "active_input_index"); - RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "file_inputs"), active_index, &active_input_ptr); + /* using different collection properties if multilayer format is enabled */ + if (multilayer) { + uiTemplateList(layout, C, ptr, "layer_slots", ptr, "active_input_index", NULL, 0, 0, 0); + RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "layer_slots"), active_index, &active_input_ptr); + } + else { + uiTemplateList(layout, C, ptr, "file_slots", ptr, "active_input_index", NULL, 0, 0, 0); + RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "file_slots"), active_index, &active_input_ptr); + } + /* XXX collection lookup does not return the ID part of the pointer, setting this manually here */ + active_input_ptr.id.data = ptr->id.data; row = uiLayoutRow(layout, 1); op_ptr = uiItemFullO(row, "NODE_OT_output_file_move_active_socket", "", ICON_TRIA_UP, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); @@ -1779,19 +1789,25 @@ static void node_composit_buts_file_output_details(uiLayout *layout, bContext *C RNA_enum_set(&op_ptr, "direction", 2); if (active_input_ptr.data) { - uiLayout *row, *col; - - col = uiLayoutColumn(layout, 1); - if (multilayer) - uiItemL(col, "Layer Name:", 0); - else + if (multilayer) { + uiLayout *row, *col; + col = uiLayoutColumn(layout, 1); + + uiItemL(col, "Layer:", 0); + row = uiLayoutRow(col, 0); + uiItemR(row, &active_input_ptr, "name", 0, "", 0); + uiItemFullO(row, "NODE_OT_output_file_remove_active_socket", "", ICON_X, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_R_ICON_ONLY); + } + else { + uiLayout *row, *col; + col = uiLayoutColumn(layout, 1); + uiItemL(col, "File Path:", 0); - row = uiLayoutRow(col, 0); - uiItemR(row, &active_input_ptr, "path", 0, "", 0); - uiItemFullO(row, "NODE_OT_output_file_remove_active_socket", "", ICON_X, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_R_ICON_ONLY); - - /* in multilayer format all socket format details are ignored */ - if (!multilayer) { + row = uiLayoutRow(col, 0); + uiItemR(row, &active_input_ptr, "path", 0, "", 0); + uiItemFullO(row, "NODE_OT_output_file_remove_active_socket", "", ICON_X, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_R_ICON_ONLY); + + /* format details for individual files */ imfptr = RNA_pointer_get(&active_input_ptr, "format"); col = uiLayoutColumn(layout, 1); diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 50bc55da412..93a5f8eca7c 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -719,41 +719,55 @@ void IMB_exr_close(void *handle) /* ********* */ +/* get a substring from the end of the name, separated by '.' */ +static int imb_exr_split_token(const char *str, const char *end, const char **token) +{ + int maxlen = end-str; + int len = 0; + while (len < maxlen && *(end-len-1) != '.') + ++len; + + *token = end-len; + return len; +} + static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *passname) { - int plen, len= strlen(echan->name); + const char *name = echan->name; + const char *end = name + strlen(name); + const char *token; + char tokenbuf[EXR_TOT_MAXNAME]; + int len; - if (len < 4) { - printf("multilayer read: name too short: %s\n", echan->name); + /* last token is single character channel identifier */ + len = imb_exr_split_token(name, end, &token); + if (len == 0) { + printf("multilayer read: bad channel name: %s\n", name); return 0; } - if (echan->name[len-2]!='.') { - printf("multilayer read: name has no Channel: %s\n", echan->name); + else if (len > 1) { + BLI_strncpy(tokenbuf, token, len); + printf("multilayer read: channel token too long: %s\n", tokenbuf); return 0; } - echan->chan_id= echan->name[len-1]; + echan->chan_id = token[0]; + end -= len + 1; /* +1 to skip '.' separator */ - len-= 3; - while (len>=0) { - if (echan->name[len]=='.') - break; - len--; - } - BLI_strncpy(passname, echan->name+len+1, EXR_PASS_MAXNAME); - plen= strlen(passname); - if (plen < 3) { - printf("multilayer read: should not happen: %s\n", echan->name); + /* second token is pass name */ + len = imb_exr_split_token(name, end, &token); + if (len == 0) { + printf("multilayer read: bad channel name: %s\n", name); return 0; } - passname[plen-2]= 0; + BLI_strncpy(passname, token, len+1); + end -= len + 1; /* +1 to skip '.' separator */ + + /* all preceding tokens combined as layer name */ + if (end > name) + BLI_strncpy(layname, name, (int)(end-name)+1); + else + layname[0] = '\0'; - if (len<1) - layname[0]= 0; - else { - BLI_strncpy(layname, echan->name, EXR_LAY_MAXNAME); - layname[len]= 0; - } - // printf("found lay %s pass %s chan %c\n", layname, passname, echan->chan_id); return 1; } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 6874e8de4f1..6fbaf1723bc 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -324,6 +324,14 @@ typedef struct NodeImageAnim { short pad; } NodeImageAnim; +/* layer info for image node outputs */ +typedef struct NodeImageLayer { + /* index in the Image->layers and Image->layers->passes lists */ + int layer_index, pass_index; + /* render pass flag, in case this is an original render pass */ + int pass_flag; +} NodeImageLayer; + typedef struct NodeBlurData { short sizex, sizey; short samples, maxspeed, minspeed, relative, aspect; @@ -364,11 +372,16 @@ typedef struct NodeImageMultiFile { int pad; } NodeImageMultiFile; typedef struct NodeImageMultiFileSocket { + /* single layer file output */ short use_render_format DNA_DEPRECATED; short use_node_format; /* use overall node image format */ - int pad2; - char path[1024]; /* 1024 = FILE_MAX */ + int pad1; + char path[1024]; /* 1024 = FILE_MAX */ ImageFormatData format; + + /* multilayer output */ + char layer[30]; /* EXR_TOT_MAXNAME-2 ('.' and channel char are appended) */ + char pad2[2]; } NodeImageMultiFileSocket; typedef struct NodeChroma { diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 0cc4fa4c221..826ebb72979 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -349,10 +349,10 @@ extern StructRNA RNA_NlaTrack; extern StructRNA RNA_Node; extern StructRNA RNA_NodeForLoop; extern StructRNA RNA_NodeGroup; -extern StructRNA RNA_NodeImageFileSocket; +extern StructRNA RNA_NodeOutputFileSlotFile; +extern StructRNA RNA_NodeOutputFileSlotLayer; extern StructRNA RNA_NodeLink; extern StructRNA RNA_NodeSocket; -extern StructRNA RNA_NodeSocketPanel; extern StructRNA RNA_NodeTree; extern StructRNA RNA_NodeWhileLoop; extern StructRNA RNA_NoiseTexture; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 3d2737f9ff4..bb1c50d8c13 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -487,18 +487,6 @@ static void rna_NodeSocketVector_range(PointerRNA *ptr, float *min, float *max, *softmax = val->max; } -static void rna_Node_image_layer_update(Main *bmain, Scene *scene, PointerRNA *ptr) -{ - bNode *node = (bNode*)ptr->data; - Image *ima = (Image *)node->id; - ImageUser *iuser = node->storage; - - BKE_image_multilayer_index(ima->rr, iuser); - BKE_image_signal(ima, iuser, IMA_SIGNAL_SRC_CHANGE); - - rna_Node_update(bmain, scene, ptr); -} - static EnumPropertyItem *renderresult_layers_add_enum(RenderLayer *rl) { EnumPropertyItem *item = NULL; @@ -518,24 +506,6 @@ static EnumPropertyItem *renderresult_layers_add_enum(RenderLayer *rl) return item; } -static EnumPropertyItem *rna_Node_image_layer_itemf(bContext *UNUSED(C), PointerRNA *ptr, - PropertyRNA *UNUSED(prop), int *free) -{ - bNode *node = (bNode*)ptr->data; - Image *ima = (Image *)node->id; - EnumPropertyItem *item = NULL; - RenderLayer *rl; - - if (!ima || !(ima->rr)) return NULL; - - rl = ima->rr->layers.first; - item = renderresult_layers_add_enum(rl); - - *free = 1; - - return item; -} - static EnumPropertyItem *rna_Node_scene_layer_itemf(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), int *free) { @@ -853,25 +823,74 @@ static void rna_Mapping_Node_update(Main *bmain, Scene *scene, PointerRNA *ptr) rna_Node_update(bmain, scene, ptr); } -static void rna_NodeOutputFile_file_inputs_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +static void rna_NodeOutputFile_slots_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { bNode *node = ptr->data; rna_iterator_listbase_begin(iter, &node->inputs, NULL); } -static PointerRNA rna_NodeOutputFile_file_inputs_get(CollectionPropertyIterator *iter) +static PointerRNA rna_NodeOutputFile_slot_file_get(CollectionPropertyIterator *iter) { PointerRNA ptr; bNodeSocket *sock = rna_iterator_listbase_get(iter); - RNA_pointer_create(iter->ptr.id.data, &RNA_NodeImageFileSocket, sock->storage, &ptr); + RNA_pointer_create(iter->ptr.id.data, &RNA_NodeOutputFileSlotFile, sock->storage, &ptr); return ptr; } -#else +static PointerRNA rna_NodeOutputFile_slot_layer_get(CollectionPropertyIterator *iter) +{ + PointerRNA ptr; + bNodeSocket *sock = rna_iterator_listbase_get(iter); + RNA_pointer_create(iter->ptr.id.data, &RNA_NodeOutputFileSlotLayer, sock->storage, &ptr); + return ptr; +} -static EnumPropertyItem prop_image_layer_items[] = { -{ 0, "PLACEHOLDER", 0, "Placeholder", ""}, -{0, NULL, 0, NULL, NULL}}; +static int rna_NodeOutputFileSocket_find_node(bNodeTree *ntree, NodeImageMultiFileSocket *data, bNode **nodep, bNodeSocket **sockp) +{ + bNode *node; + bNodeSocket *sock; + + for (node= ntree->nodes.first; node; node= node->next) { + for (sock= node->inputs.first; sock; sock= sock->next) { + NodeImageMultiFileSocket *sockdata = sock->storage; + if (sockdata==data) { + *nodep = node; + *sockp = sock; + return 1; + } + } + } + + *nodep= NULL; + *sockp= NULL; + return 0; +} + +static void rna_NodeOutputFileSlotFile_path_set(PointerRNA *ptr, const char *value) +{ + bNodeTree *ntree = ptr->id.data; + NodeImageMultiFileSocket *sockdata = ptr->data; + bNode *node; + bNodeSocket *sock; + + if (rna_NodeOutputFileSocket_find_node(ntree, sockdata, &node, &sock)) { + ntreeCompositOutputFileSetPath(node, sock, value); + } +} + +static void rna_NodeOutputFileSlotLayer_name_set(PointerRNA *ptr, const char *value) +{ + bNodeTree *ntree = ptr->id.data; + NodeImageMultiFileSocket *sockdata = ptr->data; + bNode *node; + bNodeSocket *sock; + + if (rna_NodeOutputFileSocket_find_node(ntree, sockdata, &node, &sock)) { + ntreeCompositOutputFileSetLayer(node, sock, value); + } +} + +#else static EnumPropertyItem prop_scene_layer_items[] = { { 0, "PLACEHOLDER", 0, "Placeholder", ""}, @@ -1792,13 +1811,6 @@ static void def_cmp_image(StructRNA *srna) /* copied from the rna_image.c */ RNA_def_property_ui_text(prop, "Auto-Refresh", "Always refresh image on frame changes"); RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_Node_update"); - - prop = RNA_def_property(srna, "layer", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "layer"); - RNA_def_property_enum_items(prop, prop_image_layer_items); - RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Node_image_layer_itemf"); - RNA_def_property_ui_text(prop, "Layer", ""); - RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_Node_image_layer_update"); } static void def_cmp_render_layers(StructRNA *srna) @@ -1821,14 +1833,14 @@ static void def_cmp_render_layers(StructRNA *srna) RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_Node_update"); } -static void rna_def_cmp_output_file_socket(BlenderRNA *brna) +static void rna_def_cmp_output_file_slot_file(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; - srna = RNA_def_struct(brna, "NodeImageFileSocket", NULL); + srna = RNA_def_struct(brna, "NodeOutputFileSlotFile", NULL); RNA_def_struct_sdna(srna, "NodeImageMultiFileSocket"); - RNA_def_struct_ui_text(srna, "Node Image File Socket", "Socket data of file output node"); + RNA_def_struct_ui_text(srna, "Output File Slot", "Single layer file slot of the file output node"); prop = RNA_def_property(srna, "use_node_format", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "use_node_format", 1); @@ -1840,8 +1852,25 @@ static void rna_def_cmp_output_file_socket(BlenderRNA *brna) prop = RNA_def_property(srna, "path", PROP_STRING, PROP_FILEPATH); RNA_def_property_string_sdna(prop, NULL, "path"); - RNA_def_property_ui_text(prop, "Path", "Subpath used for this input"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_NodeOutputFileSlotFile_path_set"); + RNA_def_struct_name_property(srna, prop); + RNA_def_property_ui_text(prop, "Path", "Subpath used for this slot"); + RNA_def_property_update(prop, NC_NODE|NA_EDITED, NULL); +} +static void rna_def_cmp_output_file_slot_layer(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "NodeOutputFileSlotLayer", NULL); + RNA_def_struct_sdna(srna, "NodeImageMultiFileSocket"); + RNA_def_struct_ui_text(srna, "Output File Layer Slot", "Multilayer slot of the file output node"); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "layer"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_NodeOutputFileSlotLayer_name_set"); RNA_def_struct_name_property(srna, prop); + RNA_def_property_ui_text(prop, "Name", "OpenEXR layer name used for this slot"); RNA_def_property_update(prop, NC_NODE|NA_EDITED, NULL); } static void def_cmp_output_file(StructRNA *srna) @@ -1863,11 +1892,21 @@ static void def_cmp_output_file(StructRNA *srna) prop = RNA_def_property(srna, "format", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "ImageFormatSettings"); - prop = RNA_def_property(srna, "file_inputs", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_funcs(prop, "rna_NodeOutputFile_file_inputs_begin", "rna_iterator_listbase_next", "rna_iterator_listbase_end", - "rna_NodeOutputFile_file_inputs_get", NULL, NULL, NULL, NULL); - RNA_def_property_struct_type(prop, "NodeImageFileSocket"); - RNA_def_property_ui_text(prop, "File Inputs", ""); + /* XXX using two different collections here for the same basic DNA list! + * Details of the output slots depend on whether the node is in Multilayer EXR mode. + */ + + prop = RNA_def_property(srna, "file_slots", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_funcs(prop, "rna_NodeOutputFile_slots_begin", "rna_iterator_listbase_next", "rna_iterator_listbase_end", + "rna_NodeOutputFile_slot_file_get", NULL, NULL, NULL, NULL); + RNA_def_property_struct_type(prop, "NodeOutputFileSlotFile"); + RNA_def_property_ui_text(prop, "File Slots", ""); + + prop = RNA_def_property(srna, "layer_slots", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_funcs(prop, "rna_NodeOutputFile_slots_begin", "rna_iterator_listbase_next", "rna_iterator_listbase_end", + "rna_NodeOutputFile_slot_layer_get", NULL, NULL, NULL, NULL); + RNA_def_property_struct_type(prop, "NodeOutputFileSlotLayer"); + RNA_def_property_ui_text(prop, "EXR Layer Slots", ""); } static void def_cmp_dilate_erode(StructRNA *srna) @@ -3536,7 +3575,8 @@ void RNA_def_nodetree(BlenderRNA *brna) define_specific_node(brna, NODE_FRAME, def_frame); /* special socket types */ - rna_def_cmp_output_file_socket(brna); + rna_def_cmp_output_file_slot_file(brna); + rna_def_cmp_output_file_slot_layer(brna); } /* clean up macro definition */ diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c index 02bb16f644a..4467fb1f193 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.c +++ b/source/blender/nodes/composite/nodes/node_composite_image.c @@ -66,13 +66,17 @@ static bNodeSocketTemplate cmp_node_rlayers_out[]= { { -1, 0, "" } }; -static bNodeSocket *cmp_node_image_add_render_pass_output(bNodeTree *ntree, bNode *node, int UNUSED(pass), int rres_index) +static bNodeSocket *cmp_node_image_add_render_pass_output(bNodeTree *ntree, bNode *node, int pass, int rres_index) { bNodeSocket *sock; + NodeImageLayer *sockdata; sock = node_add_output_from_template(ntree, node, &cmp_node_rlayers_out[rres_index]); - /* for render pass outputs store the pass type index as a lookup key */ - sock->storage = SET_INT_IN_POINTER(rres_index); + /* extra socket info */ + sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer"); + sock->storage = sockdata; + + sockdata->pass_flag = pass; return sock; } @@ -141,21 +145,37 @@ static void cmp_node_image_add_render_pass_outputs(bNodeTree *ntree, bNode *node cmp_node_image_add_render_pass_output(ntree, node, SCE_PASS_TRANSM_COLOR, RRES_OUT_TRANSM_COLOR); } -static void cmp_node_image_add_multilayer_outputs(bNodeTree *ntree, bNode *node, RenderLayer *rl) +static void cmp_node_image_add_multilayer_outputs(bNodeTree *ntree, bNode *node, ListBase *layers) { bNodeSocket *sock; + NodeImageLayer *sockdata; + RenderLayer *rl; RenderPass *rpass; - int index; - for (rpass=rl->passes.first, index=0; rpass; rpass=rpass->next, ++index) { - int type; - if (rpass->channels == 1) - type = SOCK_FLOAT; - else - type = SOCK_RGBA; - - sock = nodeAddSocket(ntree, node, SOCK_OUT, rpass->name, type); - /* for multilayer image use pass index directly as key */ - sock->storage = SET_INT_IN_POINTER(index); + int layer_index, pass_index; + char name[30]; /* EXR_TOT_MAXNAME-2 ('.' and channel char are appended) */ + int type; + + for (rl=layers->first, layer_index=0; rl; rl=rl->next, ++layer_index) { + for (rpass=rl->passes.first, pass_index=0; rpass; rpass=rpass->next, ++pass_index) { + /* reconstruct layer name from <render layer>.<render pass> strings */ + if (rl->name[0] != '\0') + BLI_snprintf(name, sizeof(name), "%s.%s", rl->name, rpass->name); + else + BLI_strncpy(name, rpass->name, sizeof(name)); + + if (rpass->channels == 1) + type = SOCK_FLOAT; + else + type = SOCK_RGBA; + + sock = nodeAddSocket(ntree, node, SOCK_OUT, name, type); + /* extra socket info */ + sockdata = MEM_callocN(sizeof(NodeImageLayer), "node image layer"); + sock->storage = sockdata; + + sockdata->layer_index = layer_index; + sockdata->pass_index = pass_index; + } } } @@ -169,16 +189,16 @@ static void cmp_node_image_create_outputs(bNodeTree *ntree, bNode *node) BKE_image_get_ibuf(ima, iuser); if (ima->rr) { - RenderLayer *rl= BLI_findlink(&ima->rr->layers, iuser->layer); - - if (rl) { - if (ima->type!=IMA_TYPE_MULTILAYER) + if (ima->type == IMA_TYPE_MULTILAYER) { + cmp_node_image_add_multilayer_outputs(ntree, node, &ima->rr->layers); + } + else { + RenderLayer *rl= BLI_findlink(&ima->rr->layers, iuser->layer); + if (rl) cmp_node_image_add_render_pass_outputs(ntree, node, rl->passflag); else - cmp_node_image_add_multilayer_outputs(ntree, node, rl); + cmp_node_image_add_render_pass_outputs(ntree, node, RRES_OUT_IMAGE|RRES_OUT_ALPHA); } - else - cmp_node_image_add_render_pass_outputs(ntree, node, RRES_OUT_IMAGE|RRES_OUT_ALPHA); } else cmp_node_image_add_render_pass_outputs(ntree, node, RRES_OUT_IMAGE|RRES_OUT_ALPHA|RRES_OUT_Z); @@ -261,6 +281,7 @@ static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node) */ for (oldsock=oldsocklist.first; oldsock; oldsock=oldsock_next) { oldsock_next = oldsock->next; + MEM_freeN(oldsock->storage); nodeRemoveSocket(ntree, node, oldsock); } } @@ -394,17 +415,21 @@ static CompBuf *node_composit_get_zimage(bNode *node, RenderData *rd) } /* check if layer is available, returns pass buffer */ -static CompBuf *compbuf_multilayer_get(RenderData *rd, RenderLayer *rl, Image *ima, ImageUser *iuser, int passindex) +static CompBuf *compbuf_multilayer_get(RenderData *rd, Image *ima, ImageUser *iuser, int layer_index, int pass_index) { - RenderPass *rpass = BLI_findlink(&rl->passes, passindex); - if (rpass) { - CompBuf *cbuf; - - iuser->pass = passindex; - BKE_image_multilayer_index(ima->rr, iuser); - cbuf = node_composit_get_image(rd, ima, iuser); - - return cbuf; + RenderLayer *rl = BLI_findlink(&ima->rr->layers, layer_index); + if (rl) { + RenderPass *rpass = BLI_findlink(&rl->passes, pass_index); + if (rpass) { + CompBuf *cbuf; + + iuser->layer = layer_index; + iuser->pass = pass_index; + BKE_image_multilayer_index(ima->rr, iuser); + cbuf = node_composit_get_image(rd, ima, iuser); + + return cbuf; + } } return NULL; } @@ -422,22 +447,20 @@ static void node_composit_exec_image(void *data, bNode *node, bNodeStack **UNUSE /* first set the right frame number in iuser */ BKE_image_user_frame_calc(iuser, rd->cfra, 0); - /* force a load, we assume iuser index will be set OK anyway */ - if (ima->type==IMA_TYPE_MULTILAYER) + if (ima->type==IMA_TYPE_MULTILAYER) { + /* force a load, we assume iuser index will be set OK anyway */ BKE_image_get_ibuf(ima, iuser); - if (ima->type==IMA_TYPE_MULTILAYER && ima->rr) { - RenderLayer *rl= BLI_findlink(&ima->rr->layers, iuser->layer); - - if (rl) { + if (ima->rr) { bNodeSocket *sock; + NodeImageLayer *sockdata; int out_index; CompBuf *combinedbuf= NULL, *firstbuf= NULL; for (sock=node->outputs.first, out_index=0; sock; sock=sock->next, ++out_index) { - int passindex = GET_INT_FROM_POINTER(sock->storage); + sockdata = sock->storage; if (out[out_index]->hasoutput) { - CompBuf *stackbuf = out[out_index]->data = compbuf_multilayer_get(rd, rl, ima, iuser, passindex); + CompBuf *stackbuf = out[out_index]->data = compbuf_multilayer_get(rd, ima, iuser, sockdata->layer_index, sockdata->pass_index); if (stackbuf) { /* preview policy: take first 'Combined' pass if available, * otherwise just use the first layer. @@ -446,7 +469,7 @@ static void node_composit_exec_image(void *data, bNode *node, bNodeStack **UNUSE firstbuf = stackbuf; } if (!combinedbuf && - (strcmp(sock->name, "Combined") == 0 || strcmp(sock->name, "Image") == 0)) + (strcmp(sock->name, "Combined") == 0 || strcmp(sock->name, "Image") == 0)) { combinedbuf = stackbuf; } @@ -520,6 +543,28 @@ static void node_composit_init_image(bNodeTree *ntree, bNode* node, bNodeTemplat cmp_node_image_verify_outputs(ntree, node); } +static void node_composit_free_image(bNode *node) +{ + bNodeSocket *sock; + + /* free extra socket info */ + for (sock=node->outputs.first; sock; sock=sock->next) + MEM_freeN(sock->storage); + + MEM_freeN(node->storage); +} + +static void node_composit_copy_image(bNode *orig_node, bNode *new_node) +{ + bNodeSocket *sock; + + new_node->storage= MEM_dupallocN(orig_node->storage); + + /* copy extra socket info */ + for (sock=orig_node->outputs.first; sock; sock=sock->next) + sock->new_sock->storage = MEM_dupallocN(sock->storage); +} + void register_node_type_cmp_image(bNodeTreeType *ttype) { static bNodeType ntype; @@ -527,7 +572,7 @@ void register_node_type_cmp_image(bNodeTreeType *ttype) node_type_base(ttype, &ntype, CMP_NODE_IMAGE, "Image", NODE_CLASS_INPUT, NODE_PREVIEW|NODE_OPTIONS); node_type_size(&ntype, 120, 80, 300); node_type_init(&ntype, node_composit_init_image); - node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage); + node_type_storage(&ntype, "ImageUser", node_composit_free_image, node_composit_copy_image); node_type_update(&ntype, cmp_node_image_update, NULL); node_type_exec(&ntype, node_composit_exec_image); diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.c b/source/blender/nodes/composite/nodes/node_composite_outputFile.c index 18a535018ba..a571b140a1f 100644 --- a/source/blender/nodes/composite/nodes/node_composite_outputFile.c +++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.c @@ -45,6 +45,64 @@ /* **************** OUTPUT FILE ******************** */ +/* find unique path */ +static int unique_path_unique_check(void *arg, const char *name) +{ + struct {ListBase *lb; bNodeSocket *sock;} *data= arg; + bNodeSocket *sock; + for (sock=data->lb->first; sock; sock=sock->next) { + if (sock != data->sock) { + NodeImageMultiFileSocket *sockdata = sock->storage; + if (strcmp(sockdata->path, name)==0) + return 1; + } + } + return 0; +} +void ntreeCompositOutputFileUniquePath(ListBase *list, bNodeSocket *sock, const char defname[], char delim) +{ + NodeImageMultiFileSocket *sockdata; + struct {ListBase *lb; bNodeSocket *sock;} data; + data.lb = list; + data.sock = sock; + + /* See if we are given an empty string */ + if (ELEM(NULL, sock, defname)) + return; + + sockdata = sock->storage; + BLI_uniquename_cb(unique_path_unique_check, &data, defname, delim, sockdata->path, sizeof(sockdata->path)); +} + +/* find unique EXR layer */ +static int unique_layer_unique_check(void *arg, const char *name) +{ + struct {ListBase *lb; bNodeSocket *sock;} *data= arg; + bNodeSocket *sock; + for (sock=data->lb->first; sock; sock=sock->next) { + if (sock != data->sock) { + NodeImageMultiFileSocket *sockdata = sock->storage; + if (strcmp(sockdata->layer, name)==0) + return 1; + } + } + return 0; +} +void ntreeCompositOutputFileUniqueLayer(ListBase *list, bNodeSocket *sock, const char defname[], char delim) +{ + NodeImageMultiFileSocket *sockdata; + struct {ListBase *lb; bNodeSocket *sock;} data; + data.lb = list; + data.sock = sock; + + /* See if we are given an empty string */ + if (ELEM(NULL, sock, defname)) + return; + + sockdata = sock->storage; + BLI_uniquename_cb(unique_layer_unique_check, &data, defname, delim, sockdata->layer, sizeof(sockdata->layer)); +} + bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree, bNode *node, const char *name, ImageFormatData *im_format) { NodeImageMultiFile *nimf = node->storage; @@ -54,7 +112,10 @@ bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree, bNode *node, con NodeImageMultiFileSocket *sockdata = MEM_callocN(sizeof(NodeImageMultiFileSocket), "socket image format"); sock->storage = sockdata; - BLI_strncpy(sockdata->path, name, sizeof(sockdata->path)); + BLI_strncpy_utf8(sockdata->path, name, sizeof(sockdata->path)); + ntreeCompositOutputFileUniquePath(&node->inputs, sock, name, '_'); + BLI_strncpy_utf8(sockdata->layer, name, sizeof(sockdata->layer)); + ntreeCompositOutputFileUniqueLayer(&node->inputs, sock, name, '_'); if (im_format) { sockdata->format= *im_format; @@ -89,6 +150,20 @@ int ntreeCompositOutputFileRemoveActiveSocket(bNodeTree *ntree, bNode *node) return 1; } +void ntreeCompositOutputFileSetPath(bNode *node, bNodeSocket *sock, const char *name) +{ + NodeImageMultiFileSocket *sockdata = sock->storage; + BLI_strncpy_utf8(sockdata->path, name, sizeof(sockdata->path)); + ntreeCompositOutputFileUniquePath(&node->inputs, sock, name, '_'); +} + +void ntreeCompositOutputFileSetLayer(bNode *node, bNodeSocket *sock, const char *name) +{ + NodeImageMultiFileSocket *sockdata = sock->storage; + BLI_strncpy_utf8(sockdata->layer, name, sizeof(sockdata->layer)); + ntreeCompositOutputFileUniqueLayer(&node->inputs, sock, name, '_'); +} + static void init_output_file(bNodeTree *ntree, bNode* node, bNodeTemplate *ntemp) { NodeImageMultiFile *nimf= MEM_callocN(sizeof(NodeImageMultiFile), "node image multi file"); @@ -232,8 +307,7 @@ static void exec_output_file_multilayer(RenderData *rd, bNode *node, bNodeStack if (in[i]->data) { NodeImageMultiFileSocket *sockdata = sock->storage; CompBuf *cbuf = in[i]->data; - char layname[EXR_LAY_MAXNAME]; - char channelname[EXR_PASS_MAXNAME]; + char channelname[EXR_TOT_MAXNAME]; /* '.' and single character channel name is appended */ char *channelname_ext; if (cbuf->rect_procedural) { @@ -249,39 +323,38 @@ static void exec_output_file_multilayer(RenderData *rd, bNode *node, bNodeStack continue; } - BLI_strncpy(layname, sockdata->path, sizeof(layname)); - BLI_strncpy(channelname, sockdata->path, sizeof(channelname)-2); + BLI_strncpy(channelname, sockdata->layer, 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); + IMB_exr_add_channel(exrhandle, NULL, 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); + IMB_exr_add_channel(exrhandle, NULL, channelname, 2, 2*rectx, cbuf->rect); strcpy(channelname_ext, ".Y"); - IMB_exr_add_channel(exrhandle, layname, channelname, 2, 2*rectx, cbuf->rect+1); + IMB_exr_add_channel(exrhandle, NULL, 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); + IMB_exr_add_channel(exrhandle, NULL, channelname, 3, 3*rectx, cbuf->rect); strcpy(channelname_ext, ".Y"); - IMB_exr_add_channel(exrhandle, layname, channelname, 3, 3*rectx, cbuf->rect+1); + IMB_exr_add_channel(exrhandle, NULL, channelname, 3, 3*rectx, cbuf->rect+1); strcpy(channelname_ext, ".Z"); - IMB_exr_add_channel(exrhandle, layname, channelname, 3, 3*rectx, cbuf->rect+2); + IMB_exr_add_channel(exrhandle, NULL, 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); + IMB_exr_add_channel(exrhandle, NULL, channelname, 4, 4*rectx, cbuf->rect); strcpy(channelname_ext, ".G"); - IMB_exr_add_channel(exrhandle, layname, channelname, 4, 4*rectx, cbuf->rect+1); + IMB_exr_add_channel(exrhandle, NULL, channelname, 4, 4*rectx, cbuf->rect+1); strcpy(channelname_ext, ".B"); - IMB_exr_add_channel(exrhandle, layname, channelname, 4, 4*rectx, cbuf->rect+2); + IMB_exr_add_channel(exrhandle, NULL, channelname, 4, 4*rectx, cbuf->rect+2); strcpy(channelname_ext, ".A"); - IMB_exr_add_channel(exrhandle, layname, channelname, 4, 4*rectx, cbuf->rect+3); + IMB_exr_add_channel(exrhandle, NULL, channelname, 4, 4*rectx, cbuf->rect+3); break; } |