From c8cc169d6fee3dc763075ff9d6fa5ac6722d5dd7 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Wed, 27 Sep 2023 11:09:39 +0200 Subject: [PATCH] Geometry Nodes: add Inspection Index to Repeat Zone Previously, it was only possible to inspect the data from the first iteration. That applied to both, the viewer node as well as socket inspection. Now, there is a new `Inspection Index` setting in the zone properties. It specifies which iteration should be used by the inspection features. In theory we could support features like counting the index from the end, but that can be done separately as well, as it likely requires more UI. Pull Request: https://projects.blender.org/blender/blender/pulls/112818 --- scripts/startup/bl_ui/space_node.py | 2 ++ source/blender/blenkernel/BKE_viewer_path.h | 12 +++++++-- .../blender/blenkernel/intern/viewer_path.cc | 13 ++++++--- .../blender/editors/include/ED_viewer_path.hh | 12 +++++++-- .../editors/screen/workspace_listen.cc | 18 +++++++++---- .../blender/editors/space_node/node_draw.cc | 3 +++ .../blender/editors/space_node/space_node.cc | 6 ++--- source/blender/editors/util/ed_viewer_path.cc | 27 +++++++++++++------ source/blender/makesdna/DNA_node_types.h | 2 +- .../blender/makesrna/intern/rna_nodetree.cc | 8 ++++++ .../geometry/nodes/node_geo_repeat_output.cc | 1 + .../intern/geometry_nodes_lazy_function.cc | 21 +++++++++++++-- .../nodes/intern/geometry_nodes_log.cc | 7 ++--- 13 files changed, 102 insertions(+), 30 deletions(-) diff --git a/scripts/startup/bl_ui/space_node.py b/scripts/startup/bl_ui/space_node.py index 8c816a2605e..db3031b8333 100644 --- a/scripts/startup/bl_ui/space_node.py +++ b/scripts/startup/bl_ui/space_node.py @@ -1140,6 +1140,8 @@ class NODE_PT_repeat_zone_items(Panel): layout.use_property_decorate = False layout.prop(active_item, "socket_type") + layout.prop(output_node, "inspection_index") + # Grease Pencil properties class NODE_PT_annotation(AnnotationDataPanel, Panel): diff --git a/source/blender/blenkernel/BKE_viewer_path.h b/source/blender/blenkernel/BKE_viewer_path.h index fa871166ece..aa78593c81e 100644 --- a/source/blender/blenkernel/BKE_viewer_path.h +++ b/source/blender/blenkernel/BKE_viewer_path.h @@ -35,10 +35,16 @@ struct IDRemapper; extern "C" { #endif +enum ViewerPathEqualFlag { + VIEWER_PATH_EQUAL_FLAG_IGNORE_REPEAT_ITERATION = (1 << 0), +}; + void BKE_viewer_path_init(ViewerPath *viewer_path); void BKE_viewer_path_clear(ViewerPath *viewer_path); void BKE_viewer_path_copy(ViewerPath *dst, const ViewerPath *src); -bool BKE_viewer_path_equal(const ViewerPath *a, const ViewerPath *b); +bool BKE_viewer_path_equal(const ViewerPath *a, + const ViewerPath *b, + ViewerPathEqualFlag flag = ViewerPathEqualFlag(0)); void BKE_viewer_path_blend_write(struct BlendWriter *writer, const ViewerPath *viewer_path); void BKE_viewer_path_blend_read_data(struct BlendDataReader *reader, ViewerPath *viewer_path); void BKE_viewer_path_foreach_id(struct LibraryForeachIDData *data, ViewerPath *viewer_path); @@ -52,7 +58,9 @@ SimulationZoneViewerPathElem *BKE_viewer_path_elem_new_simulation_zone(void); ViewerNodeViewerPathElem *BKE_viewer_path_elem_new_viewer_node(void); RepeatZoneViewerPathElem *BKE_viewer_path_elem_new_repeat_zone(void); ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src); -bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, const ViewerPathElem *b); +bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, + const ViewerPathElem *b, + ViewerPathEqualFlag flag = ViewerPathEqualFlag(0)); void BKE_viewer_path_elem_free(ViewerPathElem *elem); #ifdef __cplusplus diff --git a/source/blender/blenkernel/intern/viewer_path.cc b/source/blender/blenkernel/intern/viewer_path.cc index 2c3783631ad..9fbf8304370 100644 --- a/source/blender/blenkernel/intern/viewer_path.cc +++ b/source/blender/blenkernel/intern/viewer_path.cc @@ -40,13 +40,15 @@ void BKE_viewer_path_copy(ViewerPath *dst, const ViewerPath *src) } } -bool BKE_viewer_path_equal(const ViewerPath *a, const ViewerPath *b) +bool BKE_viewer_path_equal(const ViewerPath *a, + const ViewerPath *b, + const ViewerPathEqualFlag flag) { const ViewerPathElem *elem_a = static_cast(a->path.first); const ViewerPathElem *elem_b = static_cast(b->path.first); while (elem_a != nullptr && elem_b != nullptr) { - if (!BKE_viewer_path_elem_equal(elem_a, elem_b)) { + if (!BKE_viewer_path_elem_equal(elem_a, elem_b, flag)) { return false; } elem_a = elem_a->next; @@ -278,7 +280,9 @@ ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src) return dst; } -bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, const ViewerPathElem *b) +bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, + const ViewerPathElem *b, + const ViewerPathEqualFlag flag) { if (a->type != b->type) { return false; @@ -313,7 +317,8 @@ bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, const ViewerPathElem *b const auto *a_elem = reinterpret_cast(a); const auto *b_elem = reinterpret_cast(b); return a_elem->repeat_output_node_id == b_elem->repeat_output_node_id && - a_elem->iteration == b_elem->iteration; + ((flag & VIEWER_PATH_EQUAL_FLAG_IGNORE_REPEAT_ITERATION) != 0 || + a_elem->iteration == b_elem->iteration); } } return false; diff --git a/source/blender/editors/include/ED_viewer_path.hh b/source/blender/editors/include/ED_viewer_path.hh index b8e6b49ac41..c068c03bdc4 100644 --- a/source/blender/editors/include/ED_viewer_path.hh +++ b/source/blender/editors/include/ED_viewer_path.hh @@ -62,10 +62,18 @@ bNode *find_geometry_nodes_viewer(const ViewerPath &viewer_path, SpaceNode &snod */ bool exists_geometry_nodes_viewer(const ViewerPathForGeometryNodesViewer &parsed_viewer_path); +enum class UpdateActiveGeometryNodesViewerResult { + StillActive, + Updated, + NotActive, +}; + /** * Checks if the node referenced by the viewer and its entire context is still active, i.e. some - * editor is showing it. + * editor is showing it. If not, the viewer path might be updated in minor ways (like changing the + * repeat zone iteration). */ -bool is_active_geometry_nodes_viewer(const bContext &C, const ViewerPath &viewer_path); +UpdateActiveGeometryNodesViewerResult update_active_geometry_nodes_viewer(const bContext &C, + ViewerPath &viewer_path); } // namespace blender::ed::viewer_path diff --git a/source/blender/editors/screen/workspace_listen.cc b/source/blender/editors/screen/workspace_listen.cc index 8da2e451649..08cf10b5a9a 100644 --- a/source/blender/editors/screen/workspace_listen.cc +++ b/source/blender/editors/screen/workspace_listen.cc @@ -20,12 +20,20 @@ static void validate_viewer_paths(bContext &C, WorkSpace &workspace) return; } - if (blender::ed::viewer_path::is_active_geometry_nodes_viewer(C, workspace.viewer_path)) { - /* The current viewer path is still valid and active. */ - return; + using namespace blender::ed::viewer_path; + + const UpdateActiveGeometryNodesViewerResult result = update_active_geometry_nodes_viewer( + C, workspace.viewer_path); + switch (result) { + case UpdateActiveGeometryNodesViewerResult::StillActive: + return; + case UpdateActiveGeometryNodesViewerResult::Updated: + break; + case UpdateActiveGeometryNodesViewerResult::NotActive: + BKE_viewer_path_clear(&workspace.viewer_path); + break; } - /* Reset inactive viewer path. */ - BKE_viewer_path_clear(&workspace.viewer_path); + WM_event_add_notifier(&C, NC_VIEWER_PATH, nullptr); } diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index d1ba61e8dd9..9d87121572a 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -2192,6 +2192,9 @@ static void node_add_error_message_button(const TreeDrawContext &tree_draw_ctx, return nullptr; } const bNodeTreeZone *zone = zones->get_zone_by_node(node.identifier); + if (zone && ELEM(&node, zone->input_node, zone->output_node)) { + zone = zone->parent_zone; + } return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr); }(); diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc index 4354baa81ec..ee413e8a6a0 100644 --- a/source/blender/editors/space_node/space_node.cc +++ b/source/blender/editors/space_node/space_node.cc @@ -363,10 +363,10 @@ bool push_compute_context_for_tree_path(const SpaceNode &snode, break; } case GEO_NODE_REPEAT_OUTPUT: { - /* Only show data from the first iteration for now. */ - const int repeat_iteration = 0; + const auto &storage = *static_cast( + zone->output_node->storage); compute_context_builder.push(*zone->output_node, - repeat_iteration); + storage.inspection_index); break; } } diff --git a/source/blender/editors/util/ed_viewer_path.cc b/source/blender/editors/util/ed_viewer_path.cc index 9db5bcbeb78..f7b47a68781 100644 --- a/source/blender/editors/util/ed_viewer_path.cc +++ b/source/blender/editors/util/ed_viewer_path.cc @@ -16,6 +16,7 @@ #include "BLI_vector.hh" #include "DNA_modifier_types.h" +#include "DNA_node_types.h" #include "DNA_windowmanager_types.h" #include "DEG_depsgraph.hh" @@ -36,9 +37,10 @@ static ViewerPathElem *viewer_path_elem_for_zone(const bNodeTreeZone &zone) return &node_elem->base; } case GEO_NODE_REPEAT_OUTPUT: { + const auto &storage = *static_cast(zone.output_node->storage); RepeatZoneViewerPathElem *node_elem = BKE_viewer_path_elem_new_repeat_zone(); node_elem->repeat_output_node_id = zone.output_node->identifier; - node_elem->iteration = 0; + node_elem->iteration = storage.inspection_index; return &node_elem->base; } } @@ -354,14 +356,15 @@ bool exists_geometry_nodes_viewer(const ViewerPathForGeometryNodesViewer &parsed return true; } -bool is_active_geometry_nodes_viewer(const bContext &C, const ViewerPath &viewer_path) +UpdateActiveGeometryNodesViewerResult update_active_geometry_nodes_viewer(const bContext &C, + ViewerPath &viewer_path) { if (BLI_listbase_is_empty(&viewer_path.path)) { - return false; + return UpdateActiveGeometryNodesViewerResult::NotActive; } const ViewerPathElem *last_elem = static_cast(viewer_path.path.last); if (last_elem->type != VIEWER_PATH_ELEM_TYPE_VIEWER_NODE) { - return false; + return UpdateActiveGeometryNodesViewerResult::NotActive; } const int32_t viewer_node_id = reinterpret_cast(last_elem)->node_id; @@ -369,7 +372,7 @@ bool is_active_geometry_nodes_viewer(const bContext &C, const ViewerPath &viewer const Main *bmain = CTX_data_main(&C); const wmWindowManager *wm = static_cast(bmain->wm.first); if (wm == nullptr) { - return false; + return UpdateActiveGeometryNodesViewerResult::NotActive; } LISTBASE_FOREACH (const wmWindow *, window, &wm->windows) { const bScreen *active_screen = BKE_workspace_active_screen_get(window->workspace_hook); @@ -405,14 +408,22 @@ bool is_active_geometry_nodes_viewer(const bContext &C, const ViewerPath &viewer ViewerPath tmp_viewer_path{}; BLI_SCOPED_DEFER([&]() { BKE_viewer_path_clear(&tmp_viewer_path); }); viewer_path_for_geometry_node(snode, *viewer_node, tmp_viewer_path); - if (!BKE_viewer_path_equal(&viewer_path, &tmp_viewer_path)) { + if (!BKE_viewer_path_equal( + &viewer_path, &tmp_viewer_path, VIEWER_PATH_EQUAL_FLAG_IGNORE_REPEAT_ITERATION)) + { continue; } - return true; + if (!BKE_viewer_path_equal(&viewer_path, &tmp_viewer_path)) { + std::swap(viewer_path, tmp_viewer_path); + /* Make sure the viewed data becomes available. */ + DEG_id_tag_update(snode.id, ID_RECALC_GEOMETRY); + return UpdateActiveGeometryNodesViewerResult::Updated; + } + return UpdateActiveGeometryNodesViewerResult::StillActive; } } } - return false; + return UpdateActiveGeometryNodesViewerResult::NotActive; } bNode *find_geometry_nodes_viewer(const ViewerPath &viewer_path, SpaceNode &snode) diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 409f330dd33..fb99ee15e70 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1830,7 +1830,7 @@ typedef struct NodeGeometryRepeatOutput { int active_index; /** Identifier to give to the next repeat item. */ int next_identifier; - char _pad[4]; + int inspection_index; #ifdef __cplusplus blender::Span items_span() const; diff --git a/source/blender/makesrna/intern/rna_nodetree.cc b/source/blender/makesrna/intern/rna_nodetree.cc index 4ba3b8b7ccb..b3302239045 100644 --- a/source/blender/makesrna/intern/rna_nodetree.cc +++ b/source/blender/makesrna/intern/rna_nodetree.cc @@ -9091,6 +9091,14 @@ static void def_geo_repeat_output(StructRNA *srna) RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NO_DEG_UPDATE); RNA_def_property_ui_text(prop, "Active Item Index", "Index of the active item"); RNA_def_property_update(prop, NC_NODE, nullptr); + + prop = RNA_def_property(srna, "inspection_index", PROP_INT, PROP_NONE); + RNA_def_property_ui_range(prop, 0, INT32_MAX, 1, -1); + RNA_def_property_ui_text(prop, + "Inspection Index", + "Iteration index that is used by inspection features like the viewer " + "node or socket inspection"); + RNA_def_property_update(prop, NC_NODE, "rna_Node_update"); } static void def_geo_curve_handle_type_selection(StructRNA *srna) 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 b641502bc72..b5038bd441a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_repeat_output.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_repeat_output.cc @@ -161,6 +161,7 @@ static void node_copy_storage(bNodeTree * /*dst_tree*/, bNode *dst_node, const b dst_storage->items_num = src_storage.items_num; dst_storage->active_index = src_storage.active_index; dst_storage->next_identifier = src_storage.next_identifier; + dst_storage->inspection_index = src_storage.inspection_index; for (const int i : IndexRange(src_storage.items_num)) { if (char *name = src_storage.items[i].name) { dst_storage->items[i].identifier = src_storage.items[i].identifier; diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index cfd92a4a401..92f98cfd947 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -1629,6 +1629,9 @@ class LazyFunctionForRepeatZone : public LazyFunction { void execute_impl(lf::Params ¶ms, const lf::Context &context) const override { + auto &user_data = *static_cast(context.user_data); + auto &local_user_data = *static_cast(context.local_user_data); + const NodeGeometryRepeatOutput &node_storage = *static_cast( repeat_output_bnode_.storage); RepeatEvalStorage &eval_storage = *static_cast(context.storage); @@ -1641,7 +1644,8 @@ class LazyFunctionForRepeatZone : public LazyFunction { if (!eval_storage.graph_executor) { /* Create the execution graph in the first evaluation. */ - this->initialize_execution_graph(params, eval_storage, node_storage); + this->initialize_execution_graph( + params, eval_storage, node_storage, user_data, local_user_data); } /* Execute the graph for the repeat zone. */ @@ -1661,7 +1665,9 @@ class LazyFunctionForRepeatZone : public LazyFunction { */ void initialize_execution_graph(lf::Params ¶ms, RepeatEvalStorage &eval_storage, - const NodeGeometryRepeatOutput &node_storage) const + const NodeGeometryRepeatOutput &node_storage, + GeoNodesLFUserData &user_data, + GeoNodesLFLocalUserData &local_user_data) const { const int num_repeat_items = node_storage.items_num; const int num_border_links = body_fn_.indices.inputs.border_links.size(); @@ -1669,6 +1675,17 @@ class LazyFunctionForRepeatZone : public LazyFunction { /* Number of iterations to evaluate. */ const int iterations = std::max( 0, params.get_input>(zone_info_.indices.inputs.main[0]).as_value()); + + /* Show a warning when the inspection index is out of range. */ + if (node_storage.inspection_index < 0 || node_storage.inspection_index >= iterations) { + if (geo_eval_log::GeoTreeLogger *tree_logger = local_user_data.try_get_tree_logger( + user_data)) { + tree_logger->node_warnings.append( + {repeat_output_bnode_.identifier, + {NodeWarningType::Info, N_("Inspection index is out of range")}}); + } + } + /* Take iterations input into account. */ const int main_inputs_offset = 1; diff --git a/source/blender/nodes/intern/geometry_nodes_log.cc b/source/blender/nodes/intern/geometry_nodes_log.cc index c9dbe317517..126e1b8dd07 100644 --- a/source/blender/nodes/intern/geometry_nodes_log.cc +++ b/source/blender/nodes/intern/geometry_nodes_log.cc @@ -492,9 +492,10 @@ static void find_tree_zone_hash_recursive( break; } case GEO_NODE_REPEAT_OUTPUT: { - /* Only show data from the first iteration for now. */ - const int iteration = 0; - compute_context_builder.push(*zone.output_node, iteration); + const auto &storage = *static_cast( + zone.output_node->storage); + compute_context_builder.push(*zone.output_node, + storage.inspection_index); break; } }