/* 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().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(component); geometry_ = mesh_component.get_for_read(); break; } case GEO_COMPONENT_TYPE_CURVE: { const CurveComponent &curve_component = static_cast(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( component); geometry_ = pointcloud_component.get_for_read(); break; } case GEO_COMPONENT_TYPE_INSTANCES: { const InstancesComponent &instances_component = static_cast( 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 GeometryFieldContext::attributes() const { if (const Mesh *mesh = this->mesh()) { return mesh->attributes(); } if (const CurvesGeometry *curves = this->curves()) { return curves->attributes(); } if (const PointCloud *pointcloud = this->pointcloud()) { return pointcloud->attributes(); } if (const InstancesComponent *instances = this->instances()) { return instances->attributes(); } return {}; } const Mesh *GeometryFieldContext::mesh() const { return this->type() == GEO_COMPONENT_TYPE_MESH ? static_cast(geometry_) : nullptr; } const CurvesGeometry *GeometryFieldContext::curves() const { return this->type() == GEO_COMPONENT_TYPE_CURVE ? static_cast(geometry_) : nullptr; } const PointCloud *GeometryFieldContext::pointcloud() const { return this->type() == GEO_COMPONENT_TYPE_POINT_CLOUD ? static_cast(geometry_) : nullptr; } const InstancesComponent *GeometryFieldContext::instances() const { return this->type() == GEO_COMPONENT_TYPE_INSTANCES ? static_cast(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( &context)) { return this->get_varray_for_context(*geometry_context, mask); } if (const MeshFieldContext *mesh_context = dynamic_cast(&context)) { return this->get_varray_for_context({mesh_context->mesh(), mesh_context->domain()}, mask); } if (const CurvesFieldContext *curve_context = dynamic_cast( &context)) { return this->get_varray_for_context({curve_context->curves(), curve_context->domain()}, mask); } if (const PointCloudFieldContext *point_context = dynamic_cast( &context)) { return this->get_varray_for_context({point_context->pointcloud()}, mask); } if (const InstancesFieldContext *instances_context = dynamic_cast( &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( &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(&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( &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( &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( &context)) { if (const PointCloud *pointcloud = geometry_context->pointcloud()) { return this->get_varray_for_context(*pointcloud, mask); } } if (const PointCloudFieldContext *point_context = dynamic_cast( &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( &context)) { if (const InstancesComponent *instances = geometry_context->instances()) { return this->get_varray_for_context(*instances, mask); } } if (const InstancesFieldContext *instances_context = dynamic_cast( &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(&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(&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(&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(&other) != nullptr; } } // namespace blender::bke /** \} */