Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_blender.h2
-rw-r--r--source/blender/blenkernel/BKE_node.h5
-rw-r--r--source/blender/blenloader/intern/readfile.c66
-rw-r--r--source/blender/blenloader/intern/writefile.c5
-rw-r--r--source/blender/editors/space_node/drawnode.c66
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp62
-rw-r--r--source/blender/makesdna/DNA_node_types.h17
-rw-r--r--source/blender/makesrna/RNA_access.h4
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c148
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_image.c129
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_outputFile.c103
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;
}