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:
authorLukas Toenne <lukas.toenne@googlemail.com>2012-05-11 12:06:01 +0400
committerLukas Toenne <lukas.toenne@googlemail.com>2012-05-11 12:06:01 +0400
commit9d91bc38d303e4937bb56dc75d95f11936de5ff9 (patch)
tree56ce4861cada738ce5f48bfdef35a32191c306ab /source/blender/nodes
parentce17c35240a332038090628cda34d00a9996215d (diff)
A couple more changes to the file and image nodes to improve access to layers that don't follow Blender's rlayer.rpass naming scheme.
--- Changes to File Output node --- * Flat layer names in EXR multilayer files. For a socket with name "AAA" the previous resulting EXR layer name would be "AAA.AAA", i.e. the render layer as well as render pass would use the socket name. Now the "render_layer.render_pass" scheme is ignored in multilayer files, socket names are directly written to EXR layers (EXR layer name is "AAA" in this example). If sockets should have a notion of "render layer" this can still be achieved by explicitly adding a separator, e.g. "AAA.BBB". When loading such layers into a Blender Image struct, the name is interpreted as a "render_layer.render_pass" again (although the image node does not care about it, see below). * Socket sub-paths (for singlelayer) or layer names (for multilayer) are stored in dedicated string variables in the socket storage data. This way the RNA can define precise string subtypes (PROP_FILEPATH) and length. The file/layer slots are defined as separate structs with own name properties in the RNA as well, so they can be used nicely with the list template. * Ensure unique socket paths/layer names to prevent overwriting of files and layers respectively. --- Changes to Image node --- * Loading multilayer OpenEXR files has improved layer name splitting into render layer + render pass names now. This properly supports arbitrary EXR layer names now. Example: OpenEXR layer name: AAA.BBB.CCC is split into Render layer name: AAA.BBB Render pass name: CCC If the layer name has no '.' separators the render layer name is empty. * Image node ignores the selected render layer in the image user data. Instead all existing layers are displayed at the same time by combining the render layer names with render pass names again, to reconstruct the original EXR layer name. This avoids the problem that render layers with empty name are not selectetable in the dropdown and allows using all image layers at the same time without duplicating the node.
Diffstat (limited to 'source/blender/nodes')
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_image.c129
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_outputFile.c103
2 files changed, 175 insertions, 57 deletions
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;
}