diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 9b5595c1227..828a839f081 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -248,6 +248,12 @@ typedef struct bNodeType { char storagename[64]; /* struct name for DNA */ + /** Reads/writes `node->storage`. */ + void (*blend_write)(struct BlendWriter *writer, struct bNodeTree *ntree, struct bNode *node); + void (*blend_read_data)(struct BlendDataReader *reader, + struct bNodeTree *ntree, + struct bNode *node); + /* Draw the option buttons on the node */ void (*draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr); /* Additional parameters in the side panel */ diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 0387d27e60c..b826657d920 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -559,6 +559,97 @@ static void write_node_socket_interface(BlendWriter *writer, bNodeSocket *sock) write_node_socket_default_value(writer, sock); } +static void write_node_storage(BlendWriter *writer, bNodeTree *ntree, bNode *node) +{ + if (node->storage == nullptr) { + return; + } + + if (node->typeinfo->blend_write) { + node->typeinfo->blend_write(writer, ntree, node); + return; + } + + if (ELEM(ntree->type, NTREE_SHADER, NTREE_GEOMETRY) && + ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB, SH_NODE_CURVE_FLOAT)) + { + BKE_curvemapping_blend_write(writer, static_cast(node->storage)); + } + else if (ntree->type == NTREE_SHADER && (node->type == SH_NODE_SCRIPT)) { + NodeShaderScript *nss = static_cast(node->storage); + if (nss->bytecode) { + BLO_write_string(writer, nss->bytecode); + } + BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); + } + else if ((ntree->type == NTREE_COMPOSIT) && ELEM(node->type, + CMP_NODE_TIME, + CMP_NODE_CURVE_VEC, + CMP_NODE_CURVE_RGB, + CMP_NODE_HUECORRECT)) + { + BKE_curvemapping_blend_write(writer, static_cast(node->storage)); + } + else if ((ntree->type == NTREE_TEXTURE) && + ELEM(node->type, TEX_NODE_CURVE_RGB, TEX_NODE_CURVE_TIME)) + { + BKE_curvemapping_blend_write(writer, static_cast(node->storage)); + } + else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_MOVIEDISTORTION)) { + /* pass */ + } + else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_GLARE)) { + /* Simple forward compatibility for fix for #50736. + * Not ideal (there is no ideal solution here), but should do for now. */ + NodeGlare *ndg = static_cast(node->storage); + /* Not in undo case. */ + if (!BLO_write_is_undo(writer)) { + switch (ndg->type) { + case 2: /* Grrrr! magic numbers :( */ + ndg->angle = ndg->streaks; + break; + case 0: + ndg->angle = ndg->star_45; + break; + default: + break; + } + } + BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); + } + else if ((ntree->type == NTREE_COMPOSIT) && + ELEM(node->type, CMP_NODE_CRYPTOMATTE, CMP_NODE_CRYPTOMATTE_LEGACY)) + { + NodeCryptomatte *nc = static_cast(node->storage); + BLO_write_string(writer, nc->matte_id); + LISTBASE_FOREACH (CryptomatteEntry *, entry, &nc->entries) { + BLO_write_struct(writer, CryptomatteEntry, entry); + } + BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); + } + else if (node->typeinfo != &blender::bke::NodeTypeUndefined) { + BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); + } + + if (node->type == CMP_NODE_OUTPUT_FILE) { + /* Inputs have their own storage data. */ + NodeImageMultiFile *nimf = (NodeImageMultiFile *)node->storage; + BKE_image_format_blend_write(writer, &nimf->format); + + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { + NodeImageMultiFileSocket *sockdata = static_cast(sock->storage); + BLO_write_struct(writer, NodeImageMultiFileSocket, sockdata); + BKE_image_format_blend_write(writer, &sockdata->format); + } + } + if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS)) { + /* Write extra socket info. */ + LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { + BLO_write_struct(writer, NodeImageLayer, sock->storage); + } + } +} + void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) { BKE_id_blend_write(writer, &ntree->id); @@ -581,110 +672,7 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) write_node_socket(writer, sock); } - if (node->storage) { - if (ELEM(ntree->type, NTREE_SHADER, NTREE_GEOMETRY) && - ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB, SH_NODE_CURVE_FLOAT)) - { - BKE_curvemapping_blend_write(writer, static_cast(node->storage)); - } - else if (ntree->type == NTREE_SHADER && (node->type == SH_NODE_SCRIPT)) { - NodeShaderScript *nss = static_cast(node->storage); - if (nss->bytecode) { - BLO_write_string(writer, nss->bytecode); - } - BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); - } - else if ((ntree->type == NTREE_COMPOSIT) && ELEM(node->type, - CMP_NODE_TIME, - CMP_NODE_CURVE_VEC, - CMP_NODE_CURVE_RGB, - CMP_NODE_HUECORRECT)) - { - BKE_curvemapping_blend_write(writer, static_cast(node->storage)); - } - else if ((ntree->type == NTREE_TEXTURE) && - ELEM(node->type, TEX_NODE_CURVE_RGB, TEX_NODE_CURVE_TIME)) - { - BKE_curvemapping_blend_write(writer, static_cast(node->storage)); - } - else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_MOVIEDISTORTION)) { - /* pass */ - } - else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_GLARE)) { - /* Simple forward compatibility for fix for #50736. - * Not ideal (there is no ideal solution here), but should do for now. */ - NodeGlare *ndg = static_cast(node->storage); - /* Not in undo case. */ - if (!BLO_write_is_undo(writer)) { - switch (ndg->type) { - case 2: /* Grrrr! magic numbers :( */ - ndg->angle = ndg->streaks; - break; - case 0: - ndg->angle = ndg->star_45; - break; - default: - break; - } - } - BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); - } - else if ((ntree->type == NTREE_COMPOSIT) && - ELEM(node->type, CMP_NODE_CRYPTOMATTE, CMP_NODE_CRYPTOMATTE_LEGACY)) - { - NodeCryptomatte *nc = static_cast(node->storage); - BLO_write_string(writer, nc->matte_id); - LISTBASE_FOREACH (CryptomatteEntry *, entry, &nc->entries) { - BLO_write_struct(writer, CryptomatteEntry, entry); - } - BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); - } - else if (node->type == FN_NODE_INPUT_STRING) { - NodeInputString *storage = static_cast(node->storage); - if (storage->string) { - BLO_write_string(writer, storage->string); - } - BLO_write_struct_by_name(writer, node->typeinfo->storagename, storage); - } - else if (node->typeinfo != &blender::bke::NodeTypeUndefined) { - BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); - } - } - - if (node->type == CMP_NODE_OUTPUT_FILE) { - /* Inputs have their own storage data. */ - NodeImageMultiFile *nimf = (NodeImageMultiFile *)node->storage; - BKE_image_format_blend_write(writer, &nimf->format); - - LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { - NodeImageMultiFileSocket *sockdata = static_cast( - sock->storage); - BLO_write_struct(writer, NodeImageMultiFileSocket, sockdata); - BKE_image_format_blend_write(writer, &sockdata->format); - } - } - if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS)) { - /* Write extra socket info. */ - LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { - BLO_write_struct(writer, NodeImageLayer, sock->storage); - } - } - if (node->type == GEO_NODE_SIMULATION_OUTPUT) { - const NodeGeometrySimulationOutput &storage = - *static_cast(node->storage); - BLO_write_struct_array(writer, NodeSimulationItem, storage.items_num, storage.items); - for (const NodeSimulationItem &item : Span(storage.items, storage.items_num)) { - BLO_write_string(writer, item.name); - } - } - if (node->type == GEO_NODE_REPEAT_OUTPUT) { - const NodeGeometryRepeatOutput &storage = *static_cast( - node->storage); - BLO_write_struct_array(writer, NodeRepeatItem, storage.items_num, storage.items); - for (const NodeRepeatItem &item : Span(storage.items, storage.items_num)) { - BLO_write_string(writer, item.name); - } - } + write_node_storage(writer, ntree, node); } LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { @@ -739,6 +727,89 @@ static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock) sock->runtime = MEM_new(__func__); } +static void read_node_storage(BlendDataReader *reader, bNodeTree *ntree, bNode *node) +{ + if (node->type == CMP_NODE_MOVIEDISTORTION) { + /* Do nothing, this is runtime cache and hence handled by generic code using + * `IDTypeInfo.foreach_cache` callback. */ + return; + } + + BLO_read_data_address(reader, &node->storage); + + const bNodeType *node_type = nodeTypeFind(node->idname); + if (node_type && node_type->blend_read_data) { + node_type->blend_read_data(reader, ntree, node); + return; + } + + if (node->storage) { + switch (node->type) { + case SH_NODE_CURVE_VEC: + case SH_NODE_CURVE_RGB: + case SH_NODE_CURVE_FLOAT: + case CMP_NODE_TIME: + case CMP_NODE_CURVE_VEC: + case CMP_NODE_CURVE_RGB: + case CMP_NODE_HUECORRECT: + case TEX_NODE_CURVE_RGB: + case TEX_NODE_CURVE_TIME: { + BKE_curvemapping_blend_read(reader, static_cast(node->storage)); + break; + } + case SH_NODE_SCRIPT: { + NodeShaderScript *nss = static_cast(node->storage); + BLO_read_data_address(reader, &nss->bytecode); + break; + } + case SH_NODE_TEX_POINTDENSITY: { + NodeShaderTexPointDensity *npd = static_cast(node->storage); + npd->pd = blender::dna::shallow_zero_initialize(); + break; + } + case SH_NODE_TEX_IMAGE: { + NodeTexImage *tex = static_cast(node->storage); + tex->iuser.scene = nullptr; + break; + } + case SH_NODE_TEX_ENVIRONMENT: { + NodeTexEnvironment *tex = static_cast(node->storage); + tex->iuser.scene = nullptr; + break; + } + case CMP_NODE_IMAGE: + case CMP_NODE_R_LAYERS: + case CMP_NODE_VIEWER: + case CMP_NODE_SPLITVIEWER: { + ImageUser *iuser = static_cast(node->storage); + iuser->scene = nullptr; + break; + } + case CMP_NODE_CRYPTOMATTE_LEGACY: + case CMP_NODE_CRYPTOMATTE: { + NodeCryptomatte *nc = static_cast(node->storage); + BLO_read_data_address(reader, &nc->matte_id); + BLO_read_list(reader, &nc->entries); + BLI_listbase_clear(&nc->runtime.layers); + break; + } + case TEX_NODE_IMAGE: { + ImageUser *iuser = static_cast(node->storage); + iuser->scene = nullptr; + break; + } + case CMP_NODE_OUTPUT_FILE: { + NodeImageMultiFile *nimf = static_cast(node->storage); + BKE_image_format_blend_read_data(reader, &nimf->format); + break; + } + + default: + break; + } + } +} + void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree) { /* Special case for this pointer, do not rely on regular `lib_link` process here. Avoids needs @@ -799,102 +870,7 @@ void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree) BLO_read_data_address(reader, &node->prop); IDP_BlendDataRead(reader, &node->prop); - if (node->type == CMP_NODE_MOVIEDISTORTION) { - /* Do nothing, this is runtime cache and hence handled by generic code using - * `IDTypeInfo.foreach_cache` callback. */ - } - else { - BLO_read_data_address(reader, &node->storage); - } - - if (node->storage) { - switch (node->type) { - case SH_NODE_CURVE_VEC: - case SH_NODE_CURVE_RGB: - case SH_NODE_CURVE_FLOAT: - case CMP_NODE_TIME: - case CMP_NODE_CURVE_VEC: - case CMP_NODE_CURVE_RGB: - case CMP_NODE_HUECORRECT: - case TEX_NODE_CURVE_RGB: - case TEX_NODE_CURVE_TIME: { - BKE_curvemapping_blend_read(reader, static_cast(node->storage)); - break; - } - case SH_NODE_SCRIPT: { - NodeShaderScript *nss = static_cast(node->storage); - BLO_read_data_address(reader, &nss->bytecode); - break; - } - case SH_NODE_TEX_POINTDENSITY: { - NodeShaderTexPointDensity *npd = static_cast(node->storage); - npd->pd = blender::dna::shallow_zero_initialize(); - break; - } - case SH_NODE_TEX_IMAGE: { - NodeTexImage *tex = static_cast(node->storage); - tex->iuser.scene = nullptr; - break; - } - case SH_NODE_TEX_ENVIRONMENT: { - NodeTexEnvironment *tex = static_cast(node->storage); - tex->iuser.scene = nullptr; - break; - } - case CMP_NODE_IMAGE: - case CMP_NODE_R_LAYERS: - case CMP_NODE_VIEWER: - case CMP_NODE_SPLITVIEWER: { - ImageUser *iuser = static_cast(node->storage); - iuser->scene = nullptr; - break; - } - case CMP_NODE_CRYPTOMATTE_LEGACY: - case CMP_NODE_CRYPTOMATTE: { - NodeCryptomatte *nc = static_cast(node->storage); - BLO_read_data_address(reader, &nc->matte_id); - BLO_read_list(reader, &nc->entries); - BLI_listbase_clear(&nc->runtime.layers); - break; - } - case TEX_NODE_IMAGE: { - ImageUser *iuser = static_cast(node->storage); - iuser->scene = nullptr; - break; - } - case CMP_NODE_OUTPUT_FILE: { - NodeImageMultiFile *nimf = static_cast(node->storage); - BKE_image_format_blend_read_data(reader, &nimf->format); - break; - } - case FN_NODE_INPUT_STRING: { - NodeInputString *storage = static_cast(node->storage); - BLO_read_data_address(reader, &storage->string); - break; - } - case GEO_NODE_SIMULATION_OUTPUT: { - NodeGeometrySimulationOutput &storage = *static_cast( - node->storage); - BLO_read_data_address(reader, &storage.items); - for (const NodeSimulationItem &item : Span(storage.items, storage.items_num)) { - BLO_read_data_address(reader, &item.name); - } - break; - } - case GEO_NODE_REPEAT_OUTPUT: { - NodeGeometryRepeatOutput &storage = *static_cast( - node->storage); - BLO_read_data_address(reader, &storage.items); - for (const NodeRepeatItem &item : Span(storage.items, storage.items_num)) { - BLO_read_data_address(reader, &item.name); - } - break; - } - - default: - break; - } - } + read_node_storage(reader, ntree, node); } BLO_read_list(reader, &ntree->links); BLI_assert(ntree->all_nodes().size() == BLI_listbase_count(&ntree->nodes)); diff --git a/source/blender/nodes/function/CMakeLists.txt b/source/blender/nodes/function/CMakeLists.txt index ddf6ceae151..02ef152b871 100644 --- a/source/blender/nodes/function/CMakeLists.txt +++ b/source/blender/nodes/function/CMakeLists.txt @@ -6,6 +6,7 @@ set(INC . .. ../intern + ../../blenloader ../../blentranslation ../../editors/include ../../functions diff --git a/source/blender/nodes/function/nodes/node_fn_input_string.cc b/source/blender/nodes/function/nodes/node_fn_input_string.cc index ea13fdc01ab..24e9d41a089 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_string.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_string.cc @@ -7,8 +7,12 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "BLO_read_write.h" + namespace blender::nodes::node_fn_input_string_cc { +NODE_STORAGE_FUNCS(NodeInputString) + static void node_declare(NodeDeclarationBuilder &b) { b.is_function_node(); @@ -57,6 +61,19 @@ static void node_storage_copy(bNodeTree * /*dst_ntree*/, bNode *dest_node, const dest_node->storage = destination_storage; } +static void node_blend_write(BlendWriter *writer, bNodeTree * /*ntree*/, bNode *node) +{ + const NodeInputString &storage = node_storage(*node); + BLO_write_struct(writer, NodeInputString, &storage); + BLO_write_string(writer, storage.string); +} + +static void node_blend_read_data(BlendDataReader *reader, bNodeTree * /*ntree*/, bNode *node) +{ + NodeInputString &storage = node_storage(*node); + BLO_read_data_address(reader, &storage.string); +} + } // namespace blender::nodes::node_fn_input_string_cc void register_node_type_fn_input_string() @@ -72,5 +89,7 @@ void register_node_type_fn_input_string() &ntype, "NodeInputString", file_ns::node_storage_free, file_ns::node_storage_copy); ntype.build_multi_function = file_ns::node_build_multi_function; ntype.draw_buttons = file_ns::node_layout; + ntype.blend_write = file_ns::node_blend_write; + ntype.blend_read_data = file_ns::node_blend_read_data; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt index 0ddfa732cc0..703020e2741 100644 --- a/source/blender/nodes/geometry/CMakeLists.txt +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -7,6 +7,7 @@ set(INC .. ../intern ../../editors/include + ../../blenloader ../../blentranslation ../../bmesh ../../depsgraph diff --git a/source/blender/nodes/geometry/nodes/node_geo_repeat_output.cc b/source/blender/nodes/geometry/nodes/node_geo_repeat_output.cc index 0ef74d7e8fe..d468a3dc5ec 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_repeat_output.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_repeat_output.cc @@ -16,6 +16,8 @@ #include "BLI_string_utils.h" +#include "BLO_read_write.h" + #include "node_geometry_util.hh" namespace blender::nodes { @@ -193,6 +195,25 @@ static void node_copy_storage(bNodeTree * /*dst_tree*/, bNode *dst_node, const b dst_node->storage = dst_storage; } +static void node_blend_write(BlendWriter *writer, bNodeTree * /*ntree*/, bNode *node) +{ + const NodeGeometryRepeatOutput &storage = node_storage(*node); + BLO_write_struct(writer, NodeGeometryRepeatOutput, &storage); + BLO_write_struct_array(writer, NodeRepeatItem, storage.items_num, storage.items); + for (const NodeRepeatItem &item : Span(storage.items, storage.items_num)) { + BLO_write_string(writer, item.name); + } +} + +static void node_blend_read_data(BlendDataReader *reader, bNodeTree * /*ntree*/, bNode *node) +{ + NodeGeometryRepeatOutput &storage = node_storage(*node); + BLO_read_data_address(reader, &storage.items); + for (const NodeRepeatItem &item : Span(storage.items, storage.items_num)) { + BLO_read_data_address(reader, &item.name); + } +} + static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link) { NodeGeometryRepeatOutput &storage = node_storage(*node); @@ -329,6 +350,8 @@ void register_node_type_geo_repeat_output() ntype.declare_dynamic = file_ns::node_declare_dynamic; ntype.gather_add_node_search_ops = file_ns::search_node_add_ops; ntype.insert_link = file_ns::node_insert_link; + ntype.blend_write = file_ns::node_blend_write; + ntype.blend_read_data = file_ns::node_blend_read_data; node_type_storage( &ntype, "NodeGeometryRepeatOutput", file_ns::node_free_storage, file_ns::node_copy_storage); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_simulation_output.cc b/source/blender/nodes/geometry/nodes/node_geo_simulation_output.cc index 3b15f0271d5..fd3a61a9ec3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_simulation_output.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_simulation_output.cc @@ -27,6 +27,8 @@ #include "NOD_add_node_search.hh" +#include "BLO_read_write.h" + #include "node_geometry_util.hh" namespace blender::nodes { @@ -1029,6 +1031,25 @@ static void node_copy_storage(bNodeTree * /*dst_tree*/, bNode *dst_node, const b dst_node->storage = dst_storage; } +static void node_blend_write(BlendWriter *writer, bNodeTree * /*ntree*/, bNode *node) +{ + const NodeGeometrySimulationOutput &storage = node_storage(*node); + BLO_write_struct(writer, NodeGeometrySimulationOutput, &storage); + BLO_write_struct_array(writer, NodeSimulationItem, storage.items_num, storage.items); + for (const NodeSimulationItem &item : Span(storage.items, storage.items_num)) { + BLO_write_string(writer, item.name); + } +} + +static void node_blend_read_data(BlendDataReader *reader, bNodeTree * /*ntree*/, bNode *node) +{ + NodeGeometrySimulationOutput &storage = node_storage(*node); + BLO_read_data_address(reader, &storage.items); + for (const NodeSimulationItem &item : Span(storage.items, storage.items_num)) { + BLO_read_data_address(reader, &item.name); + } +} + static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link) { NodeGeometrySimulationOutput &storage = node_storage(*node); @@ -1079,6 +1100,8 @@ void register_node_type_geo_simulation_output() ntype.gather_add_node_search_ops = file_ns::search_node_add_ops; ntype.gather_link_search_ops = nullptr; ntype.insert_link = file_ns::node_insert_link; + ntype.blend_write = file_ns::node_blend_write; + ntype.blend_read_data = file_ns::node_blend_read_data; node_type_storage(&ntype, "NodeGeometrySimulationOutput", file_ns::node_free_storage,