Changeset View
Changeset View
Standalone View
Standalone View
source/blender/nodes/composite/nodes/node_composite_outputFile.cc
- This file was moved from source/blender/nodes/composite/nodes/node_composite_outputFile.c.
| Show All 17 Lines | |||||
| */ | */ | ||||
| /** \file | /** \file | ||||
| * \ingroup cmpnodes | * \ingroup cmpnodes | ||||
| */ | */ | ||||
| #include "BLI_string_utils.h" | #include "BLI_string_utils.h" | ||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include <string.h> | #include <cstring> | ||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| #include "node_composite_util.h" | #include "node_composite_util.hh" | ||||
| #include "intern/openexr/openexr_multi.h" | #include "intern/openexr/openexr_multi.h" | ||||
| /* **************** OUTPUT FILE ******************** */ | /* **************** OUTPUT FILE ******************** */ | ||||
| /* find unique path */ | /* find unique path */ | ||||
| static bool unique_path_unique_check(void *arg, const char *name) | static bool unique_path_unique_check(void *arg, const char *name) | ||||
| { | { | ||||
| struct { | struct Args { | ||||
| ListBase *lb; | ListBase *lb; | ||||
| bNodeSocket *sock; | bNodeSocket *sock; | ||||
| } *data = arg; | }; | ||||
| bNodeSocket *sock; | Args *data = (Args *)arg; | ||||
| for (sock = data->lb->first; sock; sock = sock->next) { | |||||
| LISTBASE_FOREACH (bNodeSocket *, sock, data->lb) { | |||||
| if (sock != data->sock) { | if (sock != data->sock) { | ||||
| NodeImageMultiFileSocket *sockdata = sock->storage; | NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)sock->storage; | ||||
| if (STREQ(sockdata->path, name)) { | if (STREQ(sockdata->path, name)) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void ntreeCompositOutputFileUniquePath(ListBase *list, | void ntreeCompositOutputFileUniquePath(ListBase *list, | ||||
| bNodeSocket *sock, | bNodeSocket *sock, | ||||
| const char defname[], | const char defname[], | ||||
| char delim) | char delim) | ||||
| { | { | ||||
| NodeImageMultiFileSocket *sockdata; | NodeImageMultiFileSocket *sockdata; | ||||
| struct { | struct { | ||||
| ListBase *lb; | ListBase *lb; | ||||
| bNodeSocket *sock; | bNodeSocket *sock; | ||||
| } data; | } data; | ||||
| data.lb = list; | data.lb = list; | ||||
| data.sock = sock; | data.sock = sock; | ||||
| /* See if we are given an empty string */ | /* See if we are given an empty string */ | ||||
| if (ELEM(NULL, sock, defname)) { | if (ELEM(nullptr, sock, defname)) { | ||||
| return; | return; | ||||
| } | } | ||||
| sockdata = sock->storage; | sockdata = (NodeImageMultiFileSocket *)sock->storage; | ||||
| BLI_uniquename_cb( | BLI_uniquename_cb( | ||||
| unique_path_unique_check, &data, defname, delim, sockdata->path, sizeof(sockdata->path)); | unique_path_unique_check, &data, defname, delim, sockdata->path, sizeof(sockdata->path)); | ||||
| } | } | ||||
| /* find unique EXR layer */ | /* find unique EXR layer */ | ||||
| static bool unique_layer_unique_check(void *arg, const char *name) | static bool unique_layer_unique_check(void *arg, const char *name) | ||||
| { | { | ||||
| struct { | struct Args { | ||||
| ListBase *lb; | ListBase *lb; | ||||
| bNodeSocket *sock; | bNodeSocket *sock; | ||||
| } *data = arg; | }; | ||||
| bNodeSocket *sock; | Args *data = (Args *)arg; | ||||
| for (sock = data->lb->first; sock; sock = sock->next) { | |||||
| LISTBASE_FOREACH (bNodeSocket *, sock, data->lb) { | |||||
| if (sock != data->sock) { | if (sock != data->sock) { | ||||
| NodeImageMultiFileSocket *sockdata = sock->storage; | NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)sock->storage; | ||||
| if (STREQ(sockdata->layer, name)) { | if (STREQ(sockdata->layer, name)) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void ntreeCompositOutputFileUniqueLayer(ListBase *list, | void ntreeCompositOutputFileUniqueLayer(ListBase *list, | ||||
| bNodeSocket *sock, | bNodeSocket *sock, | ||||
| const char defname[], | const char defname[], | ||||
| char delim) | char delim) | ||||
| { | { | ||||
| NodeImageMultiFileSocket *sockdata; | |||||
| struct { | struct { | ||||
| ListBase *lb; | ListBase *lb; | ||||
| bNodeSocket *sock; | bNodeSocket *sock; | ||||
| } data; | } data; | ||||
| data.lb = list; | data.lb = list; | ||||
| data.sock = sock; | data.sock = sock; | ||||
| /* See if we are given an empty string */ | /* See if we are given an empty string */ | ||||
| if (ELEM(NULL, sock, defname)) { | if (ELEM(nullptr, sock, defname)) { | ||||
| return; | return; | ||||
| } | } | ||||
| sockdata = sock->storage; | NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)sock->storage; | ||||
| BLI_uniquename_cb( | BLI_uniquename_cb( | ||||
| unique_layer_unique_check, &data, defname, delim, sockdata->layer, sizeof(sockdata->layer)); | unique_layer_unique_check, &data, defname, delim, sockdata->layer, sizeof(sockdata->layer)); | ||||
| } | } | ||||
| bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree, | bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree, | ||||
| bNode *node, | bNode *node, | ||||
| const char *name, | const char *name, | ||||
| ImageFormatData *im_format) | ImageFormatData *im_format) | ||||
| { | { | ||||
| NodeImageMultiFile *nimf = node->storage; | NodeImageMultiFile *nimf = (NodeImageMultiFile *)node->storage; | ||||
| bNodeSocket *sock = nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, NULL, name); | bNodeSocket *sock = nodeAddStaticSocket( | ||||
| ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, nullptr, name); | |||||
| /* create format data for the input socket */ | /* create format data for the input socket */ | ||||
| NodeImageMultiFileSocket *sockdata = MEM_callocN(sizeof(NodeImageMultiFileSocket), | NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)MEM_callocN( | ||||
| "socket image format"); | sizeof(NodeImageMultiFileSocket), "socket image format"); | ||||
| sock->storage = sockdata; | sock->storage = sockdata; | ||||
| BLI_strncpy_utf8(sockdata->path, name, sizeof(sockdata->path)); | BLI_strncpy_utf8(sockdata->path, name, sizeof(sockdata->path)); | ||||
| ntreeCompositOutputFileUniquePath(&node->inputs, sock, name, '_'); | ntreeCompositOutputFileUniquePath(&node->inputs, sock, name, '_'); | ||||
| BLI_strncpy_utf8(sockdata->layer, name, sizeof(sockdata->layer)); | BLI_strncpy_utf8(sockdata->layer, name, sizeof(sockdata->layer)); | ||||
| ntreeCompositOutputFileUniqueLayer(&node->inputs, sock, name, '_'); | ntreeCompositOutputFileUniqueLayer(&node->inputs, sock, name, '_'); | ||||
| if (im_format) { | if (im_format) { | ||||
| Show All 11 Lines | bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree, | ||||
| nimf->active_input = BLI_findindex(&node->inputs, sock); | nimf->active_input = BLI_findindex(&node->inputs, sock); | ||||
| return sock; | return sock; | ||||
| } | } | ||||
| int ntreeCompositOutputFileRemoveActiveSocket(bNodeTree *ntree, bNode *node) | int ntreeCompositOutputFileRemoveActiveSocket(bNodeTree *ntree, bNode *node) | ||||
| { | { | ||||
| NodeImageMultiFile *nimf = node->storage; | NodeImageMultiFile *nimf = (NodeImageMultiFile *)node->storage; | ||||
| bNodeSocket *sock = BLI_findlink(&node->inputs, nimf->active_input); | bNodeSocket *sock = (bNodeSocket *)BLI_findlink(&node->inputs, nimf->active_input); | ||||
| int totinputs = BLI_listbase_count(&node->inputs); | int totinputs = BLI_listbase_count(&node->inputs); | ||||
| if (!sock) { | if (!sock) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| if (nimf->active_input == totinputs - 1) { | if (nimf->active_input == totinputs - 1) { | ||||
| --nimf->active_input; | --nimf->active_input; | ||||
| } | } | ||||
| /* free format data */ | /* free format data */ | ||||
| MEM_freeN(sock->storage); | MEM_freeN(sock->storage); | ||||
| nodeRemoveSocket(ntree, node, sock); | nodeRemoveSocket(ntree, node, sock); | ||||
| return 1; | return 1; | ||||
| } | } | ||||
| void ntreeCompositOutputFileSetPath(bNode *node, bNodeSocket *sock, const char *name) | void ntreeCompositOutputFileSetPath(bNode *node, bNodeSocket *sock, const char *name) | ||||
| { | { | ||||
| NodeImageMultiFileSocket *sockdata = sock->storage; | NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)sock->storage; | ||||
| BLI_strncpy_utf8(sockdata->path, name, sizeof(sockdata->path)); | BLI_strncpy_utf8(sockdata->path, name, sizeof(sockdata->path)); | ||||
| ntreeCompositOutputFileUniquePath(&node->inputs, sock, name, '_'); | ntreeCompositOutputFileUniquePath(&node->inputs, sock, name, '_'); | ||||
| } | } | ||||
| void ntreeCompositOutputFileSetLayer(bNode *node, bNodeSocket *sock, const char *name) | void ntreeCompositOutputFileSetLayer(bNode *node, bNodeSocket *sock, const char *name) | ||||
| { | { | ||||
| NodeImageMultiFileSocket *sockdata = sock->storage; | NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)sock->storage; | ||||
| BLI_strncpy_utf8(sockdata->layer, name, sizeof(sockdata->layer)); | BLI_strncpy_utf8(sockdata->layer, name, sizeof(sockdata->layer)); | ||||
| ntreeCompositOutputFileUniqueLayer(&node->inputs, sock, name, '_'); | ntreeCompositOutputFileUniqueLayer(&node->inputs, sock, name, '_'); | ||||
| } | } | ||||
| /* XXX uses initfunc_api callback, regular initfunc does not support context yet */ | /* XXX uses initfunc_api callback, regular initfunc does not support context yet */ | ||||
| static void init_output_file(const bContext *C, PointerRNA *ptr) | static void init_output_file(const bContext *C, PointerRNA *ptr) | ||||
| { | { | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| bNodeTree *ntree = (bNodeTree *)ptr->owner_id; | bNodeTree *ntree = (bNodeTree *)ptr->owner_id; | ||||
| bNode *node = ptr->data; | bNode *node = (bNode *)ptr->data; | ||||
| NodeImageMultiFile *nimf = MEM_callocN(sizeof(NodeImageMultiFile), "node image multi file"); | NodeImageMultiFile *nimf = (NodeImageMultiFile *)MEM_callocN(sizeof(NodeImageMultiFile), | ||||
| ImageFormatData *format = NULL; | "node image multi file"); | ||||
| ImageFormatData *format = nullptr; | |||||
| node->storage = nimf; | node->storage = nimf; | ||||
| if (scene) { | if (scene) { | ||||
| RenderData *rd = &scene->r; | RenderData *rd = &scene->r; | ||||
| BLI_strncpy(nimf->base_path, rd->pic, sizeof(nimf->base_path)); | BLI_strncpy(nimf->base_path, rd->pic, sizeof(nimf->base_path)); | ||||
| nimf->format = rd->im_format; | nimf->format = rd->im_format; | ||||
| if (BKE_imtype_is_movie(nimf->format.imtype)) { | if (BKE_imtype_is_movie(nimf->format.imtype)) { | ||||
| nimf->format.imtype = R_IMF_IMTYPE_OPENEXR; | nimf->format.imtype = R_IMF_IMTYPE_OPENEXR; | ||||
| } | } | ||||
| format = &nimf->format; | format = &nimf->format; | ||||
| } | } | ||||
| else { | else { | ||||
| BKE_imformat_defaults(&nimf->format); | BKE_imformat_defaults(&nimf->format); | ||||
| } | } | ||||
| /* add one socket by default */ | /* add one socket by default */ | ||||
| ntreeCompositOutputFileAddSocket(ntree, node, "Image", format); | ntreeCompositOutputFileAddSocket(ntree, node, "Image", format); | ||||
| } | } | ||||
| static void free_output_file(bNode *node) | static void free_output_file(bNode *node) | ||||
| { | { | ||||
| bNodeSocket *sock; | |||||
| /* free storage data in sockets */ | /* free storage data in sockets */ | ||||
| for (sock = node->inputs.first; sock; sock = sock->next) { | LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { | ||||
| MEM_freeN(sock->storage); | MEM_freeN(sock->storage); | ||||
| } | } | ||||
| MEM_freeN(node->storage); | MEM_freeN(node->storage); | ||||
| } | } | ||||
| static void copy_output_file(bNodeTree *UNUSED(dest_ntree), | static void copy_output_file(bNodeTree *UNUSED(dest_ntree), | ||||
| bNode *dest_node, | bNode *dest_node, | ||||
| const bNode *src_node) | const bNode *src_node) | ||||
| { | { | ||||
| bNodeSocket *src_sock, *dest_sock; | bNodeSocket *src_sock, *dest_sock; | ||||
| dest_node->storage = MEM_dupallocN(src_node->storage); | dest_node->storage = MEM_dupallocN(src_node->storage); | ||||
| /* duplicate storage data in sockets */ | /* duplicate storage data in sockets */ | ||||
| for (src_sock = src_node->inputs.first, dest_sock = dest_node->inputs.first; | for (src_sock = (bNodeSocket *)src_node->inputs.first, | ||||
| dest_sock = (bNodeSocket *)dest_node->inputs.first; | |||||
| src_sock && dest_sock; | src_sock && dest_sock; | ||||
| src_sock = src_sock->next, dest_sock = dest_sock->next) { | src_sock = src_sock->next, dest_sock = (bNodeSocket *)dest_sock->next) { | ||||
| dest_sock->storage = MEM_dupallocN(src_sock->storage); | dest_sock->storage = MEM_dupallocN(src_sock->storage); | ||||
| } | } | ||||
| } | } | ||||
| static void update_output_file(bNodeTree *ntree, bNode *node) | static void update_output_file(bNodeTree *ntree, bNode *node) | ||||
| { | { | ||||
| bNodeSocket *sock, *sock_next; | |||||
| PointerRNA ptr; | PointerRNA ptr; | ||||
| /* XXX fix for T36706: remove invalid sockets added with bpy API. | /* XXX fix for T36706: remove invalid sockets added with bpy API. | ||||
| * This is not ideal, but prevents crashes from missing storage. | * This is not ideal, but prevents crashes from missing storage. | ||||
| * FileOutput node needs a redesign to support this properly. | * FileOutput node needs a redesign to support this properly. | ||||
| */ | */ | ||||
| for (sock = node->inputs.first; sock; sock = sock_next) { | LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { | ||||
| sock_next = sock->next; | if (sock->storage == nullptr) { | ||||
| if (sock->storage == NULL) { | |||||
| nodeRemoveSocket(ntree, node, sock); | nodeRemoveSocket(ntree, node, sock); | ||||
| } | } | ||||
| } | } | ||||
| for (sock = node->outputs.first; sock; sock = sock_next) { | LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { | ||||
| sock_next = sock->next; | |||||
| nodeRemoveSocket(ntree, node, sock); | nodeRemoveSocket(ntree, node, sock); | ||||
| } | } | ||||
| cmp_node_update_default(ntree, node); | cmp_node_update_default(ntree, node); | ||||
| /* automatically update the socket type based on linked input */ | /* automatically update the socket type based on linked input */ | ||||
| for (sock = node->inputs.first; sock; sock = sock->next) { | LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { | ||||
| if (sock->link) { | if (sock->link) { | ||||
| RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr); | RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr); | ||||
| RNA_enum_set(&ptr, "type", sock->link->fromsock->type); | RNA_enum_set(&ptr, "type", sock->link->fromsock->type); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void register_node_type_cmp_output_file(void) | void register_node_type_cmp_output_file(void) | ||||
| { | { | ||||
| static bNodeType ntype; | static bNodeType ntype; | ||||
| cmp_node_type_base(&ntype, CMP_NODE_OUTPUT_FILE, "File Output", NODE_CLASS_OUTPUT, NODE_PREVIEW); | cmp_node_type_base(&ntype, CMP_NODE_OUTPUT_FILE, "File Output", NODE_CLASS_OUTPUT, NODE_PREVIEW); | ||||
| node_type_socket_templates(&ntype, NULL, NULL); | node_type_socket_templates(&ntype, nullptr, nullptr); | ||||
| ntype.initfunc_api = init_output_file; | ntype.initfunc_api = init_output_file; | ||||
| node_type_storage(&ntype, "NodeImageMultiFile", free_output_file, copy_output_file); | node_type_storage(&ntype, "NodeImageMultiFile", free_output_file, copy_output_file); | ||||
| node_type_update(&ntype, update_output_file); | node_type_update(&ntype, update_output_file); | ||||
| nodeRegisterType(&ntype); | nodeRegisterType(&ntype); | ||||
| } | } | ||||