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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Goudey <h.goudey@me.com>2022-08-30 19:08:27 +0300
committerHans Goudey <h.goudey@me.com>2022-08-30 19:08:27 +0300
commit82a46ea6f8829fc40205d0d3cabf4017eb738d9a (patch)
tree0db4cf9f7a8767f98435d8b0a6589c5c783325ec /source/blender/blenkernel
parent4d107041ec78c96825dd103cacfe9704a2e59532 (diff)
Geometry Nodes: Use separate field context for each geometry type
Using the same `GeometryComponentFieldContext` for all situations, even when only one geometry type is supported is misleading, and mixes too many different abstraction levels into code that could be simpler. With the attribute API moved out of geometry components recently, the "component" system is just getting in the way here. This commit adds specific field contexts for geometry types: meshes, curves, point clouds, and instances. There are also separate field input helper classes, to help reduce boilerplate for fields that only support specific geometry types. Another benefit of this change is that it separates geometry components from fields, which makes it easier to see the purpose of the two concepts, and how they relate. Because we want to be able to evaluate a field on just `CurvesGeometry` rather than the full `Curves` data-block, the generic "geometry context" had to be changed to avoid using `GeometryComponent`, since there is no corresponding geometry component type. The resulting void pointer is ugly, but only turns up in three places in practice. When Apple clang supports `std::variant`, that could be used instead. Differential Revision: https://developer.blender.org/D15519
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_attribute.hh2
-rw-r--r--source/blender/blenkernel/BKE_geometry_fields.hh175
-rw-r--r--source/blender/blenkernel/CMakeLists.txt1
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc120
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curves.cc34
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc5
-rw-r--r--source/blender/blenkernel/intern/geometry_fields.cc365
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc43
8 files changed, 532 insertions, 213 deletions
diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh
index d29c60a7373..c2f65c93cbe 100644
--- a/source/blender/blenkernel/BKE_attribute.hh
+++ b/source/blender/blenkernel/BKE_attribute.hh
@@ -2,6 +2,8 @@
#pragma once
+#include <optional>
+
#include "BLI_color.hh"
#include "BLI_function_ref.hh"
#include "BLI_generic_span.hh"
diff --git a/source/blender/blenkernel/BKE_geometry_fields.hh b/source/blender/blenkernel/BKE_geometry_fields.hh
index 7c504826044..0e9bf700320 100644
--- a/source/blender/blenkernel/BKE_geometry_fields.hh
+++ b/source/blender/blenkernel/BKE_geometry_fields.hh
@@ -12,43 +12,181 @@
#include "FN_field.hh"
+struct Mesh;
+struct PointCloud;
+
namespace blender::bke {
-class GeometryComponentFieldContext : public fn::FieldContext {
+struct CurvesGeometry;
+class GeometryFieldInput;
+
+class MeshFieldContext : public fn::FieldContext {
+ private:
+ const Mesh &mesh_;
+ const eAttrDomain domain_;
+
+ public:
+ MeshFieldContext(const Mesh &mesh, const eAttrDomain domain);
+ const Mesh &mesh() const
+ {
+ return mesh_;
+ }
+
+ eAttrDomain domain() const
+ {
+ return domain_;
+ }
+};
+
+class CurvesFieldContext : public fn::FieldContext {
+ private:
+ const CurvesGeometry &curves_;
+ const eAttrDomain domain_;
+
+ public:
+ CurvesFieldContext(const CurvesGeometry &curves, const eAttrDomain domain);
+
+ const CurvesGeometry &curves() const
+ {
+ return curves_;
+ }
+
+ eAttrDomain domain() const
+ {
+ return domain_;
+ }
+};
+
+class PointCloudFieldContext : public fn::FieldContext {
+ private:
+ const PointCloud &pointcloud_;
+
+ public:
+ PointCloudFieldContext(const PointCloud &pointcloud) : pointcloud_(pointcloud)
+ {
+ }
+
+ const PointCloud &pointcloud() const
+ {
+ return pointcloud_;
+ }
+};
+
+class InstancesFieldContext : public fn::FieldContext {
+ private:
+ const InstancesComponent &instances_;
+
+ public:
+ InstancesFieldContext(const InstancesComponent &instances) : instances_(instances)
+ {
+ }
+
+ const InstancesComponent &instances() const
+ {
+ return instances_;
+ }
+};
+
+/**
+ * A field context that can represent meshes, curves, point clouds, or instances,
+ * used for field inputs that can work for multiple geometry types.
+ */
+class GeometryFieldContext : public fn::FieldContext {
private:
- const GeometryComponent &component_;
+ /**
+ * Store the geometry as a void pointer instead of a #GeometryComponent to allow referencing data
+ * that doesn't correspond directly to a geometry component type, in this case #CurvesGeometry
+ * instead of #Curves.
+ */
+ const void *geometry_;
+ const GeometryComponentType type_;
const eAttrDomain domain_;
+ friend GeometryFieldInput;
+
public:
- GeometryComponentFieldContext(const GeometryComponent &component, const eAttrDomain domain)
- : component_(component), domain_(domain)
+ GeometryFieldContext(const GeometryComponent &component, eAttrDomain domain);
+ GeometryFieldContext(const void *geometry, GeometryComponentType type, eAttrDomain domain);
+
+ const void *geometry() const
{
+ return geometry_;
}
- const GeometryComponent &geometry_component() const
+ GeometryComponentType type() const
{
- return component_;
+ return type_;
}
eAttrDomain domain() const
{
return domain_;
}
+
+ std::optional<AttributeAccessor> attributes() const;
+ const Mesh *mesh() const;
+ const CurvesGeometry *curves() const;
+ const PointCloud *pointcloud() const;
+ const InstancesComponent *instances() const;
+
+ private:
+ GeometryFieldContext(const Mesh &mesh, eAttrDomain domain);
+ GeometryFieldContext(const CurvesGeometry &curves, eAttrDomain domain);
+ GeometryFieldContext(const PointCloud &points);
+ GeometryFieldContext(const InstancesComponent &instances);
};
class GeometryFieldInput : public fn::FieldInput {
public:
using fn::FieldInput::FieldInput;
+ GVArray get_varray_for_context(const fn::FieldContext &context,
+ IndexMask mask,
+ ResourceScope &scope) const override;
+ virtual GVArray get_varray_for_context(const GeometryFieldContext &context,
+ IndexMask mask) const = 0;
+};
+class MeshFieldInput : public fn::FieldInput {
+ public:
+ using fn::FieldInput::FieldInput;
GVArray get_varray_for_context(const fn::FieldContext &context,
IndexMask mask,
ResourceScope &scope) const override;
+ virtual GVArray get_varray_for_context(const Mesh &mesh,
+ eAttrDomain domain,
+ IndexMask mask) const = 0;
+};
- virtual GVArray get_varray_for_context(const GeometryComponent &component,
+class CurvesFieldInput : public fn::FieldInput {
+ public:
+ using fn::FieldInput::FieldInput;
+ GVArray get_varray_for_context(const fn::FieldContext &context,
+ IndexMask mask,
+ ResourceScope &scope) const override;
+ virtual GVArray get_varray_for_context(const CurvesGeometry &curves,
eAttrDomain domain,
IndexMask mask) const = 0;
};
+class PointCloudFieldInput : public fn::FieldInput {
+ public:
+ using fn::FieldInput::FieldInput;
+ GVArray get_varray_for_context(const fn::FieldContext &context,
+ IndexMask mask,
+ ResourceScope &scope) const override;
+ virtual GVArray get_varray_for_context(const PointCloud &pointcloud, IndexMask mask) const = 0;
+};
+
+class InstancesFieldInput : public fn::FieldInput {
+ public:
+ using fn::FieldInput::FieldInput;
+ GVArray get_varray_for_context(const fn::FieldContext &context,
+ IndexMask mask,
+ ResourceScope &scope) const override;
+ virtual GVArray get_varray_for_context(const InstancesComponent &instances,
+ IndexMask mask) const = 0;
+};
+
class AttributeFieldInput : public GeometryFieldInput {
private:
std::string name_;
@@ -72,8 +210,7 @@ class AttributeFieldInput : public GeometryFieldInput {
return name_;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
- eAttrDomain domain,
+ GVArray get_varray_for_context(const GeometryFieldContext &context,
IndexMask mask) const override;
std::string socket_inspection_name() const override;
@@ -89,8 +226,7 @@ class IDAttributeFieldInput : public GeometryFieldInput {
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
- eAttrDomain domain,
+ GVArray get_varray_for_context(const GeometryFieldContext &context,
IndexMask mask) const override;
std::string socket_inspection_name() const override;
@@ -99,12 +235,9 @@ class IDAttributeFieldInput : public GeometryFieldInput {
bool is_equal_to(const fn::FieldNode &other) const override;
};
-VArray<float3> curve_normals_varray(const CurveComponent &component, const eAttrDomain domain);
+VArray<float3> curve_normals_varray(const CurvesGeometry &curves, const eAttrDomain domain);
-VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component,
- const Mesh &mesh,
- const IndexMask mask,
- eAttrDomain domain);
+VArray<float3> mesh_normals_varray(const Mesh &mesh, const IndexMask mask, eAttrDomain domain);
class NormalFieldInput : public GeometryFieldInput {
public:
@@ -113,8 +246,7 @@ class NormalFieldInput : public GeometryFieldInput {
category_ = Category::Generated;
}
- GVArray get_varray_for_context(const GeometryComponent &component,
- const eAttrDomain domain,
+ GVArray get_varray_for_context(const GeometryFieldContext &context,
IndexMask mask) const override;
std::string socket_inspection_name() const override;
@@ -152,8 +284,7 @@ class AnonymousAttributeFieldInput : public GeometryFieldInput {
return fn::Field<T>{field_input};
}
- GVArray get_varray_for_context(const GeometryComponent &component,
- eAttrDomain domain,
+ GVArray get_varray_for_context(const GeometryFieldContext &context,
IndexMask mask) const override;
std::string socket_inspection_name() const override;
@@ -162,10 +293,10 @@ class AnonymousAttributeFieldInput : public GeometryFieldInput {
bool is_equal_to(const fn::FieldNode &other) const override;
};
-class CurveLengthFieldInput final : public GeometryFieldInput {
+class CurveLengthFieldInput final : public CurvesFieldInput {
public:
CurveLengthFieldInput();
- GVArray get_varray_for_context(const GeometryComponent &component,
+ GVArray get_varray_for_context(const CurvesGeometry &curves,
eAttrDomain domain,
IndexMask mask) const final;
uint64_t hash() const override;
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 8b7fbc4938f..465573745ec 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -143,6 +143,7 @@ set(SRC
intern/geometry_component_mesh.cc
intern/geometry_component_pointcloud.cc
intern/geometry_component_volume.cc
+ intern/geometry_fields.cc
intern/geometry_set.cc
intern/geometry_set_instances.cc
intern/gpencil.c
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index b9995796a21..313e6a172ac 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -5,7 +5,6 @@
#include "BKE_attribute_math.hh"
#include "BKE_customdata.h"
#include "BKE_deform.h"
-#include "BKE_geometry_fields.hh"
#include "BKE_geometry_set.hh"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
@@ -794,7 +793,7 @@ void CustomDataAttributes::reorder(Span<AttributeIDRef> new_order)
}
/* -------------------------------------------------------------------- */
-/** \name Geometry Component
+/** \name Attribute API
* \{ */
static blender::GVArray try_adapt_data_type(blender::GVArray varray,
@@ -805,123 +804,6 @@ static blender::GVArray try_adapt_data_type(blender::GVArray varray,
return conversions.try_convert(std::move(varray), to_type);
}
-GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &context,
- IndexMask mask,
- ResourceScope &UNUSED(scope)) const
-{
- if (const GeometryComponentFieldContext *geometry_context =
- dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
- const GeometryComponent &component = geometry_context->geometry_component();
- const eAttrDomain domain = geometry_context->domain();
- return this->get_varray_for_context(component, domain, mask);
- }
- return {};
-}
-
-GVArray AttributeFieldInput::get_varray_for_context(const GeometryComponent &component,
- const eAttrDomain domain,
- IndexMask UNUSED(mask)) const
-{
- const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_);
- if (auto attributes = component.attributes()) {
- return attributes->lookup(name_, domain, data_type);
- }
- return {};
-}
-
-std::string AttributeFieldInput::socket_inspection_name() const
-{
- std::stringstream ss;
- ss << '"' << name_ << '"' << TIP_(" attribute from geometry");
- return ss.str();
-}
-
-uint64_t AttributeFieldInput::hash() const
-{
- return get_default_hash_2(name_, type_);
-}
-
-bool AttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
-{
- if (const AttributeFieldInput *other_typed = dynamic_cast<const AttributeFieldInput *>(&other)) {
- return name_ == other_typed->name_ && type_ == other_typed->type_;
- }
- return false;
-}
-
-static StringRef get_random_id_attribute_name(const eAttrDomain domain)
-{
- switch (domain) {
- case ATTR_DOMAIN_POINT:
- case ATTR_DOMAIN_INSTANCE:
- return "id";
- default:
- return "";
- }
-}
-
-GVArray IDAttributeFieldInput::get_varray_for_context(const GeometryComponent &component,
- const eAttrDomain domain,
- IndexMask mask) const
-{
-
- const StringRef name = get_random_id_attribute_name(domain);
- if (auto attributes = component.attributes()) {
- if (GVArray attribute = attributes->lookup(name, domain, CD_PROP_INT32)) {
- return attribute;
- }
- }
-
- /* Use the index as the fallback if no random ID attribute exists. */
- return fn::IndexFieldInput::get_index_varray(mask);
-}
-
-std::string IDAttributeFieldInput::socket_inspection_name() const
-{
- return TIP_("ID / Index");
-}
-
-uint64_t IDAttributeFieldInput::hash() const
-{
- /* All random ID attribute inputs are the same within the same evaluation context. */
- return 92386459827;
-}
-
-bool IDAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
-{
- /* All random ID attribute inputs are the same within the same evaluation context. */
- return dynamic_cast<const IDAttributeFieldInput *>(&other) != nullptr;
-}
-
-GVArray AnonymousAttributeFieldInput::get_varray_for_context(const GeometryComponent &component,
- const eAttrDomain domain,
- IndexMask UNUSED(mask)) const
-{
- const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_);
- return component.attributes()->lookup(anonymous_id_.get(), domain, data_type);
-}
-
-std::string AnonymousAttributeFieldInput::socket_inspection_name() const
-{
- std::stringstream ss;
- ss << '"' << debug_name_ << '"' << TIP_(" from ") << producer_name_;
- return ss.str();
-}
-
-uint64_t AnonymousAttributeFieldInput::hash() const
-{
- return get_default_hash_2(anonymous_id_.get(), type_);
-}
-
-bool AnonymousAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
-{
- if (const AnonymousAttributeFieldInput *other_typed =
- dynamic_cast<const AnonymousAttributeFieldInput *>(&other)) {
- return anonymous_id_.get() == other_typed->anonymous_id_.get() && type_ == other_typed->type_;
- }
- return false;
-}
-
GVArray AttributeAccessor::lookup(const AttributeIDRef &attribute_id,
const std::optional<eAttrDomain> domain,
const std::optional<eCustomDataType> data_type) const
diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc
index 2714c78e381..596c8e0bfc7 100644
--- a/source/blender/blenkernel/intern/geometry_component_curves.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curves.cc
@@ -206,18 +206,11 @@ static Array<float3> curve_normal_point_domain(const bke::CurvesGeometry &curves
return results;
}
-VArray<float3> curve_normals_varray(const CurveComponent &component, const eAttrDomain domain)
+VArray<float3> curve_normals_varray(const CurvesGeometry &curves, const eAttrDomain domain)
{
- if (!component.has_curves()) {
- return {};
- }
-
- const Curves &curves_id = *component.get_for_read();
- const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
-
const VArray<int8_t> types = curves.curve_types();
if (curves.is_single_type(CURVE_TYPE_POLY)) {
- return component.attributes()->adapt_domain<float3>(
+ return curves.adapt_domain<float3>(
VArray<float3>::ForSpan(curves.evaluated_normals()), ATTR_DOMAIN_POINT, domain);
}
@@ -228,7 +221,7 @@ VArray<float3> curve_normals_varray(const CurveComponent &component, const eAttr
}
if (domain == ATTR_DOMAIN_CURVE) {
- return component.attributes()->adapt_domain<float3>(
+ return curves.adapt_domain<float3>(
VArray<float3>::ForContainer(std::move(normals)), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
}
@@ -241,15 +234,9 @@ VArray<float3> curve_normals_varray(const CurveComponent &component, const eAttr
/** \name Curve Length Field Input
* \{ */
-static VArray<float> construct_curve_length_gvarray(const CurveComponent &component,
+static VArray<float> construct_curve_length_gvarray(const CurvesGeometry &curves,
const eAttrDomain domain)
{
- if (!component.has_curves()) {
- return {};
- }
- const Curves &curves_id = *component.get_for_read();
- const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
-
curves.ensure_evaluated_lengths();
VArray<bool> cyclic = curves.cyclic();
@@ -263,28 +250,23 @@ static VArray<float> construct_curve_length_gvarray(const CurveComponent &compon
}
if (domain == ATTR_DOMAIN_POINT) {
- return component.attributes()->adapt_domain<float>(
- std::move(lengths), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
+ return curves.adapt_domain<float>(std::move(lengths), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
}
return {};
}
CurveLengthFieldInput::CurveLengthFieldInput()
- : GeometryFieldInput(CPPType::get<float>(), "Spline Length node")
+ : CurvesFieldInput(CPPType::get<float>(), "Spline Length node")
{
category_ = Category::Generated;
}
-GVArray CurveLengthFieldInput::get_varray_for_context(const GeometryComponent &component,
+GVArray CurveLengthFieldInput::get_varray_for_context(const CurvesGeometry &curves,
const eAttrDomain domain,
IndexMask UNUSED(mask)) const
{
- if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- return construct_curve_length_gvarray(curve_component, domain);
- }
- return {};
+ return construct_curve_length_gvarray(curves, domain);
}
uint64_t CurveLengthFieldInput::hash() const
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
index 436868ba375..14c31da488b 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -115,8 +115,7 @@ void MeshComponent::ensure_owns_direct_data()
namespace blender::bke {
-VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component,
- const Mesh &mesh,
+VArray<float3> mesh_normals_varray(const Mesh &mesh,
const IndexMask mask,
const eAttrDomain domain)
{
@@ -150,7 +149,7 @@ VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component,
* array and copy the face normal for each of its corners. In this case using the mesh
* component's generic domain interpolation is fine, the data will still be normalized,
* since the face normal is just copied to every corner. */
- return mesh_component.attributes()->adapt_domain(
+ return mesh_attributes(mesh).adapt_domain(
VArray<float3>::ForSpan({(float3 *)BKE_mesh_poly_normals_ensure(&mesh), mesh.totpoly}),
ATTR_DOMAIN_FACE,
ATTR_DOMAIN_CORNER);
diff --git a/source/blender/blenkernel/intern/geometry_fields.cc b/source/blender/blenkernel/intern/geometry_fields.cc
new file mode 100644
index 00000000000..a52ffb6496b
--- /dev/null
+++ b/source/blender/blenkernel/intern/geometry_fields.cc
@@ -0,0 +1,365 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_attribute.hh"
+#include "BKE_curves.hh"
+#include "BKE_geometry_fields.hh"
+#include "BKE_geometry_set.hh"
+#include "BKE_mesh.h"
+#include "BKE_pointcloud.h"
+#include "BKE_type_conversions.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_pointcloud_types.h"
+
+#include "BLT_translation.h"
+
+namespace blender::bke {
+
+MeshFieldContext::MeshFieldContext(const Mesh &mesh, const eAttrDomain domain)
+ : mesh_(mesh), domain_(domain)
+{
+ BLI_assert(mesh_attributes(mesh).domain_supported(domain_));
+}
+
+CurvesFieldContext::CurvesFieldContext(const CurvesGeometry &curves, const eAttrDomain domain)
+ : curves_(curves), domain_(domain)
+{
+ BLI_assert(curves.attributes().domain_supported(domain));
+}
+
+GeometryFieldContext::GeometryFieldContext(const void *geometry,
+ const GeometryComponentType type,
+ const eAttrDomain domain)
+ : geometry_(geometry), type_(type), domain_(domain)
+{
+ BLI_assert(ELEM(type,
+ GEO_COMPONENT_TYPE_MESH,
+ GEO_COMPONENT_TYPE_CURVE,
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ GEO_COMPONENT_TYPE_INSTANCES));
+}
+
+GeometryFieldContext::GeometryFieldContext(const GeometryComponent &component,
+ const eAttrDomain domain)
+ : type_(component.type()), domain_(domain)
+{
+ switch (component.type()) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ geometry_ = mesh_component.get_for_read();
+ break;
+ }
+ case GEO_COMPONENT_TYPE_CURVE: {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ const Curves *curves = curve_component.get_for_read();
+ geometry_ = curves ? &CurvesGeometry::wrap(curves->geometry) : nullptr;
+ break;
+ }
+ case GEO_COMPONENT_TYPE_POINT_CLOUD: {
+ const PointCloudComponent &pointcloud_component = static_cast<const PointCloudComponent &>(
+ component);
+ geometry_ = pointcloud_component.get_for_read();
+ break;
+ }
+ case GEO_COMPONENT_TYPE_INSTANCES: {
+ const InstancesComponent &instances_component = static_cast<const InstancesComponent &>(
+ component);
+ geometry_ = &instances_component;
+ break;
+ }
+ case GEO_COMPONENT_TYPE_VOLUME:
+ case GEO_COMPONENT_TYPE_EDIT:
+ BLI_assert_unreachable();
+ break;
+ }
+}
+
+GeometryFieldContext::GeometryFieldContext(const Mesh &mesh, eAttrDomain domain)
+ : geometry_(&mesh), type_(GEO_COMPONENT_TYPE_MESH), domain_(domain)
+{
+}
+GeometryFieldContext::GeometryFieldContext(const CurvesGeometry &curves, eAttrDomain domain)
+ : geometry_(&curves), type_(GEO_COMPONENT_TYPE_CURVE), domain_(domain)
+{
+}
+GeometryFieldContext::GeometryFieldContext(const PointCloud &points)
+ : geometry_(&points), type_(GEO_COMPONENT_TYPE_POINT_CLOUD), domain_(ATTR_DOMAIN_POINT)
+{
+}
+GeometryFieldContext::GeometryFieldContext(const InstancesComponent &instances)
+ : geometry_(&instances), type_(GEO_COMPONENT_TYPE_INSTANCES), domain_(ATTR_DOMAIN_INSTANCE)
+{
+}
+
+std::optional<AttributeAccessor> GeometryFieldContext::attributes() const
+{
+ if (const Mesh *mesh = this->mesh()) {
+ return mesh_attributes(*mesh);
+ }
+ if (const CurvesGeometry *curves = this->curves()) {
+ return curves->attributes();
+ }
+ if (const PointCloud *pointcloud = this->pointcloud()) {
+ return pointcloud_attributes(*pointcloud);
+ }
+ if (const InstancesComponent *instances = this->instances()) {
+ return instances->attributes();
+ }
+ return {};
+}
+
+const Mesh *GeometryFieldContext::mesh() const
+{
+ return this->type() == GEO_COMPONENT_TYPE_MESH ? static_cast<const Mesh *>(geometry_) : nullptr;
+}
+const CurvesGeometry *GeometryFieldContext::curves() const
+{
+ return this->type() == GEO_COMPONENT_TYPE_CURVE ?
+ static_cast<const CurvesGeometry *>(geometry_) :
+ nullptr;
+}
+const PointCloud *GeometryFieldContext::pointcloud() const
+{
+ return this->type() == GEO_COMPONENT_TYPE_POINT_CLOUD ?
+ static_cast<const PointCloud *>(geometry_) :
+ nullptr;
+}
+const InstancesComponent *GeometryFieldContext::instances() const
+{
+ return this->type() == GEO_COMPONENT_TYPE_INSTANCES ?
+ static_cast<const InstancesComponent *>(geometry_) :
+ nullptr;
+}
+
+GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &context,
+ const IndexMask mask,
+ ResourceScope & /*scope*/) const
+{
+ if (const GeometryFieldContext *geometry_context = dynamic_cast<const GeometryFieldContext *>(
+ &context)) {
+ return this->get_varray_for_context(*geometry_context, mask);
+ }
+ if (const MeshFieldContext *mesh_context = dynamic_cast<const MeshFieldContext *>(&context)) {
+ return this->get_varray_for_context({mesh_context->mesh(), mesh_context->domain()}, mask);
+ }
+ if (const CurvesFieldContext *curve_context = dynamic_cast<const CurvesFieldContext *>(
+ &context)) {
+ return this->get_varray_for_context({curve_context->curves(), curve_context->domain()}, mask);
+ }
+ if (const PointCloudFieldContext *point_context = dynamic_cast<const PointCloudFieldContext *>(
+ &context)) {
+ return this->get_varray_for_context({point_context->pointcloud()}, mask);
+ }
+ if (const InstancesFieldContext *instances_context = dynamic_cast<const InstancesFieldContext *>(
+ &context)) {
+ return this->get_varray_for_context({instances_context->instances()}, mask);
+ }
+ return {};
+}
+
+GVArray MeshFieldInput::get_varray_for_context(const fn::FieldContext &context,
+ const IndexMask mask,
+ ResourceScope & /*scope*/) const
+{
+ if (const GeometryFieldContext *geometry_context = dynamic_cast<const GeometryFieldContext *>(
+ &context)) {
+ if (const Mesh *mesh = geometry_context->mesh()) {
+ return this->get_varray_for_context(*mesh, geometry_context->domain(), mask);
+ }
+ }
+ if (const MeshFieldContext *mesh_context = dynamic_cast<const MeshFieldContext *>(&context)) {
+ return this->get_varray_for_context(mesh_context->mesh(), mesh_context->domain(), mask);
+ }
+ return {};
+}
+
+GVArray CurvesFieldInput::get_varray_for_context(const fn::FieldContext &context,
+ IndexMask mask,
+ ResourceScope & /*scope*/) const
+{
+ if (const GeometryFieldContext *geometry_context = dynamic_cast<const GeometryFieldContext *>(
+ &context)) {
+ if (const CurvesGeometry *curves = geometry_context->curves()) {
+ return this->get_varray_for_context(*curves, geometry_context->domain(), mask);
+ }
+ }
+ if (const CurvesFieldContext *curves_context = dynamic_cast<const CurvesFieldContext *>(
+ &context)) {
+ return this->get_varray_for_context(curves_context->curves(), curves_context->domain(), mask);
+ }
+ return {};
+}
+
+GVArray PointCloudFieldInput::get_varray_for_context(const fn::FieldContext &context,
+ IndexMask mask,
+ ResourceScope & /*scope*/) const
+{
+ if (const GeometryFieldContext *geometry_context = dynamic_cast<const GeometryFieldContext *>(
+ &context)) {
+ if (const PointCloud *pointcloud = geometry_context->pointcloud()) {
+ return this->get_varray_for_context(*pointcloud, mask);
+ }
+ }
+ if (const PointCloudFieldContext *point_context = dynamic_cast<const PointCloudFieldContext *>(
+ &context)) {
+ return this->get_varray_for_context(point_context->pointcloud(), mask);
+ }
+ return {};
+}
+
+GVArray InstancesFieldInput::get_varray_for_context(const fn::FieldContext &context,
+ IndexMask mask,
+ ResourceScope & /*scope*/) const
+{
+ if (const GeometryFieldContext *geometry_context = dynamic_cast<const GeometryFieldContext *>(
+ &context)) {
+ if (const InstancesComponent *instances = geometry_context->instances()) {
+ return this->get_varray_for_context(*instances, mask);
+ }
+ }
+ if (const InstancesFieldContext *instances_context = dynamic_cast<const InstancesFieldContext *>(
+ &context)) {
+ return this->get_varray_for_context(instances_context->instances(), mask);
+ }
+ return {};
+}
+
+GVArray AttributeFieldInput::get_varray_for_context(const GeometryFieldContext &context,
+ IndexMask UNUSED(mask)) const
+{
+ const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_);
+ if (auto attributes = context.attributes()) {
+ return attributes->lookup(name_, context.domain(), data_type);
+ }
+ return {};
+}
+
+std::string AttributeFieldInput::socket_inspection_name() const
+{
+ std::stringstream ss;
+ ss << '"' << name_ << '"' << TIP_(" attribute from geometry");
+ return ss.str();
+}
+
+uint64_t AttributeFieldInput::hash() const
+{
+ return get_default_hash_2(name_, type_);
+}
+
+bool AttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
+{
+ if (const AttributeFieldInput *other_typed = dynamic_cast<const AttributeFieldInput *>(&other)) {
+ return name_ == other_typed->name_ && type_ == other_typed->type_;
+ }
+ return false;
+}
+
+static StringRef get_random_id_attribute_name(const eAttrDomain domain)
+{
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ case ATTR_DOMAIN_INSTANCE:
+ return "id";
+ default:
+ return "";
+ }
+}
+
+GVArray IDAttributeFieldInput::get_varray_for_context(const GeometryFieldContext &context,
+ const IndexMask mask) const
+{
+
+ const StringRef name = get_random_id_attribute_name(context.domain());
+ if (auto attributes = context.attributes()) {
+ if (GVArray attribute = attributes->lookup(name, context.domain(), CD_PROP_INT32)) {
+ return attribute;
+ }
+ }
+
+ /* Use the index as the fallback if no random ID attribute exists. */
+ return fn::IndexFieldInput::get_index_varray(mask);
+}
+
+std::string IDAttributeFieldInput::socket_inspection_name() const
+{
+ return TIP_("ID / Index");
+}
+
+uint64_t IDAttributeFieldInput::hash() const
+{
+ /* All random ID attribute inputs are the same within the same evaluation context. */
+ return 92386459827;
+}
+
+bool IDAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
+{
+ /* All random ID attribute inputs are the same within the same evaluation context. */
+ return dynamic_cast<const IDAttributeFieldInput *>(&other) != nullptr;
+}
+
+GVArray AnonymousAttributeFieldInput::get_varray_for_context(const GeometryFieldContext &context,
+ const IndexMask /*mask*/) const
+{
+ const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_);
+ return context.attributes()->lookup(anonymous_id_.get(), context.domain(), data_type);
+}
+
+std::string AnonymousAttributeFieldInput::socket_inspection_name() const
+{
+ std::stringstream ss;
+ ss << '"' << debug_name_ << '"' << TIP_(" from ") << producer_name_;
+ return ss.str();
+}
+
+uint64_t AnonymousAttributeFieldInput::hash() const
+{
+ return get_default_hash_2(anonymous_id_.get(), type_);
+}
+
+bool AnonymousAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
+{
+ if (const AnonymousAttributeFieldInput *other_typed =
+ dynamic_cast<const AnonymousAttributeFieldInput *>(&other)) {
+ return anonymous_id_.get() == other_typed->anonymous_id_.get() && type_ == other_typed->type_;
+ }
+ return false;
+}
+
+} // namespace blender::bke
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh and Curve Normals Field Input
+ * \{ */
+
+namespace blender::bke {
+
+GVArray NormalFieldInput::get_varray_for_context(const GeometryFieldContext &context,
+ const IndexMask mask) const
+{
+ if (const Mesh *mesh = context.mesh()) {
+ return mesh_normals_varray(*mesh, mask, context.domain());
+ }
+ if (const CurvesGeometry *curves = context.curves()) {
+ return curve_normals_varray(*curves, context.domain());
+ }
+ return {};
+}
+
+std::string NormalFieldInput::socket_inspection_name() const
+{
+ return TIP_("Normal");
+}
+
+uint64_t NormalFieldInput::hash() const
+{
+ return 213980475983;
+}
+
+bool NormalFieldInput::is_equal_to(const fn::FieldNode &other) const
+{
+ return dynamic_cast<const NormalFieldInput *>(&other) != nullptr;
+}
+
+} // namespace blender::bke
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 1a0ce4f0893..633d9ad8c49 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -8,7 +8,6 @@
#include "BKE_attribute.h"
#include "BKE_curves.hh"
-#include "BKE_geometry_fields.hh"
#include "BKE_geometry_set.hh"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
@@ -634,48 +633,6 @@ void GeometrySet::modify_geometry_sets(ForeachSubGeometryCallback callback)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Mesh and Curve Normals Field Input
- * \{ */
-
-namespace blender::bke {
-
-GVArray NormalFieldInput::get_varray_for_context(const GeometryComponent &component,
- const eAttrDomain domain,
- IndexMask mask) const
-{
- if (component.type() == GEO_COMPONENT_TYPE_MESH) {
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- if (const Mesh *mesh = mesh_component.get_for_read()) {
- return mesh_normals_varray(mesh_component, *mesh, mask, domain);
- }
- }
- else if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- return curve_normals_varray(curve_component, domain);
- }
- return {};
-}
-
-std::string NormalFieldInput::socket_inspection_name() const
-{
- return TIP_("Normal");
-}
-
-uint64_t NormalFieldInput::hash() const
-{
- return 213980475983;
-}
-
-bool NormalFieldInput::is_equal_to(const fn::FieldNode &other) const
-{
- return dynamic_cast<const NormalFieldInput *>(&other) != nullptr;
-}
-
-} // namespace blender::bke
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name C API
* \{ */