Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Goudey <h.goudey@me.com>2021-10-21 21:54:48 +0300
committerHans Goudey <h.goudey@me.com>2021-10-21 21:54:48 +0300
commit1d96a482675dd2ccad2af31c274f74b9f6603d6b (patch)
treebeb0406f7a9f1e6b826cc590eeab69e361a83b3b /source/blender/modifiers
parent65490e62708c6bb0c03d9c73fd7179fdf71355a5 (diff)
Geometry Nodes: Attribute search in the modifier
This adds attribute search to the geometry nodes modifier for the input and output attributes. The "New" search item is only shown for the output attributes. Some of the attribute search code is extracted to a new file in the interface code, to avoid some code duplication. The UI code required two fixes so that the search would work for dynamic length strings (IDProperties do not have a fixed size). Since this does changes to the UI layout of the modifier, I also addressed T91485 here. Differential Revisiion: https://developer.blender.org/D12788
Diffstat (limited to 'source/blender/modifiers')
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc211
1 files changed, 178 insertions, 33 deletions
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index 562589e2610..e6cc7663c58 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -27,11 +27,13 @@
#include "MEM_guardedalloc.h"
+#include "BLI_array.hh"
#include "BLI_float3.hh"
#include "BLI_listbase.h"
#include "BLI_multi_value_map.hh"
#include "BLI_set.hh"
#include "BLI_string.h"
+#include "BLI_string_search.h"
#include "BLI_utildefines.h"
#include "DNA_collection_types.h"
@@ -66,6 +68,7 @@
#include "BLO_read_write.h"
#include "UI_interface.h"
+#include "UI_interface.hh"
#include "UI_resources.h"
#include "BLT_translation.h"
@@ -84,6 +87,7 @@
#include "MOD_ui_common.h"
#include "ED_spreadsheet.h"
+#include "ED_undo.h"
#include "NOD_derived_node_tree.hh"
#include "NOD_geometry.h"
@@ -93,6 +97,7 @@
#include "FN_field.hh"
#include "FN_multi_function.hh"
+using blender::Array;
using blender::ColorGeometry4f;
using blender::destruct_ptr;
using blender::float3;
@@ -114,6 +119,7 @@ using blender::nodes::InputSocketFieldType;
using blender::threading::EnumerableThreadSpecific;
using namespace blender::fn::multi_function_types;
using namespace blender::nodes::derived_node_tree_types;
+using geo_log::GeometryAttributeInfo;
static void initData(ModifierData *md)
{
@@ -957,9 +963,6 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
}
}
- /* Don't keep a reference to the input geometry components to avoid copies during evaluation. */
- input_geometry_set.clear();
-
Vector<DInputSocket> group_outputs;
for (const InputSocketRef *socket_ref : output_node.inputs().drop_back(1)) {
group_outputs.append({root_context, socket_ref});
@@ -974,8 +977,13 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
find_sockets_to_preview(nmd, ctx, tree, preview_sockets);
eval_params.force_compute_sockets.extend(preview_sockets.begin(), preview_sockets.end());
geo_logger.emplace(std::move(preview_sockets));
+
+ geo_logger->log_input_geometry(input_geometry_set);
}
+ /* Don't keep a reference to the input geometry components to avoid copies during evaluation. */
+ input_geometry_set.clear();
+
eval_params.input_values = group_inputs;
eval_params.output_sockets = group_outputs;
eval_params.mf_by_node = &mf_by_node;
@@ -985,14 +993,15 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
eval_params.geo_logger = geo_logger.has_value() ? &*geo_logger : nullptr;
blender::modifiers::geometry_nodes::evaluate_geometry_nodes(eval_params);
+ GeometrySet output_geometry_set = eval_params.r_output_values[0].relocate_out<GeometrySet>();
+
if (geo_logger.has_value()) {
+ geo_logger->log_output_geometry(output_geometry_set);
NodesModifierData *nmd_orig = (NodesModifierData *)BKE_modifier_get_original(&nmd->modifier);
clear_runtime_data(nmd_orig);
nmd_orig->runtime_eval_log = new geo_log::ModifierLog(*geo_logger);
}
- GeometrySet output_geometry_set = eval_params.r_output_values[0].relocate_out<GeometrySet>();
-
for (const InputSocketRef *socket : output_node.inputs().drop_front(1).drop_back(1)) {
GMutablePointer socket_value = eval_params.r_output_values[socket->index()];
store_output_value_in_geometry(output_geometry_set, nmd, *socket, socket_value);
@@ -1108,6 +1117,154 @@ static void modifyGeometrySet(ModifierData *md,
modifyGeometry(md, ctx, *geometry_set);
}
+struct AttributeSearchData {
+ const geo_log::ModifierLog &modifier_log;
+ IDProperty &name_property;
+ bool is_output;
+};
+
+/* 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>, "");
+
+static void attribute_search_update_fn(const bContext *UNUSED(C),
+ void *arg,
+ const char *str,
+ uiSearchItems *items,
+ const bool is_first)
+{
+ AttributeSearchData *data = static_cast<AttributeSearchData *>(arg);
+
+ const geo_log::GeometryValueLog *geometry_log = data->is_output ?
+ data->modifier_log.output_geometry_log() :
+ data->modifier_log.input_geometry_log();
+ if (geometry_log == nullptr) {
+ return;
+ }
+
+ Span<GeometryAttributeInfo> infos = geometry_log->attributes();
+
+ /* The shared attribute search code expects a span of pointers, so convert to that. */
+ Array<const GeometryAttributeInfo *> info_ptrs(infos.size());
+ for (const int i : infos.index_range()) {
+ info_ptrs[i] = &infos[i];
+ }
+ blender::ui::attribute_search_add_items(
+ 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)
+{
+ if (item_v == nullptr) {
+ return;
+ }
+ AttributeSearchData &data = *static_cast<AttributeSearchData *>(data_v);
+ const GeometryAttributeInfo &item = *static_cast<const GeometryAttributeInfo *>(item_v);
+
+ IDProperty &name_property = data.name_property;
+ BLI_assert(name_property.type == IDP_STRING);
+ IDP_AssignString(&name_property, item.name.c_str(), 0);
+
+ ED_undo_push(C, "Assign Attribute Name");
+}
+
+static void add_attribute_search_button(uiLayout *layout,
+ const NodesModifierData &nmd,
+ PointerRNA *md_ptr,
+ const StringRefNull rna_path_attribute_name,
+ const bNodeSocket &socket,
+ const bool is_output)
+{
+ const geo_log::ModifierLog *log = static_cast<geo_log::ModifierLog *>(nmd.runtime_eval_log);
+ if (log == nullptr) {
+ uiItemR(layout, md_ptr, rna_path_attribute_name.c_str(), 0, "", ICON_NONE);
+ return;
+ }
+
+ uiBlock *block = uiLayoutGetBlock(layout);
+ uiBut *but = uiDefIconTextButR(block,
+ UI_BTYPE_SEARCH_MENU,
+ 0,
+ ICON_NONE,
+ "",
+ 0,
+ 0,
+ 10 * UI_UNIT_X, /* Dummy value, replaced by layout system. */
+ UI_UNIT_Y,
+ md_ptr,
+ rna_path_attribute_name.c_str(),
+ 0,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ "");
+
+ const std::string use_attribute_prop_name = socket.identifier + attribute_name_suffix;
+ IDProperty *property = IDP_GetPropertyFromGroup(nmd.settings.properties,
+ use_attribute_prop_name.c_str());
+ BLI_assert(property != nullptr);
+ if (property == nullptr) {
+ return;
+ }
+
+ AttributeSearchData *data = OBJECT_GUARDED_NEW(AttributeSearchData,
+ {*log, *property, is_output});
+
+ 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(but,
+ nullptr,
+ attribute_search_update_fn,
+ static_cast<void *>(data),
+ true,
+ nullptr,
+ attribute_search_exec_fn,
+ nullptr);
+}
+
+static void add_attribute_search_or_value_buttons(uiLayout *layout,
+ const NodesModifierData &nmd,
+ PointerRNA *md_ptr,
+ const bNodeSocket &socket)
+{
+ char socket_id_esc[sizeof(socket.identifier) * 2];
+ 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_use_attribute = "[\"" + std::string(socket_id_esc) +
+ use_attribute_suffix + "\"]";
+ const std::string rna_path_attribute_name = "[\"" + std::string(socket_id_esc) +
+ attribute_name_suffix + "\"]";
+
+ uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
+ uiLayout *name_row = uiLayoutRow(split, false);
+ uiLayoutSetAlignment(name_row, UI_LAYOUT_ALIGN_RIGHT);
+ uiItemL(name_row, socket.name, ICON_NONE);
+
+ uiLayout *row = uiLayoutRow(split, true);
+
+ PointerRNA props;
+ uiItemFullO(row,
+ "object.geometry_nodes_input_attribute_toggle",
+ "",
+ ICON_SPREADSHEET,
+ nullptr,
+ WM_OP_INVOKE_DEFAULT,
+ 0,
+ &props);
+ RNA_string_set(&props, "modifier_name", nmd.modifier.name);
+ 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;
+ if (use_attribute) {
+ add_attribute_search_button(row, nmd, md_ptr, rna_path_attribute_name, socket, false);
+ uiItemL(row, "", ICON_BLANK1);
+ }
+ else {
+ uiItemR(row, md_ptr, rna_path.c_str(), 0, "", ICON_NONE);
+ uiItemDecoratorR(row, md_ptr, rna_path.c_str(), 0);
+ }
+}
+
/* 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 correct label displayed in the UI. */
@@ -1166,39 +1323,19 @@ static void draw_property_for_socket(uiLayout *layout,
}
default: {
if (input_has_attribute_toggle(*nmd->node_group, socket_index)) {
- const std::string rna_path_use_attribute = "[\"" + std::string(socket_id_esc) +
- use_attribute_suffix + "\"]";
- const std::string rna_path_attribute_name = "[\"" + std::string(socket_id_esc) +
- attribute_name_suffix + "\"]";
-
- uiLayout *row = uiLayoutRow(layout, true);
- const int use_attribute = RNA_int_get(md_ptr, rna_path_use_attribute.c_str()) != 0;
- if (use_attribute) {
- uiItemR(row, md_ptr, rna_path_attribute_name.c_str(), 0, socket.name, ICON_NONE);
- }
- else {
- uiItemR(row, md_ptr, rna_path, 0, socket.name, ICON_NONE);
- }
- PointerRNA props;
- uiItemFullO(row,
- "object.geometry_nodes_input_attribute_toggle",
- "",
- ICON_SPREADSHEET,
- nullptr,
- WM_OP_INVOKE_DEFAULT,
- 0,
- &props);
- RNA_string_set(&props, "modifier_name", nmd->modifier.name);
- RNA_string_set(&props, "prop_path", rna_path_use_attribute.c_str());
+ add_attribute_search_or_value_buttons(layout, *nmd, md_ptr, socket);
}
else {
- uiItemR(layout, md_ptr, rna_path, 0, socket.name, ICON_NONE);
+ uiLayout *row = uiLayoutRow(layout, false);
+ uiItemR(row, md_ptr, rna_path, 0, socket.name, ICON_NONE);
+ uiItemDecoratorR(row, md_ptr, rna_path, 0);
}
}
}
}
static void draw_property_for_output_socket(uiLayout *layout,
+ const NodesModifierData &nmd,
PointerRNA *md_ptr,
const bNodeSocket &socket)
{
@@ -1207,7 +1344,13 @@ static void draw_property_for_output_socket(uiLayout *layout,
const std::string rna_path_attribute_name = "[\"" + StringRef(socket_id_esc) +
attribute_name_suffix + "\"]";
- uiItemR(layout, md_ptr, rna_path_attribute_name.c_str(), 0, socket.name, ICON_NONE);
+ uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
+ uiLayout *name_row = uiLayoutRow(split, false);
+ uiLayoutSetAlignment(name_row, UI_LAYOUT_ALIGN_RIGHT);
+ uiItemL(name_row, socket.name, ICON_NONE);
+
+ uiLayout *row = uiLayoutRow(split, true);
+ add_attribute_search_button(row, nmd, md_ptr, rna_path_attribute_name, socket, true);
}
static void panel_draw(const bContext *C, Panel *panel)
@@ -1219,7 +1362,9 @@ static void panel_draw(const bContext *C, Panel *panel)
NodesModifierData *nmd = static_cast<NodesModifierData *>(ptr->data);
uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, true);
+ /* Decorators are added manually for supported properties because the
+ * attribute/value toggle requires a manually built layout anyway. */
+ uiLayoutSetPropDecorate(layout, false);
uiTemplateID(layout,
C,
@@ -1282,7 +1427,7 @@ static void output_attribute_panel_draw(const bContext *UNUSED(C), Panel *panel)
if (nmd->node_group != nullptr && nmd->settings.properties != nullptr) {
LISTBASE_FOREACH (bNodeSocket *, socket, &nmd->node_group->outputs) {
if (socket_type_has_attribute_toggle(*socket)) {
- draw_property_for_output_socket(layout, ptr, *socket);
+ draw_property_for_output_socket(layout, *nmd, ptr, *socket);
}
}
}