Geometry Nodes: add Inspection Index to Repeat Zone #112818

Merged
Jacques Lucke merged 7 commits from JacquesLucke/blender:repeat-viewer-iteration into main 2023-09-27 11:09:46 +02:00
13 changed files with 102 additions and 30 deletions

View File

@ -1142,6 +1142,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):

View File

@ -35,10 +35,16 @@ struct IDRemapper;
extern "C" {
#endif
enum ViewerPathEqualFlag {
Review

An enum class would be much prettier here ;)

An `enum class` would be much prettier here ;)
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

View File

@ -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<const ViewerPathElem *>(a->path.first);
const ViewerPathElem *elem_b = static_cast<const ViewerPathElem *>(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<const RepeatZoneViewerPathElem *>(a);
const auto *b_elem = reinterpret_cast<const RepeatZoneViewerPathElem *>(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;

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}();

View File

@ -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<const NodeGeometryRepeatOutput *>(
zone->output_node->storage);
compute_context_builder.push<bke::RepeatZoneComputeContext>(*zone->output_node,
repeat_iteration);
storage.inspection_index);
break;
}
}

View File

@ -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<NodeGeometryRepeatOutput *>(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<ViewerPathElem *>(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<const ViewerNodeViewerPathElem *>(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<wmWindowManager *>(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)

View File

@ -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<NodeRepeatItem> items_span() const;

View File

@ -9089,6 +9089,14 @@ static void def_geo_repeat_output(StructRNA *srna)
RNA_def_property_flag(prop, PROP_EDITABLE);
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)

View File

@ -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;

View File

@ -1629,6 +1629,9 @@ class LazyFunctionForRepeatZone : public LazyFunction {
void execute_impl(lf::Params &params, const lf::Context &context) const override
{
auto &user_data = *static_cast<GeoNodesLFUserData *>(context.user_data);
auto &local_user_data = *static_cast<GeoNodesLFLocalUserData *>(context.local_user_data);
const NodeGeometryRepeatOutput &node_storage = *static_cast<const NodeGeometryRepeatOutput *>(
repeat_output_bnode_.storage);
RepeatEvalStorage &eval_storage = *static_cast<RepeatEvalStorage *>(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 &params,
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<int>(
0, params.get_input<ValueOrField<int>>(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;

View File

@ -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<bke::RepeatZoneComputeContext>(*zone.output_node, iteration);
const auto &storage = *static_cast<const NodeGeometryRepeatOutput *>(
zone.output_node->storage);
compute_context_builder.push<bke::RepeatZoneComputeContext>(*zone.output_node,
storage.inspection_index);
break;
}
}