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
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/blender/CMakeLists.txt1
-rw-r--r--source/blender/blenkernel/BKE_duplilist.h13
-rw-r--r--source/blender/blenkernel/BKE_geometry_fields.hh17
-rw-r--r--source/blender/blenkernel/BKE_viewer_path.h58
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/geometry_fields.cc171
-rw-r--r--source/blender/blenkernel/intern/node.cc6
-rw-r--r--source/blender/blenkernel/intern/object_dupli.cc100
-rw-r--r--source/blender/blenkernel/intern/screen.c9
-rw-r--r--source/blender/blenkernel/intern/viewer_path.cc270
-rw-r--r--source/blender/blenkernel/intern/workspace.cc10
-rw-r--r--source/blender/blenloader/intern/readfile.cc23
-rw-r--r--source/blender/blenloader/intern/versioning_280.c2
-rw-r--r--source/blender/blenloader/intern/versioning_300.cc13
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h10
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_iter.cc45
-rw-r--r--source/blender/draw/CMakeLists.txt7
-rw-r--r--source/blender/draw/engines/overlay/overlay_engine.cc18
-rw-r--r--source/blender/draw/engines/overlay/overlay_private.hh16
-rw-r--r--source/blender/draw/engines/overlay/overlay_shader.cc66
-rw-r--r--source/blender/draw/engines/overlay/overlay_viewer_attribute.cc181
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh12
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_viewer_attribute_info.hh62
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_pointcloud_only_vert.glsl9
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_curve_vert.glsl9
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_curves_vert.glsl28
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_frag.glsl6
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_mesh_vert.glsl9
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_pointcloud_vert.glsl10
-rw-r--r--source/blender/draw/intern/draw_cache.c19
-rw-r--r--source/blender/draw/intern/draw_cache.h3
-rw-r--r--source/blender/draw/intern/draw_cache_extract.hh3
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc1
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h3
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curve.cc45
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.cc27
-rw-r--r--source/blender/draw/intern/draw_cache_impl_pointcloud.cc47
-rw-r--r--source/blender/draw/intern/draw_manager.c10
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh.hh1
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc38
-rw-r--r--source/blender/draw/tests/shaders_test.cc5
-rw-r--r--source/blender/editors/include/ED_screen.h2
-rw-r--r--source/blender/editors/include/ED_spreadsheet.h22
-rw-r--r--source/blender/editors/include/ED_viewer_path.hh69
-rw-r--r--source/blender/editors/screen/CMakeLists.txt1
-rw-r--r--source/blender/editors/screen/workspace_listen.cc37
-rw-r--r--source/blender/editors/space_node/node_draw.cc54
-rw-r--r--source/blender/editors/space_node/node_edit.cc44
-rw-r--r--source/blender/editors/space_node/node_intern.hh1
-rw-r--r--source/blender/editors/space_node/node_ops.cc2
-rw-r--r--source/blender/editors/space_node/node_relationships.cc237
-rw-r--r--source/blender/editors/space_node/node_select.cc20
-rw-r--r--source/blender/editors/space_node/space_node.cc3
-rw-r--r--source/blender/editors/space_spreadsheet/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc213
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_context.cc591
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_context.hh13
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc73
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh2
-rw-r--r--source/blender/editors/space_view3d/space_view3d.cc23
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.cc23
-rw-r--r--source/blender/editors/util/CMakeLists.txt1
-rw-r--r--source/blender/editors/util/ed_viewer_path.cc362
-rw-r--r--source/blender/gpu/CMakeLists.txt1
-rw-r--r--source/blender/makesdna/DNA_node_types.h2
-rw-r--r--source/blender/makesdna/DNA_space_types.h36
-rw-r--r--source/blender/makesdna/DNA_view3d_defaults.h4
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h10
-rw-r--r--source/blender/makesdna/DNA_viewer_path_types.h40
-rw-r--r--source/blender/makesdna/DNA_workspace_types.h8
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c6
-rw-r--r--source/blender/makesrna/intern/rna_space.c165
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc95
-rw-r--r--source/blender/nodes/NOD_geometry_nodes_log.hh7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc11
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc31
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_selection.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_shortest_edge_paths.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_interpolate_domain.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_selection.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc58
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_viewer.cc14
-rw-r--r--source/blender/nodes/intern/geometry_nodes_lazy_function.cc40
-rw-r--r--source/blender/nodes/intern/geometry_nodes_log.cc55
-rw-r--r--source/blender/windowmanager/WM_types.h2
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.cc1
102 files changed, 2614 insertions, 1285 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index 28c15d9224c..4dd596ad93a 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -82,6 +82,7 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_view2d_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_view3d_enums.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_view3d_types.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_viewer_path_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_volume_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_windowmanager_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_workspace_types.h
diff --git a/source/blender/blenkernel/BKE_duplilist.h b/source/blender/blenkernel/BKE_duplilist.h
index 0648cdde529..831cb5031c2 100644
--- a/source/blender/blenkernel/BKE_duplilist.h
+++ b/source/blender/blenkernel/BKE_duplilist.h
@@ -16,6 +16,8 @@ struct ListBase;
struct Object;
struct ParticleSystem;
struct Scene;
+struct ViewerPath;
+struct GeomerySet;
/* ---------------------------------------------------- */
/* Dupli-Geometry */
@@ -26,6 +28,13 @@ struct Scene;
struct ListBase *object_duplilist(struct Depsgraph *depsgraph,
struct Scene *sce,
struct Object *ob);
+/**
+ * \return a #ListBase of #DupliObject for the preview geometry referenced by the #ViewerPath.
+ */
+struct ListBase *object_duplilist_preview(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob,
+ const struct ViewerPath *viewer_path);
void free_object_duplilist(struct ListBase *lb);
typedef struct DupliObject {
@@ -39,6 +48,10 @@ typedef struct DupliObject {
short type; /* from Object.transflag */
char no_draw;
+ /* If this dupli object is belongs to a preview, this is non-null. */
+ const struct GeometrySet *preview_base_geometry;
+ /* Index of the top-level instance this dupli is part of or -1 when unused. */
+ int preview_instance_index;
/* Persistent identifier for a dupli object, for inter-frame matching of
* objects with motion blur, or inter-update matching for syncing. */
diff --git a/source/blender/blenkernel/BKE_geometry_fields.hh b/source/blender/blenkernel/BKE_geometry_fields.hh
index 62aac5a4120..988e0017f04 100644
--- a/source/blender/blenkernel/BKE_geometry_fields.hh
+++ b/source/blender/blenkernel/BKE_geometry_fields.hh
@@ -145,6 +145,7 @@ class GeometryFieldInput : public fn::FieldInput {
ResourceScope &scope) const override;
virtual GVArray get_varray_for_context(const GeometryFieldContext &context,
IndexMask mask) const = 0;
+ virtual std::optional<eAttrDomain> preferred_domain(const GeometryComponent &component) const;
};
class MeshFieldInput : public fn::FieldInput {
@@ -156,6 +157,7 @@ class MeshFieldInput : public fn::FieldInput {
virtual GVArray get_varray_for_context(const Mesh &mesh,
eAttrDomain domain,
IndexMask mask) const = 0;
+ virtual std::optional<eAttrDomain> preferred_domain(const Mesh &mesh) const;
};
class CurvesFieldInput : public fn::FieldInput {
@@ -167,6 +169,7 @@ class CurvesFieldInput : public fn::FieldInput {
virtual GVArray get_varray_for_context(const CurvesGeometry &curves,
eAttrDomain domain,
IndexMask mask) const = 0;
+ virtual std::optional<eAttrDomain> preferred_domain(const CurvesGeometry &curves) const;
};
class PointCloudFieldInput : public fn::FieldInput {
@@ -218,6 +221,7 @@ class AttributeFieldInput : public GeometryFieldInput {
uint64_t hash() const override;
bool is_equal_to(const fn::FieldNode &other) const override;
+ std::optional<eAttrDomain> preferred_domain(const GeometryComponent &component) const override;
};
class IDAttributeFieldInput : public GeometryFieldInput {
@@ -292,6 +296,7 @@ class AnonymousAttributeFieldInput : public GeometryFieldInput {
uint64_t hash() const override;
bool is_equal_to(const fn::FieldNode &other) const override;
+ std::optional<eAttrDomain> preferred_domain(const GeometryComponent &component) const override;
};
class CurveLengthFieldInput final : public CurvesFieldInput {
@@ -304,4 +309,16 @@ class CurveLengthFieldInput final : public CurvesFieldInput {
bool is_equal_to(const fn::FieldNode &other) const override;
};
+bool try_capture_field_on_geometry(GeometryComponent &component,
+ const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const fn::GField &field);
+
+/**
+ * Try to find the geometry domain that the field should be evaluated on. If it is not obvious
+ * which domain is correct, none is returned.
+ */
+std::optional<eAttrDomain> try_detect_field_domain(const GeometryComponent &component,
+ const fn::GField &field);
+
} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_viewer_path.h b/source/blender/blenkernel/BKE_viewer_path.h
new file mode 100644
index 00000000000..dfba289531f
--- /dev/null
+++ b/source/blender/blenkernel/BKE_viewer_path.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+/**
+ * A #ViewerPath is a path to data that is viewed/debugged by the user. It is a list of
+ * #ViewerPathElem.
+ *
+ * This is only used for geometry nodes currently. When the user activates a viewer node the
+ * corresponding path contains the following elements:
+ * - Object the viewer is activated on.
+ * - Modifier that contains the corresponding geometry node group.
+ * - Node tree path in case the viewer node is in a nested node group.
+ * - Viewer node name.
+ *
+ * The entire path is necessary (instead of just the combination of node group and viewer name),
+ * because the same node group may be used in many different places.
+ *
+ * This file contains basic functions for creating/deleting a #ViewerPath. For more use-case
+ * specific functions look in `ED_viewer_path.hh`.
+ */
+
+#include "DNA_viewer_path_types.h"
+
+struct BlendWriter;
+struct BlendDataReader;
+struct BlendLibReader;
+struct LibraryForeachIDData;
+struct Library;
+struct IDRemapper;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+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);
+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_blend_read_lib(struct BlendLibReader *reader,
+ struct Library *lib,
+ ViewerPath *viewer_path);
+void BKE_viewer_path_foreach_id(struct LibraryForeachIDData *data, ViewerPath *viewer_path);
+void BKE_viewer_path_id_remap(ViewerPath *viewer_path, const struct IDRemapper *mappings);
+
+ViewerPathElem *BKE_viewer_path_elem_new(ViewerPathElemType type);
+IDViewerPathElem *BKE_viewer_path_elem_new_id(void);
+ModifierViewerPathElem *BKE_viewer_path_elem_new_modifier(void);
+NodeViewerPathElem *BKE_viewer_path_elem_new_node(void);
+ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src);
+bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, const ViewerPathElem *b);
+void BKE_viewer_path_elem_free(ViewerPathElem *elem);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 877407a644c..ff6f279b9c6 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -297,6 +297,7 @@ set(SRC
intern/unit.c
intern/vfont.c
intern/vfontdata_freetype.c
+ intern/viewer_path.cc
intern/volume.cc
intern/volume_render.cc
intern/volume_to_mesh.cc
@@ -482,6 +483,7 @@ set(SRC
BKE_unit.h
BKE_vfont.h
BKE_vfontdata.h
+ BKE_viewer_path.h
BKE_volume.h
BKE_volume_render.h
BKE_volume_to_mesh.hh
diff --git a/source/blender/blenkernel/intern/geometry_fields.cc b/source/blender/blenkernel/intern/geometry_fields.cc
index 56e9e9dcdff..e242154cb5b 100644
--- a/source/blender/blenkernel/intern/geometry_fields.cc
+++ b/source/blender/blenkernel/intern/geometry_fields.cc
@@ -157,6 +157,12 @@ GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &conte
return {};
}
+std::optional<eAttrDomain> GeometryFieldInput::preferred_domain(
+ const GeometryComponent & /*component*/) const
+{
+ return std::nullopt;
+}
+
GVArray MeshFieldInput::get_varray_for_context(const fn::FieldContext &context,
const IndexMask mask,
ResourceScope & /*scope*/) const
@@ -173,6 +179,11 @@ GVArray MeshFieldInput::get_varray_for_context(const fn::FieldContext &context,
return {};
}
+std::optional<eAttrDomain> MeshFieldInput::preferred_domain(const Mesh & /*mesh*/) const
+{
+ return std::nullopt;
+}
+
GVArray CurvesFieldInput::get_varray_for_context(const fn::FieldContext &context,
IndexMask mask,
ResourceScope & /*scope*/) const
@@ -190,6 +201,12 @@ GVArray CurvesFieldInput::get_varray_for_context(const fn::FieldContext &context
return {};
}
+std::optional<eAttrDomain> CurvesFieldInput::preferred_domain(
+ const CurvesGeometry & /*curves*/) const
+{
+ return std::nullopt;
+}
+
GVArray PointCloudFieldInput::get_varray_for_context(const fn::FieldContext &context,
IndexMask mask,
ResourceScope & /*scope*/) const
@@ -254,6 +271,20 @@ bool AttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
return false;
}
+std::optional<eAttrDomain> AttributeFieldInput::preferred_domain(
+ const GeometryComponent &component) const
+{
+ const std::optional<AttributeAccessor> attributes = component.attributes();
+ if (!attributes.has_value()) {
+ return std::nullopt;
+ }
+ const std::optional<AttributeMetaData> meta_data = attributes->lookup_meta_data(name_);
+ if (!meta_data.has_value()) {
+ return std::nullopt;
+ }
+ return meta_data->domain;
+}
+
static StringRef get_random_id_attribute_name(const eAttrDomain domain)
{
switch (domain) {
@@ -325,6 +356,21 @@ bool AnonymousAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
return false;
}
+std::optional<eAttrDomain> AnonymousAttributeFieldInput::preferred_domain(
+ const GeometryComponent &component) const
+{
+ const std::optional<AttributeAccessor> attributes = component.attributes();
+ if (!attributes.has_value()) {
+ return std::nullopt;
+ }
+ const std::optional<AttributeMetaData> meta_data = attributes->lookup_meta_data(
+ anonymous_id_.get());
+ if (!meta_data.has_value()) {
+ return std::nullopt;
+ }
+ return meta_data->domain;
+}
+
} // namespace blender::bke
/* -------------------------------------------------------------------- */
@@ -360,6 +406,131 @@ bool NormalFieldInput::is_equal_to(const fn::FieldNode &other) const
return dynamic_cast<const NormalFieldInput *>(&other) != nullptr;
}
+bool try_capture_field_on_geometry(GeometryComponent &component,
+ const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const fn::GField &field)
+{
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+ const int domain_size = attributes.domain_size(domain);
+ const CPPType &type = field.cpp_type();
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(type);
+
+ if (domain_size == 0) {
+ return attributes.add(attribute_id, domain, data_type, AttributeInitConstruct{});
+ }
+
+ bke::GeometryFieldContext field_context{component, domain};
+ const IndexMask mask{IndexMask(domain_size)};
+ const bke::AttributeValidator validator = attributes.lookup_validator(attribute_id);
+
+ /* Could avoid allocating a new buffer if:
+ * - We are writing to an attribute that exists already with the correct domain and type.
+ * - The field does not depend on that attribute (we can't easily check for that yet). */
+ void *buffer = MEM_mallocN(type.size() * domain_size, __func__);
+
+ fn::FieldEvaluator evaluator{field_context, &mask};
+ evaluator.add_with_destination(validator.validate_field_if_necessary(field),
+ GMutableSpan{type, buffer, domain_size});
+ evaluator.evaluate();
+
+ if (GAttributeWriter attribute = attributes.lookup_for_write(attribute_id)) {
+ if (attribute.domain == domain && attribute.varray.type() == type) {
+ attribute.varray.set_all(buffer);
+ attribute.finish();
+ type.destruct_n(buffer, domain_size);
+ MEM_freeN(buffer);
+ return true;
+ }
+ }
+ attributes.remove(attribute_id);
+ if (attributes.add(attribute_id, domain, data_type, bke::AttributeInitMoveArray{buffer})) {
+ return true;
+ }
+
+ /* If the name corresponds to a builtin attribute, removing the attribute might fail if
+ * it's required, and adding the attribute might fail if the domain or type is incorrect. */
+ type.destruct_n(buffer, domain_size);
+ MEM_freeN(buffer);
+ return false;
+}
+
+std::optional<eAttrDomain> try_detect_field_domain(const GeometryComponent &component,
+ const fn::GField &field)
+{
+ const GeometryComponentType component_type = component.type();
+ if (component_type == GEO_COMPONENT_TYPE_POINT_CLOUD) {
+ return ATTR_DOMAIN_POINT;
+ }
+ if (component_type == GEO_COMPONENT_TYPE_INSTANCES) {
+ return ATTR_DOMAIN_INSTANCE;
+ }
+ const std::shared_ptr<const fn::FieldInputs> &field_inputs = field.node().field_inputs();
+ if (!field_inputs) {
+ return std::nullopt;
+ }
+ std::optional<eAttrDomain> output_domain;
+ auto handle_domain = [&](const std::optional<eAttrDomain> domain) {
+ if (!domain.has_value()) {
+ return false;
+ }
+ if (output_domain.has_value()) {
+ if (*output_domain != *domain) {
+ return false;
+ }
+ return true;
+ }
+ output_domain = domain;
+ return true;
+ };
+ if (component_type == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return std::nullopt;
+ }
+ for (const fn::FieldInput &field_input : field_inputs->deduplicated_nodes) {
+ if (auto geometry_field_input = dynamic_cast<const GeometryFieldInput *>(&field_input)) {
+ if (!handle_domain(geometry_field_input->preferred_domain(component))) {
+ return std::nullopt;
+ }
+ }
+ else if (auto mesh_field_input = dynamic_cast<const MeshFieldInput *>(&field_input)) {
+ if (!handle_domain(mesh_field_input->preferred_domain(*mesh))) {
+ return std::nullopt;
+ }
+ }
+ else {
+ return std::nullopt;
+ }
+ }
+ }
+ if (component_type == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ const Curves *curves = curve_component.get_for_read();
+ if (curves == nullptr) {
+ return std::nullopt;
+ }
+ for (const fn::FieldInput &field_input : field_inputs->deduplicated_nodes) {
+ if (auto geometry_field_input = dynamic_cast<const GeometryFieldInput *>(&field_input)) {
+ if (!handle_domain(geometry_field_input->preferred_domain(component))) {
+ return std::nullopt;
+ }
+ }
+ else if (auto curves_field_input = dynamic_cast<const CurvesFieldInput *>(&field_input)) {
+ if (!handle_domain(
+ curves_field_input->preferred_domain(CurvesGeometry::wrap(curves->geometry)))) {
+ return std::nullopt;
+ }
+ }
+ else {
+ return std::nullopt;
+ }
+ }
+ }
+ return output_domain;
+}
+
} // namespace blender::bke
/** \} */
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 0dcb2aa3139..7d381ed2a69 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -3114,7 +3114,7 @@ void ntreeSetOutput(bNodeTree *ntree)
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->typeinfo->nclass == NODE_CLASS_OUTPUT) {
/* we need a check for which output node should be tagged like this, below an exception */
- if (node->type == CMP_NODE_OUTPUT_FILE) {
+ if (ELEM(node->type, CMP_NODE_OUTPUT_FILE, GEO_NODE_VIEWER)) {
continue;
}
@@ -3125,8 +3125,8 @@ void ntreeSetOutput(bNodeTree *ntree)
if (ntree->type == NTREE_COMPOSIT) {
/* same type, exception for viewer */
if (tnode->type == node->type ||
- (ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER) &&
- ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER))) {
+ (ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER) &&
+ ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))) {
if (tnode->flag & NODE_DO_OUTPUT) {
output++;
if (output > 1) {
diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc
index e28aaabb4e1..15a4a0bbb32 100644
--- a/source/blender/blenkernel/intern/object_dupli.cc
+++ b/source/blender/blenkernel/intern/object_dupli.cc
@@ -24,8 +24,10 @@
#include "DNA_anim_types.h"
#include "DNA_collection_types.h"
+#include "DNA_curves_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_pointcloud_types.h"
#include "DNA_scene_types.h"
#include "DNA_vfont_types.h"
@@ -44,6 +46,7 @@
#include "BKE_mesh.h"
#include "BKE_mesh_iterators.h"
#include "BKE_mesh_runtime.h"
+#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
@@ -53,13 +56,15 @@
#include "DEG_depsgraph_query.h"
#include "BLI_hash.h"
-#include "BLI_strict_flags.h"
+
+#include "NOD_geometry_nodes_log.hh"
using blender::Array;
using blender::float3;
using blender::float4x4;
using blender::Span;
using blender::Vector;
+namespace geo_log = blender::nodes::geo_eval_log;
/* -------------------------------------------------------------------- */
/** \name Internal Duplicate Context
@@ -75,6 +80,15 @@ struct DupliContext {
Scene *scene;
Object *object;
float space_mat[4][4];
+ /**
+ * Index of the top-level instance that contains this context or -1 when unused.
+ * This is an index into the instances component of #preview_base_geometry.
+ */
+ int preview_instance_index;
+ /**
+ * Top level geometry set that is previewed.
+ */
+ const GeometrySet *preview_base_geometry;
/**
* A stack that contains all the "parent" objects of a particular instance when recursive
@@ -127,6 +141,8 @@ static void init_context(DupliContext *r_ctx,
r_ctx->gen = get_dupli_generator(r_ctx);
r_ctx->duplilist = nullptr;
+ r_ctx->preview_instance_index = -1;
+ r_ctx->preview_base_geometry = nullptr;
}
/**
@@ -139,7 +155,7 @@ static bool copy_dupli_context(
/* XXX annoying, previously was done by passing an ID* argument,
* this at least is more explicit. */
- if (ctx->gen->type == OB_DUPLICOLLECTION) {
+ if (ctx->gen && ctx->gen->type == OB_DUPLICOLLECTION) {
r_ctx->collection = ctx->object->instance_collection;
}
@@ -183,7 +199,9 @@ static DupliObject *make_dupli(
dob->ob = ob;
dob->ob_data = const_cast<ID *>(object_data);
mul_m4_m4m4(dob->mat, (float(*)[4])ctx->space_mat, mat);
- dob->type = ctx->gen->type;
+ dob->type = ctx->gen == nullptr ? 0 : ctx->gen->type;
+ dob->preview_base_geometry = ctx->preview_base_geometry;
+ dob->preview_instance_index = ctx->preview_instance_index;
/* Set persistent id, which is an array with a persistent index for each level
* (particle number, vertex number, ..). by comparing this we can find the same
@@ -780,7 +798,8 @@ static const DupliGenerator gen_dupli_verts_font = {
static void make_duplis_geometry_set_impl(const DupliContext *ctx,
const GeometrySet &geometry_set,
const float parent_transform[4][4],
- bool geometry_set_is_instance)
+ bool geometry_set_is_instance,
+ bool use_new_curves_type)
{
int component_index = 0;
if (ctx->object->type != OB_MESH || geometry_set_is_instance) {
@@ -795,8 +814,15 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
}
if (!ELEM(ctx->object->type, OB_CURVES_LEGACY, OB_FONT, OB_CURVES) || geometry_set_is_instance) {
if (const CurveComponent *component = geometry_set.get_component_for_read<CurveComponent>()) {
- if (const Curve *curve = component->get_curve_for_render()) {
- make_dupli(ctx, ctx->object, &curve->id, parent_transform, component_index++);
+ if (use_new_curves_type) {
+ if (const Curves *curves = component->get_for_read()) {
+ make_dupli(ctx, ctx->object, &curves->id, parent_transform, component_index++);
+ }
+ }
+ else {
+ if (const Curve *curve = component->get_curve_for_render()) {
+ make_dupli(ctx, ctx->object, &curve->id, parent_transform, component_index++);
+ }
}
}
}
@@ -832,17 +858,26 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
const InstanceReference &reference = references[instance_reference_handles[i]];
const int id = almost_unique_ids[i];
+ const DupliContext *ctx_for_instance = instances_ctx;
+ /* Set the #preview_instance_index when necessary. */
+ DupliContext tmp_ctx_for_instance;
+ if (instances_ctx->preview_base_geometry == &geometry_set) {
+ tmp_ctx_for_instance = *instances_ctx;
+ tmp_ctx_for_instance.preview_instance_index = i;
+ ctx_for_instance = &tmp_ctx_for_instance;
+ }
+
switch (reference.type()) {
case InstanceReference::Type::Object: {
Object &object = reference.object();
float matrix[4][4];
mul_m4_m4m4(matrix, parent_transform, instance_offset_matrices[i].values);
- make_dupli(instances_ctx, &object, matrix, id);
+ make_dupli(ctx_for_instance, &object, matrix, id);
float space_matrix[4][4];
mul_m4_m4m4(space_matrix, instance_offset_matrices[i].values, object.imat);
mul_m4_m4_pre(space_matrix, parent_transform);
- make_recursive_duplis(instances_ctx, &object, space_matrix, id);
+ make_recursive_duplis(ctx_for_instance, &object, space_matrix, id);
break;
}
case InstanceReference::Type::Collection: {
@@ -854,14 +889,15 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
mul_m4_m4_pre(collection_matrix, parent_transform);
DupliContext sub_ctx;
- if (!copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id)) {
+ if (!copy_dupli_context(
+ &sub_ctx, ctx_for_instance, ctx_for_instance->object, nullptr, id)) {
break;
}
- eEvaluationMode mode = DEG_get_mode(instances_ctx->depsgraph);
+ eEvaluationMode mode = DEG_get_mode(ctx_for_instance->depsgraph);
int object_id = 0;
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (&collection, object, mode) {
- if (object == instances_ctx->object) {
+ if (object == ctx_for_instance->object) {
continue;
}
@@ -879,8 +915,10 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
mul_m4_m4m4(new_transform, parent_transform, instance_offset_matrices[i].values);
DupliContext sub_ctx;
- if (copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id)) {
- make_duplis_geometry_set_impl(&sub_ctx, reference.geometry_set(), new_transform, true);
+ if (copy_dupli_context(
+ &sub_ctx, ctx_for_instance, ctx_for_instance->object, nullptr, id)) {
+ make_duplis_geometry_set_impl(
+ &sub_ctx, reference.geometry_set(), new_transform, true, false);
}
break;
}
@@ -894,7 +932,7 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
static void make_duplis_geometry_set(const DupliContext *ctx)
{
const GeometrySet *geometry_set = ctx->object->runtime.geometry_set_eval;
- make_duplis_geometry_set_impl(ctx, *geometry_set, ctx->object->obmat, false);
+ make_duplis_geometry_set_impl(ctx, *geometry_set, ctx->object->obmat, false, false);
}
static const DupliGenerator gen_dupli_geometry_set = {
@@ -1632,6 +1670,40 @@ ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob)
return duplilist;
}
+ListBase *object_duplilist_preview(Depsgraph *depsgraph,
+ Scene *sce,
+ Object *ob_eval,
+ const ViewerPath *viewer_path)
+{
+ ListBase *duplilist = MEM_cnew<ListBase>("duplilist");
+ DupliContext ctx;
+ Vector<Object *> instance_stack;
+ instance_stack.append(ob_eval);
+ init_context(&ctx, depsgraph, sce, ob_eval, nullptr, instance_stack);
+ ctx.duplilist = duplilist;
+
+ Object *ob_orig = DEG_get_original_object(ob_eval);
+
+ LISTBASE_FOREACH (ModifierData *, md_orig, &ob_orig->modifiers) {
+ if (md_orig->type != eModifierType_Nodes) {
+ continue;
+ }
+ NodesModifierData *nmd_orig = reinterpret_cast<NodesModifierData *>(md_orig);
+ if (nmd_orig->runtime_eval_log == nullptr) {
+ continue;
+ }
+ geo_log::GeoModifierLog *log = static_cast<geo_log::GeoModifierLog *>(
+ nmd_orig->runtime_eval_log);
+ if (const geo_log::ViewerNodeLog *viewer_log = log->find_viewer_node_log_for_path(
+ *viewer_path)) {
+ ctx.preview_base_geometry = &viewer_log->geometry;
+ make_duplis_geometry_set_impl(
+ &ctx, viewer_log->geometry, ob_eval->obmat, true, ob_eval->type == OB_CURVES);
+ }
+ }
+ return duplilist;
+}
+
void free_object_duplilist(ListBase *lb)
{
BLI_freelistN(lb);
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 8517995a0d8..3e5dbc47c40 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -46,6 +46,7 @@
#include "BKE_lib_query.h"
#include "BKE_node.h"
#include "BKE_screen.h"
+#include "BKE_viewer_path.h"
#include "BKE_workspace.h"
#include "BLO_read_write.h"
@@ -97,6 +98,7 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area
if (v3d->localvd) {
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->localvd->camera, IDWALK_CB_NOP);
}
+ BKE_viewer_path_foreach_id(data, &v3d->viewer_path);
break;
}
case SPACE_GRAPH: {
@@ -197,12 +199,7 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area
}
case SPACE_SPREADSHEET: {
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
- LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
- if (context->type == SPREADSHEET_CONTEXT_OBJECT) {
- BKE_LIB_FOREACHID_PROCESS_IDSUPER(
- data, ((SpreadsheetContextObject *)context)->object, IDWALK_CB_NOP);
- }
- }
+ BKE_viewer_path_foreach_id(data, &sspreadsheet->viewer_path);
break;
}
default:
diff --git a/source/blender/blenkernel/intern/viewer_path.cc b/source/blender/blenkernel/intern/viewer_path.cc
new file mode 100644
index 00000000000..3074a007af4
--- /dev/null
+++ b/source/blender/blenkernel/intern/viewer_path.cc
@@ -0,0 +1,270 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_lib_query.h"
+#include "BKE_lib_remap.h"
+#include "BKE_viewer_path.h"
+
+#include "BLI_index_range.hh"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_string_ref.hh"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLO_read_write.h"
+
+using blender::IndexRange;
+using blender::StringRef;
+
+void BKE_viewer_path_init(ViewerPath *viewer_path)
+{
+ BLI_listbase_clear(&viewer_path->path);
+}
+
+void BKE_viewer_path_clear(ViewerPath *viewer_path)
+{
+ LISTBASE_FOREACH_MUTABLE (ViewerPathElem *, elem, &viewer_path->path) {
+ BKE_viewer_path_elem_free(elem);
+ }
+ BLI_listbase_clear(&viewer_path->path);
+}
+
+void BKE_viewer_path_copy(ViewerPath *dst, const ViewerPath *src)
+{
+ BKE_viewer_path_init(dst);
+ LISTBASE_FOREACH (const ViewerPathElem *, src_elem, &src->path) {
+ ViewerPathElem *new_elem = BKE_viewer_path_elem_copy(src_elem);
+ BLI_addtail(&dst->path, new_elem);
+ }
+}
+
+bool BKE_viewer_path_equal(const ViewerPath *a, const ViewerPath *b)
+{
+ 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)) {
+ return false;
+ }
+ elem_a = elem_a->next;
+ elem_b = elem_b->next;
+ }
+ if (elem_a == nullptr && elem_b == nullptr) {
+ return true;
+ }
+ return false;
+}
+
+void BKE_viewer_path_blend_write(struct BlendWriter *writer, const ViewerPath *viewer_path)
+{
+ LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) {
+ switch (ViewerPathElemType(elem->type)) {
+ case VIEWER_PATH_ELEM_TYPE_ID: {
+ auto typed_elem = reinterpret_cast<IDViewerPathElem *>(elem);
+ BLO_write_struct(writer, IDViewerPathElem, typed_elem);
+ break;
+ }
+ case VIEWER_PATH_ELEM_TYPE_MODIFIER: {
+ auto typed_elem = reinterpret_cast<ModifierViewerPathElem *>(elem);
+ BLO_write_struct(writer, ModifierViewerPathElem, typed_elem);
+ BLO_write_string(writer, typed_elem->modifier_name);
+ break;
+ }
+ case VIEWER_PATH_ELEM_TYPE_NODE: {
+ auto typed_elem = reinterpret_cast<NodeViewerPathElem *>(elem);
+ BLO_write_struct(writer, NodeViewerPathElem, typed_elem);
+ BLO_write_string(writer, typed_elem->node_name);
+ break;
+ }
+ }
+ }
+}
+
+void BKE_viewer_path_blend_read_data(struct BlendDataReader *reader, ViewerPath *viewer_path)
+{
+ BLO_read_list(reader, &viewer_path->path);
+ LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) {
+ switch (ViewerPathElemType(elem->type)) {
+ case VIEWER_PATH_ELEM_TYPE_ID: {
+ break;
+ }
+ case VIEWER_PATH_ELEM_TYPE_MODIFIER: {
+ auto typed_elem = reinterpret_cast<ModifierViewerPathElem *>(elem);
+ BLO_read_data_address(reader, &typed_elem->modifier_name);
+ break;
+ }
+ case VIEWER_PATH_ELEM_TYPE_NODE: {
+ auto typed_elem = reinterpret_cast<NodeViewerPathElem *>(elem);
+ BLO_read_data_address(reader, &typed_elem->node_name);
+ break;
+ }
+ }
+ }
+}
+
+void BKE_viewer_path_blend_read_lib(BlendLibReader *reader, Library *lib, ViewerPath *viewer_path)
+{
+ LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) {
+ switch (ViewerPathElemType(elem->type)) {
+ case VIEWER_PATH_ELEM_TYPE_ID: {
+ auto typed_elem = reinterpret_cast<IDViewerPathElem *>(elem);
+ BLO_read_id_address(reader, lib, &typed_elem->id);
+ break;
+ }
+ case VIEWER_PATH_ELEM_TYPE_MODIFIER:
+ case VIEWER_PATH_ELEM_TYPE_NODE: {
+ break;
+ }
+ }
+ }
+}
+
+void BKE_viewer_path_foreach_id(LibraryForeachIDData *data, ViewerPath *viewer_path)
+{
+ LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) {
+ switch (ViewerPathElemType(elem->type)) {
+ case VIEWER_PATH_ELEM_TYPE_ID: {
+ auto typed_elem = reinterpret_cast<IDViewerPathElem *>(elem);
+ BKE_LIB_FOREACHID_PROCESS_ID(data, typed_elem->id, IDWALK_CB_NOP);
+ break;
+ }
+ case VIEWER_PATH_ELEM_TYPE_MODIFIER:
+ case VIEWER_PATH_ELEM_TYPE_NODE: {
+ break;
+ }
+ }
+ }
+}
+
+void BKE_viewer_path_id_remap(ViewerPath *viewer_path, const IDRemapper *mappings)
+{
+ LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) {
+ switch (ViewerPathElemType(elem->type)) {
+ case VIEWER_PATH_ELEM_TYPE_ID: {
+ auto typed_elem = reinterpret_cast<IDViewerPathElem *>(elem);
+ BKE_id_remapper_apply(mappings, &typed_elem->id, ID_REMAP_APPLY_DEFAULT);
+ break;
+ }
+ case VIEWER_PATH_ELEM_TYPE_MODIFIER:
+ case VIEWER_PATH_ELEM_TYPE_NODE: {
+ break;
+ }
+ }
+ }
+}
+
+ViewerPathElem *BKE_viewer_path_elem_new(const ViewerPathElemType type)
+{
+ switch (type) {
+ case VIEWER_PATH_ELEM_TYPE_ID: {
+ IDViewerPathElem *elem = MEM_cnew<IDViewerPathElem>(__func__);
+ elem->base.type = type;
+ return &elem->base;
+ }
+ case VIEWER_PATH_ELEM_TYPE_MODIFIER: {
+ ModifierViewerPathElem *elem = MEM_cnew<ModifierViewerPathElem>(__func__);
+ elem->base.type = type;
+ return &elem->base;
+ }
+ case VIEWER_PATH_ELEM_TYPE_NODE: {
+ NodeViewerPathElem *elem = MEM_cnew<NodeViewerPathElem>(__func__);
+ elem->base.type = type;
+ return &elem->base;
+ }
+ }
+ BLI_assert_unreachable();
+ return nullptr;
+}
+
+IDViewerPathElem *BKE_viewer_path_elem_new_id()
+{
+ return reinterpret_cast<IDViewerPathElem *>(BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_ID));
+}
+
+ModifierViewerPathElem *BKE_viewer_path_elem_new_modifier()
+{
+ return reinterpret_cast<ModifierViewerPathElem *>(
+ BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_MODIFIER));
+}
+
+NodeViewerPathElem *BKE_viewer_path_elem_new_node()
+{
+ return reinterpret_cast<NodeViewerPathElem *>(
+ BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_NODE));
+}
+
+ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src)
+{
+ ViewerPathElem *dst = BKE_viewer_path_elem_new(ViewerPathElemType(src->type));
+ switch (ViewerPathElemType(src->type)) {
+ case VIEWER_PATH_ELEM_TYPE_ID: {
+ auto old_elem = reinterpret_cast<const IDViewerPathElem *>(src);
+ auto new_elem = reinterpret_cast<IDViewerPathElem *>(dst);
+ new_elem->id = old_elem->id;
+ break;
+ }
+ case VIEWER_PATH_ELEM_TYPE_MODIFIER: {
+ auto old_elem = reinterpret_cast<const ModifierViewerPathElem *>(src);
+ auto new_elem = reinterpret_cast<ModifierViewerPathElem *>(dst);
+ if (old_elem->modifier_name != nullptr) {
+ new_elem->modifier_name = BLI_strdup(old_elem->modifier_name);
+ }
+ break;
+ }
+ case VIEWER_PATH_ELEM_TYPE_NODE: {
+ auto old_elem = reinterpret_cast<const NodeViewerPathElem *>(src);
+ auto new_elem = reinterpret_cast<NodeViewerPathElem *>(dst);
+ if (old_elem->node_name != nullptr) {
+ new_elem->node_name = BLI_strdup(old_elem->node_name);
+ }
+ break;
+ }
+ }
+ return dst;
+}
+
+bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, const ViewerPathElem *b)
+{
+ if (a->type != b->type) {
+ return false;
+ }
+ switch (ViewerPathElemType(a->type)) {
+ case VIEWER_PATH_ELEM_TYPE_ID: {
+ auto a_elem = reinterpret_cast<const IDViewerPathElem *>(a);
+ auto b_elem = reinterpret_cast<const IDViewerPathElem *>(b);
+ return a_elem->id == b_elem->id;
+ }
+ case VIEWER_PATH_ELEM_TYPE_MODIFIER: {
+ auto a_elem = reinterpret_cast<const ModifierViewerPathElem *>(a);
+ auto b_elem = reinterpret_cast<const ModifierViewerPathElem *>(b);
+ return StringRef(a_elem->modifier_name) == StringRef(b_elem->modifier_name);
+ }
+ case VIEWER_PATH_ELEM_TYPE_NODE: {
+ auto a_elem = reinterpret_cast<const NodeViewerPathElem *>(a);
+ auto b_elem = reinterpret_cast<const NodeViewerPathElem *>(b);
+ return StringRef(a_elem->node_name) == StringRef(b_elem->node_name);
+ }
+ }
+ return false;
+}
+
+void BKE_viewer_path_elem_free(ViewerPathElem *elem)
+{
+ switch (ViewerPathElemType(elem->type)) {
+ case VIEWER_PATH_ELEM_TYPE_ID: {
+ break;
+ }
+ case VIEWER_PATH_ELEM_TYPE_MODIFIER: {
+ auto typed_elem = reinterpret_cast<ModifierViewerPathElem *>(elem);
+ MEM_SAFE_FREE(typed_elem->modifier_name);
+ break;
+ }
+ case VIEWER_PATH_ELEM_TYPE_NODE: {
+ auto typed_elem = reinterpret_cast<NodeViewerPathElem *>(elem);
+ MEM_SAFE_FREE(typed_elem->node_name);
+ break;
+ }
+ }
+ MEM_freeN(elem);
+}
diff --git a/source/blender/blenkernel/intern/workspace.cc b/source/blender/blenkernel/intern/workspace.cc
index 8008dacc853..a7fd433b42b 100644
--- a/source/blender/blenkernel/intern/workspace.cc
+++ b/source/blender/blenkernel/intern/workspace.cc
@@ -24,6 +24,7 @@
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_scene.h"
+#include "BKE_viewer_path.h"
#include "BKE_workspace.h"
#include "DNA_object_types.h"
@@ -61,6 +62,7 @@ static void workspace_free_data(ID *id)
}
MEM_SAFE_FREE(workspace->status_text);
+ BKE_viewer_path_clear(&workspace->viewer_path);
}
static void workspace_foreach_id(ID *id, LibraryForeachIDData *data)
@@ -72,6 +74,8 @@ static void workspace_foreach_id(ID *id, LibraryForeachIDData *data)
LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) {
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, layout->screen, IDWALK_CB_USER);
}
+
+ BKE_viewer_path_foreach_id(data, &workspace->viewer_path);
}
static void workspace_blend_write(BlendWriter *writer, ID *id, const void *id_address)
@@ -89,6 +93,8 @@ static void workspace_blend_write(BlendWriter *writer, ID *id, const void *id_ad
IDP_BlendWrite(writer, tref->properties);
}
}
+
+ BKE_viewer_path_blend_write(writer, &workspace->viewer_path);
}
static void workspace_blend_read_data(BlendDataReader *reader, ID *id)
@@ -115,6 +121,8 @@ static void workspace_blend_read_data(BlendDataReader *reader, ID *id)
workspace->status_text = nullptr;
id_us_ensure_real(&workspace->id);
+
+ BKE_viewer_path_blend_read_data(reader, &workspace->viewer_path);
}
static void workspace_blend_read_lib(BlendLibReader *reader, ID *id)
@@ -164,6 +172,8 @@ static void workspace_blend_read_lib(BlendLibReader *reader, ID *id)
BKE_workspace_layout_remove(bmain, workspace, layout);
}
}
+
+ BKE_viewer_path_blend_read_lib(reader, id->lib, &workspace->viewer_path);
}
static void workspace_blend_read_expand(BlendExpander *expander, ID *id)
diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc
index 7c07d373999..d627a93526e 100644
--- a/source/blender/blenloader/intern/readfile.cc
+++ b/source/blender/blenloader/intern/readfile.cc
@@ -2515,6 +2515,17 @@ static void lib_link_window_scene_data_restore(wmWindow *win, Scene *scene, View
}
}
+static void lib_link_restore_viewer_path(struct IDNameLib_Map *id_map, ViewerPath *viewer_path)
+{
+ LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) {
+ if (elem->type == VIEWER_PATH_ELEM_TYPE_ID) {
+ auto typed_elem = reinterpret_cast<IDViewerPathElem *>(elem);
+ typed_elem->id = static_cast<ID *>(
+ restore_pointer_by_name(id_map, (ID *)typed_elem->id, USER_IGNORE));
+ }
+ }
+}
+
static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map,
Main *newmain,
WorkSpaceLayout *layout)
@@ -2532,6 +2543,8 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map,
restore_pointer_by_name(id_map, (ID *)v3d->camera, USER_REAL));
v3d->ob_center = static_cast<Object *>(
restore_pointer_by_name(id_map, (ID *)v3d->ob_center, USER_REAL));
+
+ lib_link_restore_viewer_path(id_map, &v3d->viewer_path);
}
else if (sl->spacetype == SPACE_GRAPH) {
SpaceGraph *sipo = (SpaceGraph *)sl;
@@ -2741,14 +2754,7 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map,
}
else if (sl->spacetype == SPACE_SPREADSHEET) {
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
-
- LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
- if (context->type == SPREADSHEET_CONTEXT_OBJECT) {
- SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context;
- object_context->object = static_cast<Object *>(
- restore_pointer_by_name(id_map, (ID *)object_context->object, USER_IGNORE));
- }
- }
+ lib_link_restore_viewer_path(id_map, &sspreadsheet->viewer_path);
}
}
}
@@ -2770,6 +2776,7 @@ void blo_lib_link_restore(Main *oldmain,
}
workspace->pin_scene = static_cast<Scene *>(
restore_pointer_by_name(id_map, (ID *)workspace->pin_scene, USER_IGNORE));
+ lib_link_restore_viewer_path(id_map, &workspace->viewer_path);
}
LISTBASE_FOREACH (wmWindow *, win, &curwm->windows) {
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 5cbfcb66bf9..3e26516cd69 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -3385,7 +3385,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
View3D *v3d = (View3D *)sl;
v3d->flag &= ~(V3D_LOCAL_COLLECTIONS | V3D_FLAG_UNUSED_1 | V3D_FLAG_UNUSED_10 |
V3D_FLAG_UNUSED_12);
- v3d->flag2 &= ~(V3D_FLAG2_UNUSED_3 | V3D_FLAG2_UNUSED_6 | V3D_FLAG2_UNUSED_12 |
+ v3d->flag2 &= ~((1 << 3) | V3D_FLAG2_UNUSED_6 | V3D_FLAG2_UNUSED_12 |
V3D_FLAG2_UNUSED_13 | V3D_FLAG2_UNUSED_14 | V3D_FLAG2_UNUSED_15);
break;
}
diff --git a/source/blender/blenloader/intern/versioning_300.cc b/source/blender/blenloader/intern/versioning_300.cc
index f0ebc6c7942..11c88a5d69b 100644
--- a/source/blender/blenloader/intern/versioning_300.cc
+++ b/source/blender/blenloader/intern/versioning_300.cc
@@ -3586,5 +3586,18 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
+
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->flag2 |= V3D_SHOW_VIEWER;
+ v3d->overlay.flag |= V3D_OVERLAY_VIEWER_ATTRIBUTE;
+ v3d->overlay.viewer_attribute_opacity = 0.8f;
+ }
+ }
+ }
+ }
}
}
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index d832676fe2c..4a9025641f9 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -27,6 +27,7 @@ struct ListBase;
struct PointerRNA;
struct Scene;
struct ViewLayer;
+struct ViewerPath;
#ifdef __cplusplus
extern "C" {
@@ -152,6 +153,12 @@ typedef struct DEGObjectIterSettings {
* and will crash if you try to access it.
*/
uint32_t flags;
+
+ /**
+ * When set, the final evaluated geometry of the corresponding object is omitted. Instead the
+ * geometry for the viewer path included in the iterator.
+ */
+ const struct ViewerPath *viewer_path;
} DEGObjectIterSettings;
/**
@@ -170,6 +177,9 @@ typedef struct DEGObjectIterData {
eEvaluationMode eval_mode;
+ /** Object whose preview instead of evaluated geometry should be part of the iterator. */
+ struct Object *object_orig_with_preview;
+
struct Object *next_object;
/* **** Iteration over dupli-list. *** */
diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
index bcae5de1e1e..5a92f483420 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
@@ -127,14 +127,11 @@ bool deg_object_hide_original(eEvaluationMode eval_mode, Object *ob, DupliObject
return false;
}
-void deg_iterator_duplis_init(DEGObjectIterData *data, Object *object)
+void deg_iterator_duplis_init(DEGObjectIterData *data, Object *object, ListBase *duplis)
{
- if ((data->flag & DEG_ITER_OBJECT_FLAG_DUPLI) &&
- ((object->transflag & OB_DUPLI) || object->runtime.geometry_set_eval != nullptr)) {
- data->dupli_parent = object;
- data->dupli_list = object_duplilist(data->graph, data->scene, object);
- data->dupli_object_next = (DupliObject *)data->dupli_list->first;
- }
+ data->dupli_parent = object;
+ data->dupli_list = duplis;
+ data->dupli_object_next = static_cast<DupliObject *>(duplis->first);
}
/* Returns false when iterator is exhausted. */
@@ -250,7 +247,18 @@ bool deg_iterator_objects_step(DEGObjectIterData *data)
}
Object *object = (Object *)id_node->id_cow;
+ Object *object_orig = DEG_get_original_object(object);
BLI_assert(deg::deg_validate_copy_on_write_datablock(&object->id));
+ object->runtime.select_id = object_orig->runtime.select_id;
+
+ const bool use_preview = object_orig == data->object_orig_with_preview;
+ if (use_preview) {
+ ListBase *preview_duplis = object_duplilist_preview(
+ data->graph, data->scene, object, data->settings->viewer_path);
+ deg_iterator_duplis_init(data, object, preview_duplis);
+ data->id_node_index++;
+ return true;
+ }
int ob_visibility = OB_VISIBLE_ALL;
if (data->flag & DEG_ITER_OBJECT_FLAG_VISIBLE) {
@@ -261,9 +269,12 @@ bool deg_iterator_objects_step(DEGObjectIterData *data)
}
}
- object->runtime.select_id = DEG_get_original_object(object)->runtime.select_id;
if (ob_visibility & OB_VISIBLE_INSTANCES) {
- deg_iterator_duplis_init(data, object);
+ if ((data->flag & DEG_ITER_OBJECT_FLAG_DUPLI) &&
+ ((object->transflag & OB_DUPLI) || object->runtime.geometry_set_eval != nullptr)) {
+ ListBase *duplis = object_duplilist(data->graph, data->scene, object);
+ deg_iterator_duplis_init(data, object, duplis);
+ }
}
if (ob_visibility & (OB_VISIBLE_SELF | OB_VISIBLE_PARTICLES)) {
@@ -301,6 +312,22 @@ void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data)
data->eval_mode = DEG_get_mode(depsgraph);
deg_invalidate_iterator_work_data(data);
+ /* Determine if the preview of any object should be in the iterator. */
+ const ViewerPath *viewer_path = data->settings->viewer_path;
+ if (viewer_path != nullptr) {
+ if (!BLI_listbase_is_empty(&viewer_path->path)) {
+ const ViewerPathElem *elem = static_cast<const ViewerPathElem *>(viewer_path->path.first);
+ if (elem->type == VIEWER_PATH_ELEM_TYPE_ID) {
+ const IDViewerPathElem *id_elem = reinterpret_cast<const IDViewerPathElem *>(elem);
+ if (id_elem->id != nullptr) {
+ if (GS(id_elem->id->name) == ID_OB) {
+ data->object_orig_with_preview = reinterpret_cast<Object *>(id_elem->id);
+ }
+ }
+ }
+ }
+ }
+
DEG_iterator_objects_next(iter);
}
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 540041ed02a..45a7e3410eb 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -201,6 +201,7 @@ set(SRC
engines/overlay/overlay_sculpt.cc
engines/overlay/overlay_sculpt_curves.cc
engines/overlay/overlay_shader.cc
+ engines/overlay/overlay_viewer_attribute.cc
engines/overlay/overlay_volume.cc
engines/overlay/overlay_wireframe.cc
@@ -645,12 +646,18 @@ set(GLSL_SRC
engines/overlay/shaders/overlay_particle_vert.glsl
engines/overlay/shaders/overlay_point_varying_color_frag.glsl
engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl
+ engines/overlay/shaders/overlay_pointcloud_only_vert.glsl
engines/overlay/shaders/overlay_sculpt_curves_selection_frag.glsl
engines/overlay/shaders/overlay_sculpt_curves_selection_vert.glsl
engines/overlay/shaders/overlay_sculpt_mask_frag.glsl
engines/overlay/shaders/overlay_sculpt_mask_vert.glsl
engines/overlay/shaders/overlay_uniform_color_frag.glsl
engines/overlay/shaders/overlay_varying_color.glsl
+ engines/overlay/shaders/overlay_viewer_attribute_curve_vert.glsl
+ engines/overlay/shaders/overlay_viewer_attribute_curves_vert.glsl
+ engines/overlay/shaders/overlay_viewer_attribute_frag.glsl
+ engines/overlay/shaders/overlay_viewer_attribute_mesh_vert.glsl
+ engines/overlay/shaders/overlay_viewer_attribute_pointcloud_vert.glsl
engines/overlay/shaders/overlay_volume_gridlines_vert.glsl
engines/overlay/shaders/overlay_volume_velocity_vert.glsl
engines/overlay/shaders/overlay_wireframe_frag.glsl
diff --git a/source/blender/draw/engines/overlay/overlay_engine.cc b/source/blender/draw/engines/overlay/overlay_engine.cc
index bbcae92561d..c2c4706138f 100644
--- a/source/blender/draw/engines/overlay/overlay_engine.cc
+++ b/source/blender/draw/engines/overlay/overlay_engine.cc
@@ -16,6 +16,7 @@
#include "UI_interface.h"
+#include "BKE_duplilist.h"
#include "BKE_object.h"
#include "BKE_paint.h"
@@ -204,6 +205,7 @@ static void OVERLAY_cache_init(void *vedata)
}
OVERLAY_antialiasing_cache_init(data);
OVERLAY_armature_cache_init(data);
+ OVERLAY_viewer_attribute_cache_init(data);
OVERLAY_background_cache_init(data);
OVERLAY_fade_cache_init(data);
OVERLAY_mode_transfer_cache_init(data);
@@ -300,8 +302,12 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
}
const DRWContextState *draw_ctx = DRW_context_state_get();
+ DupliObject *dupli_object = DRW_object_get_dupli(ob);
+ Object *dupli_parent = DRW_object_get_dupli_parent(ob);
const bool is_select = DRW_state_is_select();
const bool renderable = DRW_object_is_renderable(ob);
+ const bool is_preview = dupli_object != nullptr &&
+ dupli_object->preview_base_geometry != nullptr;
const bool in_pose_mode = ob->type == OB_ARMATURE && OVERLAY_armature_is_pose_mode(ob, draw_ctx);
const bool in_edit_mode = overlay_object_is_edit_mode(pd, ob);
const bool is_instance = (ob->base_flag & BASE_FROM_DUPLI);
@@ -313,7 +319,8 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
(pd->ctx_mode == CTX_MODE_PARTICLE);
const bool in_paint_mode = (ob == draw_ctx->obact) &&
(draw_ctx->object_mode & OB_MODE_ALL_PAINT);
- const bool in_sculpt_curve_mode = (ob == draw_ctx->obact) &&
+ const bool in_sculpt_curve_mode = (ob == draw_ctx->obact ||
+ (is_preview && dupli_parent == draw_ctx->obact)) &&
(draw_ctx->object_mode & OB_MODE_SCULPT_CURVES);
const bool in_sculpt_mode = (ob == draw_ctx->obact) && (ob->sculpt != nullptr) &&
(ob->sculpt->mode_type == OB_MODE_SCULPT);
@@ -374,6 +381,12 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
OVERLAY_pose_cache_populate(data, ob);
}
+ if (pd->overlay.flag & V3D_OVERLAY_VIEWER_ATTRIBUTE) {
+ if (is_preview) {
+ OVERLAY_viewer_attribute_cache_populate(data, ob);
+ }
+ }
+
if (ob->type == OB_VOLUME) {
OVERLAY_volume_cache_populate(data, ob);
}
@@ -627,6 +640,9 @@ static void OVERLAY_draw_scene(void *vedata)
OVERLAY_metaball_draw(data);
OVERLAY_gpencil_draw(data);
OVERLAY_extra_draw(data);
+ if (pd->overlay.flag & V3D_OVERLAY_VIEWER_ATTRIBUTE) {
+ OVERLAY_viewer_attribute_draw(data);
+ }
if (DRW_state_is_fbo()) {
GPU_framebuffer_bind(fbl->overlay_color_only_fb);
diff --git a/source/blender/draw/engines/overlay/overlay_private.hh b/source/blender/draw/engines/overlay/overlay_private.hh
index 0a783c44029..b1118e084a6 100644
--- a/source/blender/draw/engines/overlay/overlay_private.hh
+++ b/source/blender/draw/engines/overlay/overlay_private.hh
@@ -61,6 +61,7 @@ typedef struct OVERLAY_PassList {
DRWPass *armature_ps[2];
DRWPass *armature_bone_select_ps;
DRWPass *armature_transp_ps[2];
+ DRWPass *attribute_ps;
DRWPass *background_ps;
DRWPass *clipping_frustum_ps;
DRWPass *edit_curve_wire_ps[2];
@@ -284,6 +285,12 @@ typedef struct OVERLAY_PrivateData {
DRWShadingGroup *pointcloud_dots_grp;
DRWShadingGroup *sculpt_mask_grp;
DRWShadingGroup *sculpt_curves_selection_grp;
+ DRWShadingGroup *viewer_attribute_curve_grp;
+ DRWShadingGroup *viewer_attribute_curves_grp;
+ DRWShadingGroup *viewer_attribute_mesh_grp;
+ DRWShadingGroup *viewer_attribute_pointcloud_grp;
+ DRWShadingGroup *viewer_attribute_instance_grp;
+ DRWShadingGroup *viewer_attribute_instance_pointcloud_grp;
DRWShadingGroup *volume_selection_surface_grp;
DRWShadingGroup *wires_grp[2][2]; /* With and without coloring. */
DRWShadingGroup *wires_all_grp[2][2]; /* With and without coloring. */
@@ -678,6 +685,10 @@ void OVERLAY_sculpt_curves_cache_init(OVERLAY_Data *vedata);
void OVERLAY_sculpt_curves_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_sculpt_curves_draw(OVERLAY_Data *vedata);
+void OVERLAY_viewer_attribute_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_viewer_attribute_cache_populate(OVERLAY_Data *vedata, Object *object);
+void OVERLAY_viewer_attribute_draw(OVERLAY_Data *vedata);
+
void OVERLAY_wireframe_init(OVERLAY_Data *vedata);
void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata);
void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
@@ -745,6 +756,7 @@ GPUShader *OVERLAY_shader_image(void);
GPUShader *OVERLAY_shader_motion_path_line(void);
GPUShader *OVERLAY_shader_motion_path_vert(void);
GPUShader *OVERLAY_shader_uniform_color(void);
+GPUShader *OVERLAY_shader_uniform_color_pointcloud(void);
GPUShader *OVERLAY_shader_outline_prepass(bool use_wire);
GPUShader *OVERLAY_shader_outline_prepass_curves(void);
GPUShader *OVERLAY_shader_outline_prepass_gpencil(void);
@@ -761,6 +773,10 @@ GPUShader *OVERLAY_shader_particle_dot(void);
GPUShader *OVERLAY_shader_particle_shape(void);
GPUShader *OVERLAY_shader_sculpt_mask(void);
GPUShader *OVERLAY_shader_sculpt_curves_selection(void);
+GPUShader *OVERLAY_shader_viewer_attribute_curve(void);
+GPUShader *OVERLAY_shader_viewer_attribute_curves(void);
+GPUShader *OVERLAY_shader_viewer_attribute_mesh(void);
+GPUShader *OVERLAY_shader_viewer_attribute_pointcloud(void);
GPUShader *OVERLAY_shader_volume_velocity(bool use_needle, bool use_mac);
GPUShader *OVERLAY_shader_volume_gridlines(bool color_with_flags, bool color_range);
GPUShader *OVERLAY_shader_wireframe(bool custom_bias);
diff --git a/source/blender/draw/engines/overlay/overlay_shader.cc b/source/blender/draw/engines/overlay/overlay_shader.cc
index b0a6926a57f..b7e5e8c56b7 100644
--- a/source/blender/draw/engines/overlay/overlay_shader.cc
+++ b/source/blender/draw/engines/overlay/overlay_shader.cc
@@ -93,6 +93,11 @@ typedef struct OVERLAY_Shaders {
GPUShader *sculpt_mask;
GPUShader *sculpt_curves_selection;
GPUShader *uniform_color;
+ GPUShader *uniform_color_pointcloud;
+ GPUShader *viewer_attribute_mesh;
+ GPUShader *viewer_attribute_pointcloud;
+ GPUShader *viewer_attribute_curve;
+ GPUShader *viewer_attribute_curves;
GPUShader *volume_velocity_needle_sh;
GPUShader *volume_velocity_mac_sh;
GPUShader *volume_velocity_sh;
@@ -818,6 +823,55 @@ GPUShader *OVERLAY_shader_sculpt_curves_selection(void)
return sh_data->sculpt_curves_selection;
}
+GPUShader *OVERLAY_shader_viewer_attribute_mesh(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->viewer_attribute_mesh) {
+ sh_data->viewer_attribute_mesh = GPU_shader_create_from_info_name(
+ draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED ? "overlay_viewer_attribute_mesh_clipped" :
+ "overlay_viewer_attribute_mesh");
+ }
+ return sh_data->viewer_attribute_mesh;
+}
+
+GPUShader *OVERLAY_shader_viewer_attribute_pointcloud(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->viewer_attribute_pointcloud) {
+ sh_data->viewer_attribute_pointcloud = GPU_shader_create_from_info_name(
+ draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED ?
+ "overlay_viewer_attribute_pointcloud_clipped" :
+ "overlay_viewer_attribute_pointcloud");
+ }
+ return sh_data->viewer_attribute_pointcloud;
+}
+
+GPUShader *OVERLAY_shader_viewer_attribute_curve(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->viewer_attribute_curve) {
+ sh_data->viewer_attribute_curve = GPU_shader_create_from_info_name(
+ draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED ? "overlay_viewer_attribute_curve_clipped" :
+ "overlay_viewer_attribute_curve");
+ }
+ return sh_data->viewer_attribute_curve;
+}
+
+GPUShader *OVERLAY_shader_viewer_attribute_curves(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->viewer_attribute_curves) {
+ sh_data->viewer_attribute_curves = GPU_shader_create_from_info_name(
+ draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED ? "overlay_viewer_attribute_curves_clipped" :
+ "overlay_viewer_attribute_curves");
+ }
+ return sh_data->viewer_attribute_curves;
+}
+
struct GPUShader *OVERLAY_shader_uniform_color(void)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
@@ -829,6 +883,18 @@ struct GPUShader *OVERLAY_shader_uniform_color(void)
return sh_data->uniform_color;
}
+struct GPUShader *OVERLAY_shader_uniform_color_pointcloud()
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->uniform_color_pointcloud) {
+ sh_data->uniform_color_pointcloud = GPU_shader_create_from_info_name(
+ draw_ctx->sh_cfg ? "overlay_uniform_color_pointcloud_clipped" :
+ "overlay_uniform_color_pointcloud");
+ }
+ return sh_data->uniform_color_pointcloud;
+}
+
struct GPUShader *OVERLAY_shader_volume_velocity(bool use_needle, bool use_mac)
{
OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
diff --git a/source/blender/draw/engines/overlay/overlay_viewer_attribute.cc b/source/blender/draw/engines/overlay/overlay_viewer_attribute.cc
new file mode 100644
index 00000000000..7e1949c5261
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_viewer_attribute.cc
@@ -0,0 +1,181 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_pointcloud_types.h"
+
+#include "BLI_math_vector.hh"
+#include "BLI_span.hh"
+
+#include "GPU_batch.h"
+
+#include "BKE_attribute.hh"
+#include "BKE_curves.hh"
+#include "BKE_duplilist.h"
+#include "BKE_geometry_set.hh"
+
+#include "draw_cache_extract.hh"
+#include "draw_cache_impl.h"
+#include "overlay_private.hh"
+
+void OVERLAY_viewer_attribute_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ const DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL |
+ DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->attribute_ps, state | pd->clipping_state);
+
+ GPUShader *mesh_sh = OVERLAY_shader_viewer_attribute_mesh();
+ GPUShader *pointcloud_sh = OVERLAY_shader_viewer_attribute_pointcloud();
+ GPUShader *curve_sh = OVERLAY_shader_viewer_attribute_curve();
+ GPUShader *curves_sh = OVERLAY_shader_viewer_attribute_curves();
+ GPUShader *uniform_sh = OVERLAY_shader_uniform_color();
+ GPUShader *uniform_pointcloud_sh = OVERLAY_shader_uniform_color_pointcloud();
+ pd->viewer_attribute_mesh_grp = DRW_shgroup_create(mesh_sh, psl->attribute_ps);
+ pd->viewer_attribute_pointcloud_grp = DRW_shgroup_create(pointcloud_sh, psl->attribute_ps);
+ pd->viewer_attribute_curve_grp = DRW_shgroup_create(curve_sh, psl->attribute_ps);
+ pd->viewer_attribute_curves_grp = DRW_shgroup_create(curves_sh, psl->attribute_ps);
+ pd->viewer_attribute_instance_grp = DRW_shgroup_create(uniform_sh, psl->attribute_ps);
+ pd->viewer_attribute_instance_pointcloud_grp = DRW_shgroup_create(uniform_pointcloud_sh,
+ psl->attribute_ps);
+}
+
+static void populate_cache_for_instance(Object &object,
+ OVERLAY_PrivateData &pd,
+ const DupliObject &dupli_object,
+ const float opacity)
+{
+ using namespace blender;
+ using namespace blender::bke;
+
+ const GeometrySet &base_geometry = *dupli_object.preview_base_geometry;
+ const InstancesComponent &instances =
+ *base_geometry.get_component_for_read<InstancesComponent>();
+ const AttributeAccessor instance_attributes = *instances.attributes();
+ const VArray attribute = instance_attributes.lookup<ColorGeometry4f>(".viewer");
+ if (!attribute) {
+ return;
+ }
+ ColorGeometry4f color = attribute.get(dupli_object.preview_instance_index);
+ color.a *= opacity;
+ switch (object.type) {
+ case OB_MESH: {
+ {
+ DRWShadingGroup *sub_grp = DRW_shgroup_create_sub(pd.viewer_attribute_instance_grp);
+ DRW_shgroup_uniform_vec4_copy(sub_grp, "ucolor", color);
+ GPUBatch *batch = DRW_cache_mesh_surface_get(&object);
+ DRW_shgroup_call(sub_grp, batch, &object);
+ }
+ if (GPUBatch *batch = DRW_cache_mesh_loose_edges_get(&object)) {
+ DRWShadingGroup *sub_grp = DRW_shgroup_create_sub(pd.viewer_attribute_instance_grp);
+ DRW_shgroup_uniform_vec4_copy(sub_grp, "ucolor", color);
+ DRW_shgroup_call(sub_grp, batch, &object);
+ }
+ break;
+ }
+ case OB_POINTCLOUD: {
+ DRWShadingGroup *sub_grp = DRW_shgroup_create_sub(
+ pd.viewer_attribute_instance_pointcloud_grp);
+ DRW_shgroup_uniform_vec4_copy(sub_grp, "ucolor", color);
+ GPUBatch *batch = DRW_cache_pointcloud_surface_get(&object);
+ DRW_shgroup_call_instance_range(sub_grp, &object, batch, 0, 0);
+ break;
+ }
+ case OB_CURVES_LEGACY: {
+ DRWShadingGroup *sub_grp = DRW_shgroup_create_sub(pd.viewer_attribute_instance_grp);
+ DRW_shgroup_uniform_vec4_copy(sub_grp, "ucolor", color);
+ GPUBatch *batch = DRW_cache_curve_edge_wire_get(&object);
+ DRW_shgroup_call(sub_grp, batch, &object);
+ break;
+ }
+ case OB_CURVES: {
+ /* Not supported yet because instances of this type are currently drawn as legacy curves.
+ */
+ break;
+ }
+ }
+}
+
+static void populate_cache_for_geometry(Object &object,
+ OVERLAY_PrivateData &pd,
+ const float opacity)
+{
+ using namespace blender;
+ using namespace blender::bke;
+
+ switch (object.type) {
+ case OB_MESH: {
+ Mesh *mesh = static_cast<Mesh *>(object.data);
+ if (mesh->attributes().contains(".viewer")) {
+ GPUBatch *batch = DRW_cache_mesh_surface_viewer_attribute_get(&object);
+ DRW_shgroup_uniform_float_copy(pd.viewer_attribute_mesh_grp, "opacity", opacity);
+ DRW_shgroup_call(pd.viewer_attribute_mesh_grp, batch, &object);
+ }
+ break;
+ }
+ case OB_POINTCLOUD: {
+ PointCloud *pointcloud = static_cast<PointCloud *>(object.data);
+ if (pointcloud->attributes().contains(".viewer")) {
+ GPUBatch *batch = DRW_cache_pointcloud_surface_viewer_attribute_get(&object);
+ DRW_shgroup_uniform_float_copy(pd.viewer_attribute_pointcloud_grp, "opacity", opacity);
+ DRW_shgroup_call_instance_range(pd.viewer_attribute_pointcloud_grp, &object, batch, 0, 0);
+ }
+ break;
+ }
+ case OB_CURVES_LEGACY: {
+ Curve *curve = static_cast<Curve *>(object.data);
+ const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curve->curve_eval->geometry);
+ if (curves.attributes().contains(".viewer")) {
+ GPUBatch *batch = DRW_cache_curve_edge_wire_viewer_attribute_get(&object);
+ DRW_shgroup_uniform_float_copy(pd.viewer_attribute_curve_grp, "opacity", opacity);
+ DRW_shgroup_call(pd.viewer_attribute_curve_grp, batch, &object);
+ }
+ break;
+ }
+ case OB_CURVES: {
+ Curves *curves_id = static_cast<Curves *>(object.data);
+ const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
+ if (curves.attributes().contains(".viewer")) {
+ bool is_point_domain;
+ GPUTexture **texture = DRW_curves_texture_for_evaluated_attribute(
+ curves_id, ".viewer", &is_point_domain);
+ DRWShadingGroup *grp = DRW_shgroup_curves_create_sub(
+ &object, pd.viewer_attribute_curves_grp, nullptr);
+ DRW_shgroup_uniform_float_copy(pd.viewer_attribute_curves_grp, "opacity", opacity);
+ DRW_shgroup_uniform_bool_copy(grp, "is_point_domain", is_point_domain);
+ DRW_shgroup_uniform_texture(grp, "color_tx", *texture);
+ }
+ break;
+ }
+ }
+}
+
+void OVERLAY_viewer_attribute_cache_populate(OVERLAY_Data *vedata, Object *object)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const float opacity = vedata->stl->pd->overlay.viewer_attribute_opacity;
+ DupliObject *dupli_object = DRW_object_get_dupli(object);
+
+ if (dupli_object->preview_instance_index >= 0) {
+ const InstancesComponent &instances =
+ *dupli_object->preview_base_geometry->get_component_for_read<InstancesComponent>();
+ if (instances.attributes()->contains(".viewer")) {
+ populate_cache_for_instance(*object, *pd, *dupli_object, opacity);
+ return;
+ }
+ }
+ populate_cache_for_geometry(*object, *pd, opacity);
+}
+
+void OVERLAY_viewer_attribute_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ DRW_draw_pass(psl->attribute_ps);
+}
diff --git a/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh
index 8c9c943393f..40b7249a997 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh
@@ -587,8 +587,20 @@ GPU_SHADER_CREATE_INFO(overlay_uniform_color)
.fragment_source("overlay_uniform_color_frag.glsl")
.additional_info("draw_mesh");
+GPU_SHADER_CREATE_INFO(overlay_uniform_color_pointcloud)
+ .do_static_compilation(true)
+ .push_constant(Type::VEC4, "ucolor")
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .vertex_source("overlay_pointcloud_only_vert.glsl")
+ .fragment_source("overlay_uniform_color_frag.glsl")
+ .additional_info("draw_pointcloud");
+
GPU_SHADER_CREATE_INFO(overlay_uniform_color_clipped)
.do_static_compilation(true)
.additional_info("overlay_depth_only", "drw_clipped");
+GPU_SHADER_CREATE_INFO(overlay_uniform_color_pointcloud_clipped)
+ .do_static_compilation(true)
+ .additional_info("overlay_uniform_color_pointcloud", "drw_clipped");
+
/** \} */
diff --git a/source/blender/draw/engines/overlay/shaders/infos/overlay_viewer_attribute_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_viewer_attribute_info.hh
new file mode 100644
index 00000000000..aca80992622
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_viewer_attribute_info.hh
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_INTERFACE_INFO(overlay_viewer_attribute_iface, "").smooth(Type::VEC4, "finalColor");
+
+GPU_SHADER_CREATE_INFO(overlay_viewer_attribute_common).push_constant(Type::FLOAT, "opacity");
+
+GPU_SHADER_CREATE_INFO(overlay_viewer_attribute_mesh)
+ .do_static_compilation(true)
+ .vertex_source("overlay_viewer_attribute_mesh_vert.glsl")
+ .fragment_source("overlay_viewer_attribute_frag.glsl")
+ .fragment_out(0, Type::VEC4, "out_color")
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_in(1, Type::VEC4, "attribute_value")
+ .vertex_out(overlay_viewer_attribute_iface)
+ .additional_info("overlay_viewer_attribute_common", "draw_mesh");
+
+GPU_SHADER_CREATE_INFO(overlay_viewer_attribute_mesh_clipped)
+ .do_static_compilation(true)
+ .additional_info("overlay_viewer_attribute_mesh", "drw_clipped");
+
+GPU_SHADER_CREATE_INFO(overlay_viewer_attribute_pointcloud)
+ .do_static_compilation(true)
+ .vertex_source("overlay_viewer_attribute_pointcloud_vert.glsl")
+ .fragment_source("overlay_viewer_attribute_frag.glsl")
+ .fragment_out(0, Type::VEC4, "out_color")
+ .vertex_in(3, Type::VEC4, "attribute_value")
+ .vertex_out(overlay_viewer_attribute_iface)
+ .additional_info("overlay_viewer_attribute_common", "draw_pointcloud");
+
+GPU_SHADER_CREATE_INFO(overlay_viewer_attribute_pointcloud_clipped)
+ .do_static_compilation(true)
+ .additional_info("overlay_viewer_attribute_pointcloud", "drw_clipped");
+
+GPU_SHADER_CREATE_INFO(overlay_viewer_attribute_curve)
+ .do_static_compilation(true)
+ .vertex_source("overlay_viewer_attribute_curve_vert.glsl")
+ .fragment_source("overlay_viewer_attribute_frag.glsl")
+ .fragment_out(0, Type::VEC4, "out_color")
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_in(1, Type::VEC4, "attribute_value")
+ .vertex_out(overlay_viewer_attribute_iface)
+ .additional_info("overlay_viewer_attribute_common", "draw_modelmat", "draw_resource_id");
+
+GPU_SHADER_CREATE_INFO(overlay_viewer_attribute_curve_clipped)
+ .do_static_compilation(true)
+ .additional_info("overlay_viewer_attribute_curve", "drw_clipped");
+
+GPU_SHADER_CREATE_INFO(overlay_viewer_attribute_curves)
+ .do_static_compilation(true)
+ .vertex_source("overlay_viewer_attribute_curves_vert.glsl")
+ .fragment_source("overlay_viewer_attribute_frag.glsl")
+ .fragment_out(0, Type::VEC4, "out_color")
+ .sampler(0, ImageType::FLOAT_BUFFER, "color_tx")
+ .push_constant(Type::BOOL, "is_point_domain")
+ .vertex_out(overlay_viewer_attribute_iface)
+ .additional_info("overlay_viewer_attribute_common", "draw_hair");
+
+GPU_SHADER_CREATE_INFO(overlay_viewer_attribute_curves_clipped)
+ .do_static_compilation(true)
+ .additional_info("overlay_viewer_attribute_curves", "drw_clipped");
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_pointcloud_only_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_pointcloud_only_vert.glsl
new file mode 100644
index 00000000000..8a7e81028d3
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_pointcloud_only_vert.glsl
@@ -0,0 +1,9 @@
+#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_pointcloud_lib.glsl)
+
+void main()
+{
+ vec3 world_pos = pointcloud_get_pos();
+ gl_Position = point_world_to_ndc(world_pos);
+}
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_curve_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_curve_vert.glsl
new file mode 100644
index 00000000000..7c2c386b2f5
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_curve_vert.glsl
@@ -0,0 +1,9 @@
+#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+
+void main()
+{
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+ finalColor = attribute_value;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_curves_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_curves_vert.glsl
new file mode 100644
index 00000000000..23d313e036f
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_curves_vert.glsl
@@ -0,0 +1,28 @@
+#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
+
+void main()
+{
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+ float time, thick_time, thickness;
+ vec3 world_pos, tan, binor;
+ hair_get_pos_tan_binor_time(is_persp,
+ ModelMatrixInverse,
+ ViewMatrixInverse[3].xyz,
+ ViewMatrixInverse[2].xyz,
+ world_pos,
+ tan,
+ binor,
+ time,
+ thickness,
+ thick_time);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ if (is_point_domain) {
+ finalColor = texelFetch(color_tx, hair_get_base_id());
+ }
+ else {
+ finalColor = texelFetch(color_tx, hair_get_strand_id());
+ }
+}
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_frag.glsl
new file mode 100644
index 00000000000..6176a6b96ba
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_frag.glsl
@@ -0,0 +1,6 @@
+
+void main()
+{
+ out_color = finalColor;
+ out_color.a *= opacity;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_mesh_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_mesh_vert.glsl
new file mode 100644
index 00000000000..7c2c386b2f5
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_mesh_vert.glsl
@@ -0,0 +1,9 @@
+#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+
+void main()
+{
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+ finalColor = attribute_value;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_pointcloud_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_pointcloud_vert.glsl
new file mode 100644
index 00000000000..e706e8f9033
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_pointcloud_vert.glsl
@@ -0,0 +1,10 @@
+#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_pointcloud_lib.glsl)
+
+void main()
+{
+ vec3 world_pos = pointcloud_get_pos();
+ gl_Position = point_world_to_ndc(world_pos);
+ finalColor = attribute_value;
+}
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index 6537490c06c..6da22039c2f 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -2889,6 +2889,12 @@ GPUBatch *DRW_cache_mesh_surface_mesh_analysis_get(Object *ob)
return DRW_mesh_batch_cache_get_edit_mesh_analysis(ob->data);
}
+GPUBatch *DRW_cache_mesh_surface_viewer_attribute_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_MESH);
+ return DRW_mesh_batch_cache_get_surface_viewer_attribute(ob->data);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -2902,6 +2908,13 @@ GPUBatch *DRW_cache_curve_edge_wire_get(Object *ob)
return DRW_curve_batch_cache_get_wire_edge(cu);
}
+GPUBatch *DRW_cache_curve_edge_wire_viewer_attribute_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_CURVES_LEGACY);
+ struct Curve *cu = ob->data;
+ return DRW_curve_batch_cache_get_wire_edge_viewer_attribute(cu);
+}
+
GPUBatch *DRW_cache_curve_edge_normal_get(Object *ob)
{
BLI_assert(ob->type == OB_CURVES_LEGACY);
@@ -3005,6 +3018,12 @@ GPUBatch *DRW_cache_pointcloud_surface_get(Object *object)
return DRW_pointcloud_batch_cache_get_surface(object);
}
+GPUBatch *DRW_cache_pointcloud_surface_viewer_attribute_get(Object *object)
+{
+ BLI_assert(object->type == OB_POINTCLOUD);
+ return DRW_pointcloud_batch_cache_get_surface_viewer_attribute(object);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
index 4e8788ada08..058f28f094d 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -170,10 +170,12 @@ struct GPUBatch *DRW_cache_mesh_surface_sculptcolors_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_surface_weights_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_surface_mesh_analysis_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_face_wireframe_get(struct Object *ob);
+struct GPUBatch *DRW_cache_mesh_surface_viewer_attribute_get(struct Object *ob);
/* Curve */
struct GPUBatch *DRW_cache_curve_edge_wire_get(struct Object *ob);
+struct GPUBatch *DRW_cache_curve_edge_wire_viewer_attribute_get(struct Object *ob);
/* edit-mode */
@@ -226,6 +228,7 @@ struct GPUBatch *DRW_cache_curves_edge_detection_get(struct Object *ob, bool *r_
struct GPUBatch *DRW_cache_pointcloud_get_dots(struct Object *obj);
struct GPUBatch *DRW_cache_pointcloud_surface_get(struct Object *obj);
+struct GPUBatch *DRW_cache_pointcloud_surface_viewer_attribute_get(struct Object *obj);
/* Volume */
diff --git a/source/blender/draw/intern/draw_cache_extract.hh b/source/blender/draw/intern/draw_cache_extract.hh
index 203da22406c..6f4a652ce24 100644
--- a/source/blender/draw/intern/draw_cache_extract.hh
+++ b/source/blender/draw/intern/draw_cache_extract.hh
@@ -130,6 +130,7 @@ struct MeshBufferList {
GPUVertBuf *poly_idx;
GPUVertBuf *fdot_idx;
GPUVertBuf *attr[GPU_MAX_ATTR];
+ GPUVertBuf *attr_viewer;
} vbo;
/* Index Buffers:
* Only need to be updated when topology changes. */
@@ -191,6 +192,7 @@ struct MeshBatchList {
/* Same as wire_loops but only has uvs. */
GPUBatch *wire_loops_uvs;
GPUBatch *sculpt_overlays;
+ GPUBatch *surface_viewer_attribute;
};
#define MBC_BATCH_LEN (sizeof(MeshBatchList) / sizeof(void *))
@@ -228,6 +230,7 @@ enum DRWBatchFlag {
MBC_WIRE_LOOPS = (1u << MBC_BATCH_INDEX(wire_loops)),
MBC_WIRE_LOOPS_UVS = (1u << MBC_BATCH_INDEX(wire_loops_uvs)),
MBC_SCULPT_OVERLAYS = (1u << MBC_BATCH_INDEX(sculpt_overlays)),
+ MBC_VIEWER_ATTRIBUTE_OVERLAY = (1u << MBC_BATCH_INDEX(surface_viewer_attribute)),
MBC_SURFACE_PER_MAT = (1u << MBC_BATCH_LEN),
};
ENUM_OPERATORS(DRWBatchFlag, MBC_SURFACE_PER_MAT);
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc
index fd00059bac6..d3170f4c776 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -640,6 +640,7 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
for (int i = 0; i < GPU_MAX_ATTR; i++) {
EXTRACT_ADD_REQUESTED(vbo, attr[i]);
}
+ EXTRACT_ADD_REQUESTED(vbo, attr_viewer);
EXTRACT_ADD_REQUESTED(ibo, tris);
if (DRW_ibo_requested(mbuflist->ibo.lines_loose)) {
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index 7f7d0a7613f..89432b0da83 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -100,6 +100,7 @@ void DRW_curve_batch_cache_create_requested(struct Object *ob, const struct Scen
int DRW_curve_material_count_get(struct Curve *cu);
struct GPUBatch *DRW_curve_batch_cache_get_wire_edge(struct Curve *cu);
+struct GPUBatch *DRW_curve_batch_cache_get_wire_edge_viewer_attribute(struct Curve *cu);
struct GPUBatch *DRW_curve_batch_cache_get_normal_edge(struct Curve *cu);
struct GPUBatch *DRW_curve_batch_cache_get_edit_edges(struct Curve *cu);
struct GPUBatch *DRW_curve_batch_cache_get_edit_verts(struct Curve *cu);
@@ -148,6 +149,7 @@ int DRW_pointcloud_material_count_get(struct PointCloud *pointcloud);
struct GPUBatch *DRW_pointcloud_batch_cache_get_dots(struct Object *ob);
struct GPUBatch *DRW_pointcloud_batch_cache_get_surface(struct Object *ob);
+struct GPUBatch *DRW_pointcloud_batch_cache_get_surface_viewer_attribute(struct Object *ob);
struct GPUBatch **DRW_cache_pointcloud_surface_shaded_get(struct Object *ob,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len);
@@ -198,6 +200,7 @@ struct GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(struct Object *objec
struct GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(struct Object *object, struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_surface_weights(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_sculpt_overlays(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_surface_viewer_attribute(struct Mesh *me);
/** \} */
diff --git a/source/blender/draw/intern/draw_cache_impl_curve.cc b/source/blender/draw/intern/draw_cache_impl_curve.cc
index 695c348d8e2..6188b1e0544 100644
--- a/source/blender/draw/intern/draw_cache_impl_curve.cc
+++ b/source/blender/draw/intern/draw_cache_impl_curve.cc
@@ -10,6 +10,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_array.hh"
+#include "BLI_color.hh"
#include "BLI_listbase.h"
#include "BLI_math_vec_types.hh"
#include "BLI_math_vector.h"
@@ -38,6 +39,7 @@
#include "draw_cache_impl.h" /* own include */
using blender::Array;
+using blender::ColorGeometry4f;
using blender::float3;
using blender::IndexRange;
using blender::Span;
@@ -296,6 +298,7 @@ static int curve_render_data_normal_len_get(const CurveRenderData *rdata)
struct CurveBatchCache {
struct {
GPUVertBuf *curves_pos;
+ GPUVertBuf *attr_viewer;
} ordered;
struct {
@@ -314,6 +317,7 @@ struct CurveBatchCache {
struct {
GPUBatch *curves;
+ GPUBatch *curves_viewer_attribute;
/* control handles and vertices */
GPUBatch *edit_edges;
GPUBatch *edit_verts;
@@ -474,6 +478,31 @@ static void curve_create_curves_pos(CurveRenderData *rdata, GPUVertBuf *vbo_curv
GPU_vertbuf_attr_fill(vbo_curves_pos, attr_id.pos, positions.data());
}
+static void curve_create_attribute(CurveRenderData *rdata, GPUVertBuf *vbo_attr)
+{
+ if (rdata->curve_eval == nullptr) {
+ return;
+ }
+
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "attribute_value", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ }
+
+ const int vert_len = curve_render_data_wire_verts_len_get(rdata);
+ GPU_vertbuf_init_with_format(vbo_attr, &format);
+ GPU_vertbuf_data_alloc(vbo_attr, vert_len);
+
+ const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(
+ rdata->curve_eval->geometry);
+ curves.ensure_can_interpolate_to_evaluated();
+ const blender::VArraySpan<ColorGeometry4f> colors = curves.attributes().lookup<ColorGeometry4f>(
+ ".viewer", ATTR_DOMAIN_POINT);
+ ColorGeometry4f *vbo_data = static_cast<ColorGeometry4f *>(GPU_vertbuf_get_data(vbo_attr));
+ curves.interpolate_to_evaluated(colors,
+ blender::MutableSpan<ColorGeometry4f>{vbo_data, vert_len});
+}
+
static void curve_create_curves_lines(CurveRenderData *rdata, GPUIndexBuf *ibo_curve_lines)
{
if (rdata->curve_eval == nullptr) {
@@ -769,6 +798,12 @@ GPUBatch *DRW_curve_batch_cache_get_wire_edge(Curve *cu)
return DRW_batch_request(&cache->batch.curves);
}
+GPUBatch *DRW_curve_batch_cache_get_wire_edge_viewer_attribute(Curve *cu)
+{
+ CurveBatchCache *cache = curve_batch_cache_get(cu);
+ return DRW_batch_request(&cache->batch.curves_viewer_attribute);
+}
+
GPUBatch *DRW_curve_batch_cache_get_normal_edge(Curve *cu)
{
CurveBatchCache *cache = curve_batch_cache_get(cu);
@@ -810,6 +845,11 @@ void DRW_curve_batch_cache_create_requested(Object *ob, const struct Scene *scen
DRW_ibo_request(cache->batch.curves, &cache->ibo.curves_lines);
DRW_vbo_request(cache->batch.curves, &cache->ordered.curves_pos);
}
+ if (DRW_batch_requested(cache->batch.curves_viewer_attribute, GPU_PRIM_LINE_STRIP)) {
+ DRW_ibo_request(cache->batch.curves_viewer_attribute, &cache->ibo.curves_lines);
+ DRW_vbo_request(cache->batch.curves_viewer_attribute, &cache->ordered.curves_pos);
+ DRW_vbo_request(cache->batch.curves_viewer_attribute, &cache->ordered.attr_viewer);
+ }
/* Edit mode */
if (DRW_batch_requested(cache->batch.edit_edges, GPU_PRIM_LINES)) {
@@ -833,6 +873,8 @@ void DRW_curve_batch_cache_create_requested(Object *ob, const struct Scene *scen
/* Generate MeshRenderData flags */
int mr_flag = 0;
DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.curves_pos, CU_DATATYPE_WIRE);
+ DRW_ADD_FLAG_FROM_VBO_REQUEST(
+ mr_flag, cache->ordered.attr_viewer, CU_DATATYPE_WIRE | CU_DATATYPE_OVERLAY);
DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.curves_lines, CU_DATATYPE_WIRE);
DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->edit.pos, CU_DATATYPE_OVERLAY);
@@ -851,6 +893,9 @@ void DRW_curve_batch_cache_create_requested(Object *ob, const struct Scene *scen
if (DRW_vbo_requested(cache->ordered.curves_pos)) {
curve_create_curves_pos(rdata, cache->ordered.curves_pos);
}
+ if (DRW_vbo_requested(cache->ordered.attr_viewer)) {
+ curve_create_attribute(rdata, cache->ordered.attr_viewer);
+ }
if (DRW_ibo_requested(cache->ibo.curves_lines)) {
curve_create_curves_lines(rdata, cache->ibo.curves_lines);
}
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.cc b/source/blender/draw/intern/draw_cache_impl_mesh.cc
index c22382b3e09..ed78cbbda39 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.cc
@@ -104,7 +104,8 @@ static constexpr DRWBatchFlag batches_that_use_buffer(const int buffer_index)
MBC_EDIT_EDGES | MBC_EDIT_VNOR | MBC_EDIT_LNOR | MBC_EDIT_MESH_ANALYSIS |
MBC_EDIT_SELECTION_VERTS | MBC_EDIT_SELECTION_EDGES | MBC_EDIT_SELECTION_FACES |
MBC_ALL_VERTS | MBC_ALL_EDGES | MBC_LOOSE_EDGES | MBC_EDGE_DETECTION |
- MBC_WIRE_EDGES | MBC_WIRE_LOOPS | MBC_SCULPT_OVERLAYS | MBC_SURFACE_PER_MAT;
+ MBC_WIRE_EDGES | MBC_WIRE_LOOPS | MBC_SCULPT_OVERLAYS | MBC_VIEWER_ATTRIBUTE_OVERLAY |
+ MBC_SURFACE_PER_MAT;
case BUFFER_INDEX(vbo.lnor):
return MBC_SURFACE | MBC_EDIT_LNOR | MBC_WIRE_LOOPS | MBC_SURFACE_PER_MAT;
case BUFFER_INDEX(vbo.edge_fac):
@@ -166,9 +167,12 @@ static constexpr DRWBatchFlag batches_that_use_buffer(const int buffer_index)
case BUFFER_INDEX(vbo.attr[13]):
case BUFFER_INDEX(vbo.attr[14]):
return MBC_SURFACE | MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(vbo.attr_viewer):
+ return MBC_VIEWER_ATTRIBUTE_OVERLAY;
case BUFFER_INDEX(ibo.tris):
return MBC_SURFACE | MBC_SURFACE_WEIGHTS | MBC_EDIT_TRIANGLES | MBC_EDIT_LNOR |
- MBC_EDIT_MESH_ANALYSIS | MBC_EDIT_SELECTION_FACES | MBC_SCULPT_OVERLAYS;
+ MBC_EDIT_MESH_ANALYSIS | MBC_EDIT_SELECTION_FACES | MBC_SCULPT_OVERLAYS |
+ MBC_VIEWER_ATTRIBUTE_OVERLAY;
case BUFFER_INDEX(ibo.lines):
return MBC_EDIT_EDGES | MBC_EDIT_SELECTION_EDGES | MBC_ALL_EDGES | MBC_WIRE_EDGES;
case BUFFER_INDEX(ibo.lines_loose):
@@ -1057,6 +1061,16 @@ GPUBatch *DRW_mesh_batch_cache_get_sculpt_overlays(Mesh *me)
return cache->batch.sculpt_overlays;
}
+GPUBatch *DRW_mesh_batch_cache_get_surface_viewer_attribute(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ mesh_batch_cache_add_request(cache, MBC_VIEWER_ATTRIBUTE_OVERLAY);
+ DRW_batch_request(&cache->batch.surface_viewer_attribute);
+
+ return cache->batch.surface_viewer_attribute;
+}
+
/** \} */
/* ---------------------------------------------------------------------- */
@@ -1802,6 +1816,14 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
DRW_vbo_request(cache->batch.edituv_fdots, &mbuflist->vbo.fdots_uv);
DRW_vbo_request(cache->batch.edituv_fdots, &mbuflist->vbo.fdots_edituv_data);
}
+ assert_deps_valid(
+ MBC_VIEWER_ATTRIBUTE_OVERLAY,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.attr_viewer)});
+ if (DRW_batch_requested(cache->batch.surface_viewer_attribute, GPU_PRIM_TRIS)) {
+ DRW_ibo_request(cache->batch.surface_viewer_attribute, &mbuflist->ibo.tris);
+ DRW_vbo_request(cache->batch.surface_viewer_attribute, &mbuflist->vbo.pos_nor);
+ DRW_vbo_request(cache->batch.surface_viewer_attribute, &mbuflist->vbo.attr_viewer);
+ }
#ifdef DEBUG
auto assert_final_deps_valid = [&](const int buffer_index) {
@@ -1833,6 +1855,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
for (const int i : IndexRange(GPU_MAX_ATTR)) {
assert_final_deps_valid(BUFFER_INDEX(vbo.attr[i]));
}
+ assert_final_deps_valid(BUFFER_INDEX(vbo.attr_viewer));
assert_final_deps_valid(BUFFER_INDEX(ibo.tris));
assert_final_deps_valid(BUFFER_INDEX(ibo.lines));
diff --git a/source/blender/draw/intern/draw_cache_impl_pointcloud.cc b/source/blender/draw/intern/draw_cache_impl_pointcloud.cc
index a43b23c8969..72be5b37652 100644
--- a/source/blender/draw/intern/draw_cache_impl_pointcloud.cc
+++ b/source/blender/draw/intern/draw_cache_impl_pointcloud.cc
@@ -32,11 +32,13 @@
struct PointCloudBatchCache {
GPUVertBuf *pos; /* Position and radius. */
GPUVertBuf *geom; /* Instanced geometry for each point in the cloud (small sphere). */
+ GPUVertBuf *attr_viewer;
GPUIndexBuf *geom_indices;
GPUBatch *dots;
GPUBatch *surface;
GPUBatch **surface_per_mat;
+ GPUBatch *surface_viewer_attribute;
/* settings to determine if cache is invalid */
bool is_dirty;
@@ -109,6 +111,7 @@ static void pointcloud_batch_cache_clear(PointCloud &pointcloud)
GPU_BATCH_DISCARD_SAFE(cache->surface);
GPU_VERTBUF_DISCARD_SAFE(cache->pos);
GPU_VERTBUF_DISCARD_SAFE(cache->geom);
+ GPU_VERTBUF_DISCARD_SAFE(cache->attr_viewer);
GPU_INDEXBUF_DISCARD_SAFE(cache->geom_indices);
if (cache->surface_per_mat) {
@@ -116,6 +119,7 @@ static void pointcloud_batch_cache_clear(PointCloud &pointcloud)
GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]);
}
}
+ GPU_BATCH_DISCARD_SAFE(cache->surface_viewer_attribute);
MEM_SAFE_FREE(cache->surface_per_mat);
}
@@ -227,6 +231,30 @@ static void pointcloud_batch_cache_ensure_geom(PointCloudBatchCache &cache)
cache.geom_indices = GPU_indexbuf_build(&builder);
}
+static void pointcloud_batch_cache_ensure_attribute_overlay(const PointCloud &pointcloud,
+ PointCloudBatchCache &cache)
+{
+ using namespace blender;
+ if (cache.attr_viewer != nullptr) {
+ return;
+ }
+
+ const bke::AttributeAccessor attributes = pointcloud.attributes();
+ const VArray<ColorGeometry4f> colors = attributes.lookup_or_default<ColorGeometry4f>(
+ ".viewer", ATTR_DOMAIN_POINT, {1.0f, 0.0f, 1.0f, 1.0f});
+
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "attribute_value", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ }
+ cache.attr_viewer = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(cache.attr_viewer, pointcloud.totpoint);
+ MutableSpan<ColorGeometry4f> vbo_data{
+ static_cast<ColorGeometry4f *>(GPU_vertbuf_get_data(cache.attr_viewer)),
+ pointcloud.totpoint};
+ colors.materialize(vbo_data);
+}
+
GPUBatch *DRW_pointcloud_batch_cache_get_dots(Object *ob)
{
PointCloud &pointcloud = *static_cast<PointCloud *>(ob->data);
@@ -256,6 +284,25 @@ GPUBatch *DRW_pointcloud_batch_cache_get_surface(Object *ob)
return cache->surface;
}
+GPUBatch *DRW_pointcloud_batch_cache_get_surface_viewer_attribute(Object *ob)
+{
+ PointCloud &pointcloud = *static_cast<PointCloud *>(ob->data);
+ PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud);
+
+ if (cache->surface_viewer_attribute == nullptr) {
+ pointcloud_batch_cache_ensure_pos(pointcloud, *cache);
+ pointcloud_batch_cache_ensure_geom(*cache);
+ pointcloud_batch_cache_ensure_attribute_overlay(pointcloud, *cache);
+
+ cache->surface_viewer_attribute = GPU_batch_create(
+ GPU_PRIM_TRIS, cache->geom, cache->geom_indices);
+ GPU_batch_instbuf_add_ex(cache->surface_viewer_attribute, cache->attr_viewer, false);
+ GPU_batch_instbuf_add_ex(cache->surface_viewer_attribute, cache->pos, false);
+ }
+
+ return cache->surface_viewer_attribute;
+}
+
GPUBatch **DRW_cache_pointcloud_surface_shaded_get(Object *ob,
struct GPUMaterial **UNUSED(gpumat_array),
uint gpumat_array_len)
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 51762e29506..99f75581a47 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -38,6 +38,7 @@
#include "BKE_pointcloud.h"
#include "BKE_screen.h"
#include "BKE_subdiv_modifier.h"
+#include "BKE_viewer_path.h"
#include "BKE_volume.h"
#include "DNA_camera_types.h"
@@ -1695,6 +1696,9 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
DEGObjectIterSettings deg_iter_settings = {0};
deg_iter_settings.depsgraph = depsgraph;
deg_iter_settings.flags = DEG_OBJECT_ITER_FOR_RENDER_ENGINE_FLAGS;
+ if (v3d->flag2 & V3D_SHOW_VIEWER) {
+ deg_iter_settings.viewer_path = &v3d->viewer_path;
+ }
DEG_OBJECT_ITER_BEGIN (&deg_iter_settings, ob) {
if ((object_type_exclude_viewport & (1 << ob->type)) != 0) {
continue;
@@ -2497,6 +2501,9 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
DEGObjectIterSettings deg_iter_settings = {0};
deg_iter_settings.depsgraph = depsgraph;
deg_iter_settings.flags = DEG_OBJECT_ITER_FOR_RENDER_ENGINE_FLAGS;
+ if (v3d->flag2 & V3D_SHOW_VIEWER) {
+ deg_iter_settings.viewer_path = &v3d->viewer_path;
+ }
DEG_OBJECT_ITER_BEGIN (&deg_iter_settings, ob) {
if (!BKE_object_is_visible_in_viewport(v3d, ob)) {
continue;
@@ -2662,6 +2669,9 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph,
DEGObjectIterSettings deg_iter_settings = {0};
deg_iter_settings.depsgraph = DST.draw_ctx.depsgraph;
deg_iter_settings.flags = DEG_OBJECT_ITER_FOR_RENDER_ENGINE_FLAGS;
+ if (v3d->flag2 & V3D_SHOW_VIEWER) {
+ deg_iter_settings.viewer_path = &v3d->viewer_path;
+ }
DEG_OBJECT_ITER_BEGIN (&deg_iter_settings, ob) {
if ((object_type_exclude_viewport & (1 << ob->type)) != 0) {
continue;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.hh b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh
index 0bce05577b2..d9bb8d1d2b4 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh.hh
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh
@@ -440,3 +440,4 @@ extern const MeshExtract extract_edge_idx;
extern const MeshExtract extract_vert_idx;
extern const MeshExtract extract_fdot_idx;
extern const MeshExtract extract_attr[GPU_MAX_ATTR];
+extern const MeshExtract extract_attr_viewer;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
index 240e9b4fa60..c602b768df9 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
@@ -14,6 +14,8 @@
#include "BLI_string.h"
#include "BKE_attribute.h"
+#include "BKE_attribute.hh"
+#include "BKE_mesh.h"
#include "draw_attributes.h"
#include "draw_subdivision.h"
@@ -432,6 +434,40 @@ constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivF
return extractor;
}
+static void extract_mesh_attr_viewer_init(const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *UNUSED(tls_data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "attribute_value", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ }
+
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, mr->loop_len);
+ MutableSpan<ColorGeometry4f> attr{static_cast<ColorGeometry4f *>(GPU_vertbuf_get_data(vbo)),
+ mr->loop_len};
+
+ const StringRefNull attr_name = ".viewer";
+ const bke::AttributeAccessor attributes = mr->me->attributes();
+ attributes
+ .lookup_or_default<ColorGeometry4f>(attr_name, ATTR_DOMAIN_CORNER, {1.0f, 0.0f, 1.0f, 1.0f})
+ .materialize(attr);
+}
+
+constexpr MeshExtract create_extractor_attr_viewer()
+{
+ MeshExtract extractor = {nullptr};
+ extractor.init = extract_mesh_attr_viewer_init;
+ extractor.data_type = MR_DATA_NONE;
+ extractor.data_size = 0;
+ extractor.use_threading = false;
+ extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.attr_viewer);
+ return extractor;
+}
+
/** \} */
} // namespace blender::draw
@@ -457,3 +493,5 @@ const MeshExtract extract_attr[GPU_MAX_ATTR] = {
CREATE_EXTRACTOR_ATTR(13),
CREATE_EXTRACTOR_ATTR(14),
};
+
+const MeshExtract extract_attr_viewer = blender::draw::create_extractor_attr_viewer();
diff --git a/source/blender/draw/tests/shaders_test.cc b/source/blender/draw/tests/shaders_test.cc
index dc631483857..f238c7e25b1 100644
--- a/source/blender/draw/tests/shaders_test.cc
+++ b/source/blender/draw/tests/shaders_test.cc
@@ -254,6 +254,7 @@ static void test_overlay_glsl_shaders()
EXPECT_NE(OVERLAY_shader_motion_path_line(), nullptr);
EXPECT_NE(OVERLAY_shader_motion_path_vert(), nullptr);
EXPECT_NE(OVERLAY_shader_uniform_color(), nullptr);
+ EXPECT_NE(OVERLAY_shader_uniform_color_pointcloud(), nullptr);
EXPECT_NE(OVERLAY_shader_outline_prepass(false), nullptr);
EXPECT_NE(OVERLAY_shader_outline_prepass(true), nullptr);
EXPECT_NE(OVERLAY_shader_outline_prepass_curves(), nullptr);
@@ -272,6 +273,10 @@ static void test_overlay_glsl_shaders()
EXPECT_NE(OVERLAY_shader_particle_shape(), nullptr);
EXPECT_NE(OVERLAY_shader_sculpt_mask(), nullptr);
EXPECT_NE(OVERLAY_shader_sculpt_curves_selection(), nullptr);
+ EXPECT_NE(OVERLAY_shader_viewer_attribute_curve(), nullptr);
+ EXPECT_NE(OVERLAY_shader_viewer_attribute_curves(), nullptr);
+ EXPECT_NE(OVERLAY_shader_viewer_attribute_mesh(), nullptr);
+ EXPECT_NE(OVERLAY_shader_viewer_attribute_pointcloud(), nullptr);
EXPECT_NE(OVERLAY_shader_volume_velocity(false, false), nullptr);
EXPECT_NE(OVERLAY_shader_volume_velocity(false, true), nullptr);
EXPECT_NE(OVERLAY_shader_volume_velocity(true, false), nullptr);
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 144fa4e0b93..e1fd53ccdee 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -469,6 +469,8 @@ bool ED_workspace_layout_cycle(struct WorkSpace *workspace, short direction, str
void ED_workspace_status_text(struct bContext *C, const char *str);
+void ED_workspace_do_listen(struct bContext *C, const struct wmNotifier *note);
+
/* anim */
/**
* Results in fully updated anim system.
diff --git a/source/blender/editors/include/ED_spreadsheet.h b/source/blender/editors/include/ED_spreadsheet.h
index da13e6d3636..736da367a44 100644
--- a/source/blender/editors/include/ED_spreadsheet.h
+++ b/source/blender/editors/include/ED_spreadsheet.h
@@ -7,7 +7,6 @@ struct Main;
struct Object;
struct SpaceNode;
struct SpaceSpreadsheet;
-struct SpreadsheetContext;
struct bContext;
struct bNode;
@@ -15,29 +14,8 @@ struct bNode;
extern "C" {
#endif
-struct SpreadsheetContext *ED_spreadsheet_context_new(int type);
-void ED_spreadsheet_context_free(struct SpreadsheetContext *context);
-void ED_spreadsheet_context_path_clear(struct SpaceSpreadsheet *sspreadsheet);
-bool ED_spreadsheet_context_path_update_tag(struct SpaceSpreadsheet *sspreadsheet);
-uint64_t ED_spreadsheet_context_path_hash(const struct SpaceSpreadsheet *sspreadsheet);
-
struct ID *ED_spreadsheet_get_current_id(const struct SpaceSpreadsheet *sspreadsheet);
-void ED_spreadsheet_context_path_set_geometry_node(struct SpaceSpreadsheet *sspreadsheet,
- struct SpaceNode *snode,
- struct bNode *node);
-void ED_spreadsheet_context_paths_set_geometry_node(struct Main *bmain,
- struct SpaceNode *snode,
- struct bNode *node);
-void ED_spreadsheet_context_path_set_evaluated_object(struct SpaceSpreadsheet *sspreadsheet,
- struct Object *object);
-
-void ED_spreadsheet_context_path_guess(const struct bContext *C,
- struct SpaceSpreadsheet *sspreadsheet);
-bool ED_spreadsheet_context_path_is_active(const struct bContext *C,
- struct SpaceSpreadsheet *sspreadsheet);
-bool ED_spreadsheet_context_path_exists(struct Main *bmain, struct SpaceSpreadsheet *sspreadsheet);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_viewer_path.hh b/source/blender/editors/include/ED_viewer_path.hh
new file mode 100644
index 00000000000..957dfddb8af
--- /dev/null
+++ b/source/blender/editors/include/ED_viewer_path.hh
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include <optional>
+
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+
+#include "BKE_viewer_path.h"
+
+struct Main;
+struct SpaceNode;
+struct bNode;
+struct bContext;
+struct Object;
+
+namespace blender::ed::viewer_path {
+
+/**
+ * Activates the given node in the context provided by the editor. This indirectly updates all
+ * non-pinned viewer paths in other editors (spreadsheet and 3d view).
+ */
+void activate_geometry_node(Main &bmain, SpaceNode &snode, bNode &node);
+
+/**
+ * Returns the object referenced by the viewer path. This only returns something if the viewer path
+ * *only* contains the object and nothing more.
+ */
+Object *parse_object_only(const ViewerPath &viewer_path);
+
+/**
+ * Represents a parsed #ViewerPath for easier consumption.
+ */
+struct ViewerPathForGeometryNodesViewer {
+ Object *object;
+ blender::StringRefNull modifier_name;
+ blender::Vector<blender::StringRefNull> group_node_names;
+ blender::StringRefNull viewer_node_name;
+};
+
+/**
+ * Parses a #ViewerPath into a #ViewerPathForGeometryNodesViewer or returns none if that does not
+ * work.
+ */
+std::optional<ViewerPathForGeometryNodesViewer> parse_geometry_nodes_viewer(
+ const ViewerPath &viewer_path);
+
+/**
+ * Finds the node referenced by the #ViewerPath within the provided editor. If no node is
+ * referenced, null is returned. When two different editors show the same node group but in a
+ * different context, it's possible that the same node is active in one editor but not the other.
+ */
+bNode *find_geometry_nodes_viewer(const ViewerPath &viewer_path, SpaceNode &snode);
+
+/**
+ * Checks if the node referenced by the viewer path and its entire context still exists. The node
+ * does not have to be visible for this to return true.
+ */
+bool exists_geometry_nodes_viewer(const ViewerPathForGeometryNodesViewer &parsed_viewer_path);
+
+/**
+ * Checks if the node referenced by the viewer and its entire context is still active, i.e. some
+ * editor is showing it.
+ */
+bool is_active_geometry_nodes_viewer(const bContext &C,
+ const ViewerPathForGeometryNodesViewer &parsed_viewer_path);
+
+} // namespace blender::ed::viewer_path
diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt
index 119758f3335..bde73402277 100644
--- a/source/blender/editors/screen/CMakeLists.txt
+++ b/source/blender/editors/screen/CMakeLists.txt
@@ -34,6 +34,7 @@ set(SRC
screendump.c
workspace_edit.c
workspace_layout_edit.c
+ workspace_listen.cc
screen_intern.h
)
diff --git a/source/blender/editors/screen/workspace_listen.cc b/source/blender/editors/screen/workspace_listen.cc
new file mode 100644
index 00000000000..84326007d66
--- /dev/null
+++ b/source/blender/editors/screen/workspace_listen.cc
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_context.h"
+
+#include "ED_screen.h"
+#include "ED_viewer_path.hh"
+
+#include "WM_api.h"
+
+/**
+ * Checks if the viewer path stored in the workspace is still active and resets it if not.
+ * The viewer path stored in the workspace is the ground truth for other editors, so it should be
+ * updated before other editors look at it.
+ */
+static void validate_viewer_paths(bContext &C, WorkSpace &workspace)
+{
+ if (BLI_listbase_is_empty(&workspace.viewer_path.path)) {
+ return;
+ }
+
+ const std::optional<blender::ed::viewer_path::ViewerPathForGeometryNodesViewer> parsed_path =
+ blender::ed::viewer_path::parse_geometry_nodes_viewer(workspace.viewer_path);
+ if (parsed_path.has_value() &&
+ blender::ed::viewer_path::is_active_geometry_nodes_viewer(C, *parsed_path)) {
+ /* The current viewer path is still valid and active. */
+ return;
+ }
+ /* Reset inactive viewer path. */
+ BKE_viewer_path_clear(&workspace.viewer_path);
+ WM_event_add_notifier(&C, NC_VIEWER_PATH, nullptr);
+}
+
+void ED_workspace_do_listen(bContext *C, const wmNotifier * /*note*/)
+{
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ validate_viewer_paths(*C, *workspace);
+}
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index 8f72d292740..29dad103dc3 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -60,6 +60,7 @@
#include "ED_node.h"
#include "ED_screen.h"
#include "ED_space_api.h"
+#include "ED_viewer_path.hh"
#include "UI_interface.hh"
#include "UI_resources.h"
@@ -95,6 +96,14 @@ extern void ui_draw_dropshadow(
*/
struct TreeDrawContext {
/**
+ * Whether a viewer node is active in geometry nodes can not be determined by a flag on the node
+ * alone. That's because if the node group with the viewer is used multiple times, it's only
+ * active in one of these cases.
+ * The active node is cached here to avoid doing the more expensive check for every viewer node
+ * in the tree.
+ */
+ const bNode *active_geometry_nodes_viewer = nullptr;
+ /**
* Geometry nodes logs various data during execution. The logged data that corresponds to the
* currently drawn node tree can be retrieved from the log below.
*/
@@ -639,15 +648,19 @@ static void node_update_hidden(bNode &node, uiBlock &block)
node.totr.ymax);
}
-static int node_get_colorid(const bNode &node)
+static int node_get_colorid(TreeDrawContext &tree_draw_ctx, const bNode &node)
{
const int nclass = (node.typeinfo->ui_class == nullptr) ? node.typeinfo->nclass :
node.typeinfo->ui_class(&node);
switch (nclass) {
case NODE_CLASS_INPUT:
return TH_NODE_INPUT;
- case NODE_CLASS_OUTPUT:
+ case NODE_CLASS_OUTPUT: {
+ if (node.type == GEO_NODE_VIEWER) {
+ return &node == tree_draw_ctx.active_geometry_nodes_viewer ? TH_NODE_OUTPUT : TH_NODE;
+ }
return (node.flag & NODE_DO_OUTPUT) ? TH_NODE_OUTPUT : TH_NODE;
+ }
case NODE_CLASS_CONVERTER:
return TH_NODE_CONVERTER;
case NODE_CLASS_OP_COLOR:
@@ -2055,7 +2068,7 @@ static void node_draw_basis(const bContext &C,
const rctf &rct = node.totr;
float color[4];
- int color_id = node_get_colorid(node);
+ int color_id = node_get_colorid(tree_draw_ctx, node);
GPU_line_width(1.0f);
@@ -2153,6 +2166,29 @@ static void node_draw_basis(const bContext &C,
"");
UI_block_emboss_set(&block, UI_EMBOSS);
}
+ if (node.type == GEO_NODE_VIEWER) {
+ const bool is_active = &node == tree_draw_ctx.active_geometry_nodes_viewer;
+ iconofs -= iconbutw;
+ UI_block_emboss_set(&block, UI_EMBOSS_NONE);
+ uiBut *but = uiDefIconBut(&block,
+ UI_BTYPE_BUT,
+ 0,
+ is_active ? ICON_HIDE_OFF : ICON_HIDE_ON,
+ iconofs,
+ rct.ymax - NODE_DY,
+ iconbutw,
+ UI_UNIT_Y,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ "");
+ /* Selection implicitly activates the node. */
+ const char *operator_idname = is_active ? "NODE_OT_deactivate_viewer" : "NODE_OT_select";
+ UI_but_func_set(but, node_toggle_button_cb, &node, (void *)operator_idname);
+ UI_block_emboss_set(&block, UI_EMBOSS);
+ }
node_add_error_message_button(tree_draw_ctx, node, block, rct, iconofs);
@@ -2341,7 +2377,7 @@ static void node_draw_hidden(const bContext &C,
float scale;
UI_view2d_scale_get(&v2d, &scale, nullptr);
- const int color_id = node_get_colorid(node);
+ const int color_id = node_get_colorid(tree_draw_ctx, node);
node_draw_extra_info_panel(tree_draw_ctx, snode, node, block);
@@ -2698,7 +2734,8 @@ static void node_update_nodetree(const bContext &C,
}
}
-static void frame_node_draw_label(const bNodeTree &ntree,
+static void frame_node_draw_label(TreeDrawContext &tree_draw_ctx,
+ const bNodeTree &ntree,
const bNode &node,
const SpaceNode &snode)
{
@@ -2717,7 +2754,7 @@ static void frame_node_draw_label(const bNodeTree &ntree,
BLF_size(fontid, MIN2(24.0f, font_size) * U.dpi_fac);
/* title color */
- int color_id = node_get_colorid(node);
+ int color_id = node_get_colorid(tree_draw_ctx, node);
uchar color[3];
UI_GetThemeColorBlendShade3ubv(TH_TEXT, color_id, 0.4f, 10, color);
BLF_color3ubv(fontid, color);
@@ -2831,7 +2868,7 @@ static void frame_node_draw(const bContext &C,
}
/* label and text */
- frame_node_draw_label(ntree, node, snode);
+ frame_node_draw_label(tree_draw_ctx, ntree, node, snode);
node_draw_extra_info_panel(tree_draw_ctx, snode, node, block);
@@ -3036,6 +3073,9 @@ static void draw_nodetree(const bContext &C,
tree_draw_ctx.geo_tree_log->ensure_node_warnings();
tree_draw_ctx.geo_tree_log->ensure_node_run_time();
}
+ WorkSpace *workspace = CTX_wm_workspace(&C);
+ tree_draw_ctx.active_geometry_nodes_viewer = viewer_path::find_geometry_nodes_viewer(
+ workspace->viewer_path, *snode);
}
node_update_nodetree(C, tree_draw_ctx, ntree, nodes, blocks);
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index e446d5421e7..8135369f271 100644
--- a/source/blender/editors/space_node/node_edit.cc
+++ b/source/blender/editors/space_node/node_edit.cc
@@ -43,7 +43,7 @@
#include "ED_render.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
-#include "ED_spreadsheet.h"
+#include "ED_viewer_path.hh"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -821,8 +821,8 @@ void ED_node_set_active(
}
}
node->flag |= NODE_DO_OUTPUT;
- ED_spreadsheet_context_paths_set_geometry_node(bmain, snode, node);
}
+ blender::ed::viewer_path::activate_geometry_node(*bmain, *snode, *node);
}
}
}
@@ -1700,6 +1700,46 @@ void NODE_OT_preview_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static int node_deactivate_viewer_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ WorkSpace &workspace = *CTX_wm_workspace(C);
+
+ bNode *active_viewer = viewer_path::find_geometry_nodes_viewer(workspace.viewer_path, snode);
+
+ LISTBASE_FOREACH (bNode *, node, &snode.edittree->nodes) {
+ if (node->type != GEO_NODE_VIEWER) {
+ continue;
+ }
+ if (!(node->flag & SELECT)) {
+ continue;
+ }
+ if (node == active_viewer) {
+ node->flag &= ~NODE_DO_OUTPUT;
+ BKE_ntree_update_tag_node_property(snode.edittree, node);
+ }
+ }
+
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
+
+ return OPERATOR_FINISHED;
+}
+
+void NODE_OT_deactivate_viewer(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Deactivate Viewer Node";
+ ot->description = "Deactivate selected viewer node in geometry nodes";
+ ot->idname = __func__;
+
+ /* callbacks */
+ ot->exec = node_deactivate_viewer_exec;
+ ot->poll = ED_operator_node_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
static int node_options_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceNode *snode = CTX_wm_space_node(C);
diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh
index 70ac0e48d01..50c03489027 100644
--- a/source/blender/editors/space_node/node_intern.hh
+++ b/source/blender/editors/space_node/node_intern.hh
@@ -322,6 +322,7 @@ void NODE_OT_hide_socket_toggle(wmOperatorType *ot);
void NODE_OT_preview_toggle(wmOperatorType *ot);
void NODE_OT_options_toggle(wmOperatorType *ot);
void NODE_OT_node_copy_color(wmOperatorType *ot);
+void NODE_OT_deactivate_viewer(wmOperatorType *ot);
void NODE_OT_read_viewlayers(wmOperatorType *ot);
void NODE_OT_render_changed(wmOperatorType *ot);
diff --git a/source/blender/editors/space_node/node_ops.cc b/source/blender/editors/space_node/node_ops.cc
index f02c019359d..6c52dae5b86 100644
--- a/source/blender/editors/space_node/node_ops.cc
+++ b/source/blender/editors/space_node/node_ops.cc
@@ -44,6 +44,7 @@ void node_operatortypes()
WM_operatortype_append(NODE_OT_options_toggle);
WM_operatortype_append(NODE_OT_hide_socket_toggle);
WM_operatortype_append(NODE_OT_node_copy_color);
+ WM_operatortype_append(NODE_OT_deactivate_viewer);
WM_operatortype_append(NODE_OT_duplicate);
WM_operatortype_append(NODE_OT_delete);
@@ -135,6 +136,7 @@ void ED_operatormacros_node()
mot = WM_operatortype_macro_define(ot, "NODE_OT_select");
RNA_boolean_set(mot->ptr, "extend", false);
RNA_boolean_set(mot->ptr, "socket_select", true);
+ RNA_boolean_set(mot->ptr, "clear_viewer", true);
WM_operatortype_macro_define(ot, "NODE_OT_link_viewer");
ot = WM_operatortype_append_macro("NODE_OT_translate_attach",
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index f597bf20b55..84cef798907 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -27,8 +27,8 @@
#include "ED_render.h"
#include "ED_screen.h"
#include "ED_space_api.h"
-#include "ED_spreadsheet.h"
#include "ED_util.h"
+#include "ED_viewer_path.hh"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -495,17 +495,6 @@ static bool is_viewer_node(const bNode &node)
return ELEM(node.type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER);
}
-static Vector<const bNode *> find_viewer_nodes(const bNodeTree &tree)
-{
- Vector<const bNode *> viewer_nodes;
- for (const bNode *node : tree.all_nodes()) {
- if (is_viewer_node(*node)) {
- viewer_nodes.append(node);
- }
- }
- return viewer_nodes;
-}
-
static bool is_viewer_socket_in_viewer(const bNodeSocket &socket)
{
const bNode &node = socket.owner_node();
@@ -516,18 +505,10 @@ static bool is_viewer_socket_in_viewer(const bNodeSocket &socket)
return socket.index() == 0;
}
-static bool is_linked_to_viewer(const bNodeSocket &socket, const bNode &viewer_node)
+static bool is_viewer_socket(const bNodeSocket &socket)
{
- for (const bNodeSocket *target_socket : socket.directly_linked_sockets()) {
- if (&target_socket->owner_node() != &viewer_node) {
- continue;
- }
- if (!target_socket->is_available()) {
- continue;
- }
- if (is_viewer_socket_in_viewer(*target_socket)) {
- return true;
- }
+ if (is_viewer_node(socket.owner_node())) {
+ return is_viewer_socket_in_viewer(socket);
}
return false;
}
@@ -549,137 +530,165 @@ static void remove_links_to_unavailable_viewer_sockets(bNodeTree &btree, bNode &
}
}
-static const bNode *get_existing_viewer(const bNodeTree &tree)
+static bNodeSocket *determine_socket_to_view(bNode &node_to_view)
{
- Vector<const bNode *> viewer_nodes = find_viewer_nodes(tree);
-
- /* Check if there is already an active viewer node that should be used. */
- for (const bNode *viewer_node : viewer_nodes) {
- if (viewer_node->flag & NODE_DO_OUTPUT) {
- return viewer_node;
+ int last_linked_socket_index = -1;
+ for (bNodeSocket *socket : node_to_view.output_sockets()) {
+ if (!socket_can_be_viewed(*socket)) {
+ continue;
}
- }
-
- /* If no active but non-active viewers exist, make one active. */
- if (!viewer_nodes.is_empty()) {
- const_cast<bNode *>(viewer_nodes[0])->flag |= NODE_DO_OUTPUT;
- return viewer_nodes[0];
- }
- return nullptr;
-}
-
-static const bNodeSocket *find_output_socket_to_be_viewed(const bNode *active_viewer_node,
- const bNode &node_to_view)
-{
- /* Check if any of the output sockets is selected, which is the case when the user just clicked
- * on the socket. */
- for (const bNodeSocket *output_socket : node_to_view.output_sockets()) {
- if (output_socket->flag & SELECT) {
- return output_socket;
+ for (bNodeLink *link : socket->directly_linked_links()) {
+ bNodeSocket &target_socket = *link->tosock;
+ bNode &target_node = *link->tonode;
+ if (is_viewer_socket(target_socket)) {
+ if (link->is_muted() || !(target_node.flag & NODE_DO_OUTPUT)) {
+ /* This socket is linked to a deactivated viewer, the viewer should be activated. */
+ return socket;
+ }
+ last_linked_socket_index = socket->index();
+ }
}
}
- const bNodeSocket *last_socket_linked_to_viewer = nullptr;
- if (active_viewer_node != nullptr) {
- for (const bNodeSocket *output_socket : node_to_view.output_sockets()) {
- if (!socket_can_be_viewed(*output_socket)) {
- continue;
- }
- if (is_linked_to_viewer(*output_socket, *active_viewer_node)) {
- last_socket_linked_to_viewer = output_socket;
+ if (last_linked_socket_index == -1) {
+ /* Returnt he first socket that can be viewed. */
+ for (bNodeSocket *socket : node_to_view.output_sockets()) {
+ if (socket_can_be_viewed(*socket)) {
+ return socket;
}
}
+ return nullptr;
}
- if (last_socket_linked_to_viewer == nullptr) {
- /* If no output is connected to a viewer, use the first output that can be viewed. */
- for (const bNodeSocket *output_socket : node_to_view.output_sockets()) {
- if (socket_can_be_viewed(*output_socket)) {
- return output_socket;
- }
+
+ /* Pick the next socket to be linked to the viewer. */
+ const int tot_outputs = node_to_view.output_sockets().size();
+ for (const int offset : IndexRange(1, tot_outputs)) {
+ const int index = (last_linked_socket_index + offset) % tot_outputs;
+ bNodeSocket &output_socket = node_to_view.output_socket(index);
+ if (!socket_can_be_viewed(output_socket)) {
+ continue;
}
- }
- else {
- /* Pick the next socket to be linked to the viewer. */
- const int tot_outputs = node_to_view.output_sockets().size();
- for (const int offset : IndexRange(1, tot_outputs - 1)) {
- const int index = (last_socket_linked_to_viewer->index() + offset) % tot_outputs;
- const bNodeSocket &output_socket = node_to_view.output_socket(index);
- if (!socket_can_be_viewed(output_socket)) {
+ bool is_currently_viewed = false;
+ for (const bNodeLink *link : output_socket.directly_linked_links()) {
+ bNodeSocket &target_socket = *link->tosock;
+ bNode &target_node = *link->tonode;
+ if (!is_viewer_socket(target_socket)) {
continue;
}
- if (is_linked_to_viewer(output_socket, *active_viewer_node)) {
+ if (link->is_muted()) {
continue;
}
- return &output_socket;
+ if (!(target_node.flag & NODE_DO_OUTPUT)) {
+ continue;
+ }
+ is_currently_viewed = true;
+ break;
}
+ if (is_currently_viewed) {
+ continue;
+ }
+ return &output_socket;
}
return nullptr;
}
-static int link_socket_to_viewer(const bContext &C,
- bNode *viewer_bnode,
- bNode &bnode_to_view,
- bNodeSocket &bsocket_to_view)
+static void finalize_viewer_link(const bContext &C,
+ SpaceNode &snode,
+ bNode &viewer_node,
+ bNodeLink &viewer_link)
{
- SpaceNode &snode = *CTX_wm_space_node(&C);
- bNodeTree &btree = *snode.edittree;
+ Main *bmain = CTX_data_main(&C);
+ remove_links_to_unavailable_viewer_sockets(*snode.edittree, viewer_node);
+ viewer_link.flag &= ~NODE_LINK_MUTED;
+ viewer_node.flag &= ~NODE_MUTED;
+ viewer_node.flag |= NODE_DO_OUTPUT;
+ if (snode.edittree->type == NTREE_GEOMETRY) {
+ viewer_path::activate_geometry_node(*bmain, snode, viewer_node);
+ }
+ ED_node_tree_propagate_change(&C, bmain, snode.edittree);
+}
+
+static int view_socket(const bContext &C,
+ SpaceNode &snode,
+ bNodeTree &btree,
+ bNode &bnode_to_view,
+ bNodeSocket &bsocket_to_view)
+{
+ bNode *viewer_node = nullptr;
+ /* Try to find a viewer that is already active. */
+ LISTBASE_FOREACH (bNode *, node, &btree.nodes) {
+ if (is_viewer_node(*node)) {
+ if (node->flag & NODE_DO_OUTPUT) {
+ viewer_node = node;
+ break;
+ }
+ }
+ }
- if (viewer_bnode == nullptr) {
- /* Create a new viewer node if none exists. */
+ /* Try to reactivate existing viewer connection. */
+ for (bNodeLink *link : bsocket_to_view.directly_linked_links()) {
+ bNodeSocket &target_socket = *link->tosock;
+ bNode &target_node = *link->tonode;
+ if (is_viewer_socket(target_socket) && ELEM(viewer_node, nullptr, &target_node)) {
+ finalize_viewer_link(C, snode, target_node, *link);
+ return OPERATOR_FINISHED;
+ }
+ }
+
+ if (viewer_node == nullptr) {
+ LISTBASE_FOREACH (bNode *, node, &btree.nodes) {
+ if (is_viewer_node(*node)) {
+ viewer_node = node;
+ break;
+ }
+ }
+ }
+ if (viewer_node == nullptr) {
const int viewer_type = get_default_viewer_type(&C);
const float2 location{bsocket_to_view.locx / UI_DPI_FAC + 100,
bsocket_to_view.locy / UI_DPI_FAC};
- viewer_bnode = add_static_node(C, viewer_type, location);
- if (viewer_bnode == nullptr) {
- return OPERATOR_CANCELLED;
- }
+ viewer_node = add_static_node(C, viewer_type, location);
}
- bNodeSocket *viewer_bsocket = node_link_viewer_get_socket(btree, *viewer_bnode, bsocket_to_view);
+ bNodeSocket *viewer_bsocket = node_link_viewer_get_socket(btree, *viewer_node, bsocket_to_view);
if (viewer_bsocket == nullptr) {
return OPERATOR_CANCELLED;
}
-
- bNodeLink *link_to_change = nullptr;
- LISTBASE_FOREACH (bNodeLink *, link, &btree.links) {
+ bNodeLink *viewer_link = nullptr;
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &btree.links) {
if (link->tosock == viewer_bsocket) {
- link_to_change = link;
+ viewer_link = link;
break;
}
}
-
- if (link_to_change == nullptr) {
- nodeAddLink(&btree, &bnode_to_view, &bsocket_to_view, viewer_bnode, viewer_bsocket);
+ if (viewer_link == nullptr) {
+ viewer_link = nodeAddLink(
+ &btree, &bnode_to_view, &bsocket_to_view, viewer_node, viewer_bsocket);
}
else {
- link_to_change->fromnode = &bnode_to_view;
- link_to_change->fromsock = &bsocket_to_view;
+ viewer_link->fromnode = &bnode_to_view;
+ viewer_link->fromsock = &bsocket_to_view;
BKE_ntree_update_tag_link_changed(&btree);
}
-
- remove_links_to_unavailable_viewer_sockets(btree, *viewer_bnode);
-
- if (btree.type == NTREE_GEOMETRY) {
- ED_spreadsheet_context_paths_set_geometry_node(CTX_data_main(&C), &snode, viewer_bnode);
- }
-
- ED_node_tree_propagate_change(&C, CTX_data_main(&C), &btree);
- return OPERATOR_FINISHED;
+ finalize_viewer_link(C, snode, *viewer_node, *viewer_link);
+ return OPERATOR_CANCELLED;
}
-static int node_link_viewer(const bContext &C, bNode &bnode_to_view)
+static int node_link_viewer(const bContext &C, bNode &bnode_to_view, bNodeSocket *bsocket_to_view)
{
SpaceNode &snode = *CTX_wm_space_node(&C);
bNodeTree *btree = snode.edittree;
btree->ensure_topology_cache();
- bNode *active_viewer_bnode = const_cast<bNode *>(get_existing_viewer(*btree));
- bNodeSocket *bsocket_to_view = const_cast<bNodeSocket *>(
- find_output_socket_to_be_viewed(active_viewer_bnode, bnode_to_view));
if (bsocket_to_view == nullptr) {
- return OPERATOR_FINISHED;
+ bsocket_to_view = determine_socket_to_view(bnode_to_view);
}
- return link_socket_to_viewer(C, active_viewer_bnode, bnode_to_view, *bsocket_to_view);
+
+ if (bsocket_to_view == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ return view_socket(C, snode, *btree, bnode_to_view, *bsocket_to_view);
}
/** \} */
@@ -701,7 +710,15 @@ static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op))
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- if (viewer_linking::node_link_viewer(*C, *node) == OPERATOR_CANCELLED) {
+ bNodeSocket *socket_to_view = nullptr;
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ if (socket->flag & SELECT) {
+ socket_to_view = socket;
+ break;
+ }
+ }
+
+ if (viewer_linking::node_link_viewer(*C, *node, socket_to_view) == OPERATOR_CANCELLED) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc
index 1b47316ebd0..c11ae323115 100644
--- a/source/blender/editors/space_node/node_select.cc
+++ b/source/blender/editors/space_node/node_select.cc
@@ -23,13 +23,14 @@
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_node_runtime.hh"
+#include "BKE_node_tree_update.h"
#include "BKE_workspace.h"
#include "ED_node.h" /* own include */
#include "ED_screen.h"
#include "ED_select_utils.h"
-#include "ED_spreadsheet.h"
#include "ED_view3d.h"
+#include "ED_viewer_path.hh"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -644,6 +645,15 @@ static bool node_mouse_select(bContext *C,
}
}
+ if (RNA_boolean_get(op->ptr, "clear_viewer")) {
+ if (node == nullptr) {
+ /* Disable existing active viewer. */
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ BKE_viewer_path_clear(&workspace->viewer_path);
+ WM_event_add_notifier(C, NC_VIEWER_PATH, nullptr);
+ }
+ }
+
if (!(changed || found)) {
return false;
}
@@ -655,7 +665,7 @@ static bool node_mouse_select(bContext *C,
ED_node_set_active(&bmain, &snode, snode.edittree, node, &active_texture_changed);
}
else if (node != nullptr && node->type == GEO_NODE_VIEWER) {
- ED_spreadsheet_context_paths_set_geometry_node(&bmain, &snode, node);
+ viewer_path::activate_geometry_node(bmain, snode, *node);
}
ED_node_set_active_viewer_key(&snode);
node_sort(*snode.edittree);
@@ -731,6 +741,12 @@ void NODE_OT_select(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_boolean(ot->srna, "socket_select", false, "Socket Select", "");
+
+ RNA_def_boolean(ot->srna,
+ "clear_viewer",
+ false,
+ "Clear Viewer",
+ "Deactivate geometry nodes viewer when clicking in empty space");
}
/** \} */
diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc
index ea551b7488a..3e5cbf88e15 100644
--- a/source/blender/editors/space_node/space_node.cc
+++ b/source/blender/editors/space_node/space_node.cc
@@ -823,6 +823,9 @@ static void node_region_listener(const wmRegionListenerParams *params)
ED_region_tag_redraw(region);
}
break;
+ case NC_VIEWER_PATH:
+ ED_region_tag_redraw(region);
+ break;
}
}
diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt
index a551e096b48..08032ddbaeb 100644
--- a/source/blender/editors/space_spreadsheet/CMakeLists.txt
+++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt
@@ -27,7 +27,6 @@ set(SRC
space_spreadsheet.cc
spreadsheet_cache.cc
spreadsheet_column.cc
- spreadsheet_context.cc
spreadsheet_data_source.cc
spreadsheet_data_source_geometry.cc
spreadsheet_dataset_draw.cc
@@ -41,7 +40,6 @@ set(SRC
spreadsheet_cache.hh
spreadsheet_column.hh
spreadsheet_column_values.hh
- spreadsheet_context.hh
spreadsheet_data_source.hh
spreadsheet_data_source_geometry.hh
spreadsheet_dataset_draw.hh
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index d5fa0145fe5..ee43519e260 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -10,6 +10,7 @@
#include "ED_screen.h"
#include "ED_space_api.h"
#include "ED_spreadsheet.h"
+#include "ED_viewer_path.hh"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
@@ -34,7 +35,6 @@
#include "BLF_api.h"
-#include "spreadsheet_context.hh"
#include "spreadsheet_data_source_geometry.hh"
#include "spreadsheet_dataset_draw.hh"
#include "spreadsheet_intern.hh"
@@ -107,9 +107,7 @@ static void spreadsheet_free(SpaceLink *sl)
LISTBASE_FOREACH_MUTABLE (SpreadsheetColumn *, column, &sspreadsheet->columns) {
spreadsheet_column_free(column);
}
- LISTBASE_FOREACH_MUTABLE (SpreadsheetContext *, context, &sspreadsheet->context_path) {
- spreadsheet_context_free(context);
- }
+ BKE_viewer_path_clear(&sspreadsheet->viewer_path);
}
static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *area)
@@ -143,11 +141,7 @@ static SpaceLink *spreadsheet_duplicate(SpaceLink *sl)
BLI_addtail(&sspreadsheet_new->columns, new_column);
}
- BLI_listbase_clear(&sspreadsheet_new->context_path);
- LISTBASE_FOREACH_MUTABLE (SpreadsheetContext *, src_context, &sspreadsheet_old->context_path) {
- SpreadsheetContext *new_context = spreadsheet_context_copy(src_context);
- BLI_addtail(&sspreadsheet_new->context_path, new_context);
- }
+ BKE_viewer_path_copy(&sspreadsheet_new->viewer_path, &sspreadsheet_old->viewer_path);
return (SpaceLink *)sspreadsheet_new;
}
@@ -163,19 +157,7 @@ static void spreadsheet_id_remap(ScrArea *UNUSED(area),
const IDRemapper *mappings)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)slink;
- LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
- if (context->type != SPREADSHEET_CONTEXT_OBJECT) {
- continue;
- }
- SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context;
-
- if (object_context->object != nullptr && GS(object_context->object->id.name) != ID_OB) {
- object_context->object = nullptr;
- continue;
- }
-
- BKE_id_remapper_apply(mappings, ((ID **)&object_context->object), ID_REMAP_APPLY_DEFAULT);
- }
+ BKE_viewer_path_id_remap(&sspreadsheet->viewer_path, mappings);
}
static void spreadsheet_main_region_init(wmWindowManager *wm, ARegion *region)
@@ -201,54 +183,105 @@ static void spreadsheet_main_region_init(wmWindowManager *wm, ARegion *region)
ID *ED_spreadsheet_get_current_id(const struct SpaceSpreadsheet *sspreadsheet)
{
- if (BLI_listbase_is_empty(&sspreadsheet->context_path)) {
+ if (BLI_listbase_is_empty(&sspreadsheet->viewer_path.path)) {
return nullptr;
}
- SpreadsheetContext *root_context = (SpreadsheetContext *)sspreadsheet->context_path.first;
- if (root_context->type != SPREADSHEET_CONTEXT_OBJECT) {
+ ViewerPathElem *root_context = static_cast<ViewerPathElem *>(
+ sspreadsheet->viewer_path.path.first);
+ if (root_context->type != VIEWER_PATH_ELEM_TYPE_ID) {
return nullptr;
}
- SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)root_context;
- return (ID *)object_context->object;
+ IDViewerPathElem *id_elem = reinterpret_cast<IDViewerPathElem *>(root_context);
+ return id_elem->id;
}
-/* Check if the pinned context still exists. If it doesn't try to find a new context. */
-static void update_pinned_context_path_if_outdated(const bContext *C)
+static void view_active_object(const bContext *C, SpaceSpreadsheet *sspreadsheet)
{
- SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
- Main *bmain = CTX_data_main(C);
- if (!ED_spreadsheet_context_path_exists(bmain, sspreadsheet)) {
- ED_spreadsheet_context_path_guess(C, sspreadsheet);
- if (ED_spreadsheet_context_path_update_tag(sspreadsheet)) {
- ED_area_tag_redraw(CTX_wm_area(C));
- }
- }
-
- if (BLI_listbase_is_empty(&sspreadsheet->context_path)) {
- /* Don't pin empty context_path, that could be annoying. */
- sspreadsheet->flag &= ~SPREADSHEET_FLAG_PINNED;
+ BKE_viewer_path_clear(&sspreadsheet->viewer_path);
+ Object *ob = CTX_data_active_object(C);
+ if (ob == nullptr) {
+ return;
}
+ IDViewerPathElem *id_elem = BKE_viewer_path_elem_new_id();
+ id_elem->id = &ob->id;
+ BLI_addtail(&sspreadsheet->viewer_path.path, id_elem);
+ ED_area_tag_redraw(CTX_wm_area(C));
}
-static void update_context_path_from_context(const bContext *C)
+static void spreadsheet_update_context(const bContext *C)
{
+ using blender::ed::viewer_path::ViewerPathForGeometryNodesViewer;
+
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
- if (!ED_spreadsheet_context_path_is_active(C, sspreadsheet)) {
- ED_spreadsheet_context_path_guess(C, sspreadsheet);
- if (ED_spreadsheet_context_path_update_tag(sspreadsheet)) {
- ED_area_tag_redraw(CTX_wm_area(C));
+ Object *active_object = CTX_data_active_object(C);
+ Object *context_object = blender::ed::viewer_path::parse_object_only(sspreadsheet->viewer_path);
+ switch (eSpaceSpreadsheet_ObjectEvalState(sspreadsheet->object_eval_state)) {
+ case SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL:
+ case SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED: {
+ if (sspreadsheet->flag & SPREADSHEET_FLAG_PINNED) {
+ if (context_object == nullptr) {
+ /* Object is not available anymore, so clear the pinning. */
+ sspreadsheet->flag &= ~SPREADSHEET_FLAG_PINNED;
+ }
+ else {
+ /* The object is still pinned, do nothing. */
+ break;
+ }
+ }
+ else {
+ if (active_object != context_object) {
+ /* The active object has changed, so view the new active object. */
+ view_active_object(C, sspreadsheet);
+ }
+ else {
+ /* Nothing changed. */
+ break;
+ }
+ }
+ break;
}
- }
-}
+ case SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE: {
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ if (sspreadsheet->flag & SPREADSHEET_FLAG_PINNED) {
+ const std::optional<ViewerPathForGeometryNodesViewer> parsed_path =
+ blender::ed::viewer_path::parse_geometry_nodes_viewer(sspreadsheet->viewer_path);
+ if (parsed_path.has_value()) {
+ if (blender::ed::viewer_path::exists_geometry_nodes_viewer(*parsed_path)) {
+ /* The pinned path is still valid, do nothing. */
+ break;
+ }
+ else {
+ /* The pinned path does not exist anymore, clear pinning. */
+ sspreadsheet->flag &= ~SPREADSHEET_FLAG_PINNED;
+ }
+ }
+ else {
+ /* Unknown pinned path, clear pinning. */
+ sspreadsheet->flag &= ~SPREADSHEET_FLAG_PINNED;
+ }
+ }
+ /* Now try to update the viewer path from the workspace. */
+ const std::optional<ViewerPathForGeometryNodesViewer> workspace_parsed_path =
+ blender::ed::viewer_path::parse_geometry_nodes_viewer(workspace->viewer_path);
+ if (workspace_parsed_path.has_value()) {
+ if (BKE_viewer_path_equal(&sspreadsheet->viewer_path, &workspace->viewer_path)) {
+ /* Nothing changed. */
+ break;
+ }
+ else {
+ /* Update the viewer path from the workspace. */
+ BKE_viewer_path_clear(&sspreadsheet->viewer_path);
+ BKE_viewer_path_copy(&sspreadsheet->viewer_path, &workspace->viewer_path);
+ }
+ }
+ else {
+ /* No active viewer node, change back to showing evaluated active object. */
+ sspreadsheet->object_eval_state = SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED;
+ view_active_object(C, sspreadsheet);
+ }
-void spreadsheet_update_context_path(const bContext *C)
-{
- SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
- if (sspreadsheet->flag & SPREADSHEET_FLAG_PINNED) {
- update_pinned_context_path_if_outdated(C);
- }
- else {
- update_context_path_from_context(C);
+ break;
+ }
}
}
@@ -390,7 +423,7 @@ static void spreadsheet_main_region_draw(const bContext *C, ARegion *region)
{
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
sspreadsheet->runtime->cache.set_all_unused();
- spreadsheet_update_context_path(C);
+ spreadsheet_update_context(C);
std::unique_ptr<DataSource> data_source = get_data_source(C);
if (!data_source) {
@@ -439,6 +472,7 @@ static void spreadsheet_main_region_listener(const wmRegionListenerParams *param
{
ARegion *region = params->region;
const wmNotifier *wmn = params->notifier;
+ SpaceSpreadsheet *sspreadsheet = static_cast<SpaceSpreadsheet *>(params->area->spacedata.first);
switch (wmn->category) {
case NC_SCENE: {
@@ -467,6 +501,12 @@ static void spreadsheet_main_region_listener(const wmRegionListenerParams *param
ED_region_tag_redraw(region);
break;
}
+ case NC_VIEWER_PATH: {
+ if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE) {
+ ED_region_tag_redraw(region);
+ }
+ break;
+ }
}
}
@@ -477,7 +517,7 @@ static void spreadsheet_header_region_init(wmWindowManager *UNUSED(wm), ARegion
static void spreadsheet_header_region_draw(const bContext *C, ARegion *region)
{
- spreadsheet_update_context_path(C);
+ spreadsheet_update_context(C);
ED_region_header(C, region);
}
@@ -489,6 +529,7 @@ static void spreadsheet_header_region_listener(const wmRegionListenerParams *par
{
ARegion *region = params->region;
const wmNotifier *wmn = params->notifier;
+ SpaceSpreadsheet *sspreadsheet = static_cast<SpaceSpreadsheet *>(params->area->spacedata.first);
switch (wmn->category) {
case NC_SCENE: {
@@ -515,6 +556,12 @@ static void spreadsheet_header_region_listener(const wmRegionListenerParams *par
ED_region_tag_redraw(region);
break;
}
+ case NC_VIEWER_PATH: {
+ if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE) {
+ ED_region_tag_redraw(region);
+ }
+ break;
+ }
}
}
@@ -593,7 +640,7 @@ static void spreadsheet_dataset_region_listener(const wmRegionListenerParams *pa
static void spreadsheet_dataset_region_draw(const bContext *C, ARegion *region)
{
- spreadsheet_update_context_path(C);
+ spreadsheet_update_context(C);
ED_region_panels(C, region);
}
@@ -634,34 +681,13 @@ static void spreadsheet_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
BLO_read_data_address(reader, &column->display_name);
}
- BLO_read_list(reader, &sspreadsheet->context_path);
- LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
- switch (context->type) {
- case SPREADSHEET_CONTEXT_NODE: {
- SpreadsheetContextNode *node_context = (SpreadsheetContextNode *)context;
- BLO_read_data_address(reader, &node_context->node_name);
- break;
- }
- case SPREADSHEET_CONTEXT_MODIFIER: {
- SpreadsheetContextModifier *modifier_context = (SpreadsheetContextModifier *)context;
- BLO_read_data_address(reader, &modifier_context->modifier_name);
- break;
- }
- case SPREADSHEET_CONTEXT_OBJECT: {
- break;
- }
- }
- }
+ BKE_viewer_path_blend_read_data(reader, &sspreadsheet->viewer_path);
}
static void spreadsheet_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
- LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
- if (context->type == SPREADSHEET_CONTEXT_OBJECT) {
- BLO_read_id_address(reader, parent_id->lib, &((SpreadsheetContextObject *)context)->object);
- }
- }
+ BKE_viewer_path_blend_read_lib(reader, parent_id->lib, &sspreadsheet->viewer_path);
}
static void spreadsheet_blend_write(BlendWriter *writer, SpaceLink *sl)
@@ -683,27 +709,8 @@ static void spreadsheet_blend_write(BlendWriter *writer, SpaceLink *sl)
* This would ideally be cleared here. */
BLO_write_string(writer, column->display_name);
}
- LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
- switch (context->type) {
- case SPREADSHEET_CONTEXT_OBJECT: {
- SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context;
- BLO_write_struct(writer, SpreadsheetContextObject, object_context);
- break;
- }
- case SPREADSHEET_CONTEXT_MODIFIER: {
- SpreadsheetContextModifier *modifier_context = (SpreadsheetContextModifier *)context;
- BLO_write_struct(writer, SpreadsheetContextModifier, modifier_context);
- BLO_write_string(writer, modifier_context->modifier_name);
- break;
- }
- case SPREADSHEET_CONTEXT_NODE: {
- SpreadsheetContextNode *node_context = (SpreadsheetContextNode *)context;
- BLO_write_struct(writer, SpreadsheetContextNode, node_context);
- BLO_write_string(writer, node_context->node_name);
- break;
- }
- }
- }
+
+ BKE_viewer_path_blend_write(writer, &sspreadsheet->viewer_path);
}
void ED_spacetype_spreadsheet()
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc
deleted file mode 100644
index ec9fa72edb1..00000000000
--- a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc
+++ /dev/null
@@ -1,591 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_hash.h"
-#include "BLI_hash.hh"
-#include "BLI_hash_mm2a.h"
-#include "BLI_listbase.h"
-#include "BLI_string.h"
-#include "BLI_utildefines.h"
-#include "BLI_vector.hh"
-
-#include "ED_screen.h"
-#include "ED_spreadsheet.h"
-
-#include "DEG_depsgraph.h"
-
-#include "BKE_context.h"
-#include "BKE_main.h"
-#include "BKE_modifier.h"
-#include "BKE_node.h"
-#include "BKE_object.h"
-#include "BKE_workspace.h"
-
-#include "DNA_modifier_types.h"
-#include "DNA_windowmanager_types.h"
-
-#include "spreadsheet_context.hh"
-
-using blender::IndexRange;
-using blender::Span;
-using blender::StringRef;
-using blender::Vector;
-
-namespace blender::ed::spreadsheet {
-
-static SpreadsheetContextObject *spreadsheet_context_object_new()
-{
- SpreadsheetContextObject *context = MEM_cnew<SpreadsheetContextObject>(__func__);
- context->base.type = SPREADSHEET_CONTEXT_OBJECT;
- return context;
-}
-
-static SpreadsheetContextObject *spreadsheet_context_object_copy(
- const SpreadsheetContextObject *src_context)
-{
- SpreadsheetContextObject *new_context = spreadsheet_context_object_new();
- new_context->object = src_context->object;
- return new_context;
-}
-
-static void spreadsheet_context_object_hash(const SpreadsheetContextObject *context,
- BLI_HashMurmur2A *mm2)
-{
- BLI_hash_mm2a_add(mm2, (const uchar *)&context->object, sizeof(Object *));
-}
-
-static void spreadsheet_context_object_free(SpreadsheetContextObject *context)
-{
- MEM_freeN(context);
-}
-
-static SpreadsheetContextModifier *spreadsheet_context_modifier_new()
-{
- SpreadsheetContextModifier *context = MEM_cnew<SpreadsheetContextModifier>(__func__);
- context->base.type = SPREADSHEET_CONTEXT_MODIFIER;
- return context;
-}
-
-static SpreadsheetContextModifier *spreadsheet_context_modifier_copy(
- const SpreadsheetContextModifier *src_context)
-{
- SpreadsheetContextModifier *new_context = spreadsheet_context_modifier_new();
- if (src_context->modifier_name) {
- new_context->modifier_name = BLI_strdup(src_context->modifier_name);
- }
- return new_context;
-}
-
-static void spreadsheet_context_modifier_hash(const SpreadsheetContextModifier *context,
- BLI_HashMurmur2A *mm2)
-{
- if (context->modifier_name) {
- BLI_hash_mm2a_add(mm2, (const uchar *)context->modifier_name, strlen(context->modifier_name));
- }
-}
-
-static void spreadsheet_context_modifier_free(SpreadsheetContextModifier *context)
-{
- if (context->modifier_name) {
- MEM_freeN(context->modifier_name);
- }
- MEM_freeN(context);
-}
-
-static SpreadsheetContextNode *spreadsheet_context_node_new()
-{
- SpreadsheetContextNode *context = MEM_cnew<SpreadsheetContextNode>(__func__);
- context->base.type = SPREADSHEET_CONTEXT_NODE;
- return context;
-}
-
-static SpreadsheetContextNode *spreadsheet_context_node_copy(
- const SpreadsheetContextNode *src_context)
-{
- SpreadsheetContextNode *new_context = spreadsheet_context_node_new();
- if (src_context->node_name) {
- new_context->node_name = BLI_strdup(src_context->node_name);
- }
- return new_context;
-}
-
-static void spreadsheet_context_node_hash(const SpreadsheetContextNode *context,
- BLI_HashMurmur2A *mm2)
-{
- if (context->node_name) {
- BLI_hash_mm2a_add(mm2, (const uchar *)context->node_name, strlen(context->node_name));
- }
-}
-
-static void spreadsheet_context_node_free(SpreadsheetContextNode *context)
-{
- if (context->node_name) {
- MEM_freeN(context->node_name);
- }
- MEM_freeN(context);
-}
-
-SpreadsheetContext *spreadsheet_context_new(eSpaceSpreadsheet_ContextType type)
-{
- switch (type) {
- case SPREADSHEET_CONTEXT_OBJECT: {
- return (SpreadsheetContext *)spreadsheet_context_object_new();
- }
- case SPREADSHEET_CONTEXT_MODIFIER: {
- return (SpreadsheetContext *)spreadsheet_context_modifier_new();
- }
- case SPREADSHEET_CONTEXT_NODE: {
- return (SpreadsheetContext *)spreadsheet_context_node_new();
- }
- }
- BLI_assert_unreachable();
- return nullptr;
-}
-
-SpreadsheetContext *spreadsheet_context_copy(const SpreadsheetContext *old_context)
-{
- switch (old_context->type) {
- case SPREADSHEET_CONTEXT_OBJECT: {
- return (SpreadsheetContext *)spreadsheet_context_object_copy(
- (const SpreadsheetContextObject *)old_context);
- }
- case SPREADSHEET_CONTEXT_MODIFIER: {
- return (SpreadsheetContext *)spreadsheet_context_modifier_copy(
- (const SpreadsheetContextModifier *)old_context);
- }
- case SPREADSHEET_CONTEXT_NODE: {
- return (SpreadsheetContext *)spreadsheet_context_node_copy(
- (const SpreadsheetContextNode *)old_context);
- }
- }
- BLI_assert_unreachable();
- return nullptr;
-}
-
-static void spreadsheet_context_hash(const SpreadsheetContext *context, BLI_HashMurmur2A *mm2)
-{
- BLI_hash_mm2a_add_int(mm2, context->type);
- switch (context->type) {
- case SPREADSHEET_CONTEXT_OBJECT: {
- spreadsheet_context_object_hash((const SpreadsheetContextObject *)context, mm2);
- break;
- }
- case SPREADSHEET_CONTEXT_MODIFIER: {
- spreadsheet_context_modifier_hash((const SpreadsheetContextModifier *)context, mm2);
- break;
- }
- case SPREADSHEET_CONTEXT_NODE: {
- spreadsheet_context_node_hash((const SpreadsheetContextNode *)context, mm2);
- break;
- }
- }
-}
-
-void spreadsheet_context_free(SpreadsheetContext *context)
-{
- switch (context->type) {
- case SPREADSHEET_CONTEXT_OBJECT: {
- return spreadsheet_context_object_free((SpreadsheetContextObject *)context);
- }
- case SPREADSHEET_CONTEXT_MODIFIER: {
- return spreadsheet_context_modifier_free((SpreadsheetContextModifier *)context);
- }
- case SPREADSHEET_CONTEXT_NODE: {
- return spreadsheet_context_node_free((SpreadsheetContextNode *)context);
- }
- }
- BLI_assert_unreachable();
-}
-
-/**
- * Tag any data relevant to the spreadsheet's context for recalculation in order to collect
- * information to display in the editor, which may be cached during evaluation.
- * \return True when any data has been tagged for update.
- */
-static bool spreadsheet_context_update_tag(SpaceSpreadsheet *sspreadsheet)
-{
- using namespace blender;
- Vector<const SpreadsheetContext *> context_path = sspreadsheet->context_path;
- if (context_path.is_empty()) {
- return false;
- }
- if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) {
- return false;
- }
- SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context_path[0];
- Object *object = object_context->object;
- if (object == nullptr) {
- return false;
- }
- if (context_path.size() == 1) {
- /* No need to reevaluate, when the final or original object is viewed. */
- return false;
- }
-
- DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
- return true;
-}
-
-} // namespace blender::ed::spreadsheet
-
-SpreadsheetContext *ED_spreadsheet_context_new(int type)
-{
- return blender::ed::spreadsheet::spreadsheet_context_new((eSpaceSpreadsheet_ContextType)type);
-}
-
-void ED_spreadsheet_context_free(struct SpreadsheetContext *context)
-{
- blender::ed::spreadsheet::spreadsheet_context_free(context);
-}
-
-void ED_spreadsheet_context_path_clear(struct SpaceSpreadsheet *sspreadsheet)
-{
- LISTBASE_FOREACH_MUTABLE (SpreadsheetContext *, context, &sspreadsheet->context_path) {
- ED_spreadsheet_context_free(context);
- }
- BLI_listbase_clear(&sspreadsheet->context_path);
-}
-
-bool ED_spreadsheet_context_path_update_tag(SpaceSpreadsheet *sspreadsheet)
-{
- return blender::ed::spreadsheet::spreadsheet_context_update_tag(sspreadsheet);
-}
-
-uint64_t ED_spreadsheet_context_path_hash(const SpaceSpreadsheet *sspreadsheet)
-{
- BLI_HashMurmur2A mm2;
- BLI_hash_mm2a_init(&mm2, 1234);
- LISTBASE_FOREACH (const SpreadsheetContext *, context, &sspreadsheet->context_path) {
- blender::ed::spreadsheet::spreadsheet_context_hash(context, &mm2);
- }
- return BLI_hash_mm2a_end(&mm2);
-}
-
-void ED_spreadsheet_context_path_set_geometry_node(struct SpaceSpreadsheet *sspreadsheet,
- struct SpaceNode *snode,
- struct bNode *node)
-{
- using namespace blender::ed::spreadsheet;
-
- Object *object = (Object *)snode->id;
- /* Try to find the modifier the node tree belongs to. */
- ModifierData *modifier = BKE_object_active_modifier(object);
- if (modifier && modifier->type != eModifierType_Nodes) {
- modifier = nullptr;
- LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
- if (md->type == eModifierType_Nodes) {
- NodesModifierData *nmd = (NodesModifierData *)md;
- if (nmd->node_group == snode->nodetree) {
- modifier = md;
- break;
- }
- }
- }
- }
- if (modifier == nullptr) {
- return;
- }
-
- ED_spreadsheet_context_path_clear(sspreadsheet);
-
- {
- SpreadsheetContextObject *context = spreadsheet_context_object_new();
- context->object = object;
- BLI_addtail(&sspreadsheet->context_path, context);
- }
- {
- SpreadsheetContextModifier *context = spreadsheet_context_modifier_new();
- context->modifier_name = BLI_strdup(modifier->name);
- BLI_addtail(&sspreadsheet->context_path, context);
- }
- {
- int i;
- LISTBASE_FOREACH_INDEX (bNodeTreePath *, path, &snode->treepath, i) {
- if (i == 0) {
- continue;
- }
- SpreadsheetContextNode *context = spreadsheet_context_node_new();
- context->node_name = BLI_strdup(path->node_name);
- BLI_addtail(&sspreadsheet->context_path, context);
- }
- }
- {
- SpreadsheetContextNode *context = spreadsheet_context_node_new();
- context->node_name = BLI_strdup(node->name);
- BLI_addtail(&sspreadsheet->context_path, context);
- }
-
- sspreadsheet->object_eval_state = SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE;
-}
-
-void ED_spreadsheet_context_paths_set_geometry_node(Main *bmain, SpaceNode *snode, bNode *node)
-{
- wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
- if (wm == nullptr) {
- return;
- }
- LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
- bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
- LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
- SpaceLink *sl = (SpaceLink *)area->spacedata.first;
- if (sl->spacetype == SPACE_SPREADSHEET) {
- SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
- if ((sspreadsheet->flag & SPREADSHEET_FLAG_PINNED) == 0) {
- const uint64_t context_hash_before = ED_spreadsheet_context_path_hash(sspreadsheet);
- ED_spreadsheet_context_path_set_geometry_node(sspreadsheet, snode, node);
- const uint64_t context_hash_after = ED_spreadsheet_context_path_hash(sspreadsheet);
- if (context_hash_before != context_hash_after) {
- ED_spreadsheet_context_path_update_tag(sspreadsheet);
- }
- ED_area_tag_redraw(area);
- }
- }
- }
- }
-}
-
-void ED_spreadsheet_context_path_set_evaluated_object(SpaceSpreadsheet *sspreadsheet,
- Object *object)
-{
- using namespace blender::ed::spreadsheet;
- ED_spreadsheet_context_path_clear(sspreadsheet);
-
- SpreadsheetContextObject *context = spreadsheet_context_object_new();
- context->object = object;
- BLI_addtail(&sspreadsheet->context_path, context);
-}
-
-static bScreen *find_screen_to_search_for_context(wmWindow *window,
- SpaceSpreadsheet *current_space)
-{
- bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
- if (ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL)) {
- /* If the spreadsheet is maximized, try to find the context in the unmaximized screen. */
- ScrArea *main_area = (ScrArea *)screen->areabase.first;
- SpaceLink *sl = (SpaceLink *)main_area->spacedata.first;
- if (sl == (SpaceLink *)current_space) {
- return main_area->full;
- }
- }
- return screen;
-}
-
-void ED_spreadsheet_context_path_guess(const bContext *C, SpaceSpreadsheet *sspreadsheet)
-{
- ED_spreadsheet_context_path_clear(sspreadsheet);
-
- Main *bmain = CTX_data_main(C);
- wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
- if (wm == nullptr) {
- return;
- }
-
- if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE) {
- LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
- bScreen *screen = find_screen_to_search_for_context(window, sspreadsheet);
- LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
- SpaceLink *sl = (SpaceLink *)area->spacedata.first;
- if (sl == nullptr) {
- continue;
- }
- if (sl->spacetype == SPACE_NODE) {
- SpaceNode *snode = (SpaceNode *)sl;
- if (snode->edittree != nullptr) {
- if (snode->edittree->type == NTREE_GEOMETRY) {
- LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
- if (node->type == GEO_NODE_VIEWER) {
- if (node->flag & NODE_DO_OUTPUT) {
- ED_spreadsheet_context_path_set_geometry_node(sspreadsheet, snode, node);
- return;
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- Object *active_object = CTX_data_active_object(C);
- if (active_object != nullptr) {
- ED_spreadsheet_context_path_set_evaluated_object(sspreadsheet, active_object);
- return;
- }
-}
-
-bool ED_spreadsheet_context_path_is_active(const bContext *C, SpaceSpreadsheet *sspreadsheet)
-{
- Main *bmain = CTX_data_main(C);
- wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
- if (wm == nullptr) {
- return false;
- }
- Vector<SpreadsheetContext *> context_path = sspreadsheet->context_path;
- if (context_path.is_empty()) {
- return false;
- }
- if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) {
- return false;
- }
- Object *object = ((SpreadsheetContextObject *)context_path[0])->object;
- if (object == nullptr) {
- return false;
- }
- if (context_path.size() == 1) {
- if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE) {
- return false;
- }
- Object *active_object = CTX_data_active_object(C);
- return object == active_object;
- }
- if (sspreadsheet->object_eval_state != SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE) {
- return false;
- }
- if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) {
- return false;
- }
- const char *modifier_name = ((SpreadsheetContextModifier *)context_path[1])->modifier_name;
- const ModifierData *modifier = BKE_modifiers_findby_name(object, modifier_name);
- if (modifier == nullptr) {
- return false;
- }
- const bool modifier_is_active = modifier->flag & eModifierFlag_Active;
- if (modifier->type != eModifierType_Nodes) {
- return false;
- }
- bNodeTree *root_node_tree = ((NodesModifierData *)modifier)->node_group;
- if (root_node_tree == nullptr) {
- return false;
- }
- const Span<SpreadsheetContext *> node_context_path = context_path.as_span().drop_front(2);
- if (node_context_path.is_empty()) {
- return false;
- }
-
- LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
- bScreen *screen = find_screen_to_search_for_context(window, sspreadsheet);
- LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
- SpaceLink *sl = (SpaceLink *)area->spacedata.first;
- if (sl == nullptr) {
- continue;
- }
- if (sl->spacetype != SPACE_NODE) {
- continue;
- }
- SpaceNode *snode = (SpaceNode *)sl;
- if (snode->nodetree != root_node_tree) {
- continue;
- }
- if (!modifier_is_active) {
- if (!(snode->flag & SNODE_PIN)) {
- /* Node tree has to be pinned when the modifier is not active. */
- continue;
- }
- }
- if (snode->id != &object->id) {
- continue;
- }
- Vector<bNodeTreePath *> tree_path = snode->treepath;
- if (node_context_path.size() != tree_path.size()) {
- continue;
- }
- int valid_count = 0;
- for (const int i : IndexRange(tree_path.size() - 1)) {
- if (node_context_path[i]->type != SPREADSHEET_CONTEXT_NODE) {
- break;
- }
- SpreadsheetContextNode *node_context = (SpreadsheetContextNode *)node_context_path[i];
- if (!STREQ(node_context->node_name, tree_path[i + 1]->node_name)) {
- break;
- }
- valid_count++;
- }
- if (valid_count != tree_path.size() - 1) {
- continue;
- }
- SpreadsheetContext *last_context = node_context_path.last();
- if (last_context->type != SPREADSHEET_CONTEXT_NODE) {
- return false;
- }
- const char *node_name = ((SpreadsheetContextNode *)last_context)->node_name;
- bNode *node = nodeFindNodebyName(snode->edittree, node_name);
- if (node == nullptr) {
- return false;
- }
- if (node->type != GEO_NODE_VIEWER) {
- return false;
- }
- if (!(node->flag & NODE_DO_OUTPUT)) {
- return false;
- }
- return true;
- }
- }
- return false;
-}
-
-bool ED_spreadsheet_context_path_exists(Main *UNUSED(bmain), SpaceSpreadsheet *sspreadsheet)
-{
- Vector<SpreadsheetContext *> context_path = sspreadsheet->context_path;
- if (context_path.is_empty()) {
- return false;
- }
- if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) {
- return false;
- }
- Object *object = ((SpreadsheetContextObject *)context_path[0])->object;
- if (object == nullptr) {
- return false;
- }
- if (context_path.size() == 1) {
- return true;
- }
- if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) {
- return false;
- }
- const char *modifier_name = ((SpreadsheetContextModifier *)context_path[1])->modifier_name;
- const ModifierData *modifier = BKE_modifiers_findby_name(object, modifier_name);
- if (modifier == nullptr) {
- return false;
- }
- if (modifier->type != eModifierType_Nodes) {
- return false;
- }
- bNodeTree *root_node_tree = ((NodesModifierData *)modifier)->node_group;
- if (root_node_tree == nullptr) {
- return false;
- }
- const Span<SpreadsheetContext *> node_context_path = context_path.as_span().drop_front(2);
- if (node_context_path.is_empty()) {
- return false;
- }
- bNodeTree *node_tree = root_node_tree;
- for (const int i : node_context_path.index_range()) {
- if (node_context_path[i]->type != SPREADSHEET_CONTEXT_NODE) {
- return false;
- }
- const char *node_name = ((SpreadsheetContextNode *)node_context_path[i])->node_name;
- bNode *node = nodeFindNodebyName(node_tree, node_name);
- if (node == nullptr) {
- return false;
- }
- if (node->type == GEO_NODE_VIEWER) {
- if (i == node_context_path.index_range().last()) {
- return true;
- }
- return false;
- }
- if (node->id != nullptr) {
- if (GS(node->id->name) != ID_NT) {
- return false;
- }
- node_tree = (bNodeTree *)node->id;
- }
- else {
- return false;
- }
- }
- return false;
-}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_context.hh b/source/blender/editors/space_spreadsheet/spreadsheet_context.hh
deleted file mode 100644
index 758ae392894..00000000000
--- a/source/blender/editors/space_spreadsheet/spreadsheet_context.hh
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#pragma once
-
-#include "DNA_space_types.h"
-
-namespace blender::ed::spreadsheet {
-
-SpreadsheetContext *spreadsheet_context_new(eSpaceSpreadsheet_ContextType type);
-SpreadsheetContext *spreadsheet_context_copy(const SpreadsheetContext *old_context);
-void spreadsheet_context_free(SpreadsheetContext *context);
-
-} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
index fd2ac4d39a1..8af12590b0f 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -98,7 +98,8 @@ void GeometryDataSource::foreach_default_column_ids(
}
SpreadsheetColumnID column_id;
column_id.name = (char *)attribute_id.name().data();
- fn(column_id, false);
+ const bool is_front = attribute_id.name() == ".viewer";
+ fn(column_id, is_front);
return true;
});
@@ -228,7 +229,12 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
return {};
}
- return std::make_unique<ColumnValues>(column_id.name, std::move(varray));
+ StringRefNull column_display_name = column_id.name;
+ if (column_display_name == ".viewer") {
+ column_display_name = "Viewer";
+ }
+
+ return std::make_unique<ColumnValues>(column_display_name, std::move(varray));
}
int GeometryDataSource::tot_rows() const
@@ -463,7 +469,7 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread
mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
}
else {
- if (BLI_listbase_count(&sspreadsheet->context_path) == 1) {
+ if (BLI_listbase_count(&sspreadsheet->viewer_path.path) == 1) {
/* Use final evaluated object. */
if (object_eval->runtime.geometry_set_eval != nullptr) {
geometry_set = *object_eval->runtime.geometry_set_eval;
@@ -471,8 +477,8 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread
}
else {
if (const ViewerNodeLog *viewer_log =
- nodes::geo_eval_log::GeoModifierLog::find_viewer_node_log_for_spreadsheet(
- *sspreadsheet)) {
+ nodes::geo_eval_log::GeoModifierLog::find_viewer_node_log_for_path(
+ sspreadsheet->viewer_path)) {
geometry_set = viewer_log->geometry;
}
}
@@ -481,25 +487,6 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread
return geometry_set;
}
-static void find_fields_to_evaluate(const SpaceSpreadsheet *sspreadsheet,
- Map<std::string, GField> &r_fields)
-{
- if (sspreadsheet->object_eval_state != SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE) {
- return;
- }
- if (BLI_listbase_count(&sspreadsheet->context_path) <= 1) {
- /* No viewer is currently referenced by the context path. */
- return;
- }
- if (const ViewerNodeLog *viewer_log =
- nodes::geo_eval_log::GeoModifierLog::find_viewer_node_log_for_spreadsheet(
- *sspreadsheet)) {
- if (viewer_log->field) {
- r_fields.add("Viewer", viewer_log->field);
- }
- }
-}
-
class GeometryComponentCacheKey : public SpreadsheetCache::Key {
public:
/* Use the pointer to the geometry component as a key to detect when the geometry changed. */
@@ -531,38 +518,6 @@ class GeometryComponentCacheValue : public SpreadsheetCache::Value {
Map<std::pair<eAttrDomain, GField>, GArray<>> arrays;
};
-static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet,
- const GeometryComponent &component,
- ExtraColumns &r_extra_columns)
-{
- Map<std::string, GField> fields_to_show;
- find_fields_to_evaluate(sspreadsheet, fields_to_show);
-
- GeometryComponentCacheValue &cache =
- sspreadsheet->runtime->cache.lookup_or_add<GeometryComponentCacheValue>(
- std::make_unique<GeometryComponentCacheKey>(component));
-
- const eAttrDomain domain = (eAttrDomain)sspreadsheet->attribute_domain;
- const int domain_num = component.attribute_domain_size(domain);
- for (const auto item : fields_to_show.items()) {
- const StringRef name = item.key;
- const GField &field = item.value;
-
- /* Use the cached evaluated array if it exists, otherwise evaluate the field now. */
- GArray<> &evaluated_array = cache.arrays.lookup_or_add_cb({domain, field}, [&]() {
- GArray<> evaluated_array(field.cpp_type(), domain_num);
-
- bke::GeometryFieldContext field_context{component, domain};
- fn::FieldEvaluator field_evaluator{field_context, domain_num};
- field_evaluator.add_with_destination(field, evaluated_array);
- field_evaluator.evaluate();
- return evaluated_array;
- });
-
- r_extra_columns.add(name, evaluated_array.as_span());
- }
-}
-
std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object *object_eval)
{
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
@@ -574,15 +529,11 @@ std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object
return {};
}
- const GeometryComponent &component = *geometry_set.get_component_for_read(component_type);
- ExtraColumns extra_columns;
- add_fields_as_extra_columns(sspreadsheet, component, extra_columns);
-
if (component_type == GEO_COMPONENT_TYPE_VOLUME) {
return std::make_unique<VolumeDataSource>(std::move(geometry_set));
}
return std::make_unique<GeometryDataSource>(
- object_eval, std::move(geometry_set), component_type, domain, std::move(extra_columns));
+ object_eval, std::move(geometry_set), component_type, domain);
}
} // namespace blender::ed::spreadsheet
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
index 71bc4768949..478b3372427 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
@@ -54,7 +54,7 @@ class GeometryDataSource : public DataSource {
GeometrySet geometry_set,
const GeometryComponentType component_type,
const eAttrDomain domain,
- ExtraColumns extra_columns)
+ ExtraColumns extra_columns = {})
: object_eval_(object_eval),
geometry_set_(std::move(geometry_set)),
component_(geometry_set_.get_component_for_read(component_type)),
diff --git a/source/blender/editors/space_view3d/space_view3d.cc b/source/blender/editors/space_view3d/space_view3d.cc
index 7398a109b19..345958d86ec 100644
--- a/source/blender/editors/space_view3d/space_view3d.cc
+++ b/source/blender/editors/space_view3d/space_view3d.cc
@@ -44,6 +44,7 @@
#include "BKE_object.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_viewer_path.h"
#include "BKE_workspace.h"
#include "ED_object.h"
@@ -53,6 +54,7 @@
#include "ED_space_api.h"
#include "ED_transform.h"
#include "ED_undo.h"
+#include "ED_viewer_path.hh"
#include "GPU_matrix.h"
@@ -322,6 +324,8 @@ static void view3d_free(SpaceLink *sl)
IDP_FreeProperty(vd->shading.prop);
vd->shading.prop = nullptr;
}
+
+ BKE_viewer_path_clear(&vd->viewer_path);
}
/* spacetype; init callback */
@@ -360,6 +364,8 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl)
v3dn->shading.prop = IDP_CopyProperty(v3do->shading.prop);
}
+ BKE_viewer_path_copy(&v3dn->viewer_path, &v3do->viewer_path);
+
/* copy or clear inside new stuff */
return (SpaceLink *)v3dn;
@@ -1319,6 +1325,16 @@ static void view3d_main_region_listener(const wmRegionListenerParams *params)
/* In case the region displays workspace settings. */
ED_region_tag_redraw(region);
break;
+ case NC_VIEWER_PATH: {
+ if (v3d->flag2 & V3D_SHOW_VIEWER) {
+ ViewLayer *view_layer = WM_window_get_active_view_layer(window);
+ if (Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer)) {
+ ED_render_view3d_update(depsgraph, window, area, true);
+ }
+ ED_region_tag_redraw(region);
+ }
+ break;
+ }
}
}
@@ -1980,6 +1996,7 @@ static void view3d_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRema
/* Object centers in local-view aren't used, see: T52663 */
view3d_id_remap_v3d(area, slink, view3d->localvd, mappings, true);
}
+ BKE_viewer_path_id_remap(&view3d->viewer_path, mappings);
}
static void view3d_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
@@ -2003,6 +2020,8 @@ static void view3d_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
BKE_screen_view3d_shading_blend_read_data(reader, &v3d->shading);
BKE_screen_view3d_do_versions_250(v3d, &sl->regionbase);
+
+ BKE_viewer_path_blend_read_data(reader, &v3d->viewer_path);
}
static void view3d_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl)
@@ -2015,6 +2034,8 @@ static void view3d_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLi
if (v3d->localvd) {
BLO_read_id_address(reader, parent_id->lib, &v3d->localvd->camera);
}
+
+ BKE_viewer_path_blend_read_lib(reader, parent_id->lib, &v3d->viewer_path);
}
static void view3d_blend_write(BlendWriter *writer, SpaceLink *sl)
@@ -2027,6 +2048,8 @@ static void view3d_blend_write(BlendWriter *writer, SpaceLink *sl)
}
BKE_screen_view3d_shading_blend_write(writer, &v3d->shading);
+
+ BKE_viewer_path_blend_write(writer, &v3d->viewer_path);
}
void ED_spacetype_view3d(void)
diff --git a/source/blender/editors/space_view3d/view3d_draw.cc b/source/blender/editors/space_view3d/view3d_draw.cc
index 9686609fa65..bc8800120f8 100644
--- a/source/blender/editors/space_view3d/view3d_draw.cc
+++ b/source/blender/editors/space_view3d/view3d_draw.cc
@@ -55,6 +55,7 @@
#include "ED_screen_types.h"
#include "ED_transform.h"
#include "ED_view3d_offscreen.h"
+#include "ED_viewer_path.hh"
#include "DEG_depsgraph_query.h"
@@ -1294,7 +1295,7 @@ static void draw_viewport_name(ARegion *region, View3D *v3d, int xoffset, int *y
* frame-number, collection, object name, bone name (if available), marker name (if available).
*/
static void draw_selected_name(
- Scene *scene, ViewLayer *view_layer, Object *ob, int xoffset, int *yoffset)
+ const View3D *v3d, Scene *scene, ViewLayer *view_layer, Object *ob, int xoffset, int *yoffset)
{
const int cfra = scene->r.cfra;
const char *msg_pin = " (Pinned)";
@@ -1409,6 +1410,12 @@ static void draw_selected_name(
s += sprintf(s, " <%s>", markern);
}
+ if (v3d->flag2 & V3D_SHOW_VIEWER) {
+ if (!BLI_listbase_is_empty(&v3d->viewer_path.path)) {
+ s += sprintf(s, IFACE_(" (Viewer)"));
+ }
+ }
+
BLF_enable(font_id, BLF_SHADOW);
BLF_shadow(font_id, 5, float4{0.0f, 0.0f, 0.0f, 1.0f});
BLF_shadow_offset(font_id, 1, -1);
@@ -1502,7 +1509,7 @@ void view3d_draw_region_info(const bContext *C, ARegion *region)
if (U.uiflag & USER_DRAWVIEWINFO) {
BKE_view_layer_synced_ensure(scene, view_layer);
Object *ob = BKE_view_layer_active_object_get(view_layer);
- draw_selected_name(scene, view_layer, ob, xoffset, &yoffset);
+ draw_selected_name(v3d, scene, view_layer, ob, xoffset, &yoffset);
}
if (v3d->gridflag & (V3D_SHOW_FLOOR | V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z)) {
@@ -1558,11 +1565,23 @@ RenderEngineType *ED_view3d_engine_type(const Scene *scene, int drawtype)
return type;
}
+static void view3d_update_viewer_path(const bContext *C)
+{
+ View3D *v3d = CTX_wm_view3d(C);
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ /* Always use viewer path from workspace, pinning is not supported currently. */
+ if (!BKE_viewer_path_equal(&v3d->viewer_path, &workspace->viewer_path)) {
+ BKE_viewer_path_clear(&v3d->viewer_path);
+ BKE_viewer_path_copy(&v3d->viewer_path, &workspace->viewer_path);
+ }
+}
+
void view3d_main_region_draw(const bContext *C, ARegion *region)
{
Main *bmain = CTX_data_main(C);
View3D *v3d = CTX_wm_view3d(C);
+ view3d_update_viewer_path(C);
view3d_draw_view(C, region);
DRW_cache_free_old_subdiv();
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index a9e6adc6e60..164e594b37c 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -28,6 +28,7 @@ set(SRC
ed_util.c
ed_util_imbuf.c
ed_util_ops.cc
+ ed_viewer_path.cc
gizmo_utils.c
numinput.c
select_utils.c
diff --git a/source/blender/editors/util/ed_viewer_path.cc b/source/blender/editors/util/ed_viewer_path.cc
new file mode 100644
index 00000000000..5c03367cba8
--- /dev/null
+++ b/source/blender/editors/util/ed_viewer_path.cc
@@ -0,0 +1,362 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "ED_viewer_path.hh"
+#include "ED_screen.h"
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_node_runtime.hh"
+#include "BKE_workspace.h"
+
+#include "BLI_listbase.h"
+#include "BLI_vector.hh"
+
+#include "DNA_modifier_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+
+namespace blender::ed::viewer_path {
+
+static void viewer_path_for_geometry_node(const SpaceNode &snode,
+ const bNode &node,
+ ViewerPath &r_dst)
+{
+ BKE_viewer_path_init(&r_dst);
+
+ Object *ob = reinterpret_cast<Object *>(snode.id);
+ IDViewerPathElem *id_elem = BKE_viewer_path_elem_new_id();
+ id_elem->id = &ob->id;
+ BLI_addtail(&r_dst.path, id_elem);
+
+ NodesModifierData *modifier = nullptr;
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ if (md->type != eModifierType_Nodes) {
+ continue;
+ }
+ NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
+ if (nmd->node_group != snode.nodetree) {
+ continue;
+ }
+ if (snode.flag & SNODE_PIN) {
+ /* If the node group is pinned, use the first matching modifier. This can be improved by
+ * storing the modifier name in the node editor when the context is pinned. */
+ modifier = nmd;
+ break;
+ }
+ if (md->flag & eModifierFlag_Active) {
+ modifier = nmd;
+ }
+ }
+
+ ModifierViewerPathElem *modifier_elem = BKE_viewer_path_elem_new_modifier();
+ modifier_elem->modifier_name = BLI_strdup(modifier->modifier.name);
+ BLI_addtail(&r_dst.path, modifier_elem);
+
+ Vector<const bNodeTreePath *, 16> tree_path = snode.treepath;
+ for (const bNodeTreePath *tree_path_elem : tree_path.as_span().drop_front(1)) {
+ NodeViewerPathElem *node_elem = BKE_viewer_path_elem_new_node();
+ node_elem->node_name = BLI_strdup(tree_path_elem->node_name);
+ BLI_addtail(&r_dst.path, node_elem);
+ }
+
+ NodeViewerPathElem *viewer_node_elem = BKE_viewer_path_elem_new_node();
+ viewer_node_elem->node_name = BLI_strdup(node.name);
+ BLI_addtail(&r_dst.path, viewer_node_elem);
+}
+
+void activate_geometry_node(Main &bmain, SpaceNode &snode, bNode &node)
+{
+ wmWindowManager *wm = (wmWindowManager *)bmain.wm.first;
+ if (wm == nullptr) {
+ return;
+ }
+ LISTBASE_FOREACH (bNode *, iter_node, &snode.edittree->nodes) {
+ if (iter_node->type == GEO_NODE_VIEWER) {
+ SET_FLAG_FROM_TEST(iter_node->flag, iter_node == &node, NODE_DO_OUTPUT);
+ }
+ }
+ ViewerPath new_viewer_path{};
+ BLI_SCOPED_DEFER([&]() { BKE_viewer_path_clear(&new_viewer_path); });
+ viewer_path_for_geometry_node(snode, node, new_viewer_path);
+
+ bool found_view3d_with_enabled_viewer = false;
+ View3D *any_view3d_without_viewer = nullptr;
+ LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
+ WorkSpace *workspace = BKE_workspace_active_get(window->workspace_hook);
+ bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
+ if (sl->spacetype == SPACE_SPREADSHEET) {
+ SpaceSpreadsheet &sspreadsheet = *reinterpret_cast<SpaceSpreadsheet *>(sl);
+ if (!(sspreadsheet.flag & SPREADSHEET_FLAG_PINNED)) {
+ sspreadsheet.object_eval_state = SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE;
+ }
+ }
+ else if (sl->spacetype == SPACE_VIEW3D) {
+ View3D &v3d = *reinterpret_cast<View3D *>(sl);
+ if (v3d.flag2 & V3D_SHOW_VIEWER) {
+ found_view3d_with_enabled_viewer = true;
+ }
+ else {
+ any_view3d_without_viewer = &v3d;
+ }
+ }
+ }
+
+ /* Enable viewer in one viewport if it is disable in all of them. */
+ if (!found_view3d_with_enabled_viewer && any_view3d_without_viewer != nullptr) {
+ any_view3d_without_viewer->flag2 |= V3D_SHOW_VIEWER;
+ }
+
+ BKE_viewer_path_clear(&workspace->viewer_path);
+ BKE_viewer_path_copy(&workspace->viewer_path, &new_viewer_path);
+
+ /* Make sure the viewed data becomes available. */
+ DEG_id_tag_update(snode.id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_VIEWER_PATH, nullptr);
+ }
+}
+
+Object *parse_object_only(const ViewerPath &viewer_path)
+{
+ if (BLI_listbase_count(&viewer_path.path) != 1) {
+ return nullptr;
+ }
+ const ViewerPathElem *elem = static_cast<ViewerPathElem *>(viewer_path.path.first);
+ if (elem->type != VIEWER_PATH_ELEM_TYPE_ID) {
+ return nullptr;
+ }
+ ID *id = reinterpret_cast<const IDViewerPathElem *>(elem)->id;
+ if (id == nullptr) {
+ return nullptr;
+ }
+ if (GS(id->name) != ID_OB) {
+ return nullptr;
+ }
+ return reinterpret_cast<Object *>(id);
+}
+
+std::optional<ViewerPathForGeometryNodesViewer> parse_geometry_nodes_viewer(
+ const ViewerPath &viewer_path)
+{
+ const Vector<const ViewerPathElem *, 16> elems_vec = viewer_path.path;
+ if (elems_vec.size() < 3) {
+ /* Need at least the object, modifier and viewer node name. */
+ return std::nullopt;
+ }
+ Span<const ViewerPathElem *> remaining_elems = elems_vec;
+ const ViewerPathElem &id_elem = *remaining_elems[0];
+ if (id_elem.type != VIEWER_PATH_ELEM_TYPE_ID) {
+ return std::nullopt;
+ }
+ ID *root_id = reinterpret_cast<const IDViewerPathElem &>(id_elem).id;
+ if (root_id == nullptr) {
+ return std::nullopt;
+ }
+ if (GS(root_id->name) != ID_OB) {
+ return std::nullopt;
+ }
+ Object *root_ob = reinterpret_cast<Object *>(root_id);
+ remaining_elems = remaining_elems.drop_front(1);
+ const ViewerPathElem &modifier_elem = *remaining_elems[0];
+ if (modifier_elem.type != VIEWER_PATH_ELEM_TYPE_MODIFIER) {
+ return std::nullopt;
+ }
+ const char *modifier_name =
+ reinterpret_cast<const ModifierViewerPathElem &>(modifier_elem).modifier_name;
+ if (modifier_name == nullptr) {
+ return std::nullopt;
+ }
+ remaining_elems = remaining_elems.drop_front(1);
+ Vector<StringRefNull> node_names;
+ for (const ViewerPathElem *elem : remaining_elems) {
+ if (elem->type != VIEWER_PATH_ELEM_TYPE_NODE) {
+ return std::nullopt;
+ }
+ const char *node_name = reinterpret_cast<const NodeViewerPathElem *>(elem)->node_name;
+ if (node_name == nullptr) {
+ return std::nullopt;
+ }
+ node_names.append(node_name);
+ }
+ const StringRefNull viewer_node_name = node_names.pop_last();
+ return ViewerPathForGeometryNodesViewer{root_ob, modifier_name, node_names, viewer_node_name};
+}
+
+bool exists_geometry_nodes_viewer(const ViewerPathForGeometryNodesViewer &parsed_viewer_path)
+{
+ const NodesModifierData *modifier = nullptr;
+ LISTBASE_FOREACH (const ModifierData *, md, &parsed_viewer_path.object->modifiers) {
+ if (md->type != eModifierType_Nodes) {
+ continue;
+ }
+ if (md->name != parsed_viewer_path.modifier_name) {
+ continue;
+ }
+ modifier = reinterpret_cast<const NodesModifierData *>(md);
+ break;
+ }
+ if (modifier == nullptr) {
+ return false;
+ }
+ if (modifier->node_group == nullptr) {
+ return false;
+ }
+ const bNodeTree *ngroup = modifier->node_group;
+ ngroup->ensure_topology_cache();
+ for (const StringRefNull group_node_name : parsed_viewer_path.group_node_names) {
+ const bNode *group_node = nullptr;
+ for (const bNode *node : ngroup->group_nodes()) {
+ if (node->name != group_node_name) {
+ continue;
+ }
+ group_node = node;
+ break;
+ }
+ if (group_node == nullptr) {
+ return false;
+ }
+ if (group_node->id == nullptr) {
+ return false;
+ }
+ ngroup = reinterpret_cast<const bNodeTree *>(group_node->id);
+ }
+ const bNode *viewer_node = nullptr;
+ for (const bNode *node : ngroup->nodes_by_type("GeometryNodeViewer")) {
+ if (node->name != parsed_viewer_path.viewer_node_name) {
+ continue;
+ }
+ viewer_node = node;
+ break;
+ }
+ if (viewer_node == nullptr) {
+ return false;
+ }
+ return true;
+}
+
+bool is_active_geometry_nodes_viewer(const bContext &C,
+ const ViewerPathForGeometryNodesViewer &parsed_viewer_path)
+{
+ const NodesModifierData *modifier = nullptr;
+ LISTBASE_FOREACH (const ModifierData *, md, &parsed_viewer_path.object->modifiers) {
+ if (md->name != parsed_viewer_path.modifier_name) {
+ continue;
+ }
+ if (md->type != eModifierType_Nodes) {
+ return false;
+ }
+ modifier = reinterpret_cast<const NodesModifierData *>(md);
+ break;
+ }
+ if (modifier == nullptr) {
+ return false;
+ }
+ if (modifier->node_group == nullptr) {
+ return false;
+ }
+ const bool modifier_is_active = modifier->modifier.flag & eModifierFlag_Active;
+
+ const Main *bmain = CTX_data_main(&C);
+ const wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
+ if (wm == nullptr) {
+ return false;
+ }
+ LISTBASE_FOREACH (const wmWindow *, window, &wm->windows) {
+ const bScreen *active_screen = BKE_workspace_active_screen_get(window->workspace_hook);
+ Vector<const bScreen *> screens = {active_screen};
+ if (ELEM(active_screen->state, SCREENMAXIMIZED, SCREENFULL)) {
+ const ScrArea *area = static_cast<ScrArea *>(active_screen->areabase.first);
+ screens.append(area->full);
+ }
+ for (const bScreen *screen : screens) {
+ LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
+ const SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
+ if (sl == nullptr) {
+ continue;
+ }
+ if (sl->spacetype != SPACE_NODE) {
+ continue;
+ }
+ const SpaceNode &snode = *reinterpret_cast<const SpaceNode *>(sl);
+ if (!modifier_is_active) {
+ if (!(snode.flag & SNODE_PIN)) {
+ /* Node tree has to be pinned when the modifier is not active. */
+ continue;
+ }
+ }
+ if (snode.id != &parsed_viewer_path.object->id) {
+ continue;
+ }
+ if (snode.nodetree != modifier->node_group) {
+ continue;
+ }
+ Vector<const bNodeTreePath *, 16> tree_path = snode.treepath;
+ if (tree_path.size() != parsed_viewer_path.group_node_names.size() + 1) {
+ continue;
+ }
+ bool valid_path = true;
+ for (const int i : parsed_viewer_path.group_node_names.index_range()) {
+ if (parsed_viewer_path.group_node_names[i] != tree_path[i + 1]->node_name) {
+ valid_path = false;
+ break;
+ }
+ }
+ if (!valid_path) {
+ continue;
+ }
+ const bNodeTree *ngroup = snode.edittree;
+ ngroup->ensure_topology_cache();
+ const bNode *viewer_node = nullptr;
+ for (const bNode *node : ngroup->nodes_by_type("GeometryNodeViewer")) {
+ if (node->name != parsed_viewer_path.viewer_node_name) {
+ continue;
+ }
+ viewer_node = node;
+ }
+ if (viewer_node == nullptr) {
+ continue;
+ }
+ if (!(viewer_node->flag & NODE_DO_OUTPUT)) {
+ continue;
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bNode *find_geometry_nodes_viewer(const ViewerPath &viewer_path, SpaceNode &snode)
+{
+ const std::optional<ViewerPathForGeometryNodesViewer> parsed_viewer_path =
+ parse_geometry_nodes_viewer(viewer_path);
+ if (!parsed_viewer_path.has_value()) {
+ return nullptr;
+ }
+
+ snode.edittree->ensure_topology_cache();
+ bNode *possible_viewer = nullptr;
+ for (bNode *node : snode.edittree->nodes_by_type("GeometryNodeViewer")) {
+ if (node->name == parsed_viewer_path->viewer_node_name) {
+ possible_viewer = node;
+ break;
+ }
+ }
+ if (possible_viewer == nullptr) {
+ return nullptr;
+ }
+ ViewerPath tmp_viewer_path;
+ BLI_SCOPED_DEFER([&]() { BKE_viewer_path_clear(&tmp_viewer_path); });
+ viewer_path_for_geometry_node(snode, *possible_viewer, tmp_viewer_path);
+
+ if (BKE_viewer_path_equal(&viewer_path, &tmp_viewer_path)) {
+ return possible_viewer;
+ }
+ return nullptr;
+}
+
+} // namespace blender::ed::viewer_path
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index a322922e86e..779dc052649 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -550,6 +550,7 @@ set(SRC_SHADER_CREATE_INFOS
../draw/engines/gpencil/shaders/infos/gpencil_vfx_info.hh
../draw/engines/overlay/shaders/infos/overlay_antialiasing_info.hh
../draw/engines/overlay/shaders/infos/overlay_armature_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_viewer_attribute_info.hh
../draw/engines/overlay/shaders/infos/overlay_background_info.hh
../draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh
../draw/engines/overlay/shaders/infos/overlay_extra_info.hh
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index dbda24fb8b7..963567133d9 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -1598,6 +1598,8 @@ typedef struct NodeGeometryImageTexture {
typedef struct NodeGeometryViewer {
/* eCustomDataType. */
int8_t data_type;
+ /* eAttrDomain. */
+ int8_t domain;
} NodeGeometryViewer;
typedef struct NodeGeometryUVUnwrap {
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 5a819ead4ec..7f0dd2f9be6 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -22,6 +22,7 @@
#include "DNA_vec_types.h"
/* Hum ... Not really nice... but needed for spacebuts. */
#include "DNA_view2d_types.h"
+#include "DNA_viewer_path_types.h"
#ifdef __cplusplus
extern "C" {
@@ -1888,32 +1889,6 @@ typedef struct SpreadsheetColumn {
char *display_name;
} SpreadsheetColumn;
-/**
- * An item in SpaceSpreadsheet.context_path.
- * This is a bases struct for the structs below.
- */
-typedef struct SpreadsheetContext {
- struct SpreadsheetContext *next, *prev;
- /* eSpaceSpreadsheet_ContextType. */
- int type;
- char _pad[4];
-} SpreadsheetContext;
-
-typedef struct SpreadsheetContextObject {
- SpreadsheetContext base;
- struct Object *object;
-} SpreadsheetContextObject;
-
-typedef struct SpreadsheetContextModifier {
- SpreadsheetContext base;
- char *modifier_name;
-} SpreadsheetContextModifier;
-
-typedef struct SpreadsheetContextNode {
- SpreadsheetContext base;
- char *node_name;
-} SpreadsheetContextNode;
-
typedef struct SpaceSpreadsheet {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -1930,12 +1905,11 @@ typedef struct SpaceSpreadsheet {
ListBase row_filters;
/**
- * List of #SpreadsheetContext.
- * This is a path to the data that is displayed in the spreadsheet.
- * It can be set explicitly by an action of the user (e.g. clicking the preview icon in a
- * geometry node) or it can be derived from context automatically based on some heuristic.
+ * Context that is currently displayed in the editor. This is usually a either a single object
+ * (in original/evaluated mode) or path to a viewer node. This is retrieved from the workspace
+ * but can be pinned so that it stays constant even when the active node changes.
*/
- ListBase context_path;
+ ViewerPath viewer_path;
/* eSpaceSpreadsheet_FilterFlag. */
uint8_t filter_flag;
diff --git a/source/blender/makesdna/DNA_view3d_defaults.h b/source/blender/makesdna/DNA_view3d_defaults.h
index b2d17b0ea22..c6c93c33086 100644
--- a/source/blender/makesdna/DNA_view3d_defaults.h
+++ b/source/blender/makesdna/DNA_view3d_defaults.h
@@ -36,8 +36,10 @@
#define _DNA_DEFAULT_View3DOverlay \
{ \
+ .flag = V3D_OVERLAY_VIEWER_ATTRIBUTE, \
.wireframe_threshold = 1.0f, \
.wireframe_opacity = 1.0f, \
+ .viewer_attribute_opacity = 0.8f, \
.xray_alpha_bone = 0.5f, \
.bone_wire_alpha = 1.0f, \
.fade_alpha = 0.40f, \
@@ -81,7 +83,7 @@
.gridflag = V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_FLOOR | V3D_SHOW_ORTHO_GRID, \
\
.flag = V3D_SELECT_OUTLINE, \
- .flag2 = V3D_SHOW_RECONSTRUCTION | V3D_SHOW_ANNOTATION, \
+ .flag2 = V3D_SHOW_RECONSTRUCTION | V3D_SHOW_ANNOTATION | V3D_SHOW_VIEWER, \
\
.lens = 50.0f, \
.clip_start = 0.01f, \
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 2b422f9aebf..f3e56ba7039 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -22,6 +22,7 @@ struct wmTimer;
#include "DNA_movieclip_types.h"
#include "DNA_object_types.h"
#include "DNA_view3d_enums.h"
+#include "DNA_viewer_path_types.h"
#ifdef __cplusplus
extern "C" {
@@ -205,6 +206,7 @@ typedef struct View3DOverlay {
float weight_paint_mode_opacity;
float sculpt_mode_mask_opacity;
float sculpt_mode_face_sets_opacity;
+ float viewer_attribute_opacity;
/** Armature edit/pose mode settings. */
float xray_alpha_bone;
@@ -227,8 +229,6 @@ typedef struct View3DOverlay {
float gpencil_vertex_paint_opacity;
/** Handles display type for curves. */
int handle_display;
-
- char _pad[4];
} View3DOverlay;
/** #View3DOverlay.handle_display */
@@ -348,6 +348,9 @@ typedef struct View3D {
View3DShading shading;
View3DOverlay overlay;
+ /** Path to the viewer node that is currently previewed. This is retrieved from the workspace. */
+ ViewerPath viewer_path;
+
/** Runtime evaluation data (keep last). */
View3D_Runtime runtime;
} View3D;
@@ -443,7 +446,7 @@ enum {
/** #View3D.flag2 (int) */
#define V3D_HIDE_OVERLAYS (1 << 2)
-#define V3D_FLAG2_UNUSED_3 (1 << 3) /* cleared */
+#define V3D_SHOW_VIEWER (1 << 3)
#define V3D_SHOW_ANNOTATION (1 << 4)
#define V3D_LOCK_CAMERA (1 << 5)
#define V3D_FLAG2_UNUSED_6 (1 << 6) /* cleared */
@@ -528,6 +531,7 @@ enum {
V3D_OVERLAY_HIDE_OBJECT_ORIGINS = (1 << 10),
V3D_OVERLAY_STATS = (1 << 11),
V3D_OVERLAY_FADE_INACTIVE = (1 << 12),
+ V3D_OVERLAY_VIEWER_ATTRIBUTE = (1 << 13),
};
/** #View3DOverlay.edit_flag */
diff --git a/source/blender/makesdna/DNA_viewer_path_types.h b/source/blender/makesdna/DNA_viewer_path_types.h
new file mode 100644
index 00000000000..8f470b66ca0
--- /dev/null
+++ b/source/blender/makesdna/DNA_viewer_path_types.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include "BLI_listbase.h"
+#include "BLI_utildefines.h"
+
+struct ID;
+
+typedef enum ViewerPathElemType {
+ VIEWER_PATH_ELEM_TYPE_ID = 0,
+ VIEWER_PATH_ELEM_TYPE_MODIFIER = 1,
+ VIEWER_PATH_ELEM_TYPE_NODE = 2,
+} ViewerPathElemType;
+
+typedef struct ViewerPathElem {
+ struct ViewerPathElem *next, *prev;
+ int type;
+ char _pad[4];
+} ViewerPathElem;
+
+typedef struct IDViewerPathElem {
+ ViewerPathElem base;
+ struct ID *id;
+} IDViewerPathElem;
+
+typedef struct ModifierViewerPathElem {
+ ViewerPathElem base;
+ char *modifier_name;
+} ModifierViewerPathElem;
+
+typedef struct NodeViewerPathElem {
+ ViewerPathElem base;
+ char *node_name;
+} NodeViewerPathElem;
+
+typedef struct ViewerPath {
+ /** List of #ViewerPathElem. */
+ ListBase path;
+} ViewerPath;
diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h
index 1a6e19c31ad..e99f317f057 100644
--- a/source/blender/makesdna/DNA_workspace_types.h
+++ b/source/blender/makesdna/DNA_workspace_types.h
@@ -10,6 +10,7 @@
#include "DNA_ID.h"
#include "DNA_asset_types.h"
+#include "DNA_viewer_path_types.h"
#ifdef __cplusplus
extern "C" {
@@ -143,6 +144,13 @@ typedef struct WorkSpace {
/** Workspace-wide active asset library, for asset UIs to use (e.g. asset view UI template). The
* Asset Browser has its own and doesn't use this. */
AssetLibraryReference asset_library_ref;
+
+ /**
+ * Ground truth for the currently active viewer node. When a viewer node is activated its path is
+ * set here. Editors can check here for which node is active (currently the node editor,
+ * spreadsheet and viewport do this).
+ */
+ ViewerPath viewer_path;
} WorkSpace;
/**
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index c9f63e7c315..4ec2799186e 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -10803,6 +10803,12 @@ static void def_geo_viewer(StructRNA *srna)
RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
RNA_def_property_ui_text(prop, "Data Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
+
+ prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_attribute_domain_with_auto_items);
+ RNA_def_property_enum_default(prop, ATTR_DOMAIN_POINT);
+ RNA_def_property_ui_text(prop, "Domain", "Domain to evaluate the field on");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_geo_realize_instances(StructRNA *srna)
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 9bbe37b5187..738b41828e0 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -19,6 +19,7 @@
#include "BKE_movieclip.h"
#include "BKE_node.h"
#include "BKE_studiolight.h"
+#include "BKE_viewer_path.h"
#include "ED_asset.h"
#include "ED_spreadsheet.h"
@@ -3279,59 +3280,21 @@ const EnumPropertyItem *rna_SpaceSpreadsheet_attribute_domain_itemf(bContext *UN
return item_array;
}
-static SpreadsheetContext *rna_SpaceSpreadsheet_context_path_append(SpaceSpreadsheet *sspreadsheet,
- int type)
+static StructRNA *rna_viewer_path_elem_refine(PointerRNA *ptr)
{
- SpreadsheetContext *context = ED_spreadsheet_context_new(type);
- BLI_addtail(&sspreadsheet->context_path, context);
- ED_spreadsheet_context_path_update_tag(sspreadsheet);
- WM_main_add_notifier(NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
- return context;
-}
-
-static void rna_SpaceSpreadsheet_context_path_clear(SpaceSpreadsheet *sspreadsheet)
-{
- ED_spreadsheet_context_path_clear(sspreadsheet);
- ED_spreadsheet_context_path_update_tag(sspreadsheet);
- WM_main_add_notifier(NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
-}
-
-static StructRNA *rna_spreadsheet_context_refine(PointerRNA *ptr)
-{
- SpreadsheetContext *context = ptr->data;
- switch (context->type) {
- case SPREADSHEET_CONTEXT_OBJECT:
- return &RNA_SpreadsheetContextObject;
- case SPREADSHEET_CONTEXT_MODIFIER:
- return &RNA_SpreadsheetContextModifier;
- case SPREADSHEET_CONTEXT_NODE:
- return &RNA_SpreadsheetContextNode;
+ ViewerPathElem *elem = ptr->data;
+ switch (elem->type) {
+ case VIEWER_PATH_ELEM_TYPE_ID:
+ return &RNA_IDViewerPathElem;
+ case VIEWER_PATH_ELEM_TYPE_MODIFIER:
+ return &RNA_ModifierViewerPathElem;
+ case VIEWER_PATH_ELEM_TYPE_NODE:
+ return &RNA_NodeViewerPathElem;
}
BLI_assert_unreachable();
return NULL;
}
-static void rna_spreadsheet_context_update(Main *UNUSED(bmain),
- Scene *UNUSED(scene),
- PointerRNA *ptr)
-{
- bScreen *screen = (bScreen *)ptr->owner_id;
- LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
- SpaceLink *sl = area->spacedata.first;
- if (sl->spacetype == SPACE_SPREADSHEET) {
- SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
- ED_spreadsheet_context_path_update_tag(sspreadsheet);
- }
- }
-}
-
-static void rna_SpaceSpreadsheet_context_path_guess(SpaceSpreadsheet *sspreadsheet, bContext *C)
-{
- ED_spreadsheet_context_path_guess(C, sspreadsheet);
- ED_spreadsheet_context_path_update_tag(sspreadsheet);
- WM_main_add_notifier(NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
-}
-
static void rna_FileAssetSelectParams_catalog_id_get(PointerRNA *ptr, char *value)
{
const FileAssetSelectParams *params = ptr->data;
@@ -4456,6 +4419,20 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ prop = RNA_def_property(srna, "show_viewer_attribute", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_VIEWER_ATTRIBUTE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Viewer Node", "Show attribute overlay for active viewer node");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "viewer_attribute_opacity", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "overlay.viewer_attribute_opacity");
+ RNA_def_property_ui_text(
+ prop, "Viewer Attribute Opacity", "Opacity of the attribute that is currently visualized");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
prop = RNA_def_property(srna, "show_paint_wire", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "overlay.paint_flag", V3D_OVERLAY_PAINT_WIRE);
RNA_def_property_ui_text(prop, "Show Wire", "Use wireframe display in painting modes");
@@ -5107,6 +5084,11 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Visibility Icon", "");
+ prop = RNA_def_property(srna, "show_viewer", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SHOW_VIEWER);
+ RNA_def_property_ui_text(prop, "Show Viewer", "Display non-final geometry from viewer nodes");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
+
/* Nested Structs */
prop = RNA_def_property(srna, "shading", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
@@ -7883,93 +7865,77 @@ static void rna_def_spreadsheet_row_filter(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
}
-static const EnumPropertyItem spreadsheet_context_type_items[] = {
- {SPREADSHEET_CONTEXT_OBJECT, "OBJECT", ICON_NONE, "Object", ""},
- {SPREADSHEET_CONTEXT_MODIFIER, "MODIFIER", ICON_NONE, "Modifier", ""},
- {SPREADSHEET_CONTEXT_NODE, "NODE", ICON_NONE, "Node", ""},
+static const EnumPropertyItem viewer_path_elem_type_items[] = {
+ {VIEWER_PATH_ELEM_TYPE_ID, "ID", ICON_NONE, "ID", ""},
+ {VIEWER_PATH_ELEM_TYPE_MODIFIER, "MODIFIER", ICON_NONE, "Modifier", ""},
+ {VIEWER_PATH_ELEM_TYPE_NODE, "NODE", ICON_NONE, "Node", ""},
{0, NULL, 0, NULL, NULL},
};
-static void rna_def_space_spreadsheet_context(BlenderRNA *brna)
+static void rna_def_viewer_path_elem(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
- srna = RNA_def_struct(brna, "SpreadsheetContext", NULL);
- RNA_def_struct_ui_text(srna, "Spreadsheet Context", "Element of spreadsheet context path");
- RNA_def_struct_refine_func(srna, "rna_spreadsheet_context_refine");
+ srna = RNA_def_struct(brna, "ViewerPathElem", NULL);
+ RNA_def_struct_ui_text(srna, "Viewer Path Element", "Element of a viewer path");
+ RNA_def_struct_refine_func(srna, "rna_viewer_path_elem_refine");
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, spreadsheet_context_type_items);
- RNA_def_property_ui_text(prop, "Type", "Type of the context");
+ RNA_def_property_enum_items(prop, viewer_path_elem_type_items);
+ RNA_def_property_ui_text(prop, "Type", "Type of the path element");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- rna_def_space_generic_show_region_toggles(srna,
- (1 << RGN_TYPE_CHANNELS) | (1 << RGN_TYPE_FOOTER));
}
-static void rna_def_space_spreadsheet_context_object(BlenderRNA *brna)
+static void rna_def_id_viewer_path_elem(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
- srna = RNA_def_struct(brna, "SpreadsheetContextObject", "SpreadsheetContext");
+ srna = RNA_def_struct(brna, "IDViewerPathElem", "ViewerPathElem");
- prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, "rna_spreadsheet_context_update");
+ prop = RNA_def_property(srna, "id", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "ID", "");
}
-static void rna_def_space_spreadsheet_context_modifier(BlenderRNA *brna)
+static void rna_def_modifier_viewer_path_elem(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
- srna = RNA_def_struct(brna, "SpreadsheetContextModifier", "SpreadsheetContext");
+ srna = RNA_def_struct(brna, "ModifierViewerPathElem", "ViewerPathElem");
prop = RNA_def_property(srna, "modifier_name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Modifier Name", "");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, "rna_spreadsheet_context_update");
}
-static void rna_def_space_spreadsheet_context_node(BlenderRNA *brna)
+static void rna_def_node_viewer_path_elem(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
- srna = RNA_def_struct(brna, "SpreadsheetContextNode", "SpreadsheetContext");
+ srna = RNA_def_struct(brna, "NodeViewerPathElem", "ViewerPathElem");
prop = RNA_def_property(srna, "node_name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Node Name", "");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, "rna_spreadsheet_context_update");
}
-static void rna_def_space_spreadsheet_context_path(BlenderRNA *brna, PropertyRNA *cprop)
+static void rna_def_viewer_path(BlenderRNA *brna)
{
StructRNA *srna;
- PropertyRNA *parm;
- FunctionRNA *func;
-
- RNA_def_property_srna(cprop, "SpreadsheetContextPath");
- srna = RNA_def_struct(brna, "SpreadsheetContextPath", NULL);
- RNA_def_struct_sdna(srna, "SpaceSpreadsheet");
+ PropertyRNA *prop;
- func = RNA_def_function(srna, "append", "rna_SpaceSpreadsheet_context_path_append");
- RNA_def_function_ui_description(func, "Append a context path element");
- parm = RNA_def_property(func, "type", PROP_ENUM, PROP_NONE);
- RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- RNA_def_property_enum_items(parm, spreadsheet_context_type_items);
- parm = RNA_def_pointer(
- func, "context", "SpreadsheetContext", "", "Newly created context path element");
- RNA_def_function_return(func, parm);
+ rna_def_viewer_path_elem(brna);
+ rna_def_id_viewer_path_elem(brna);
+ rna_def_modifier_viewer_path_elem(brna);
+ rna_def_node_viewer_path_elem(brna);
- func = RNA_def_function(srna, "clear", "rna_SpaceSpreadsheet_context_path_clear");
- RNA_def_function_ui_description(func, "Clear entire context path");
+ srna = RNA_def_struct(brna, "ViewerPath", NULL);
+ RNA_def_struct_ui_text(srna, "Viewer Path", "Path to data that is viewed");
- func = RNA_def_function(srna, "guess", "rna_SpaceSpreadsheet_context_path_guess");
- RNA_def_function_ui_description(func, "Guess the context path from the current context");
- RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ prop = RNA_def_property(srna, "path", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "ViewerPathElem");
+ RNA_def_property_ui_text(prop, "Viewer Path", NULL);
}
static void rna_def_space_spreadsheet(BlenderRNA *brna)
@@ -7996,11 +7962,6 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
- rna_def_space_spreadsheet_context(brna);
- rna_def_space_spreadsheet_context_object(brna);
- rna_def_space_spreadsheet_context_modifier(brna);
- rna_def_space_spreadsheet_context_node(brna);
-
srna = RNA_def_struct(brna, "SpaceSpreadsheet", "Space");
RNA_def_struct_ui_text(srna, "Space Spreadsheet", "Spreadsheet space data");
@@ -8017,15 +7978,14 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Use Filter", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
- prop = RNA_def_property(srna, "display_context_path_collapsed", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "display_viewer_path_collapsed", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SPREADSHEET_FLAG_CONTEXT_PATH_COLLAPSED);
RNA_def_property_ui_text(prop, "Display Context Path Collapsed", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
- prop = RNA_def_property(srna, "context_path", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_struct_type(prop, "SpreadsheetContext");
- RNA_def_property_ui_text(prop, "Context Path", "Context path to the data being displayed");
- rna_def_space_spreadsheet_context_path(brna, prop);
+ prop = RNA_def_property(srna, "viewer_path", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(
+ prop, "Viewer Path", "Path to the data that is displayed in the spreadsheet");
prop = RNA_def_property(srna, "show_only_selected", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filter_flag", SPREADSHEET_FILTER_SELECTED_ONLY);
@@ -8073,6 +8033,7 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
void RNA_def_space(BlenderRNA *brna)
{
rna_def_space(brna);
+ rna_def_viewer_path(brna);
rna_def_space_image(brna);
rna_def_space_sequencer(brna);
rna_def_space_text(brna);
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index 7c5bb988012..ba4c03f68de 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -33,6 +33,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
#include "DNA_windowmanager_types.h"
#include "BKE_attribute_math.hh"
@@ -80,6 +81,7 @@
#include "ED_screen.h"
#include "ED_spreadsheet.h"
#include "ED_undo.h"
+#include "ED_viewer_path.hh"
#include "NOD_geometry.h"
#include "NOD_geometry_nodes_lazy_function.hh"
@@ -828,25 +830,6 @@ static void initialize_group_input(NodesModifierData &nmd,
}
}
-static Vector<SpaceSpreadsheet *> find_spreadsheet_editors(Main *bmain)
-{
- wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
- if (wm == nullptr) {
- return {};
- }
- Vector<SpaceSpreadsheet *> spreadsheets;
- LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
- bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
- LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
- SpaceLink *sl = (SpaceLink *)area->spacedata.first;
- if (sl->spacetype == SPACE_SPREADSHEET) {
- spreadsheets.append((SpaceSpreadsheet *)sl);
- }
- }
- }
- return spreadsheets;
-}
-
static const lf::FunctionNode &find_viewer_lf_node(const bNode &viewer_bnode)
{
return *blender::nodes::ensure_geometry_nodes_lazy_function_graph(viewer_bnode.owner_tree())
@@ -858,50 +841,33 @@ static const lf::FunctionNode &find_group_lf_node(const bNode &group_bnode)
->mapping.group_node_map.lookup(&group_bnode);
}
-static void find_side_effect_nodes_for_spreadsheet(
- const SpaceSpreadsheet &sspreadsheet,
+static void find_side_effect_nodes_for_viewer_path(
+ const ViewerPath &viewer_path,
const NodesModifierData &nmd,
const ModifierEvalContext &ctx,
- const bNodeTree &root_tree,
MultiValueMap<blender::ComputeContextHash, const lf::FunctionNode *> &r_side_effect_nodes)
{
- Vector<SpreadsheetContext *> context_path = sspreadsheet.context_path;
- if (context_path.size() < 3) {
- return;
- }
- if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) {
- return;
- }
- if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) {
+ const std::optional<blender::ed::viewer_path::ViewerPathForGeometryNodesViewer> parsed_path =
+ blender::ed::viewer_path::parse_geometry_nodes_viewer(viewer_path);
+ if (!parsed_path.has_value()) {
return;
}
- SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context_path[0];
- if (object_context->object != DEG_get_original_object(ctx.object)) {
+ if (parsed_path->object != DEG_get_original_object(ctx.object)) {
return;
}
- SpreadsheetContextModifier *modifier_context = (SpreadsheetContextModifier *)context_path[1];
- if (StringRef(modifier_context->modifier_name) != nmd.modifier.name) {
+ if (parsed_path->modifier_name != nmd.modifier.name) {
return;
}
- for (SpreadsheetContext *context : context_path.as_span().drop_front(2)) {
- if (context->type != SPREADSHEET_CONTEXT_NODE) {
- return;
- }
- }
blender::ComputeContextBuilder compute_context_builder;
- compute_context_builder.push<blender::bke::ModifierComputeContext>(nmd.modifier.name);
-
- const Span<SpreadsheetContextNode *> nested_group_contexts =
- context_path.as_span().drop_front(2).drop_back(1).cast<SpreadsheetContextNode *>();
- const SpreadsheetContextNode *last_context = (SpreadsheetContextNode *)context_path.last();
+ compute_context_builder.push<blender::bke::ModifierComputeContext>(parsed_path->modifier_name);
+ const bNodeTree *group = nmd.node_group;
Stack<const bNode *> group_node_stack;
- const bNodeTree *group = &root_tree;
- for (SpreadsheetContextNode *node_context : nested_group_contexts) {
+ for (const StringRefNull group_node_name : parsed_path->group_node_names) {
const bNode *found_node = nullptr;
for (const bNode *node : group->group_nodes()) {
- if (STREQ(node->name, node_context->node_name)) {
+ if (node->name == group_node_name) {
found_node = node;
break;
}
@@ -913,13 +879,13 @@ static void find_side_effect_nodes_for_spreadsheet(
return;
}
group_node_stack.push(found_node);
- group = reinterpret_cast<const bNodeTree *>(found_node->id);
- compute_context_builder.push<blender::bke::NodeGroupComputeContext>(node_context->node_name);
+ group = reinterpret_cast<bNodeTree *>(found_node->id);
+ compute_context_builder.push<blender::bke::NodeGroupComputeContext>(group_node_name);
}
const bNode *found_viewer_node = nullptr;
for (const bNode *viewer_node : group->nodes_by_type("GeometryNodeViewer")) {
- if (STREQ(viewer_node->name, last_context->node_name)) {
+ if (viewer_node->name == parsed_path->viewer_node_name) {
found_viewer_node = viewer_node;
break;
}
@@ -943,16 +909,29 @@ static void find_side_effect_nodes_for_spreadsheet(
static void find_side_effect_nodes(
const NodesModifierData &nmd,
const ModifierEvalContext &ctx,
- const bNodeTree &tree,
MultiValueMap<blender::ComputeContextHash, const lf::FunctionNode *> &r_side_effect_nodes)
{
Main *bmain = DEG_get_bmain(ctx.depsgraph);
-
- /* Based on every visible spreadsheet context path, get a list of sockets that need to have their
- * intermediate geometries cached for display. */
- Vector<SpaceSpreadsheet *> spreadsheets = find_spreadsheet_editors(bmain);
- for (SpaceSpreadsheet *sspreadsheet : spreadsheets) {
- find_side_effect_nodes_for_spreadsheet(*sspreadsheet, nmd, ctx, tree, r_side_effect_nodes);
+ wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
+ if (wm == nullptr) {
+ return;
+ }
+ LISTBASE_FOREACH (const wmWindow *, window, &wm->windows) {
+ const bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
+ const WorkSpace *workspace = BKE_workspace_active_get(window->workspace_hook);
+ find_side_effect_nodes_for_viewer_path(workspace->viewer_path, nmd, ctx, r_side_effect_nodes);
+ LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
+ const SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
+ if (sl->spacetype == SPACE_SPREADSHEET) {
+ const SpaceSpreadsheet &sspreadsheet = *reinterpret_cast<const SpaceSpreadsheet *>(sl);
+ find_side_effect_nodes_for_viewer_path(
+ sspreadsheet.viewer_path, nmd, ctx, r_side_effect_nodes);
+ }
+ if (sl->spacetype == SPACE_VIEW3D) {
+ const View3D &v3d = *reinterpret_cast<const View3D *>(sl);
+ find_side_effect_nodes_for_viewer_path(v3d.viewer_path, nmd, ctx, r_side_effect_nodes);
+ }
+ }
}
}
@@ -1162,7 +1141,7 @@ static GeometrySet compute_geometry(
geo_nodes_modifier_data.eval_log = eval_log.get();
}
MultiValueMap<blender::ComputeContextHash, const lf::FunctionNode *> r_side_effect_nodes;
- find_side_effect_nodes(*nmd, *ctx, btree, r_side_effect_nodes);
+ find_side_effect_nodes(*nmd, *ctx, r_side_effect_nodes);
geo_nodes_modifier_data.side_effect_nodes = &r_side_effect_nodes;
blender::nodes::GeoNodesLFUserData user_data;
user_data.modifier_data = &geo_nodes_modifier_data;
diff --git a/source/blender/nodes/NOD_geometry_nodes_log.hh b/source/blender/nodes/NOD_geometry_nodes_log.hh
index cf59c99bc79..2b0c16c8656 100644
--- a/source/blender/nodes/NOD_geometry_nodes_log.hh
+++ b/source/blender/nodes/NOD_geometry_nodes_log.hh
@@ -33,6 +33,7 @@
#include "BKE_attribute.h"
#include "BKE_geometry_set.hh"
+#include "BKE_viewer_path.h"
#include "FN_field.hh"
@@ -156,7 +157,6 @@ class GeometryInfoLog : public ValueLog {
class ViewerNodeLog {
public:
GeometrySet geometry;
- GField field;
};
using Clock = std::chrono::steady_clock;
@@ -214,7 +214,7 @@ class GeoTreeLogger {
~GeoTreeLogger();
void log_value(const bNode &node, const bNodeSocket &socket, GPointer value);
- void log_viewer_node(const bNode &viewer_node, const GeometrySet &geometry, const GField &field);
+ void log_viewer_node(const bNode &viewer_node, GeometrySet geometry);
};
/**
@@ -333,8 +333,7 @@ class GeoModifierLog {
* Utility accessor to logged data.
*/
static GeoTreeLog *get_tree_log_for_node_editor(const SpaceNode &snode);
- static const ViewerNodeLog *find_viewer_node_log_for_spreadsheet(
- const SpaceSpreadsheet &sspreadsheet);
+ static const ViewerNodeLog *find_viewer_node_log_for_path(const ViewerPath &viewer_path);
};
} // namespace blender::nodes::geo_eval_log
diff --git a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
index 4ad6efebfa8..613375bca57 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
@@ -285,6 +285,12 @@ template<typename T> class AccumulateFieldInput final : public bke::GeometryFiel
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(
+ const GeometryComponent & /*component*/) const override
+ {
+ return source_domain_;
+ }
};
template<typename T> class TotalFieldInput final : public bke::GeometryFieldInput {
@@ -355,6 +361,11 @@ template<typename T> class TotalFieldInput final : public bke::GeometryFieldInpu
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(const GeometryComponent & /*component*/) const
+ {
+ return source_domain_;
+ }
};
template<typename T> std::string identifier_suffix()
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
index c9df66f1eea..99dd4d9f798 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
@@ -106,33 +106,6 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
}
}
-static void try_capture_field_on_geometry(GeometryComponent &component,
- const AttributeIDRef &attribute_id,
- const eAttrDomain domain,
- const GField &field)
-{
- const int domain_size = component.attribute_domain_size(domain);
- if (domain_size == 0) {
- return;
- }
- bke::GeometryFieldContext field_context{component, domain};
- MutableAttributeAccessor attributes = *component.attributes_for_write();
- const IndexMask mask{IndexMask(domain_size)};
-
- const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(field.cpp_type());
- GAttributeWriter output_attribute = attributes.lookup_or_add_for_write(
- attribute_id, domain, data_type);
- if (!output_attribute) {
- return;
- }
-
- fn::FieldEvaluator evaluator{field_context, &mask};
- evaluator.add_with_destination(field, output_attribute.varray);
- evaluator.evaluate();
-
- output_attribute.finish();
-}
-
static StringRefNull identifier_suffix(eCustomDataType data_type)
{
switch (data_type) {
@@ -206,7 +179,7 @@ static void node_geo_exec(GeoNodeExecParams params)
if (geometry_set.has_instances()) {
GeometryComponent &component = geometry_set.get_component_for_write(
GEO_COMPONENT_TYPE_INSTANCES);
- try_capture_field_on_geometry(component, anonymous_id.get(), domain, field);
+ bke::try_capture_field_on_geometry(component, anonymous_id.get(), domain, field);
}
}
else {
@@ -217,7 +190,7 @@ static void node_geo_exec(GeoNodeExecParams params)
for (const GeometryComponentType type : types) {
if (geometry_set.has(type)) {
GeometryComponent &component = geometry_set.get_component_for_write(type);
- try_capture_field_on_geometry(component, anonymous_id.get(), domain, field);
+ bke::try_capture_field_on_geometry(component, anonymous_id.get(), domain, field);
}
}
});
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
index 28d979facac..d3d0dcfb794 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
@@ -90,6 +90,11 @@ class EndpointFieldInput final : public bke::CurvesFieldInput {
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(const CurvesGeometry & /*curves*/) const
+ {
+ return ATTR_DOMAIN_POINT;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
index b1c3bbfb81e..b4181528696 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
@@ -108,6 +108,11 @@ class HandleTypeFieldInput final : public bke::CurvesFieldInput {
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(const CurvesGeometry & /*curves*/) const
+ {
+ return ATTR_DOMAIN_POINT;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
index b5d8d1f020a..6fe806adb7c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
@@ -280,6 +280,11 @@ class IndexOnSplineFieldInput final : public bke::CurvesFieldInput {
{
return dynamic_cast<const IndexOnSplineFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const CurvesGeometry & /*curves*/) const
+ {
+ return ATTR_DOMAIN_POINT;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_selection.cc
index 9ef9ee8ad6e..f0bd01a012b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_selection.cc
@@ -106,6 +106,11 @@ class PathToEdgeSelectionFieldInput final : public bke::MeshFieldInput {
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_EDGE;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc b/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc
index 4d7e4b00c5a..d5feaae46ed 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc
@@ -141,6 +141,12 @@ class FieldAtIndex final : public bke::GeometryFieldInput {
return output_array;
}
+
+ std::optional<eAttrDomain> preferred_domain(
+ const GeometryComponent & /*component*/) const override
+ {
+ return value_field_domain_;
+ }
};
static StringRefNull identifier_suffix(eCustomDataType data_type)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
index bff2e7831c6..2979d0e4639 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
@@ -84,6 +84,11 @@ class HandlePositionFieldInput final : public bke::CurvesFieldInput {
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(const CurvesGeometry & /*curves*/) const
+ {
+ return ATTR_DOMAIN_POINT;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc
index f2e7379b3a2..0b9084d3715 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc
@@ -95,6 +95,11 @@ class AngleFieldInput final : public bke::MeshFieldInput {
{
return dynamic_cast<const AngleFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_EDGE;
+ }
};
class SignedAngleFieldInput final : public bke::MeshFieldInput {
@@ -162,6 +167,11 @@ class SignedAngleFieldInput final : public bke::MeshFieldInput {
{
return dynamic_cast<const SignedAngleFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_EDGE;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc
index bfe8753c039..a579202738d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc
@@ -48,6 +48,11 @@ class EdgeNeighborCountFieldInput final : public bke::MeshFieldInput {
{
return dynamic_cast<const EdgeNeighborCountFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_EDGE;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
index c8ceae239a4..c80b3797874 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
@@ -73,6 +73,11 @@ class EdgeVerticesFieldInput final : public bke::MeshFieldInput {
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_EDGE;
+ }
};
static VArray<float3> construct_edge_positions_gvarray(const Mesh &mesh,
@@ -127,6 +132,11 @@ class EdgePositionFieldInput final : public bke::MeshFieldInput {
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_EDGE;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc
index be921c1f1c5..a8670209014 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc
@@ -55,6 +55,11 @@ class FaceAreaFieldInput final : public bke::MeshFieldInput {
{
return dynamic_cast<const FaceAreaFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_FACE;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
index 90fa47c8217..7b084995fc3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
@@ -87,6 +87,11 @@ class PlanarFieldInput final : public bke::MeshFieldInput {
{
return dynamic_cast<const PlanarFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_FACE;
+ }
};
static void geo_node_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc
index 9e85eae3a31..429526588ce 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc
@@ -66,6 +66,11 @@ class FaceNeighborCountFieldInput final : public bke::MeshFieldInput {
{
return dynamic_cast<const FaceNeighborCountFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_FACE;
+ }
};
static VArray<int> construct_vertex_count_varray(const Mesh &mesh, const eAttrDomain domain)
@@ -102,6 +107,11 @@ class FaceVertexCountFieldInput final : public bke::MeshFieldInput {
{
return dynamic_cast<const FaceVertexCountFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_FACE;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
index 9d7735e707d..6d19d3be511 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
@@ -61,6 +61,11 @@ class IslandFieldInput final : public bke::MeshFieldInput {
{
return dynamic_cast<const IslandFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_POINT;
+ }
};
class IslandCountFieldInput final : public bke::MeshFieldInput {
@@ -100,6 +105,11 @@ class IslandCountFieldInput final : public bke::MeshFieldInput {
{
return dynamic_cast<const IslandCountFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_POINT;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc
index ab44a6c8515..6b7f62a944c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc
@@ -58,6 +58,11 @@ class VertexCountFieldInput final : public bke::MeshFieldInput {
{
return dynamic_cast<const VertexCountFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_POINT;
+ }
};
static VArray<int> construct_face_count_gvarray(const Mesh &mesh, const eAttrDomain domain)
@@ -98,6 +103,11 @@ class VertexFaceCountFieldInput final : public bke::MeshFieldInput {
{
return dynamic_cast<const VertexFaceCountFieldInput *>(&other) != nullptr;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_POINT;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_shortest_edge_paths.cc b/source/blender/nodes/geometry/nodes/node_geo_input_shortest_edge_paths.cc
index a54daabde3b..00c92e30443 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_shortest_edge_paths.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_shortest_edge_paths.cc
@@ -143,6 +143,11 @@ class ShortestEdgePathsNextVertFieldInput final : public bke::MeshFieldInput {
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_POINT;
+ }
};
class ShortestEdgePathsCostFieldInput final : public bke::MeshFieldInput {
@@ -206,6 +211,11 @@ class ShortestEdgePathsCostFieldInput final : public bke::MeshFieldInput {
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_POINT;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_interpolate_domain.cc b/source/blender/nodes/geometry/nodes/node_geo_interpolate_domain.cc
index df1427ac5b9..0326c55b65a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_interpolate_domain.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_interpolate_domain.cc
@@ -111,6 +111,12 @@ class InterpolateDomain final : public bke::GeometryFieldInput {
return attributes.adapt_domain(
GVArray::ForGArray(std::move(values)), src_domain_, context.domain());
}
+
+ std::optional<eAttrDomain> preferred_domain(
+ const GeometryComponent & /*component*/) const override
+ {
+ return src_domain_;
+ }
};
static StringRefNull identifier_suffix(eCustomDataType data_type)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
index 628688f3b47..dfb4181926e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
@@ -100,6 +100,12 @@ class MaterialSelectionFieldInput final : public bke::GeometryFieldInput {
}
return false;
}
+
+ std::optional<eAttrDomain> preferred_domain(
+ const GeometryComponent & /*component*/) const override
+ {
+ return ATTR_DOMAIN_FACE;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc
index 88cccfb2f94..1b9852cf7b9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc
@@ -65,6 +65,11 @@ class BoundaryFieldInput final : public bke::MeshFieldInput {
return mesh.attributes().adapt_domain<bool>(
VArray<bool>::ForContainer(std::move(boundary)), ATTR_DOMAIN_EDGE, domain);
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_EDGE;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc
index d0b770aadad..51b21b218fe 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc
@@ -87,56 +87,6 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
}
}
-static void try_capture_field_on_geometry(GeometryComponent &component,
- const StringRef name,
- const eAttrDomain domain,
- const GField &field,
- std::atomic<bool> &r_failure)
-{
- MutableAttributeAccessor attributes = *component.attributes_for_write();
- const int domain_size = attributes.domain_size(domain);
- if (domain_size == 0) {
- return;
- }
-
- bke::GeometryFieldContext field_context{component, domain};
- const IndexMask mask{IndexMask(domain_size)};
-
- const CPPType &type = field.cpp_type();
- const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(type);
- const bke::AttributeValidator validator = attributes.lookup_validator(name);
-
- /* Could avoid allocating a new buffer if:
- * - We are writing to an attribute that exists already with the correct domain and type.
- * - The field does not depend on that attribute (we can't easily check for that yet). */
- void *buffer = MEM_mallocN(type.size() * domain_size, __func__);
-
- fn::FieldEvaluator evaluator{field_context, &mask};
- evaluator.add_with_destination(validator.validate_field_if_necessary(field),
- GMutableSpan{type, buffer, domain_size});
- evaluator.evaluate();
-
- if (GAttributeWriter attribute = attributes.lookup_for_write(name)) {
- if (attribute.domain == domain && attribute.varray.type() == type) {
- attribute.varray.set_all(buffer);
- attribute.finish();
- type.destruct_n(buffer, domain_size);
- MEM_freeN(buffer);
- return;
- }
- }
- attributes.remove(name);
- if (attributes.add(name, domain, data_type, bke::AttributeInitMoveArray{buffer})) {
- return;
- }
-
- /* If the name corresponds to a builtin attribute, removing the attribute might fail if
- * it's required, and adding the attribute might fail if the domain or type is incorrect. */
- type.destruct_n(buffer, domain_size);
- MEM_freeN(buffer);
- r_failure = true;
-}
-
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -192,7 +142,9 @@ static void node_geo_exec(GeoNodeExecParams params)
if (geometry_set.has_instances()) {
GeometryComponent &component = geometry_set.get_component_for_write(
GEO_COMPONENT_TYPE_INSTANCES);
- try_capture_field_on_geometry(component, name, domain, field, failure);
+ if (!bke::try_capture_field_on_geometry(component, name, domain, field)) {
+ failure.store(true);
+ }
}
}
else {
@@ -201,7 +153,9 @@ static void node_geo_exec(GeoNodeExecParams params)
{GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}) {
if (geometry_set.has(type)) {
GeometryComponent &component = geometry_set.get_component_for_write(type);
- try_capture_field_on_geometry(component, name, domain, field, failure);
+ if (!bke::try_capture_field_on_geometry(component, name, domain, field)) {
+ failure.store(true);
+ }
}
}
});
diff --git a/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc b/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc
index ccb489f6e29..67e35f1f023 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc
@@ -118,6 +118,11 @@ class PackIslandsFieldInput final : public bke::MeshFieldInput {
{
return construct_uv_gvarray(mesh, selection_field, uv_field, rotate, margin, domain);
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_CORNER;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc b/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc
index 801bc3f4642..ae9a532ed66 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc
@@ -160,6 +160,11 @@ class UnwrapFieldInput final : public bke::MeshFieldInput {
{
return construct_uv_gvarray(mesh, selection, seam, fill_holes, margin, method, domain);
}
+
+ std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
+ {
+ return ATTR_DOMAIN_CORNER;
+ }
};
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
index 2c8a70901f8..ec900a41bbc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
@@ -6,7 +6,7 @@
#include "UI_resources.h"
#include "ED_node.h"
-#include "ED_spreadsheet.h"
+#include "ED_viewer_path.hh"
#include "NOD_socket_search_link.hh"
@@ -30,12 +30,18 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryViewer *data = MEM_cnew<NodeGeometryViewer>(__func__);
data->data_type = CD_PROP_FLOAT;
+ data->domain = ATTR_DOMAIN_AUTO;
node->storage = data;
}
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
+}
+
+static void node_layout_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
}
@@ -79,7 +85,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
SpaceNode *snode = CTX_wm_space_node(&params.C);
Main *bmain = CTX_data_main(&params.C);
ED_node_set_active(bmain, snode, &params.node_tree, &viewer_node, nullptr);
- ED_spreadsheet_context_paths_set_geometry_node(bmain, snode, &viewer_node);
+ ed::viewer_path::activate_geometry_node(*bmain, *snode, viewer_node);
};
const std::optional<eCustomDataType> type = node_socket_to_custom_data_type(
@@ -132,7 +138,9 @@ void register_node_type_geo_viewer()
node_type_update(&ntype, file_ns::node_update);
node_type_init(&ntype, file_ns::node_init);
ntype.declare = file_ns::node_declare;
- ntype.draw_buttons_ex = file_ns::node_layout;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.draw_buttons_ex = file_ns::node_layout_ex;
ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
+ ntype.no_muting = true;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc
index 7a78547b10b..0dec27da0bd 100644
--- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc
+++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc
@@ -543,19 +543,53 @@ class LazyFunctionForViewerNode : public LazyFunction {
}
GeometrySet geometry = params.extract_input<GeometrySet>(0);
+ const NodeGeometryViewer *storage = static_cast<NodeGeometryViewer *>(bnode_.storage);
- GField field;
if (use_field_input_) {
const void *value_or_field = params.try_get_input_data_ptr(1);
BLI_assert(value_or_field != nullptr);
const ValueOrFieldCPPType &value_or_field_type = static_cast<const ValueOrFieldCPPType &>(
*inputs_[1].type);
- field = value_or_field_type.as_field(value_or_field);
+ GField field = value_or_field_type.as_field(value_or_field);
+ const eAttrDomain domain = eAttrDomain(storage->domain);
+ const StringRefNull viewer_attribute_name = ".viewer";
+ if (domain == ATTR_DOMAIN_INSTANCE) {
+ if (geometry.has_instances()) {
+ GeometryComponent &component = geometry.get_component_for_write(
+ GEO_COMPONENT_TYPE_INSTANCES);
+ bke::try_capture_field_on_geometry(
+ component, viewer_attribute_name, ATTR_DOMAIN_INSTANCE, field);
+ }
+ }
+ else {
+ geometry.modify_geometry_sets([&](GeometrySet &geometry) {
+ for (const GeometryComponentType type : {GEO_COMPONENT_TYPE_MESH,
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ GEO_COMPONENT_TYPE_CURVE}) {
+ if (geometry.has(type)) {
+ GeometryComponent &component = geometry.get_component_for_write(type);
+ eAttrDomain used_domain = domain;
+ if (used_domain == ATTR_DOMAIN_AUTO) {
+ if (const std::optional<eAttrDomain> detected_domain =
+ bke::try_detect_field_domain(component, field)) {
+ used_domain = *detected_domain;
+ }
+ else {
+ used_domain = type == GEO_COMPONENT_TYPE_MESH ? ATTR_DOMAIN_CORNER :
+ ATTR_DOMAIN_POINT;
+ }
+ }
+ bke::try_capture_field_on_geometry(
+ component, viewer_attribute_name, used_domain, field);
+ }
+ }
+ });
+ }
}
geo_eval_log::GeoTreeLogger &tree_logger =
user_data->modifier_data->eval_log->get_local_tree_logger(*user_data->compute_context);
- tree_logger.log_viewer_node(bnode_, geometry, field);
+ tree_logger.log_viewer_node(bnode_, std::move(geometry));
}
};
diff --git a/source/blender/nodes/intern/geometry_nodes_log.cc b/source/blender/nodes/intern/geometry_nodes_log.cc
index aadf69f10c5..909f7779e95 100644
--- a/source/blender/nodes/intern/geometry_nodes_log.cc
+++ b/source/blender/nodes/intern/geometry_nodes_log.cc
@@ -6,12 +6,15 @@
#include "BKE_compute_contexts.hh"
#include "BKE_curves.hh"
#include "BKE_node_runtime.hh"
+#include "BKE_viewer_path.h"
#include "FN_field_cpp_type.hh"
#include "DNA_modifier_types.h"
#include "DNA_space_types.h"
+#include "ED_viewer_path.hh"
+
namespace blender::nodes::geo_eval_log {
using fn::FieldInput;
@@ -188,13 +191,10 @@ void GeoTreeLogger::log_value(const bNode &node, const bNodeSocket &socket, cons
}
}
-void GeoTreeLogger::log_viewer_node(const bNode &viewer_node,
- const GeometrySet &geometry,
- const GField &field)
+void GeoTreeLogger::log_viewer_node(const bNode &viewer_node, GeometrySet geometry)
{
destruct_ptr<ViewerNodeLog> log = this->allocator->construct<ViewerNodeLog>();
- log->geometry = geometry;
- log->field = field;
+ log->geometry = std::move(geometry);
log->geometry.ensure_owns_direct_data();
this->viewer_node_logs.append({this->allocator->copy_string(viewer_node.name), std::move(log)});
}
@@ -545,29 +545,17 @@ GeoTreeLog *GeoModifierLog::get_tree_log_for_node_editor(const SpaceNode &snode)
return &modifier_log->get_tree_log(compute_context_builder.hash());
}
-const ViewerNodeLog *GeoModifierLog::find_viewer_node_log_for_spreadsheet(
- const SpaceSpreadsheet &sspreadsheet)
+const ViewerNodeLog *GeoModifierLog::find_viewer_node_log_for_path(const ViewerPath &viewer_path)
{
- Vector<const SpreadsheetContext *> context_path = sspreadsheet.context_path;
- if (context_path.size() < 3) {
- return nullptr;
- }
- if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) {
- return nullptr;
- }
- if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) {
- return nullptr;
- }
- const SpreadsheetContextObject *object_context =
- reinterpret_cast<const SpreadsheetContextObject *>(context_path[0]);
- const SpreadsheetContextModifier *modifier_context =
- reinterpret_cast<const SpreadsheetContextModifier *>(context_path[1]);
- if (object_context->object == nullptr) {
+ const std::optional<ed::viewer_path::ViewerPathForGeometryNodesViewer> parsed_path =
+ ed::viewer_path::parse_geometry_nodes_viewer(viewer_path);
+ if (!parsed_path.has_value()) {
return nullptr;
}
+ const Object *object = parsed_path->object;
NodesModifierData *nmd = nullptr;
- LISTBASE_FOREACH (ModifierData *, md, &object_context->object->modifiers) {
- if (STREQ(md->name, modifier_context->modifier_name)) {
+ LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
+ if (md->name == parsed_path->modifier_name) {
if (md->type == eModifierType_Nodes) {
nmd = reinterpret_cast<NodesModifierData *>(md);
}
@@ -583,27 +571,16 @@ const ViewerNodeLog *GeoModifierLog::find_viewer_node_log_for_spreadsheet(
static_cast<nodes::geo_eval_log::GeoModifierLog *>(nmd->runtime_eval_log);
ComputeContextBuilder compute_context_builder;
- compute_context_builder.push<bke::ModifierComputeContext>(modifier_context->modifier_name);
- for (const SpreadsheetContext *context : context_path.as_span().drop_front(2).drop_back(1)) {
- if (context->type != SPREADSHEET_CONTEXT_NODE) {
- return nullptr;
- }
- const SpreadsheetContextNode &node_context = *reinterpret_cast<const SpreadsheetContextNode *>(
- context);
- compute_context_builder.push<bke::NodeGroupComputeContext>(node_context.node_name);
+ compute_context_builder.push<bke::ModifierComputeContext>(parsed_path->modifier_name);
+ for (const StringRef group_node_name : parsed_path->group_node_names) {
+ compute_context_builder.push<bke::NodeGroupComputeContext>(group_node_name);
}
const ComputeContextHash context_hash = compute_context_builder.hash();
nodes::geo_eval_log::GeoTreeLog &tree_log = modifier_log->get_tree_log(context_hash);
tree_log.ensure_viewer_node_logs();
- const SpreadsheetContext *last_context = context_path.last();
- if (last_context->type != SPREADSHEET_CONTEXT_NODE) {
- return nullptr;
- }
- const SpreadsheetContextNode &last_node_context =
- *reinterpret_cast<const SpreadsheetContextNode *>(last_context);
const ViewerNodeLog *viewer_log = tree_log.viewer_node_logs.lookup_default(
- last_node_context.node_name, nullptr);
+ parsed_path->viewer_node_name, nullptr);
return viewer_log;
}
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index ba1d8d3ccb7..e25169109e7 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -353,6 +353,8 @@ typedef struct wmNotifier {
#define NC_LIGHTPROBE (26 << 24)
/* Changes to asset data in the current .blend. */
#define NC_ASSET (27 << 24)
+/* Changes to the active viewer path. */
+#define NC_VIEWER_PATH (28 << 24)
/* data type, 256 entries is enough, it can overlap */
#define NOTE_DATA 0x00FF0000
diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc
index d88a5a5a18b..38e37d73eb9 100644
--- a/source/blender/windowmanager/intern/wm_event_system.cc
+++ b/source/blender/windowmanager/intern/wm_event_system.cc
@@ -632,6 +632,7 @@ void wm_event_do_notifiers(bContext *C)
win->screen->id.name + 2,
note->category);
# endif
+ ED_workspace_do_listen(C, note);
ED_screen_do_listen(C, note);
LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {