Replace `mesh_attributes`, `mesh_attributes_for_write` and the point cloud versions with methods on the `Mesh` and `PointCloud` types. This makes them friendlier to use and improves readability. Differential Revision: https://developer.blender.org/D15907
366 lines
12 KiB
C++
366 lines
12 KiB
C++
/* 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<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();
|
|
}
|
|
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<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
|
|
|
|
/** \} */
|