diff --git a/source/blender/editors/curves/intern/node_group_operator.cc b/source/blender/editors/curves/intern/node_group_operator.cc index 34d4768ef38..cb8b69a5e4d 100644 --- a/source/blender/editors/curves/intern/node_group_operator.cc +++ b/source/blender/editors/curves/intern/node_group_operator.cc @@ -87,7 +87,7 @@ static int run_node_group_exec(bContext *C, wmOperator *op) bke::ModifierComputeContext compute_context{nullptr, "actually not a modifier"}; GeometrySet new_geometry = nodes::execute_geometry_nodes( node_tree, - nullptr, + op->properties, compute_context, original_geometry, [&](nodes::GeoNodesLFUserData &user_data) { @@ -113,12 +113,29 @@ static int run_node_group_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static int run_node_group_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + char name[MAX_ID_NAME]; + RNA_string_get(op->ptr, "name", name); + const ID *id = BKE_libblock_find_name(CTX_data_main(C), ID_NT, name); + if (!id) { + return OPERATOR_CANCELLED; + } + const bNodeTree &node_tree = reinterpret_cast(*id); + + nodes::update_input_properties_from_node_tree(node_tree, op->properties, *op->properties); + nodes::update_output_properties_from_node_tree(node_tree, op->properties, *op->properties); + + return run_node_group_exec(C, op); +} + void CURVES_OT_node_group(wmOperatorType *ot) { ot->name = "Run Node Group"; ot->idname = __func__; ot->description = "Execute a node group on curves"; // TODO: Retrieve from node group. + ot->invoke = run_node_group_invoke; ot->exec = run_node_group_exec; ot->poll = editable_curves_poll; diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 24265cc90c6..9da05e73f0e 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -378,127 +378,6 @@ static bool logging_enabled(const ModifierEvalContext *ctx) static const std::string use_attribute_suffix = "_use_attribute"; static const std::string attribute_name_suffix = "_attribute_name"; -static void update_input_properties_from_node_tree(const bNodeTree &tree, - const IDProperty *old_properties, - IDProperty &properties) -{ - tree.ensure_topology_cache(); - const Span tree_inputs = tree.interface_inputs(); - for (const int i : tree_inputs.index_range()) { - const bNodeSocket &socket = *tree_inputs[i]; - IDProperty *new_prop = nodes::id_property_create_from_socket(socket).release(); - if (new_prop == nullptr) { - /* Out of the set of supported input sockets, only - * geometry sockets aren't added to the modifier. */ - BLI_assert(socket.type == SOCK_GEOMETRY); - continue; - } - - new_prop->flag |= IDP_FLAG_OVERRIDABLE_LIBRARY; - if (socket.description[0] != '\0') { - IDPropertyUIData *ui_data = IDP_ui_data_ensure(new_prop); - ui_data->description = BLI_strdup(socket.description); - } - IDP_AddToGroup(&properties, new_prop); - - if (old_properties != nullptr) { - const IDProperty *old_prop = IDP_GetPropertyFromGroup(old_properties, socket.identifier); - if (old_prop != nullptr) { - if (nodes::id_property_type_matches_socket(socket, *old_prop)) { - /* #IDP_CopyPropertyContent replaces the UI data as well, which we don't (we only - * want to replace the values). So release it temporarily and replace it after. */ - IDPropertyUIData *ui_data = new_prop->ui_data; - new_prop->ui_data = nullptr; - IDP_CopyPropertyContent(new_prop, old_prop); - if (new_prop->ui_data != nullptr) { - IDP_ui_data_free(new_prop); - } - new_prop->ui_data = ui_data; - } - else if (old_prop->type == IDP_INT && new_prop->type == IDP_BOOLEAN) { - /* Support versioning from integer to boolean property values. The actual value is stored - * in the same variable for both types. */ - new_prop->data.val = old_prop->data.val != 0; - } - } - } - - if (nodes::socket_type_has_attribute_toggle(socket)) { - const std::string use_attribute_id = socket.identifier + use_attribute_suffix; - const std::string attribute_name_id = socket.identifier + attribute_name_suffix; - - IDPropertyTemplate idprop = {0}; - IDProperty *use_attribute_prop = IDP_New(IDP_INT, &idprop, use_attribute_id.c_str()); - IDP_AddToGroup(&properties, use_attribute_prop); - - IDProperty *attribute_prop = IDP_New(IDP_STRING, &idprop, attribute_name_id.c_str()); - IDP_AddToGroup(&properties, attribute_prop); - - if (old_properties == nullptr) { - if (socket.default_attribute_name && socket.default_attribute_name[0] != '\0') { - IDP_AssignString(attribute_prop, socket.default_attribute_name, MAX_NAME); - IDP_Int(use_attribute_prop) = 1; - } - } - else { - IDProperty *old_prop_use_attribute = IDP_GetPropertyFromGroup(old_properties, - use_attribute_id.c_str()); - if (old_prop_use_attribute != nullptr) { - IDP_CopyPropertyContent(use_attribute_prop, old_prop_use_attribute); - } - - IDProperty *old_attribute_name_prop = IDP_GetPropertyFromGroup(old_properties, - attribute_name_id.c_str()); - if (old_attribute_name_prop != nullptr) { - IDP_CopyPropertyContent(attribute_prop, old_attribute_name_prop); - } - } - } - } -} - -static void update_output_properties_from_node_tree(const bNodeTree &tree, - const IDProperty *old_properties, - IDProperty &properties) -{ - tree.ensure_topology_cache(); - const Span tree_outputs = tree.interface_outputs(); - for (const int i : tree_outputs.index_range()) { - const bNodeSocket &socket = *tree_outputs[i]; - if (!nodes::socket_type_has_attribute_toggle(socket)) { - continue; - } - - const std::string idprop_name = socket.identifier + attribute_name_suffix; - IDProperty *new_prop = IDP_NewString("", idprop_name.c_str(), MAX_NAME); - if (socket.description[0] != '\0') { - IDPropertyUIData *ui_data = IDP_ui_data_ensure(new_prop); - ui_data->description = BLI_strdup(socket.description); - } - IDP_AddToGroup(&properties, new_prop); - - if (old_properties == nullptr) { - if (socket.default_attribute_name && socket.default_attribute_name[0] != '\0') { - IDP_AssignString(new_prop, socket.default_attribute_name, MAX_NAME); - } - } - else { - IDProperty *old_prop = IDP_GetPropertyFromGroup(old_properties, idprop_name.c_str()); - if (old_prop != nullptr) { - /* #IDP_CopyPropertyContent replaces the UI data as well, which we don't (we only - * want to replace the values). So release it temporarily and replace it after. */ - IDPropertyUIData *ui_data = new_prop->ui_data; - new_prop->ui_data = nullptr; - IDP_CopyPropertyContent(new_prop, old_prop); - if (new_prop->ui_data != nullptr) { - IDP_ui_data_free(new_prop); - } - new_prop->ui_data = ui_data; - } - } - } -} - } // namespace blender void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd) @@ -519,8 +398,9 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd) } IDProperty *new_properties = nmd->settings.properties; - update_input_properties_from_node_tree(*nmd->node_group, old_properties, *new_properties); - update_output_properties_from_node_tree(*nmd->node_group, old_properties, *new_properties); + nodes::update_input_properties_from_node_tree(*nmd->node_group, old_properties, *new_properties); + nodes::update_output_properties_from_node_tree( + *nmd->node_group, old_properties, *new_properties); if (old_properties != nullptr) { IDP_FreeProperty(old_properties); diff --git a/source/blender/nodes/NOD_geometry_nodes_execute.hh b/source/blender/nodes/NOD_geometry_nodes_execute.hh index 2cb8bbcda0e..d0f26da25c4 100644 --- a/source/blender/nodes/NOD_geometry_nodes_execute.hh +++ b/source/blender/nodes/NOD_geometry_nodes_execute.hh @@ -63,4 +63,12 @@ GeometrySet execute_geometry_nodes(const bNodeTree &btree, GeometrySet input_geometry, FunctionRef fill_user_data); +void update_input_properties_from_node_tree(const bNodeTree &tree, + const IDProperty *old_properties, + IDProperty &properties); + +void update_output_properties_from_node_tree(const bNodeTree &tree, + const IDProperty *old_properties, + IDProperty &properties); + } // namespace blender::nodes diff --git a/source/blender/nodes/intern/geometry_nodes_execute.cc b/source/blender/nodes/intern/geometry_nodes_execute.cc index fa0f559f835..1f15e75d0b7 100644 --- a/source/blender/nodes/intern/geometry_nodes_execute.cc +++ b/source/blender/nodes/intern/geometry_nodes_execute.cc @@ -582,4 +582,125 @@ GeometrySet execute_geometry_nodes( return output_geometry; } +void update_input_properties_from_node_tree(const bNodeTree &tree, + const IDProperty *old_properties, + IDProperty &properties) +{ + tree.ensure_topology_cache(); + const Span tree_inputs = tree.interface_inputs(); + for (const int i : tree_inputs.index_range()) { + const bNodeSocket &socket = *tree_inputs[i]; + IDProperty *new_prop = nodes::id_property_create_from_socket(socket).release(); + if (new_prop == nullptr) { + /* Out of the set of supported input sockets, only + * geometry sockets aren't added to the modifier. */ + BLI_assert(socket.type == SOCK_GEOMETRY); + continue; + } + + new_prop->flag |= IDP_FLAG_OVERRIDABLE_LIBRARY; + if (socket.description[0] != '\0') { + IDPropertyUIData *ui_data = IDP_ui_data_ensure(new_prop); + ui_data->description = BLI_strdup(socket.description); + } + IDP_AddToGroup(&properties, new_prop); + + if (old_properties != nullptr) { + const IDProperty *old_prop = IDP_GetPropertyFromGroup(old_properties, socket.identifier); + if (old_prop != nullptr) { + if (nodes::id_property_type_matches_socket(socket, *old_prop)) { + /* #IDP_CopyPropertyContent replaces the UI data as well, which we don't (we only + * want to replace the values). So release it temporarily and replace it after. */ + IDPropertyUIData *ui_data = new_prop->ui_data; + new_prop->ui_data = nullptr; + IDP_CopyPropertyContent(new_prop, old_prop); + if (new_prop->ui_data != nullptr) { + IDP_ui_data_free(new_prop); + } + new_prop->ui_data = ui_data; + } + else if (old_prop->type == IDP_INT && new_prop->type == IDP_BOOLEAN) { + /* Support versioning from integer to boolean property values. The actual value is stored + * in the same variable for both types. */ + new_prop->data.val = old_prop->data.val != 0; + } + } + } + + if (nodes::socket_type_has_attribute_toggle(socket)) { + const std::string use_attribute_id = socket.identifier + use_attribute_suffix; + const std::string attribute_name_id = socket.identifier + attribute_name_suffix; + + IDPropertyTemplate idprop = {0}; + IDProperty *use_attribute_prop = IDP_New(IDP_INT, &idprop, use_attribute_id.c_str()); + IDP_AddToGroup(&properties, use_attribute_prop); + + IDProperty *attribute_prop = IDP_New(IDP_STRING, &idprop, attribute_name_id.c_str()); + IDP_AddToGroup(&properties, attribute_prop); + + if (old_properties == nullptr) { + if (socket.default_attribute_name && socket.default_attribute_name[0] != '\0') { + IDP_AssignString(attribute_prop, socket.default_attribute_name, MAX_NAME); + IDP_Int(use_attribute_prop) = 1; + } + } + else { + IDProperty *old_prop_use_attribute = IDP_GetPropertyFromGroup(old_properties, + use_attribute_id.c_str()); + if (old_prop_use_attribute != nullptr) { + IDP_CopyPropertyContent(use_attribute_prop, old_prop_use_attribute); + } + + IDProperty *old_attribute_name_prop = IDP_GetPropertyFromGroup(old_properties, + attribute_name_id.c_str()); + if (old_attribute_name_prop != nullptr) { + IDP_CopyPropertyContent(attribute_prop, old_attribute_name_prop); + } + } + } + } +} + +void update_output_properties_from_node_tree(const bNodeTree &tree, + const IDProperty *old_properties, + IDProperty &properties) +{ + tree.ensure_topology_cache(); + const Span tree_outputs = tree.interface_outputs(); + for (const int i : tree_outputs.index_range()) { + const bNodeSocket &socket = *tree_outputs[i]; + if (!nodes::socket_type_has_attribute_toggle(socket)) { + continue; + } + + const std::string idprop_name = socket.identifier + attribute_name_suffix; + IDProperty *new_prop = IDP_NewString("", idprop_name.c_str(), MAX_NAME); + if (socket.description[0] != '\0') { + IDPropertyUIData *ui_data = IDP_ui_data_ensure(new_prop); + ui_data->description = BLI_strdup(socket.description); + } + IDP_AddToGroup(&properties, new_prop); + + if (old_properties == nullptr) { + if (socket.default_attribute_name && socket.default_attribute_name[0] != '\0') { + IDP_AssignString(new_prop, socket.default_attribute_name, MAX_NAME); + } + } + else { + IDProperty *old_prop = IDP_GetPropertyFromGroup(old_properties, idprop_name.c_str()); + if (old_prop != nullptr) { + /* #IDP_CopyPropertyContent replaces the UI data as well, which we don't (we only + * want to replace the values). So release it temporarily and replace it after. */ + IDPropertyUIData *ui_data = new_prop->ui_data; + new_prop->ui_data = nullptr; + IDP_CopyPropertyContent(new_prop, old_prop); + if (new_prop->ui_data != nullptr) { + IDP_ui_data_free(new_prop); + } + new_prop->ui_data = ui_data; + } + } + } +} + } // namespace blender::nodes