diff --git a/source/blender/blenkernel/BKE_node.hh b/source/blender/blenkernel/BKE_node.hh index 7b10e2bd561..296cdf8603f 100644 --- a/source/blender/blenkernel/BKE_node.hh +++ b/source/blender/blenkernel/BKE_node.hh @@ -421,6 +421,13 @@ struct bNodeType { /** True when the node still works but it's usage is discouraged. */ const char *deprecation_notice = nullptr; + /** + * In some nodes the set of sockets depends on other data like linked nodes. For example, the + * Separate Bundle node can adapt based on what the bundle contains that is linked to it. When + * this function returns true, a sync button should be shown for the node that updates the node. + */ + bool (*can_sync_sockets)(const bContext &C, const bNodeTree &tree, const bNode &node) = nullptr; + /* RNA integration */ ExtensionRNA rna_ext = {}; diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc index ab40a7fac4c..1962ccac652 100644 --- a/source/blender/blenkernel/intern/node_tree_update.cc +++ b/source/blender/blenkernel/intern/node_tree_update.cc @@ -22,6 +22,7 @@ #include "BKE_anim_data.hh" #include "BKE_image.hh" #include "BKE_lib_id.hh" +#include "BKE_library.hh" #include "BKE_main.hh" #include "BKE_node.hh" #include "BKE_node_enum.hh" @@ -291,6 +292,12 @@ struct NodeTreeRelations { BLI_assert(group_node_users_.has_value()); return group_node_users_->lookup(ntree); } + + Span get_all_trees() + { + this->ensure_all_trees(); + return *all_trees_; + } }; struct TreeUpdateResult { @@ -305,6 +312,7 @@ class NodeTreeMainUpdater { Map update_result_by_tree_; NodeTreeRelations relations_; bool needs_relations_update_ = false; + bool found_updated_sync_node_ = false; public: NodeTreeMainUpdater(Main *bmain, const NodeTreeUpdateExtraParams ¶ms) @@ -408,6 +416,13 @@ class NodeTreeMainUpdater { DEG_relations_tag_update(bmain_); } } + if (found_updated_sync_node_) { + for (bNodeTree *ntree : relations_.get_all_trees()) { + if (ID_IS_EDITABLE(&ntree->id)) { + this->tag_possibly_outdated_sync_nodes(*ntree); + } + } + } } private: @@ -509,6 +524,7 @@ class NodeTreeMainUpdater { this->update_internal_links(ntree); this->update_generic_callback(ntree); this->remove_unused_previews_when_necessary(ntree); + this->check_for_updated_sync_nodes(ntree); this->make_node_previews_dirty(ntree); this->propagate_runtime_flags(ntree); @@ -800,6 +816,50 @@ class NodeTreeMainUpdater { ntree.typeinfo->update(&ntree); } + /** + * Checks if any node has been updated that may be synced with other nodes. + */ + void check_for_updated_sync_nodes(const bNodeTree &ntree) + { + if (found_updated_sync_node_) { + return; + } + ntree.ensure_topology_cache(); + for (const StringRefNull idname : {"GeometryNodeClosureInput", + "GeometryNodeClosureOutput", + "GeometryNodeEvaluateClosure", + "GeometryNodeCombineBundle", + "GeometryNodeSeparateBundle"}) + { + for (const bNode *node : ntree.nodes_by_type(idname)) { + if (node->runtime->changed_flag & NTREE_CHANGED_NODE_PROPERTY) { + found_updated_sync_node_ = true; + break; + } + } + } + } + + void tag_possibly_outdated_sync_nodes(bNodeTree &ntree) + { + for (bNode *node : ntree.nodes_by_type("GeometryNodeClosureOutput")) { + auto &storage = *static_cast(node->storage); + storage.flag |= NODE_GEO_CLOSURE_FLAG_MAY_NEED_SYNC; + } + for (bNode *node : ntree.nodes_by_type("GeometryNodeEvaluateClosure")) { + auto &storage = *static_cast(node->storage); + storage.flag |= NODE_GEO_EVALUATE_CLOSURE_FLAG_MAY_NEED_SYNC; + } + for (bNode *node : ntree.nodes_by_type("GeometryNodeCombineBundle")) { + auto &storage = *static_cast(node->storage); + storage.flag |= NODE_GEO_COMBINE_BUNDLE_FLAG_MAY_NEED_SYNC; + } + for (bNode *node : ntree.nodes_by_type("GeometryNodeSeparateBundle")) { + auto &storage = *static_cast(node->storage); + storage.flag |= NODE_GEO_SEPARATE_BUNDLE_FLAG_MAY_NEED_SYNC; + } + } + void remove_unused_previews_when_necessary(bNodeTree &ntree) { /* Don't trigger preview removal when only those flags are set. */ diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index 964b84fff84..1354bcf0085 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -9,6 +9,7 @@ #include +#include "BKE_idprop.hh" #include "MEM_guardedalloc.h" #include "DNA_light_types.h" @@ -2504,18 +2505,20 @@ static void node_draw_extra_info_row(const bNode &node, 0, 0, extra_info_row.tooltip); + if (extra_info_row.set_execute_fn) { + extra_info_row.set_execute_fn(*but_icon); + } if (extra_info_row.tooltip_fn != nullptr) { UI_but_func_tooltip_set( but_icon, extra_info_row.tooltip_fn, tooltip_arg, extra_info_row.tooltip_fn_free_arg); } - UI_block_emboss_set(&block, ui::EmbossType::Emboss); const float but_text_left = but_icon_right + 6.0f * UI_SCALE_FAC; const float but_text_right = rect.xmax; const float but_text_width = but_text_right - but_text_left; uiBut *but_text = uiDefBut(&block, - ButType::Label, + extra_info_row.set_execute_fn ? ButType::But : ButType::Label, 0, extra_info_row.text.c_str(), int(but_text_left), @@ -2526,7 +2529,10 @@ static void node_draw_extra_info_row(const bNode &node, 0, 0, extra_info_row.tooltip); - + UI_but_drawflag_enable(but_text, UI_BUT_TEXT_LEFT); + if (extra_info_row.set_execute_fn) { + extra_info_row.set_execute_fn(*but_text); + } if (extra_info_row.tooltip_fn != nullptr) { /* Don't pass tooltip free function because it's already used on the uiBut above. */ UI_but_func_tooltip_set(but_text, extra_info_row.tooltip_fn, tooltip_arg, nullptr); @@ -2536,6 +2542,8 @@ static void node_draw_extra_info_row(const bNode &node, UI_but_flag_enable(but_text, UI_BUT_INACTIVE); UI_but_flag_enable(but_icon, UI_BUT_INACTIVE); } + + UI_block_emboss_set(&block, ui::EmbossType::Emboss); } static void node_draw_extra_info_panel_back(const bNode &node, const rctf &extra_info_rect) @@ -2857,6 +2865,31 @@ static void node_draw_basis(const bContext &C, } UI_block_emboss_set(&block, ui::EmbossType::Emboss); } + + if (node.typeinfo->can_sync_sockets && node.typeinfo->can_sync_sockets(C, ntree, node)) { + iconofs -= iconbutw; + UI_block_emboss_set(&block, ui::EmbossType::None); + uiBut *but = uiDefIconBut(&block, + ButType::ButToggle, + 0, + ICON_FILE_REFRESH, + iconofs, + rct.ymax - NODE_DY, + iconbutw, + UI_UNIT_Y, + nullptr, + 0, + 0, + ""); + + wmOperatorType *ot = WM_operatortype_find("NODE_OT_sockets_sync", false); + UI_but_operator_set(but, ot, wm::OpCallContext::InvokeDefault); + PointerRNA *opptr = UI_but_operator_ptr_ensure(but); + opptr->data = bke::idprop::create_group("wmOperatorProperties").release(); + RNA_string_set(opptr, "node_name", node.name); + UI_block_emboss_set(&block, ui::EmbossType::Emboss); + } + /* Preview. */ if (node_is_previewable(snode, ntree, node)) { const bool is_active = node.flag & NODE_PREVIEW; diff --git a/source/blender/editors/space_node/node_sync_sockets.cc b/source/blender/editors/space_node/node_sync_sockets.cc index 8a28bdb1f75..d36cd34bdb4 100644 --- a/source/blender/editors/space_node/node_sync_sockets.cc +++ b/source/blender/editors/space_node/node_sync_sockets.cc @@ -2,6 +2,8 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ +#include + #include "DNA_node_types.h" #include "DNA_space_types.h" #include "DNA_windowmanager_enums.h" @@ -24,6 +26,8 @@ #include "BLI_listbase.h" +#include "BLT_translation.hh" + #include "NOD_geo_bundle.hh" #include "NOD_geo_closure.hh" #include "NOD_socket_items.hh" @@ -392,6 +396,37 @@ void sync_sockets_closure(SpaceNode &snode, } } +static Vector get_nodes_to_sync(bContext &C, PointerRNA *ptr) +{ + SpaceNode &snode = *CTX_wm_space_node(&C); + if (!snode.edittree) { + return {}; + } + + std::optional node_name; + PropertyRNA *node_name_prop = RNA_struct_find_property(ptr, "node_name"); + if (RNA_property_is_set(ptr, node_name_prop)) { + node_name = RNA_property_string_get(ptr, node_name_prop); + } + + Vector nodes_to_sync; + bNodeTree &tree = *snode.edittree; + for (bNode *node : tree.all_nodes()) { + if (node_name.has_value()) { + if (node->name != node_name) { + continue; + } + } + else { + if (!(node->flag & NODE_SELECT)) { + continue; + } + } + nodes_to_sync.append(node); + } + return nodes_to_sync; +} + static wmOperatorStatus sockets_sync_exec(bContext *C, wmOperator *op) { Main &bmain = *CTX_data_main(C); @@ -400,14 +435,16 @@ static wmOperatorStatus sockets_sync_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + Vector nodes_to_sync = get_nodes_to_sync(*C, op->ptr); + if (nodes_to_sync.is_empty()) { + return OPERATOR_CANCELLED; + } + bNodeTree &tree = *snode.edittree; const bke::bNodeZoneType &closure_zone_type = *bke::zone_type_by_node_type( GEO_NODE_CLOSURE_OUTPUT); - for (bNode *node : tree.all_nodes()) { - if (!(node->flag & NODE_SELECT)) { - continue; - } + for (bNode *node : nodes_to_sync) { if (node->is_type("GeometryNodeEvaluateClosure")) { sync_sockets_evaluate_closure(snode, *node, op->reports); } @@ -438,16 +475,182 @@ static wmOperatorStatus sockets_sync_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static std::string get_bundle_sync_tooltip(const nodes::BundleSignature &old_signature, + const nodes::BundleSignature &new_signature) +{ + Vector added_items; + Vector removed_items; + Vector changed_items; + + for (const nodes::BundleSignature::Item &new_item : new_signature.items) { + if (const nodes::BundleSignature::Item *old_item = old_signature.items.lookup_key_ptr_as( + new_item.key)) + { + if (new_item.type->type != old_item->type->type) { + changed_items.append(new_item.key); + } + } + else { + added_items.append(new_item.key); + } + } + for (const nodes::BundleSignature ::Item &old_item : old_signature.items) { + if (!new_signature.items.contains_as(old_item.key)) { + removed_items.append(old_item.key); + } + } + + fmt::memory_buffer string_buffer; + auto buf = fmt::appender(string_buffer); + if (!added_items.is_empty()) { + fmt::format_to(buf, "{}: {}\n", TIP_("Add"), fmt::join(added_items, ", ")); + } + if (!removed_items.is_empty()) { + fmt::format_to(buf, "{}: {}\n", TIP_("Remove"), fmt::join(removed_items, ", ")); + } + if (!changed_items.is_empty()) { + fmt::format_to(buf, "{}: {}\n", TIP_("Change"), fmt::join(changed_items, ", ")); + } + fmt::format_to(buf, TIP_("\nUpdate based on linked bundle signature")); + + return fmt::to_string(string_buffer); +} + +static std::string get_closure_sync_tooltip(const nodes::ClosureSignature &old_signature, + const nodes::ClosureSignature &new_signature) +{ + Vector added_inputs; + Vector removed_inputs; + Vector changed_inputs; + + Vector added_outputs; + Vector removed_outputs; + Vector changed_outputs; + + for (const nodes::ClosureSignature::Item &new_item : new_signature.inputs) { + if (const nodes::ClosureSignature::Item *old_item = old_signature.inputs.lookup_key_ptr_as( + new_item.key)) + { + if (new_item.type->type != old_item->type->type) { + changed_inputs.append(new_item.key); + } + } + else { + added_inputs.append(new_item.key); + } + } + for (const nodes::ClosureSignature::Item &old_item : old_signature.inputs) { + if (!new_signature.inputs.contains_as(old_item.key)) { + removed_inputs.append(old_item.key); + } + } + for (const nodes::ClosureSignature::Item &new_item : new_signature.outputs) { + if (const nodes::ClosureSignature::Item *old_item = old_signature.outputs.lookup_key_ptr_as( + new_item.key)) + { + if (new_item.type->type != old_item->type->type) { + changed_outputs.append(new_item.key); + } + } + else { + added_outputs.append(new_item.key); + } + } + for (const nodes::ClosureSignature::Item &old_item : old_signature.outputs) { + if (!new_signature.outputs.contains_as(old_item.key)) { + removed_outputs.append(old_item.key); + } + } + + fmt::memory_buffer string_buffer; + auto buf = fmt::appender(string_buffer); + if (!added_inputs.is_empty()) { + fmt::format_to(buf, "{}: {}\n", TIP_("Add Inputs"), fmt::join(added_inputs, ", ")); + } + if (!removed_inputs.is_empty()) { + fmt::format_to(buf, "{}: {}\n", TIP_("Remove Inputs"), fmt::join(removed_inputs, ", ")); + } + if (!changed_inputs.is_empty()) { + fmt::format_to(buf, "{}: {}\n", TIP_("Change Inputs"), fmt::join(changed_inputs, ", ")); + } + if (!added_outputs.is_empty()) { + fmt::format_to(buf, "{}: {}\n", TIP_("Add Outputs"), fmt::join(added_outputs, ", ")); + } + if (!removed_outputs.is_empty()) { + fmt::format_to(buf, "{}: {}\n", TIP_("Remove Outputs"), fmt::join(removed_outputs, ", ")); + } + if (!changed_outputs.is_empty()) { + fmt::format_to(buf, "{}: {}\n", TIP_("Change Outputs"), fmt::join(changed_outputs, ", ")); + } + fmt::format_to(buf, TIP_("\nUpdate based on linked closure signature")); + + return fmt::to_string(string_buffer); +} + +static std::string sockets_sync_get_description(bContext *C, wmOperatorType *ot, PointerRNA *ptr) +{ + const SpaceNode &snode = *CTX_wm_space_node(C); + Vector nodes_to_sync = get_nodes_to_sync(*C, ptr); + if (nodes_to_sync.size() != 1) { + return ot->description; + } + const bNode &node = *nodes_to_sync.first(); + + if (node.is_type("GeometryNodeSeparateBundle")) { + const nodes::BundleSignature old_signature = nodes::BundleSignature::from_separate_bundle_node( + node); + if (const std::optional new_signature = + get_sync_state_separate_bundle(snode, node).source_signature) + { + return get_bundle_sync_tooltip(old_signature, *new_signature); + } + } + else if (node.is_type("GeometryNodeCombineBundle")) { + const nodes::BundleSignature old_signature = nodes::BundleSignature::from_combine_bundle_node( + node); + if (const std::optional new_signature = + get_sync_state_combine_bundle(snode, node).source_signature) + { + return get_bundle_sync_tooltip(old_signature, *new_signature); + } + } + else if (node.is_type("GeometryNodeEvaluateClosure")) { + const nodes::ClosureSignature old_signature = + nodes::ClosureSignature::from_evaluate_closure_node(node); + if (const std::optional new_signature = + get_sync_state_evaluate_closure(snode, node).source_signature) + { + return get_closure_sync_tooltip(old_signature, *new_signature); + } + } + else if (node.is_type("GeometryNodeClosureOutput")) { + const nodes::ClosureSignature old_signature = + nodes::ClosureSignature::from_closure_output_node(node); + if (const std::optional new_signature = + get_sync_state_closure_output(snode, node).source_signature) + { + return get_closure_sync_tooltip(old_signature, *new_signature); + } + } + + return ot->description; +} + void NODE_OT_sockets_sync(wmOperatorType *ot) { ot->name = "Sync Sockets"; ot->idname = "NODE_OT_sockets_sync"; ot->description = "Update sockets to match what is actually used"; + ot->get_description = sockets_sync_get_description; ot->poll = ED_operator_node_editable; ot->exec = sockets_sync_exec; ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + PropertyRNA *prop; + prop = RNA_def_string(ot->srna, "node_name", nullptr, 0, "Node Name", nullptr); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } } // namespace blender::ed::space_node diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index f43652a569a..8cb955828d6 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -2225,9 +2225,16 @@ typedef struct NodeGeometryClosureOutputItems { char _pad[4]; } NodeGeometryClosureOutputItems; +typedef enum NodeGeometryClosureFlag { + NODE_GEO_CLOSURE_FLAG_MAY_NEED_SYNC = 1 << 0, +} NodeGeometryClosureFlag; + typedef struct NodeGeometryClosureOutput { NodeGeometryClosureInputItems input_items; NodeGeometryClosureOutputItems output_items; + /** #NodeGeometryClosureFlag */ + uint32_t flag; + char _pad[4]; } NodeGeometryClosureOutput; typedef struct NodeGeometryEvaluateClosureInputItem { @@ -2266,9 +2273,16 @@ typedef struct NodeGeometryEvaluateClosureOutputItems { char _pad[4]; } NodeGeometryEvaluateClosureOutputItems; +typedef enum NodeGeometryEvaluateClosureFlag { + NODE_GEO_EVALUATE_CLOSURE_FLAG_MAY_NEED_SYNC = 1 << 0, +} NodeGeometryEvaluateClosureFlag; + typedef struct NodeGeometryEvaluateClosure { NodeGeometryEvaluateClosureInputItems input_items; NodeGeometryEvaluateClosureOutputItems output_items; + /** #NodeGeometryEvaluateClosureFlag */ + uint32_t flag; + char _pad[4]; } NodeGeometryEvaluateClosure; typedef struct IndexSwitchItem { @@ -2392,12 +2406,17 @@ typedef struct NodeGeometryCombineBundleItem { char _pad[2]; } NodeGeometryCombineBundleItem; +typedef enum NodeGeometryCombineBundleFlag { + NODE_GEO_COMBINE_BUNDLE_FLAG_MAY_NEED_SYNC = 1 << 0, +} NodeGeometryCombineBundleFlag; + typedef struct NodeGeometryCombineBundle { NodeGeometryCombineBundleItem *items; int items_num; int next_identifier; int active_index; - char _pad[4]; + /** #NodeGeometryCombineBundleFlag */ + uint32_t flag; } NodeGeometryCombineBundle; typedef struct NodeGeometrySeparateBundleItem { @@ -2407,12 +2426,17 @@ typedef struct NodeGeometrySeparateBundleItem { char _pad[2]; } NodeGeometrySeparateBundleItem; +typedef enum NodeGeometrySeparateBundleFlag { + NODE_GEO_SEPARATE_BUNDLE_FLAG_MAY_NEED_SYNC = 1 << 0, +} NodeGeometrySeparateBundleFlag; + typedef struct NodeGeometrySeparateBundle { NodeGeometrySeparateBundleItem *items; int items_num; int next_identifier; int active_index; - char _pad[4]; + /** #NodeGeometrySeparateBundleFlag */ + uint32_t flag; } NodeGeometrySeparateBundle; typedef struct NodeFunctionFormatStringItem { diff --git a/source/blender/nodes/NOD_geometry_nodes_bundle_signature.hh b/source/blender/nodes/NOD_geometry_nodes_bundle_signature.hh index b13bd00c60c..e60d3f8f63a 100644 --- a/source/blender/nodes/NOD_geometry_nodes_bundle_signature.hh +++ b/source/blender/nodes/NOD_geometry_nodes_bundle_signature.hh @@ -4,17 +4,34 @@ #pragma once +#include "BLI_vector_set.hh" + #include "BKE_node.hh" namespace blender::nodes { struct BundleSignature { + struct Item { std::string key; const bke::bNodeSocketType *type = nullptr; + + uint64_t hash() const + { + return get_default_hash(this->key); + } + + BLI_STRUCT_EQUALITY_OPERATORS_1(Item, key) }; - Vector items; + struct ItemKeyGetter { + std::string operator()(const Item &item) + { + return item.key; + } + }; + + CustomIDVectorSet items; bool matches_exactly(const BundleSignature &other) const; diff --git a/source/blender/nodes/NOD_geometry_nodes_closure_signature.hh b/source/blender/nodes/NOD_geometry_nodes_closure_signature.hh index df098db363d..902f1695705 100644 --- a/source/blender/nodes/NOD_geometry_nodes_closure_signature.hh +++ b/source/blender/nodes/NOD_geometry_nodes_closure_signature.hh @@ -6,6 +6,8 @@ #include "BKE_node.hh" +#include "BLI_vector_set.hh" + namespace blender::nodes { /** Describes the names and types of the inputs and outputs of a closure. */ @@ -17,8 +19,15 @@ class ClosureSignature { std::optional structure_type = std::nullopt; }; - Vector inputs; - Vector outputs; + struct ItemKeyGetter { + std::string operator()(const Item &item) + { + return item.key; + } + }; + + CustomIDVectorSet inputs; + CustomIDVectorSet outputs; std::optional find_input_index(StringRef key) const; std::optional find_output_index(StringRef key) const; diff --git a/source/blender/nodes/NOD_node_extra_info.hh b/source/blender/nodes/NOD_node_extra_info.hh index afec135775b..9c3b3487126 100644 --- a/source/blender/nodes/NOD_node_extra_info.hh +++ b/source/blender/nodes/NOD_node_extra_info.hh @@ -19,6 +19,8 @@ struct NodeExtraInfoRow { void *tooltip_fn_arg = nullptr; void (*tooltip_fn_free_arg)(void *) = nullptr; void *(*tooltip_fn_copy_arg)(void *) = nullptr; + + std::function set_execute_fn; }; struct NodeExtraInfoParams { diff --git a/source/blender/nodes/geometry/nodes/node_geo_closure.cc b/source/blender/nodes/geometry/nodes/node_geo_closure.cc index c4dac338a4e..98079827fa6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_closure.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_closure.cc @@ -6,6 +6,8 @@ #include "BLI_string_utf8.h" +#include "BKE_idprop.hh" + #include "NOD_geo_closure.hh" #include "NOD_socket_items_blend.hh" #include "NOD_socket_items_ops.hh" @@ -225,6 +227,37 @@ static void node_blend_read(bNodeTree & /*tree*/, bNode &node, BlendDataReader & socket_items::blend_read_data(&reader, node); } +static bool node_can_sync_sockets(const bContext &C, + const bNodeTree & /*ntree*/, + const bNode &node) +{ + const SpaceNode *snode = CTX_wm_space_node(&C); + if (!snode) { + return false; + } + const NodeGeometryClosureOutput &storage = node_storage(node); + if (!(storage.flag & NODE_GEO_CLOSURE_FLAG_MAY_NEED_SYNC)) { + return false; + } + const ed::space_node::NodeSyncState state = ed::space_node::sync_sockets_state_closure_output( + *snode, node); + switch (state) { + case ed::space_node::NodeSyncState::NoSyncSource: + case ed::space_node::NodeSyncState::Synced: { + const_cast(storage).flag &= + ~NODE_GEO_CLOSURE_FLAG_MAY_NEED_SYNC; + break; + } + case ed::space_node::NodeSyncState::CanBeSynced: { + return true; + } + case ed::space_node::NodeSyncState::ConflictingSyncSources: { + break; + } + } + return false; +} + static void node_register() { static blender::bke::bNodeType ntype; @@ -239,6 +272,7 @@ static void node_register() ntype.gather_link_search_ops = node_gather_link_searches; ntype.insert_link = node_insert_link; ntype.draw_buttons_ex = node_layout_ex; + ntype.can_sync_sockets = node_can_sync_sockets; ntype.blend_write_storage_content = node_blend_write; ntype.blend_data_read_storage_content = node_blend_read; bke::node_type_storage(ntype, "NodeGeometryClosureOutput", node_free_storage, node_copy_storage); diff --git a/source/blender/nodes/geometry/nodes/node_geo_combine_bundle.cc b/source/blender/nodes/geometry/nodes/node_geo_combine_bundle.cc index 74d86331603..f5c645d759e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_combine_bundle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_combine_bundle.cc @@ -10,6 +10,8 @@ #include "NOD_socket_items_ui.hh" #include "NOD_socket_search_link.hh" +#include "BKE_idprop.hh" + #include "BLO_read_write.hh" #include "NOD_geometry_nodes_bundle.hh" @@ -151,6 +153,37 @@ static void node_blend_read(bNodeTree & /*tree*/, bNode &node, BlendDataReader & socket_items::blend_read_data(&reader, node); } +static bool node_can_sync_sockets(const bContext &C, + const bNodeTree & /*ntree*/, + const bNode &node) +{ + const SpaceNode *snode = CTX_wm_space_node(&C); + if (!snode) { + return false; + } + const NodeGeometryCombineBundle &storage = node_storage(node); + if (!(storage.flag & NODE_GEO_COMBINE_BUNDLE_FLAG_MAY_NEED_SYNC)) { + return false; + } + const ed::space_node::NodeSyncState state = ed::space_node::sync_sockets_state_combine_bundle( + *snode, node); + switch (state) { + case ed::space_node::NodeSyncState::NoSyncSource: + case ed::space_node::NodeSyncState::Synced: { + const_cast(storage).flag &= + ~NODE_GEO_COMBINE_BUNDLE_FLAG_MAY_NEED_SYNC; + break; + } + case ed::space_node::NodeSyncState::CanBeSynced: { + return true; + } + case ed::space_node::NodeSyncState::ConflictingSyncSources: { + break; + } + } + return false; +} + static void node_register() { static blender::bke::bNodeType ntype; @@ -168,6 +201,7 @@ static void node_register() ntype.register_operators = node_operators; ntype.blend_write_storage_content = node_blend_write; ntype.blend_data_read_storage_content = node_blend_read; + ntype.can_sync_sockets = node_can_sync_sockets; bke::node_type_storage(ntype, "NodeGeometryCombineBundle", node_free_storage, node_copy_storage); blender::bke::node_register_type(ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_evaluate_closure.cc b/source/blender/nodes/geometry/nodes/node_geo_evaluate_closure.cc index 986f9d2e985..ba144a807c5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_evaluate_closure.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_evaluate_closure.cc @@ -11,6 +11,8 @@ #include "NOD_socket_items_ui.hh" #include "NOD_socket_search_link.hh" +#include "BKE_idprop.hh" + #include "BLO_read_write.hh" #include "node_geometry_util.hh" @@ -155,6 +157,37 @@ static void node_blend_read(bNodeTree & /*tree*/, bNode &node, BlendDataReader & socket_items::blend_read_data(&reader, node); } +static bool node_can_sync_sockets(const bContext &C, + const bNodeTree & /*ntree*/, + const bNode &node) +{ + const SpaceNode *snode = CTX_wm_space_node(&C); + if (!snode) { + return false; + } + const NodeGeometryEvaluateClosure &storage = node_storage(node); + if (!(storage.flag & NODE_GEO_EVALUATE_CLOSURE_FLAG_MAY_NEED_SYNC)) { + return false; + } + const ed::space_node::NodeSyncState state = ed::space_node::sync_sockets_state_evaluate_closure( + *snode, node); + switch (state) { + case ed::space_node::NodeSyncState::NoSyncSource: + case ed::space_node::NodeSyncState::Synced: { + const_cast(storage).flag &= + ~NODE_GEO_EVALUATE_CLOSURE_FLAG_MAY_NEED_SYNC; + break; + } + case ed::space_node::NodeSyncState::CanBeSynced: { + return true; + } + case ed::space_node::NodeSyncState::ConflictingSyncSources: { + break; + } + } + return false; +} + static void node_register() { static blender::bke::bNodeType ntype; @@ -171,6 +204,7 @@ static void node_register() ntype.register_operators = node_operators; ntype.blend_write_storage_content = node_blend_write; ntype.blend_data_read_storage_content = node_blend_read; + ntype.can_sync_sockets = node_can_sync_sockets; bke::node_type_storage( ntype, "NodeGeometryEvaluateClosure", node_free_storage, node_copy_storage); blender::bke::node_register_type(ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_bundle.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_bundle.cc index a7ba9e482f3..8b99cc06f23 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_separate_bundle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_separate_bundle.cc @@ -12,6 +12,8 @@ #include "NOD_socket_items_ui.hh" #include "NOD_socket_search_link.hh" +#include "BKE_idprop.hh" + #include "BLO_read_write.hh" #include "NOD_geometry_nodes_bundle.hh" @@ -198,6 +200,37 @@ static void node_blend_read(bNodeTree & /*tree*/, bNode &node, BlendDataReader & socket_items::blend_read_data(&reader, node); } +static bool node_can_sync_sockets(const bContext &C, + const bNodeTree & /*ntree*/, + const bNode &node) +{ + const SpaceNode *snode = CTX_wm_space_node(&C); + if (!snode) { + return false; + } + const NodeGeometrySeparateBundle &storage = node_storage(node); + if (!(storage.flag & NODE_GEO_SEPARATE_BUNDLE_FLAG_MAY_NEED_SYNC)) { + return false; + } + const ed::space_node::NodeSyncState state = ed::space_node::sync_sockets_state_separate_bundle( + *snode, node); + switch (state) { + case ed::space_node::NodeSyncState::NoSyncSource: + case ed::space_node::NodeSyncState::Synced: { + const_cast(storage).flag &= + ~NODE_GEO_SEPARATE_BUNDLE_FLAG_MAY_NEED_SYNC; + break; + } + case ed::space_node::NodeSyncState::CanBeSynced: { + return true; + } + case ed::space_node::NodeSyncState::ConflictingSyncSources: { + break; + } + } + return false; +} + static void node_register() { static blender::bke::bNodeType ntype; @@ -215,6 +248,7 @@ static void node_register() ntype.register_operators = node_operators; ntype.blend_write_storage_content = node_blend_write; ntype.blend_data_read_storage_content = node_blend_read; + ntype.can_sync_sockets = node_can_sync_sockets; bke::node_type_storage( ntype, "NodeGeometrySeparateBundle", node_free_storage, node_copy_storage); blender::bke::node_register_type(ntype); diff --git a/source/blender/nodes/intern/geometry_nodes_bundle.cc b/source/blender/nodes/intern/geometry_nodes_bundle.cc index a57379351cd..ab98b794074 100644 --- a/source/blender/nodes/intern/geometry_nodes_bundle.cc +++ b/source/blender/nodes/intern/geometry_nodes_bundle.cc @@ -293,7 +293,7 @@ BundleSignature BundleSignature::from_combine_bundle_node(const bNode &node) for (const int i : IndexRange(storage.items_num)) { const NodeGeometryCombineBundleItem &item = storage.items[i]; if (const bke::bNodeSocketType *stype = bke::node_socket_type_find_static(item.socket_type)) { - signature.items.append({item.name, stype}); + signature.items.add({item.name, stype}); } } return signature; @@ -307,7 +307,7 @@ BundleSignature BundleSignature::from_separate_bundle_node(const bNode &node) for (const int i : IndexRange(storage.items_num)) { const NodeGeometrySeparateBundleItem &item = storage.items[i]; if (const bke::bNodeSocketType *stype = bke::node_socket_type_find_static(item.socket_type)) { - signature.items.append({item.name, stype}); + signature.items.add({item.name, stype}); } } return signature; diff --git a/source/blender/nodes/intern/geometry_nodes_closure.cc b/source/blender/nodes/intern/geometry_nodes_closure.cc index 9d62954d4f5..f37025cf296 100644 --- a/source/blender/nodes/intern/geometry_nodes_closure.cc +++ b/source/blender/nodes/intern/geometry_nodes_closure.cc @@ -94,13 +94,13 @@ ClosureSignature ClosureSignature::from_closure_output_node(const bNode &node) for (const int i : IndexRange(storage.input_items.items_num)) { const NodeGeometryClosureInputItem &item = storage.input_items.items[i]; if (const bke::bNodeSocketType *stype = bke::node_socket_type_find_static(item.socket_type)) { - signature.inputs.append({item.name, stype}); + signature.inputs.add({item.name, stype}); } } for (const int i : IndexRange(storage.output_items.items_num)) { const NodeGeometryClosureOutputItem &item = storage.output_items.items[i]; if (const bke::bNodeSocketType *stype = bke::node_socket_type_find_static(item.socket_type)) { - signature.outputs.append({item.name, stype}); + signature.outputs.add({item.name, stype}); } } return signature; @@ -114,13 +114,13 @@ ClosureSignature ClosureSignature::from_evaluate_closure_node(const bNode &node) for (const int i : IndexRange(storage.input_items.items_num)) { const NodeGeometryEvaluateClosureInputItem &item = storage.input_items.items[i]; if (const bke::bNodeSocketType *stype = bke::node_socket_type_find_static(item.socket_type)) { - signature.inputs.append({item.name, stype, nodes::StructureType(item.structure_type)}); + signature.inputs.add({item.name, stype, nodes::StructureType(item.structure_type)}); } } for (const int i : IndexRange(storage.output_items.items_num)) { const NodeGeometryEvaluateClosureOutputItem &item = storage.output_items.items[i]; if (const bke::bNodeSocketType *stype = bke::node_socket_type_find_static(item.socket_type)) { - signature.outputs.append({item.name, stype, nodes::StructureType(item.structure_type)}); + signature.outputs.add({item.name, stype, nodes::StructureType(item.structure_type)}); } } return signature; diff --git a/source/blender/nodes/intern/geometry_nodes_closure_zone.cc b/source/blender/nodes/intern/geometry_nodes_closure_zone.cc index 8e3dc550f9c..4d036fdb2e7 100644 --- a/source/blender/nodes/intern/geometry_nodes_closure_zone.cc +++ b/source/blender/nodes/intern/geometry_nodes_closure_zone.cc @@ -125,11 +125,11 @@ class LazyFunctionForClosureZone : public LazyFunction { for (const int i : IndexRange(storage.input_items.items_num)) { const bNodeSocket &bsocket = zone_.input_node()->output_socket(i); - closure_signature_->inputs.append({bsocket.name, bsocket.typeinfo}); + closure_signature_->inputs.add({bsocket.name, bsocket.typeinfo}); } for (const int i : IndexRange(storage.output_items.items_num)) { const bNodeSocket &bsocket = zone_.output_node()->input_socket(i); - closure_signature_->outputs.append({bsocket.name, bsocket.typeinfo}); + closure_signature_->outputs.add({bsocket.name, bsocket.typeinfo}); } }