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-03-01 11:56:15 +0400
committerLukas Toenne <lukas.toenne@googlemail.com>2012-03-01 11:56:15 +0400
commit2eb29e4788008c1346b3a757cccec503b73c9b90 (patch)
tree8b27a7524ad45b8cfcadff31cfa17d2885a0f18b /source/blender/nodes
parent1d5a3886a175da808df1872f161e4eb8848ab358 (diff)
A number of improvements for the file output node(s).
1) Old CMP_NODE_OUTPUT_FILE and CMP_NODE_OUTPUT_MULTI_FILE have been merged, only CMP_NODE_OUTPUT_FILE remains. All functions renamed accordingly. 2) do_versions code for converting single-file output nodes into multi-file output nodes. If a Z buffer input is used, the node is made into a multilayer exr with two inputs. (see below). Also re-identifies multi-file output nodes with the CMP_NODE_OUTPUT_FILE type. 3) "Global" format is stored in node now. By default this overrides any per-socket settings. 4) Multilayer EXR output implemented. When M.EXR format is selected for node format, all socket format details are ignored. Socket names are used for layer names. 5) Input buffer types are used as-is when possible, i.e. stored as B/W, RGB or RGBA. In regular file output the format dictates the number of actual channels, so the CompBuf is typechecked to the right type first. For multilayer EXR the number of channels is more flexible, so an input buffer will store only the channels it actually uses. 6) The editor socket type is updated from linked sockets as an indicator of the actual data written to files. This may not be totally accurate for regular file output though, due to restrictions of format setting.
Diffstat (limited to 'source/blender/nodes')
-rw-r--r--source/blender/nodes/CMakeLists.txt4
-rw-r--r--source/blender/nodes/NOD_composite.h1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_outputFile.c314
3 files changed, 187 insertions, 132 deletions
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index b458ae3a77d..aabf13f3bb2 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -222,4 +222,8 @@ if(WITH_PYTHON)
add_definitions(-DWITH_PYTHON)
endif()
+if(WITH_IMAGE_OPENEXR)
+ add_definitions(-DWITH_OPENEXR)
+endif()
+
blender_add_lib(bf_nodes "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index e2bbaea8c7f..284b89bc095 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -55,7 +55,6 @@ void register_node_type_cmp_composite(struct bNodeTreeType *ttype);
void register_node_type_cmp_viewer(struct bNodeTreeType *ttype);
void register_node_type_cmp_splitviewer(struct bNodeTreeType *ttype);
void register_node_type_cmp_output_file(struct bNodeTreeType *ttype);
-void register_node_type_cmp_output_multi_file(struct bNodeTreeType *ttype);
void register_node_type_cmp_view_levels(struct bNodeTreeType *ttype);
void register_node_type_cmp_curve_rgb(struct bNodeTreeType *ttype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.c b/source/blender/nodes/composite/nodes/node_composite_outputFile.c
index 66075f1bba4..90aa03997c1 100644
--- a/source/blender/nodes/composite/nodes/node_composite_outputFile.c
+++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.c
@@ -37,107 +37,22 @@
#include "node_composite_util.h"
-/* **************** OUTPUT FILE ******************** */
-static bNodeSocketTemplate cmp_node_output_file_in[]= {
- { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 1, "Z", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- { -1, 0, "" }
-};
-
-static void node_composit_exec_output_file(void *data, bNode *node, bNodeStack **in, bNodeStack **UNUSED(out))
-{
- /* image assigned to output */
- /* stack order input sockets: col, alpha */
-
- if(in[0]->data) {
- RenderData *rd= data;
- NodeImageFile *nif= node->storage;
- if(nif->sfra!=nif->efra && (rd->cfra<nif->sfra || rd->cfra>nif->efra)) {
- return; /* BAIL OUT RETURN */
- }
- else if (!G.rendering) {
- /* only output files when rendering a sequence -
- * otherwise, it overwrites the output files just
- * scrubbing through the timeline when the compositor updates */
- return;
- } else {
- Main *bmain= G.main; /* TODO, have this passed along */
- CompBuf *cbuf= typecheck_compbuf(in[0]->data, CB_RGBA);
- ImBuf *ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0);
- char string[FILE_MAX];
-
- ibuf->rect_float= cbuf->rect;
- ibuf->dither= rd->dither_intensity;
-
- if (rd->color_mgt_flag & R_COLOR_MANAGEMENT)
- ibuf->profile = IB_PROFILE_LINEAR_RGB;
-
- if(in[1]->data) {
- CompBuf *zbuf= in[1]->data;
- if(zbuf->type==CB_VAL && zbuf->x==cbuf->x && zbuf->y==cbuf->y) {
- nif->im_format.flag |= R_IMF_FLAG_ZBUF;
- ibuf->zbuf_float= zbuf->rect;
- }
- }
-
- BKE_makepicstring(string, nif->name, bmain->name, rd->cfra, nif->im_format.imtype, (rd->scemode & R_EXTENSION), TRUE);
-
- if(0 == BKE_write_ibuf(ibuf, string, &nif->im_format))
- printf("Cannot save Node File Output to %s\n", string);
- else
- printf("Saved: %s\n", string);
-
- IMB_freeImBuf(ibuf);
-
- generate_preview(data, node, cbuf);
-
- if(in[0]->data != cbuf)
- free_compbuf(cbuf);
- }
- }
-}
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
-static void node_composit_init_output_file(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *ntemp)
-{
- RenderData *rd = &ntemp->scene->r;
- NodeImageFile *nif= MEM_callocN(sizeof(NodeImageFile), "node image file");
- node->storage= nif;
+#include "intern/openexr/openexr_multi.h"
- BLI_strncpy(nif->name, rd->pic, sizeof(nif->name));
- nif->im_format= rd->im_format;
- if (BKE_imtype_is_movie(nif->im_format.imtype)) {
- nif->im_format.imtype= R_IMF_IMTYPE_OPENEXR;
- }
- nif->sfra= rd->sfra;
- nif->efra= rd->efra;
-}
-
-void register_node_type_cmp_output_file(bNodeTreeType *ttype)
-{
- static bNodeType ntype;
-
- node_type_base(ttype, &ntype, CMP_NODE_OUTPUT_FILE, "File Output", NODE_CLASS_OUTPUT, NODE_PREVIEW|NODE_OPTIONS);
- node_type_socket_templates(&ntype, cmp_node_output_file_in, NULL);
- node_type_size(&ntype, 140, 80, 300);
- node_type_init(&ntype, node_composit_init_output_file);
- node_type_storage(&ntype, "NodeImageFile", node_free_standard_storage, node_copy_standard_storage);
- node_type_exec(&ntype, node_composit_exec_output_file);
-
- nodeRegisterType(ttype, &ntype);
-}
-
-
-/* =============================================================================== */
+/* **************** OUTPUT FILE ******************** */
-void ntreeCompositOutputMultiFileAddSocket(bNodeTree *ntree, bNode *node, ImageFormatData *im_format)
+bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree, bNode *node, const char *name, ImageFormatData *im_format)
{
- bNodeSocket *sock = nodeAddSocket(ntree, node, SOCK_IN, "", SOCK_RGBA);
+ bNodeSocket *sock = nodeAddSocket(ntree, node, SOCK_IN, name, SOCK_RGBA);
/* create format data for the input socket */
NodeImageMultiFileSocket *sockdata = MEM_callocN(sizeof(NodeImageMultiFileSocket), "socket image format");
sock->storage = sockdata;
- sock->struct_type = SOCK_STRUCT_OUTPUT_MULTI_FILE;
+ sock->struct_type = SOCK_STRUCT_OUTPUT_FILE;
if(im_format) {
sockdata->format= *im_format;
@@ -145,11 +60,13 @@ void ntreeCompositOutputMultiFileAddSocket(bNodeTree *ntree, bNode *node, ImageF
sockdata->format.imtype= R_IMF_IMTYPE_OPENEXR;
}
}
- /* use render data format by default */
- sockdata->use_render_format = 1;
+ /* use node data format by default */
+ sockdata->use_node_format = 1;
+
+ return sock;
}
-int ntreeCompositOutputMultiFileRemoveActiveSocket(bNodeTree *ntree, bNode *node)
+int ntreeCompositOutputFileRemoveActiveSocket(bNodeTree *ntree, bNode *node)
{
NodeImageMultiFile *nimf = node->storage;
bNodeSocket *sock = BLI_findlink(&node->inputs, nimf->active_input);
@@ -164,19 +81,20 @@ int ntreeCompositOutputMultiFileRemoveActiveSocket(bNodeTree *ntree, bNode *node
return 1;
}
-static void init_output_multi_file(bNodeTree *ntree, bNode* node, bNodeTemplate *ntemp)
+static void init_output_file(bNodeTree *ntree, bNode* node, bNodeTemplate *ntemp)
{
RenderData *rd = &ntemp->scene->r;
NodeImageMultiFile *nimf= MEM_callocN(sizeof(NodeImageMultiFile), "node image multi file");
node->storage= nimf;
BLI_strncpy(nimf->base_path, rd->pic, sizeof(nimf->base_path));
+ nimf->format = rd->im_format;
/* add one socket by default */
- ntreeCompositOutputMultiFileAddSocket(ntree, node, &rd->im_format);
+ ntreeCompositOutputFileAddSocket(ntree, node, "Image", &rd->im_format);
}
-void free_output_multi_file(bNode *node)
+static void free_output_file(bNode *node)
{
bNodeSocket *sock;
@@ -188,7 +106,7 @@ void free_output_multi_file(bNode *node)
MEM_freeN(node->storage);
}
-void copy_output_multi_file(struct bNode *node, struct bNode *target)
+static void copy_output_file(struct bNode *node, struct bNode *target)
{
bNodeSocket *sock, *newsock;
@@ -200,52 +118,73 @@ void copy_output_multi_file(struct bNode *node, struct bNode *target)
}
}
-static void exec_output_multi_file(void *data, bNode *node, bNodeStack **in, bNodeStack **UNUSED(out))
+static void update_output_file(bNodeTree *UNUSED(ntree), bNode *node)
{
- RenderData *rd= data;
+ bNodeSocket *sock;
+
+ /* automatically update the socket type based on linked input */
+ for (sock=node->inputs.first; sock; sock=sock->next) {
+ if (sock->link) {
+ int linktype = sock->link->fromsock->type;
+ if (linktype != sock->type)
+ nodeSocketSetType(sock, linktype);
+ }
+ }
+}
+
+/* write input data into individual files */
+static void exec_output_file_singlelayer(RenderData *rd, bNode *node, bNodeStack **in)
+{
+ Main *bmain= G.main; /* TODO, have this passed along */
NodeImageMultiFile *nimf= node->storage;
bNodeSocket *sock;
int i;
+ int has_preview = 0;
for (sock=node->inputs.first, i=0; sock; sock=sock->next, ++i) {
- if (!in[i]->data)
- continue;
-
- if (!G.rendering) {
- /* only output files when rendering a sequence -
- * otherwise, it overwrites the output files just
- * scrubbing through the timeline when the compositor updates */
- return;
- } else {
- Main *bmain= G.main; /* TODO, have this passed along */
+ if (in[i]->data) {
NodeImageMultiFileSocket *sockdata = sock->storage;
- CompBuf *cbuf= typecheck_compbuf(in[i]->data, CB_RGBA);
- ImBuf *ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0);
- ImageFormatData *format = (sockdata->use_render_format ? &rd->im_format : &sockdata->format);
+ ImageFormatData *format = (sockdata->use_node_format ? &nimf->format : &sockdata->format);
char path[FILE_MAX];
- char string[FILE_MAX];
+ char filename[FILE_MAX];
+ CompBuf *cbuf;
+ ImBuf *ibuf;
- ibuf->rect_float= cbuf->rect;
- ibuf->dither= rd->dither_intensity;
+ switch (format->planes) {
+ case R_IMF_PLANES_BW:
+ cbuf = typecheck_compbuf(in[i]->data, CB_VAL);
+ break;
+ case R_IMF_PLANES_RGB:
+ cbuf = typecheck_compbuf(in[i]->data, CB_VEC3);
+ break;
+ case R_IMF_PLANES_RGBA:
+ cbuf = typecheck_compbuf(in[i]->data, CB_RGBA);
+ break;
+ }
+
+ ibuf = IMB_allocImBuf(cbuf->x, cbuf->y, format->planes, 0);
+ ibuf->rect_float = cbuf->rect;
+ ibuf->dither = rd->dither_intensity;
if (rd->color_mgt_flag & R_COLOR_MANAGEMENT)
ibuf->profile = IB_PROFILE_LINEAR_RGB;
/* get full path */
BLI_join_dirfile(path, FILE_MAX, nimf->base_path, sock->name);
+ BKE_makepicstring(filename, path, bmain->name, rd->cfra, format->imtype, (rd->scemode & R_EXTENSION), TRUE);
- BKE_makepicstring(string, path, bmain->name, rd->cfra, format->imtype, (rd->scemode & R_EXTENSION), TRUE);
-
- if(0 == BKE_write_ibuf(ibuf, string, format))
- printf("Cannot save Node File Output to %s\n", string);
+ if(0 == BKE_write_ibuf(ibuf, filename, format))
+ printf("Cannot save Node File Output to %s\n", filename);
else
- printf("Saved: %s\n", string);
+ printf("Saved: %s\n", filename);
- IMB_freeImBuf(ibuf);
+ IMB_freeImBuf(ibuf);
- #if 0 /* XXX not used yet */
- generate_preview(data, node, cbuf);
- #endif
+ /* simply pick the first valid input for preview */
+ if (!has_preview) {
+ generate_preview(rd, node, cbuf);
+ has_preview = 1;
+ }
if(in[i]->data != cbuf)
free_compbuf(cbuf);
@@ -253,16 +192,129 @@ static void exec_output_multi_file(void *data, bNode *node, bNodeStack **in, bNo
}
}
-void register_node_type_cmp_output_multi_file(bNodeTreeType *ttype)
+/* write input data into layers */
+static void exec_output_file_multilayer(RenderData *rd, bNode *node, bNodeStack **in)
+{
+ Main *bmain= G.main; /* TODO, have this passed along */
+ NodeImageMultiFile *nimf= node->storage;
+ void *exrhandle= IMB_exr_get_handle();
+ char filename[FILE_MAX];
+ bNodeSocket *sock;
+ int i;
+ /* Must have consistent pixel size for exr file, simply take the first valid input size. */
+ int rectx = -1;
+ int recty = -1;
+ int has_preview = 0;
+
+ BKE_makepicstring(filename, nimf->base_path, bmain->name, rd->cfra, R_IMF_IMTYPE_MULTILAYER, (rd->scemode & R_EXTENSION), TRUE);
+ BLI_make_existing_file(filename);
+
+ for (sock=node->inputs.first, i=0; sock; sock=sock->next, ++i) {
+ if (in[i]->data) {
+ CompBuf *cbuf = in[i]->data;
+ char layname[EXR_LAY_MAXNAME];
+ char channelname[EXR_PASS_MAXNAME];
+ char *channelname_ext;
+
+ if (cbuf->rect_procedural) {
+ printf("Error writing multilayer EXR: Procedural buffer not supported\n");
+ continue;
+ }
+ if (rectx < 0) {
+ rectx = cbuf->x;
+ recty = cbuf->y;
+ }
+ else if (cbuf->x != rectx || cbuf->y != recty) {
+ printf("Error: Multilayer EXR output node %s expects same resolution for all input buffers. Layer %s skipped.\n", node->name, sock->name);
+ continue;
+ }
+
+ BLI_strncpy(layname, sock->name, sizeof(layname));
+ BLI_strncpy(channelname, sock->name, sizeof(channelname)-2);
+ channelname_ext = channelname + strlen(channelname);
+
+ /* create channels */
+ switch (cbuf->type) {
+ case CB_VAL:
+ strcpy(channelname_ext, ".V");
+ IMB_exr_add_channel(exrhandle, layname, channelname, 1, rectx, cbuf->rect);
+ break;
+ case CB_VEC2:
+ strcpy(channelname_ext, ".X");
+ IMB_exr_add_channel(exrhandle, layname, channelname, 2, 2*rectx, cbuf->rect);
+ strcpy(channelname_ext, ".Y");
+ IMB_exr_add_channel(exrhandle, layname, channelname, 2, 2*rectx, cbuf->rect+1);
+ break;
+ case CB_VEC3:
+ strcpy(channelname_ext, ".X");
+ IMB_exr_add_channel(exrhandle, layname, channelname, 3, 3*rectx, cbuf->rect);
+ strcpy(channelname_ext, ".Y");
+ IMB_exr_add_channel(exrhandle, layname, channelname, 3, 3*rectx, cbuf->rect+1);
+ strcpy(channelname_ext, ".Z");
+ IMB_exr_add_channel(exrhandle, layname, channelname, 3, 3*rectx, cbuf->rect+2);
+ break;
+ case CB_RGBA:
+ strcpy(channelname_ext, ".R");
+ IMB_exr_add_channel(exrhandle, layname, channelname, 4, 4*rectx, cbuf->rect);
+ strcpy(channelname_ext, ".G");
+ IMB_exr_add_channel(exrhandle, layname, channelname, 4, 4*rectx, cbuf->rect+1);
+ strcpy(channelname_ext, ".B");
+ IMB_exr_add_channel(exrhandle, layname, channelname, 4, 4*rectx, cbuf->rect+2);
+ strcpy(channelname_ext, ".A");
+ IMB_exr_add_channel(exrhandle, layname, channelname, 4, 4*rectx, cbuf->rect+3);
+ break;
+ }
+
+ /* simply pick the first valid input for preview */
+ if (!has_preview) {
+ generate_preview(rd, node, cbuf);
+ has_preview = 1;
+ }
+ }
+ }
+
+ /* when the filename has no permissions, this can fail */
+ if(IMB_exr_begin_write(exrhandle, filename, rectx, recty, nimf->format.compress)) {
+ IMB_exr_write_channels(exrhandle);
+ }
+ else {
+ /* TODO, get the error from openexr's exception */
+ /* XXX nice way to do report? */
+ printf("Error Writing Render Result, see console\n");
+ }
+
+ IMB_exr_close(exrhandle);
+}
+
+static void exec_output_file(void *data, bNode *node, bNodeStack **in, bNodeStack **UNUSED(out))
+{
+ RenderData *rd= data;
+ NodeImageMultiFile *nimf= node->storage;
+
+ if (!G.rendering) {
+ /* only output files when rendering a sequence -
+ * otherwise, it overwrites the output files just
+ * scrubbing through the timeline when the compositor updates */
+ return;
+ }
+
+ if (nimf->format.imtype==R_IMF_IMTYPE_MULTILAYER)
+ exec_output_file_multilayer(rd, node, in);
+ else
+ exec_output_file_singlelayer(rd, node, in);
+}
+
+void register_node_type_cmp_output_file(bNodeTreeType *ttype)
{
static bNodeType ntype;
- node_type_base(ttype, &ntype, CMP_NODE_OUTPUT_MULTI_FILE, "Multi File Output", NODE_CLASS_OUTPUT, NODE_OPTIONS);
+ node_type_base(ttype, &ntype, CMP_NODE_OUTPUT_FILE, "File Output", NODE_CLASS_OUTPUT, NODE_OPTIONS|NODE_PREVIEW);
node_type_socket_templates(&ntype, NULL, NULL);
node_type_size(&ntype, 140, 80, 300);
- node_type_init(&ntype, init_output_multi_file);
- node_type_storage(&ntype, "NodeImageMultiFile", free_output_multi_file, copy_output_multi_file);
- node_type_exec(&ntype, exec_output_multi_file);
+ node_type_init(&ntype, init_output_file);
+ node_type_storage(&ntype, "NodeImageMultiFile", free_output_file, copy_output_file);
+ node_type_update(&ntype, update_output_file, NULL);
+ node_type_exec(&ntype, exec_output_file);
nodeRegisterType(ttype, &ntype);
}