Changeset View
Changeset View
Standalone View
Standalone View
source/blender/modifiers/intern/MOD_nodes.cc
| Show First 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
| #include "DNA_space_types.h" | #include "DNA_space_types.h" | ||||
| #include "DNA_windowmanager_types.h" | #include "DNA_windowmanager_types.h" | ||||
| #include "BKE_attribute_math.hh" | #include "BKE_attribute_math.hh" | ||||
| #include "BKE_customdata.h" | #include "BKE_customdata.h" | ||||
| #include "BKE_geometry_set_instances.hh" | #include "BKE_geometry_set_instances.hh" | ||||
| #include "BKE_global.h" | #include "BKE_global.h" | ||||
| #include "BKE_idprop.h" | #include "BKE_idprop.h" | ||||
| #include "BKE_lib_id.h" | |||||
| #include "BKE_lib_query.h" | #include "BKE_lib_query.h" | ||||
| #include "BKE_main.h" | #include "BKE_main.h" | ||||
| #include "BKE_mesh.h" | #include "BKE_mesh.h" | ||||
| #include "BKE_modifier.h" | #include "BKE_modifier.h" | ||||
| #include "BKE_object.h" | #include "BKE_object.h" | ||||
| #include "BKE_pointcloud.h" | #include "BKE_pointcloud.h" | ||||
| #include "BKE_screen.h" | #include "BKE_screen.h" | ||||
| #include "BKE_simulation.h" | #include "BKE_simulation.h" | ||||
| Show All 15 Lines | |||||
| #include "DEG_depsgraph_build.h" | #include "DEG_depsgraph_build.h" | ||||
| #include "DEG_depsgraph_query.h" | #include "DEG_depsgraph_query.h" | ||||
| #include "MOD_modifiertypes.h" | #include "MOD_modifiertypes.h" | ||||
| #include "MOD_nodes.h" | #include "MOD_nodes.h" | ||||
| #include "MOD_nodes_evaluator.hh" | #include "MOD_nodes_evaluator.hh" | ||||
| #include "MOD_ui_common.h" | #include "MOD_ui_common.h" | ||||
| #include "ED_object.h" | |||||
| #include "ED_spreadsheet.h" | #include "ED_spreadsheet.h" | ||||
| #include "ED_undo.h" | #include "ED_undo.h" | ||||
| #include "NOD_derived_node_tree.hh" | #include "NOD_derived_node_tree.hh" | ||||
| #include "NOD_geometry.h" | #include "NOD_geometry.h" | ||||
| #include "NOD_geometry_nodes_eval_log.hh" | #include "NOD_geometry_nodes_eval_log.hh" | ||||
| #include "NOD_node_declaration.hh" | #include "NOD_node_declaration.hh" | ||||
| ▲ Show 20 Lines • Show All 1,020 Lines • ▼ Show 20 Lines | |||||
| static void modifyGeometrySet(ModifierData *md, | static void modifyGeometrySet(ModifierData *md, | ||||
| const ModifierEvalContext *ctx, | const ModifierEvalContext *ctx, | ||||
| GeometrySet *geometry_set) | GeometrySet *geometry_set) | ||||
| { | { | ||||
| modifyGeometry(md, ctx, *geometry_set); | modifyGeometry(md, ctx, *geometry_set); | ||||
| } | } | ||||
| struct AttributeSearchData { | struct AttributeSearchData { | ||||
| const geo_log::ModifierLog &modifier_log; | uint32_t object_session_uid; | ||||
| IDProperty &name_property; | char modifier_name[MAX_NAME]; | ||||
| char socket_identifier[MAX_NAME]; | |||||
| bool is_output; | bool is_output; | ||||
| }; | }; | ||||
| /* This class must not have a destructor, since it is used by buttons and freed with #MEM_freeN. */ | /* This class must not have a destructor, since it is used by buttons and freed with #MEM_freeN. */ | ||||
| BLI_STATIC_ASSERT(std::is_trivially_destructible_v<AttributeSearchData>, ""); | BLI_STATIC_ASSERT(std::is_trivially_destructible_v<AttributeSearchData>, ""); | ||||
| static void attribute_search_update_fn(const bContext *UNUSED(C), | static NodesModifierData *get_modifier_data(const bContext &C, const AttributeSearchData &data) | ||||
Severin: I'd like to avoid passing `bContext`, especially to lower level functions as much as possible. | |||||
| void *arg, | { | ||||
| const char *str, | Main *bmain = CTX_data_main(&C); | ||||
| uiSearchItems *items, | const Object *object = (Object *)BKE_libblock_find_session_uuid( | ||||
| const bool is_first) | bmain, ID_OB, data.object_session_uid); | ||||
| { | if (object == nullptr) { | ||||
| AttributeSearchData *data = static_cast<AttributeSearchData *>(arg); | return nullptr; | ||||
| } | |||||
| const geo_log::GeometryValueLog *geometry_log = data->is_output ? | ModifierData *md = BKE_modifiers_findby_name(object, data.modifier_name); | ||||
| data->modifier_log.output_geometry_log() : | if (md == nullptr) { | ||||
| data->modifier_log.input_geometry_log(); | return nullptr; | ||||
| } | |||||
| BLI_assert(md->type == eModifierType_Nodes); | |||||
| return reinterpret_cast<NodesModifierData *>(md); | |||||
| } | |||||
| static void attribute_search_update_fn( | |||||
| const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first) | |||||
| { | |||||
| AttributeSearchData &data = *static_cast<AttributeSearchData *>(arg); | |||||
| const NodesModifierData *nmd = get_modifier_data(*C, data); | |||||
| if (nmd == nullptr) { | |||||
| return; | |||||
| } | |||||
| const geo_log::ModifierLog *modifier_log = static_cast<const geo_log::ModifierLog *>( | |||||
| nmd->runtime_eval_log); | |||||
| if (modifier_log == nullptr) { | |||||
| return; | |||||
| } | |||||
| const geo_log::GeometryValueLog *geometry_log = data.is_output ? | |||||
| modifier_log->output_geometry_log() : | |||||
| modifier_log->input_geometry_log(); | |||||
| if (geometry_log == nullptr) { | if (geometry_log == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| Span<GeometryAttributeInfo> infos = geometry_log->attributes(); | Span<GeometryAttributeInfo> infos = geometry_log->attributes(); | ||||
| /* The shared attribute search code expects a span of pointers, so convert to that. */ | /* The shared attribute search code expects a span of pointers, so convert to that. */ | ||||
| Array<const GeometryAttributeInfo *> info_ptrs(infos.size()); | Array<const GeometryAttributeInfo *> info_ptrs(infos.size()); | ||||
| for (const int i : infos.index_range()) { | for (const int i : infos.index_range()) { | ||||
| info_ptrs[i] = &infos[i]; | info_ptrs[i] = &infos[i]; | ||||
| } | } | ||||
| blender::ui::attribute_search_add_items( | blender::ui::attribute_search_add_items( | ||||
| str, data->is_output, info_ptrs.as_span(), items, is_first); | str, data.is_output, info_ptrs.as_span(), items, is_first); | ||||
| } | } | ||||
| static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v) | static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v) | ||||
| { | { | ||||
| if (item_v == nullptr) { | if (item_v == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| AttributeSearchData &data = *static_cast<AttributeSearchData *>(data_v); | AttributeSearchData &data = *static_cast<AttributeSearchData *>(data_v); | ||||
| const GeometryAttributeInfo &item = *static_cast<const GeometryAttributeInfo *>(item_v); | const GeometryAttributeInfo &item = *static_cast<const GeometryAttributeInfo *>(item_v); | ||||
| const NodesModifierData *nmd = get_modifier_data(*C, data); | |||||
| if (nmd == nullptr) { | |||||
| return; | |||||
| } | |||||
| IDProperty &name_property = data.name_property; | const std::string attribute_prop_name = data.socket_identifier + attribute_name_suffix; | ||||
| BLI_assert(name_property.type == IDP_STRING); | IDProperty &name_property = *IDP_GetPropertyFromGroup(nmd->settings.properties, | ||||
| attribute_prop_name.c_str()); | |||||
| IDP_AssignString(&name_property, item.name.c_str(), 0); | IDP_AssignString(&name_property, item.name.c_str(), 0); | ||||
| ED_undo_push(C, "Assign Attribute Name"); | ED_undo_push(C, "Assign Attribute Name"); | ||||
| } | } | ||||
| static void add_attribute_search_button(uiLayout *layout, | static void add_attribute_search_button(const bContext &C, | ||||
| uiLayout *layout, | |||||
| const NodesModifierData &nmd, | const NodesModifierData &nmd, | ||||
| PointerRNA *md_ptr, | PointerRNA *md_ptr, | ||||
| const StringRefNull rna_path_attribute_name, | const StringRefNull rna_path_attribute_name, | ||||
| const bNodeSocket &socket, | const bNodeSocket &socket, | ||||
| const bool is_output) | const bool is_output) | ||||
| { | { | ||||
| const geo_log::ModifierLog *log = static_cast<geo_log::ModifierLog *>(nmd.runtime_eval_log); | const geo_log::ModifierLog *log = static_cast<geo_log::ModifierLog *>(nmd.runtime_eval_log); | ||||
| if (log == nullptr) { | if (log == nullptr) { | ||||
| Show All 15 Lines | uiBut *but = uiDefIconTextButR(block, | ||||
| rna_path_attribute_name.c_str(), | rna_path_attribute_name.c_str(), | ||||
| 0, | 0, | ||||
| 0.0f, | 0.0f, | ||||
| 0.0f, | 0.0f, | ||||
| 0.0f, | 0.0f, | ||||
| 0.0f, | 0.0f, | ||||
| ""); | ""); | ||||
| const std::string use_attribute_prop_name = socket.identifier + attribute_name_suffix; | const Object *object = ED_object_context(&C); | ||||
| IDProperty *property = IDP_GetPropertyFromGroup(nmd.settings.properties, | BLI_assert(object != nullptr); | ||||
| use_attribute_prop_name.c_str()); | if (object == nullptr) { | ||||
Done Inline ActionsUse ED_object_context. JacquesLucke: Use `ED_object_context`. | |||||
| BLI_assert(property != nullptr); | |||||
| if (property == nullptr) { | |||||
| return; | return; | ||||
| } | } | ||||
| AttributeSearchData *data = OBJECT_GUARDED_NEW(AttributeSearchData, | AttributeSearchData *data = OBJECT_GUARDED_NEW(AttributeSearchData); | ||||
| {*log, *property, is_output}); | data->object_session_uid = object->id.session_uuid; | ||||
| STRNCPY(data->modifier_name, nmd.modifier.name); | |||||
| STRNCPY(data->socket_identifier, socket.identifier); | |||||
| data->is_output = is_output; | |||||
| UI_but_func_search_set_results_are_suggestions(but, true); | UI_but_func_search_set_results_are_suggestions(but, true); | ||||
| UI_but_func_search_set_sep_string(but, UI_MENU_ARROW_SEP); | UI_but_func_search_set_sep_string(but, UI_MENU_ARROW_SEP); | ||||
| UI_but_func_search_set(but, | UI_but_func_search_set(but, | ||||
| nullptr, | nullptr, | ||||
| attribute_search_update_fn, | attribute_search_update_fn, | ||||
| static_cast<void *>(data), | static_cast<void *>(data), | ||||
| true, | true, | ||||
| nullptr, | nullptr, | ||||
| attribute_search_exec_fn, | attribute_search_exec_fn, | ||||
| nullptr); | nullptr); | ||||
| } | } | ||||
| static void add_attribute_search_or_value_buttons(uiLayout *layout, | static void add_attribute_search_or_value_buttons(const bContext &C, | ||||
| uiLayout *layout, | |||||
| const NodesModifierData &nmd, | const NodesModifierData &nmd, | ||||
| PointerRNA *md_ptr, | PointerRNA *md_ptr, | ||||
| const bNodeSocket &socket) | const bNodeSocket &socket) | ||||
| { | { | ||||
| char socket_id_esc[sizeof(socket.identifier) * 2]; | char socket_id_esc[sizeof(socket.identifier) * 2]; | ||||
| BLI_str_escape(socket_id_esc, socket.identifier, sizeof(socket_id_esc)); | BLI_str_escape(socket_id_esc, socket.identifier, sizeof(socket_id_esc)); | ||||
| const std::string rna_path = "[\"" + std::string(socket_id_esc) + "\"]"; | const std::string rna_path = "[\"" + std::string(socket_id_esc) + "\"]"; | ||||
| const std::string rna_path_use_attribute = "[\"" + std::string(socket_id_esc) + | const std::string rna_path_use_attribute = "[\"" + std::string(socket_id_esc) + | ||||
| Show All 17 Lines | uiItemFullO(row, | ||||
| WM_OP_INVOKE_DEFAULT, | WM_OP_INVOKE_DEFAULT, | ||||
| 0, | 0, | ||||
| &props); | &props); | ||||
| RNA_string_set(&props, "modifier_name", nmd.modifier.name); | RNA_string_set(&props, "modifier_name", nmd.modifier.name); | ||||
| RNA_string_set(&props, "prop_path", rna_path_use_attribute.c_str()); | RNA_string_set(&props, "prop_path", rna_path_use_attribute.c_str()); | ||||
| const int use_attribute = RNA_int_get(md_ptr, rna_path_use_attribute.c_str()) != 0; | const int use_attribute = RNA_int_get(md_ptr, rna_path_use_attribute.c_str()) != 0; | ||||
| if (use_attribute) { | if (use_attribute) { | ||||
| add_attribute_search_button(row, nmd, md_ptr, rna_path_attribute_name, socket, false); | add_attribute_search_button(C, row, nmd, md_ptr, rna_path_attribute_name, socket, false); | ||||
| uiItemL(row, "", ICON_BLANK1); | uiItemL(row, "", ICON_BLANK1); | ||||
| } | } | ||||
| else { | else { | ||||
| uiItemR(row, md_ptr, rna_path.c_str(), 0, "", ICON_NONE); | uiItemR(row, md_ptr, rna_path.c_str(), 0, "", ICON_NONE); | ||||
| uiItemDecoratorR(row, md_ptr, rna_path.c_str(), 0); | uiItemDecoratorR(row, md_ptr, rna_path.c_str(), 0); | ||||
| } | } | ||||
| } | } | ||||
| /* Drawing the properties manually with #uiItemR instead of #uiDefAutoButsRNA allows using | /* Drawing the properties manually with #uiItemR instead of #uiDefAutoButsRNA allows using | ||||
| * the node socket identifier for the property names, since they are unique, but also having | * the node socket identifier for the property names, since they are unique, but also having | ||||
| * the correct label displayed in the UI. */ | * the correct label displayed in the UI. */ | ||||
| static void draw_property_for_socket(uiLayout *layout, | static void draw_property_for_socket(const bContext &C, | ||||
| uiLayout *layout, | |||||
| NodesModifierData *nmd, | NodesModifierData *nmd, | ||||
| PointerRNA *bmain_ptr, | PointerRNA *bmain_ptr, | ||||
| PointerRNA *md_ptr, | PointerRNA *md_ptr, | ||||
| const bNodeSocket &socket, | const bNodeSocket &socket, | ||||
| const int socket_index) | const int socket_index) | ||||
| { | { | ||||
| /* The property should be created in #MOD_nodes_update_interface with the correct type. */ | /* The property should be created in #MOD_nodes_update_interface with the correct type. */ | ||||
| IDProperty *property = IDP_GetPropertyFromGroup(nmd->settings.properties, socket.identifier); | IDProperty *property = IDP_GetPropertyFromGroup(nmd->settings.properties, socket.identifier); | ||||
| Show All 38 Lines | case SOCK_TEXTURE: { | ||||
| break; | break; | ||||
| } | } | ||||
| case SOCK_IMAGE: { | case SOCK_IMAGE: { | ||||
| uiItemPointerR(layout, md_ptr, rna_path, bmain_ptr, "images", socket.name, ICON_IMAGE); | uiItemPointerR(layout, md_ptr, rna_path, bmain_ptr, "images", socket.name, ICON_IMAGE); | ||||
| break; | break; | ||||
| } | } | ||||
| default: { | default: { | ||||
| if (input_has_attribute_toggle(*nmd->node_group, socket_index)) { | if (input_has_attribute_toggle(*nmd->node_group, socket_index)) { | ||||
| add_attribute_search_or_value_buttons(layout, *nmd, md_ptr, socket); | add_attribute_search_or_value_buttons(C, layout, *nmd, md_ptr, socket); | ||||
| } | } | ||||
| else { | else { | ||||
| uiLayout *row = uiLayoutRow(layout, false); | uiLayout *row = uiLayoutRow(layout, false); | ||||
| uiItemR(row, md_ptr, rna_path, 0, socket.name, ICON_NONE); | uiItemR(row, md_ptr, rna_path, 0, socket.name, ICON_NONE); | ||||
| uiItemDecoratorR(row, md_ptr, rna_path, 0); | uiItemDecoratorR(row, md_ptr, rna_path, 0); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void draw_property_for_output_socket(uiLayout *layout, | static void draw_property_for_output_socket(const bContext &C, | ||||
| uiLayout *layout, | |||||
| const NodesModifierData &nmd, | const NodesModifierData &nmd, | ||||
| PointerRNA *md_ptr, | PointerRNA *md_ptr, | ||||
| const bNodeSocket &socket) | const bNodeSocket &socket) | ||||
| { | { | ||||
| char socket_id_esc[sizeof(socket.identifier) * 2]; | char socket_id_esc[sizeof(socket.identifier) * 2]; | ||||
| BLI_str_escape(socket_id_esc, socket.identifier, sizeof(socket_id_esc)); | BLI_str_escape(socket_id_esc, socket.identifier, sizeof(socket_id_esc)); | ||||
| const std::string rna_path_attribute_name = "[\"" + StringRef(socket_id_esc) + | const std::string rna_path_attribute_name = "[\"" + StringRef(socket_id_esc) + | ||||
| attribute_name_suffix + "\"]"; | attribute_name_suffix + "\"]"; | ||||
| uiLayout *split = uiLayoutSplit(layout, 0.4f, false); | uiLayout *split = uiLayoutSplit(layout, 0.4f, false); | ||||
| uiLayout *name_row = uiLayoutRow(split, false); | uiLayout *name_row = uiLayoutRow(split, false); | ||||
| uiLayoutSetAlignment(name_row, UI_LAYOUT_ALIGN_RIGHT); | uiLayoutSetAlignment(name_row, UI_LAYOUT_ALIGN_RIGHT); | ||||
| uiItemL(name_row, socket.name, ICON_NONE); | uiItemL(name_row, socket.name, ICON_NONE); | ||||
| uiLayout *row = uiLayoutRow(split, true); | uiLayout *row = uiLayoutRow(split, true); | ||||
| add_attribute_search_button(row, nmd, md_ptr, rna_path_attribute_name, socket, true); | add_attribute_search_button(C, row, nmd, md_ptr, rna_path_attribute_name, socket, true); | ||||
| } | } | ||||
| static void panel_draw(const bContext *C, Panel *panel) | static void panel_draw(const bContext *C, Panel *panel) | ||||
| { | { | ||||
| uiLayout *layout = panel->layout; | uiLayout *layout = panel->layout; | ||||
| Main *bmain = CTX_data_main(C); | Main *bmain = CTX_data_main(C); | ||||
| PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); | PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); | ||||
| Show All 16 Lines | uiTemplateID(layout, | ||||
| nullptr); | nullptr); | ||||
| if (nmd->node_group != nullptr && nmd->settings.properties != nullptr) { | if (nmd->node_group != nullptr && nmd->settings.properties != nullptr) { | ||||
| PointerRNA bmain_ptr; | PointerRNA bmain_ptr; | ||||
| RNA_main_pointer_create(bmain, &bmain_ptr); | RNA_main_pointer_create(bmain, &bmain_ptr); | ||||
| int socket_index; | int socket_index; | ||||
| LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &nmd->node_group->inputs, socket_index) { | LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &nmd->node_group->inputs, socket_index) { | ||||
| draw_property_for_socket(layout, nmd, &bmain_ptr, ptr, *socket, socket_index); | draw_property_for_socket(*C, layout, nmd, &bmain_ptr, ptr, *socket, socket_index); | ||||
| } | } | ||||
| } | } | ||||
| /* Draw node warnings. */ | /* Draw node warnings. */ | ||||
| bool has_legacy_node = false; | bool has_legacy_node = false; | ||||
| if (nmd->runtime_eval_log != nullptr) { | if (nmd->runtime_eval_log != nullptr) { | ||||
| const geo_log::ModifierLog &log = *static_cast<geo_log::ModifierLog *>(nmd->runtime_eval_log); | const geo_log::ModifierLog &log = *static_cast<geo_log::ModifierLog *>(nmd->runtime_eval_log); | ||||
| log.foreach_node_log([&](const geo_log::NodeLog &node_log) { | log.foreach_node_log([&](const geo_log::NodeLog &node_log) { | ||||
| Show All 14 Lines | if (has_legacy_node) { | ||||
| uiLayout *sub = uiLayoutRow(row, false); | uiLayout *sub = uiLayoutRow(row, false); | ||||
| uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT); | uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT); | ||||
| uiItemO(sub, "", ICON_VIEWZOOM, "NODE_OT_geometry_node_view_legacy"); | uiItemO(sub, "", ICON_VIEWZOOM, "NODE_OT_geometry_node_view_legacy"); | ||||
| } | } | ||||
| modifier_panel_end(layout, ptr); | modifier_panel_end(layout, ptr); | ||||
| } | } | ||||
| static void output_attribute_panel_draw(const bContext *UNUSED(C), Panel *panel) | static void output_attribute_panel_draw(const bContext *C, Panel *panel) | ||||
| { | { | ||||
| uiLayout *layout = panel->layout; | uiLayout *layout = panel->layout; | ||||
| PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); | PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); | ||||
| NodesModifierData *nmd = static_cast<NodesModifierData *>(ptr->data); | NodesModifierData *nmd = static_cast<NodesModifierData *>(ptr->data); | ||||
| uiLayoutSetPropSep(layout, true); | uiLayoutSetPropSep(layout, true); | ||||
| uiLayoutSetPropDecorate(layout, true); | uiLayoutSetPropDecorate(layout, true); | ||||
| bool has_output_attribute = false; | bool has_output_attribute = false; | ||||
| if (nmd->node_group != nullptr && nmd->settings.properties != nullptr) { | if (nmd->node_group != nullptr && nmd->settings.properties != nullptr) { | ||||
| LISTBASE_FOREACH (bNodeSocket *, socket, &nmd->node_group->outputs) { | LISTBASE_FOREACH (bNodeSocket *, socket, &nmd->node_group->outputs) { | ||||
| if (socket_type_has_attribute_toggle(*socket)) { | if (socket_type_has_attribute_toggle(*socket)) { | ||||
| has_output_attribute = true; | has_output_attribute = true; | ||||
| draw_property_for_output_socket(layout, *nmd, ptr, *socket); | draw_property_for_output_socket(*C, layout, *nmd, ptr, *socket); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (!has_output_attribute) { | if (!has_output_attribute) { | ||||
| uiItemL(layout, TIP_("No group output attributes connected"), ICON_INFO); | uiItemL(layout, TIP_("No group output attributes connected"), ICON_INFO); | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 101 Lines • Show Last 20 Lines | |||||
I'd like to avoid passing bContext, especially to lower level functions as much as possible. So I'd suggest just taking const Main * directly here.