2023-08-16 00:20:26 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2021-03-08 11:41:23 -05:00
|
|
|
|
|
|
|
|
#include "BLI_map.hh"
|
|
|
|
|
#include "BLI_span.hh"
|
|
|
|
|
#include "BLI_string_ref.hh"
|
|
|
|
|
#include "BLI_vector.hh"
|
2021-03-17 11:50:13 +01:00
|
|
|
#include "BLI_vector_set.hh"
|
|
|
|
|
|
|
|
|
|
#include "BKE_geometry_set.hh"
|
2021-03-08 11:41:23 -05:00
|
|
|
|
|
|
|
|
namespace blender::bke {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Utility to group together multiple functions that are used to access custom data on geometry
|
|
|
|
|
* components in a generic way.
|
|
|
|
|
*/
|
|
|
|
|
struct CustomDataAccessInfo {
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
using CustomDataGetter = CustomData *(*)(void *owner);
|
|
|
|
|
using ConstCustomDataGetter = const CustomData *(*)(const void *owner);
|
|
|
|
|
using GetElementNum = int (*)(const void *owner);
|
|
|
|
|
using UpdateCustomDataPointers = void (*)(void *owner);
|
2021-03-08 11:41:23 -05:00
|
|
|
|
|
|
|
|
CustomDataGetter get_custom_data;
|
|
|
|
|
ConstCustomDataGetter get_const_custom_data;
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
GetElementNum get_element_num;
|
2021-03-08 11:41:23 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A #BuiltinAttributeProvider is responsible for exactly one attribute on a geometry component.
|
|
|
|
|
* The attribute is identified by its name and has a fixed domain and type. Builtin attributes do
|
|
|
|
|
* not follow the same loose rules as other attributes, because they are mapped to internal
|
|
|
|
|
* "legacy" data structures. For example, some builtin attributes cannot be deleted. */
|
|
|
|
|
class BuiltinAttributeProvider {
|
|
|
|
|
public:
|
|
|
|
|
/* Some utility enums to avoid hard to read booleans in function calls. */
|
|
|
|
|
enum CreatableEnum {
|
|
|
|
|
Creatable,
|
|
|
|
|
NonCreatable,
|
|
|
|
|
};
|
|
|
|
|
enum DeletableEnum {
|
|
|
|
|
Deletable,
|
|
|
|
|
NonDeletable,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
const std::string name_;
|
2022-06-01 14:38:06 +10:00
|
|
|
const eAttrDomain domain_;
|
|
|
|
|
const eCustomDataType data_type_;
|
2021-03-08 11:41:23 -05:00
|
|
|
const CreatableEnum createable_;
|
|
|
|
|
const DeletableEnum deletable_;
|
2022-09-17 14:38:30 -05:00
|
|
|
const AttributeValidator validator_;
|
2021-03-08 11:41:23 -05:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
BuiltinAttributeProvider(std::string name,
|
2022-06-01 14:38:06 +10:00
|
|
|
const eAttrDomain domain,
|
|
|
|
|
const eCustomDataType data_type,
|
2021-03-08 11:41:23 -05:00
|
|
|
const CreatableEnum createable,
|
2022-09-17 14:38:30 -05:00
|
|
|
const DeletableEnum deletable,
|
|
|
|
|
AttributeValidator validator = {})
|
2021-03-08 11:41:23 -05:00
|
|
|
: name_(std::move(name)),
|
|
|
|
|
domain_(domain),
|
|
|
|
|
data_type_(data_type),
|
|
|
|
|
createable_(createable),
|
2022-09-17 14:38:30 -05:00
|
|
|
deletable_(deletable),
|
|
|
|
|
validator_(validator)
|
2021-03-08 11:41:23 -05:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-19 11:21:06 +02:00
|
|
|
virtual GAttributeReader try_get_for_read(const void *owner) const = 0;
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
virtual GAttributeWriter try_get_for_write(void *owner) const = 0;
|
|
|
|
|
virtual bool try_delete(void *owner) const = 0;
|
|
|
|
|
virtual bool try_create(void *onwer, const AttributeInit &initializer) const = 0;
|
|
|
|
|
virtual bool exists(const void *owner) const = 0;
|
2021-03-08 11:41:23 -05:00
|
|
|
|
2021-03-17 11:51:51 +01:00
|
|
|
StringRefNull name() const
|
2021-03-08 11:41:23 -05:00
|
|
|
{
|
|
|
|
|
return name_;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-01 14:38:06 +10:00
|
|
|
eAttrDomain domain() const
|
2021-03-08 11:41:23 -05:00
|
|
|
{
|
|
|
|
|
return domain_;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-01 14:38:06 +10:00
|
|
|
eCustomDataType data_type() const
|
2021-03-08 11:41:23 -05:00
|
|
|
{
|
|
|
|
|
return data_type_;
|
|
|
|
|
}
|
2022-09-17 14:38:30 -05:00
|
|
|
|
|
|
|
|
AttributeValidator validator() const
|
|
|
|
|
{
|
|
|
|
|
return validator_;
|
|
|
|
|
}
|
2021-03-08 11:41:23 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A #DynamicAttributesProvider manages a set of named attributes on a geometry component. Each
|
|
|
|
|
* attribute has a name, domain and type.
|
|
|
|
|
*/
|
|
|
|
|
class DynamicAttributesProvider {
|
|
|
|
|
public:
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
virtual GAttributeReader try_get_for_read(const void *owner,
|
|
|
|
|
const AttributeIDRef &attribute_id) const = 0;
|
|
|
|
|
virtual GAttributeWriter try_get_for_write(void *owner,
|
|
|
|
|
const AttributeIDRef &attribute_id) const = 0;
|
|
|
|
|
virtual bool try_delete(void *owner, const AttributeIDRef &attribute_id) const = 0;
|
|
|
|
|
virtual bool try_create(void *owner,
|
|
|
|
|
const AttributeIDRef &attribute_id,
|
|
|
|
|
const eAttrDomain domain,
|
|
|
|
|
const eCustomDataType data_type,
|
|
|
|
|
const AttributeInit &initializer) const
|
2021-03-08 11:41:23 -05:00
|
|
|
{
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
UNUSED_VARS(owner, attribute_id, domain, data_type, initializer);
|
2021-03-08 11:41:23 -05:00
|
|
|
/* Some providers should not create new attributes. */
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
virtual bool foreach_attribute(const void *owner,
|
2021-03-08 11:41:23 -05:00
|
|
|
const AttributeForeachCallback callback) const = 0;
|
2022-06-01 14:38:06 +10:00
|
|
|
virtual void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const = 0;
|
2021-03-08 11:41:23 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This is the attribute provider for most user generated attributes.
|
|
|
|
|
*/
|
|
|
|
|
class CustomDataAttributeProvider final : public DynamicAttributesProvider {
|
|
|
|
|
private:
|
2022-09-02 11:58:44 +02:00
|
|
|
static constexpr uint64_t supported_types_mask = CD_MASK_PROP_ALL;
|
2023-10-20 19:32:26 +02:00
|
|
|
eAttrDomain domain_;
|
|
|
|
|
CustomDataAccessInfo custom_data_access_;
|
2021-03-08 11:41:23 -05:00
|
|
|
|
|
|
|
|
public:
|
2022-06-01 14:38:06 +10:00
|
|
|
CustomDataAttributeProvider(const eAttrDomain domain,
|
2021-03-08 11:41:23 -05:00
|
|
|
const CustomDataAccessInfo custom_data_access)
|
|
|
|
|
: domain_(domain), custom_data_access_(custom_data_access)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
GAttributeReader try_get_for_read(const void *owner,
|
|
|
|
|
const AttributeIDRef &attribute_id) const final;
|
2021-03-08 11:41:23 -05:00
|
|
|
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final;
|
2021-03-08 11:41:23 -05:00
|
|
|
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final;
|
2021-03-08 11:41:23 -05:00
|
|
|
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
bool try_create(void *owner,
|
2021-09-09 12:54:20 +02:00
|
|
|
const AttributeIDRef &attribute_id,
|
2022-06-01 14:38:06 +10:00
|
|
|
eAttrDomain domain,
|
|
|
|
|
const eCustomDataType data_type,
|
2021-04-22 09:20:03 -05:00
|
|
|
const AttributeInit &initializer) const final;
|
2021-03-08 11:41:23 -05:00
|
|
|
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const final;
|
2021-03-08 11:41:23 -05:00
|
|
|
|
2022-06-01 14:38:06 +10:00
|
|
|
void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const final
|
2021-03-08 11:41:23 -05:00
|
|
|
{
|
2021-03-17 11:50:13 +01:00
|
|
|
callback(domain_);
|
2021-03-08 11:41:23 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2022-06-01 14:38:06 +10:00
|
|
|
bool type_is_supported(eCustomDataType data_type) const
|
2021-03-08 11:41:23 -05:00
|
|
|
{
|
|
|
|
|
return ((1ULL << data_type) & supported_types_mask) != 0;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This provider is used to provide access to builtin attributes. It supports making internal types
|
Mesh: Move positions to a generic attribute
**Changes**
As described in T93602, this patch removes all use of the `MVert`
struct, replacing it with a generic named attribute with the name
`"position"`, consistent with other geometry types.
Variable names have been changed from `verts` to `positions`, to align
with the attribute name and the more generic design (positions are not
vertices, they are just an attribute stored on the point domain).
This change is made possible by previous commits that moved all other
data out of `MVert` to runtime data or other generic attributes. What
remains is mostly a simple type change. Though, the type still shows up
859 times, so the patch is quite large.
One compromise is that now `CD_MASK_BAREMESH` now contains
`CD_PROP_FLOAT3`. With the general move towards generic attributes
over custom data types, we are removing use of these type masks anyway.
**Benefits**
The most obvious benefit is reduced memory usage and the benefits
that brings in memory-bound situations. `float3` is only 3 bytes, in
comparison to `MVert` which was 4. When there are millions of vertices
this starts to matter more.
The other benefits come from using a more generic type. Instead of
writing algorithms specifically for `MVert`, code can just use arrays
of vectors. This will allow eliminating many temporary arrays or
wrappers used to extract positions.
Many possible improvements aren't implemented in this patch, though
I did switch simplify or remove the process of creating temporary
position arrays in a few places.
The design clarity that "positions are just another attribute" brings
allows removing explicit copying of vertices in some procedural
operations-- they are just processed like most other attributes.
**Performance**
This touches so many areas that it's hard to benchmark exhaustively,
but I observed some areas as examples.
* The mesh line node with 4 million count was 1.5x (8ms to 12ms) faster.
* The Spring splash screen went from ~4.3 to ~4.5 fps.
* The subdivision surface modifier/node was slightly faster
RNA access through Python may be slightly slower, since now we need
a name lookup instead of just a custom data type lookup for each index.
**Future Improvements**
* Remove uses of "vert_coords" functions:
* `BKE_mesh_vert_coords_alloc`
* `BKE_mesh_vert_coords_get`
* `BKE_mesh_vert_coords_apply{_with_mat4}`
* Remove more hidden copying of positions
* General simplification now possible in many areas
* Convert more code to C++ to use `float3` instead of `float[3]`
* Currently `reinterpret_cast` is used for those C-API functions
Differential Revision: https://developer.blender.org/D15982
2023-01-10 00:10:43 -05:00
|
|
|
* available as different types.
|
2021-10-20 10:54:54 -05:00
|
|
|
*
|
|
|
|
|
* It also supports named builtin attributes, and will look up attributes in #CustomData by name
|
|
|
|
|
* if the stored type is the same as the attribute type.
|
2021-03-08 11:41:23 -05:00
|
|
|
*/
|
|
|
|
|
class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
|
2022-07-23 19:59:59 -05:00
|
|
|
using UpdateOnChange = void (*)(void *owner);
|
2022-06-01 14:38:06 +10:00
|
|
|
const eCustomDataType stored_type_;
|
2021-03-08 11:41:23 -05:00
|
|
|
const CustomDataAccessInfo custom_data_access_;
|
2022-07-23 19:59:59 -05:00
|
|
|
const UpdateOnChange update_on_change_;
|
2021-10-20 10:54:54 -05:00
|
|
|
bool stored_as_named_attribute_;
|
2021-03-08 11:41:23 -05:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
BuiltinCustomDataLayerProvider(std::string attribute_name,
|
2022-06-01 14:38:06 +10:00
|
|
|
const eAttrDomain domain,
|
|
|
|
|
const eCustomDataType attribute_type,
|
|
|
|
|
const eCustomDataType stored_type,
|
2021-03-08 11:41:23 -05:00
|
|
|
const CreatableEnum creatable,
|
|
|
|
|
const DeletableEnum deletable,
|
|
|
|
|
const CustomDataAccessInfo custom_data_access,
|
2022-09-17 14:38:30 -05:00
|
|
|
const UpdateOnChange update_on_write,
|
|
|
|
|
const AttributeValidator validator = {})
|
2023-02-20 11:51:16 +01:00
|
|
|
: BuiltinAttributeProvider(
|
|
|
|
|
std::move(attribute_name), domain, attribute_type, creatable, deletable, validator),
|
2021-03-08 11:41:23 -05:00
|
|
|
stored_type_(stored_type),
|
|
|
|
|
custom_data_access_(custom_data_access),
|
2022-07-23 19:59:59 -05:00
|
|
|
update_on_change_(update_on_write),
|
2021-10-20 10:54:54 -05:00
|
|
|
stored_as_named_attribute_(data_type_ == stored_type_)
|
2021-03-08 11:41:23 -05:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-19 11:21:06 +02:00
|
|
|
GAttributeReader try_get_for_read(const void *owner) const final;
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
GAttributeWriter try_get_for_write(void *owner) const final;
|
|
|
|
|
bool try_delete(void *owner) const final;
|
|
|
|
|
bool try_create(void *owner, const AttributeInit &initializer) const final;
|
|
|
|
|
bool exists(const void *owner) const final;
|
2022-09-06 13:20:03 -05:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
bool layer_exists(const CustomData &custom_data) const;
|
2021-03-08 11:41:23 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This is a container for multiple attribute providers that are used by one geometry component
|
|
|
|
|
* type (e.g. there is a set of attribute providers for mesh components).
|
|
|
|
|
*/
|
|
|
|
|
class ComponentAttributeProviders {
|
|
|
|
|
private:
|
|
|
|
|
/**
|
|
|
|
|
* Builtin attribute providers are identified by their name. Attribute names that are in this
|
|
|
|
|
* map will only be accessed using builtin attribute providers. Therefore, these providers have
|
|
|
|
|
* higher priority when an attribute name is looked up. Usually, that means that builtin
|
|
|
|
|
* providers are checked before dynamic ones.
|
|
|
|
|
*/
|
2021-03-17 11:51:51 +01:00
|
|
|
Map<std::string, const BuiltinAttributeProvider *> builtin_attribute_providers_;
|
2021-03-08 11:41:23 -05:00
|
|
|
/**
|
|
|
|
|
* An ordered list of dynamic attribute providers. The order is important because that is order
|
|
|
|
|
* in which they are checked when an attribute is looked up.
|
|
|
|
|
*/
|
2021-03-17 11:51:51 +01:00
|
|
|
Vector<const DynamicAttributesProvider *> dynamic_attribute_providers_;
|
2021-03-08 11:41:23 -05:00
|
|
|
/**
|
|
|
|
|
* All the domains that are supported by at least one of the providers above.
|
|
|
|
|
*/
|
2022-06-01 14:38:06 +10:00
|
|
|
VectorSet<eAttrDomain> supported_domains_;
|
2021-03-08 11:41:23 -05:00
|
|
|
|
|
|
|
|
public:
|
2021-03-17 11:51:51 +01:00
|
|
|
ComponentAttributeProviders(Span<const BuiltinAttributeProvider *> builtin_attribute_providers,
|
|
|
|
|
Span<const DynamicAttributesProvider *> dynamic_attribute_providers)
|
2021-03-08 11:41:23 -05:00
|
|
|
: dynamic_attribute_providers_(dynamic_attribute_providers)
|
|
|
|
|
{
|
|
|
|
|
for (const BuiltinAttributeProvider *provider : builtin_attribute_providers) {
|
|
|
|
|
/* Use #add_new to make sure that no two builtin attributes have the same name. */
|
|
|
|
|
builtin_attribute_providers_.add_new(provider->name(), provider);
|
2021-03-17 11:50:13 +01:00
|
|
|
supported_domains_.add(provider->domain());
|
2021-03-08 11:41:23 -05:00
|
|
|
}
|
|
|
|
|
for (const DynamicAttributesProvider *provider : dynamic_attribute_providers) {
|
2022-06-01 14:38:06 +10:00
|
|
|
provider->foreach_domain([&](eAttrDomain domain) { supported_domains_.add(domain); });
|
2021-03-08 11:41:23 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-17 11:51:51 +01:00
|
|
|
const Map<std::string, const BuiltinAttributeProvider *> &builtin_attribute_providers() const
|
2021-03-08 11:41:23 -05:00
|
|
|
{
|
|
|
|
|
return builtin_attribute_providers_;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-17 11:51:51 +01:00
|
|
|
Span<const DynamicAttributesProvider *> dynamic_attribute_providers() const
|
2021-03-08 11:41:23 -05:00
|
|
|
{
|
|
|
|
|
return dynamic_attribute_providers_;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-01 14:38:06 +10:00
|
|
|
Span<eAttrDomain> supported_domains() const
|
2021-03-08 11:41:23 -05:00
|
|
|
{
|
|
|
|
|
return supported_domains_;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
namespace attribute_accessor_functions {
|
|
|
|
|
|
|
|
|
|
template<const ComponentAttributeProviders &providers>
|
2022-10-03 17:37:25 -05:00
|
|
|
inline bool is_builtin(const void * /*owner*/, const AttributeIDRef &attribute_id)
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
{
|
2023-01-05 14:05:30 +01:00
|
|
|
if (attribute_id.is_anonymous()) {
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
const StringRef name = attribute_id.name();
|
|
|
|
|
return providers.builtin_attribute_providers().contains_as(name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<const ComponentAttributeProviders &providers>
|
|
|
|
|
inline GAttributeReader lookup(const void *owner, const AttributeIDRef &attribute_id)
|
|
|
|
|
{
|
2023-01-05 14:05:30 +01:00
|
|
|
if (!attribute_id.is_anonymous()) {
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
const StringRef name = attribute_id.name();
|
|
|
|
|
if (const BuiltinAttributeProvider *provider =
|
|
|
|
|
providers.builtin_attribute_providers().lookup_default_as(name, nullptr))
|
|
|
|
|
{
|
2023-04-19 11:21:06 +02:00
|
|
|
return provider->try_get_for_read(owner);
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) {
|
|
|
|
|
GAttributeReader attribute = provider->try_get_for_read(owner, attribute_id);
|
|
|
|
|
if (attribute) {
|
|
|
|
|
return attribute;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<const ComponentAttributeProviders &providers>
|
|
|
|
|
inline bool for_all(const void *owner,
|
|
|
|
|
FunctionRef<bool(const AttributeIDRef &, const AttributeMetaData &)> fn)
|
|
|
|
|
{
|
|
|
|
|
Set<AttributeIDRef> handled_attribute_ids;
|
|
|
|
|
for (const BuiltinAttributeProvider *provider : providers.builtin_attribute_providers().values())
|
|
|
|
|
{
|
|
|
|
|
if (provider->exists(owner)) {
|
|
|
|
|
AttributeMetaData meta_data{provider->domain(), provider->data_type()};
|
|
|
|
|
if (!fn(provider->name(), meta_data)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
handled_attribute_ids.add_new(provider->name());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) {
|
|
|
|
|
const bool continue_loop = provider->foreach_attribute(
|
|
|
|
|
owner, [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
|
|
|
|
|
if (handled_attribute_ids.add(attribute_id)) {
|
|
|
|
|
return fn(attribute_id, meta_data);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
if (!continue_loop) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-17 14:38:30 -05:00
|
|
|
template<const ComponentAttributeProviders &providers>
|
|
|
|
|
inline AttributeValidator lookup_validator(const void * /*owner*/,
|
|
|
|
|
const blender::bke::AttributeIDRef &attribute_id)
|
|
|
|
|
{
|
2023-01-05 14:05:30 +01:00
|
|
|
if (attribute_id.is_anonymous()) {
|
2022-09-17 14:38:30 -05:00
|
|
|
return {};
|
|
|
|
|
}
|
2022-09-17 20:27:36 -05:00
|
|
|
const BuiltinAttributeProvider *provider =
|
|
|
|
|
providers.builtin_attribute_providers().lookup_default_as(attribute_id.name(), nullptr);
|
2022-09-17 14:38:30 -05:00
|
|
|
if (!provider) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
return provider->validator();
|
|
|
|
|
}
|
|
|
|
|
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
template<const ComponentAttributeProviders &providers>
|
|
|
|
|
inline bool contains(const void *owner, const blender::bke::AttributeIDRef &attribute_id)
|
|
|
|
|
{
|
|
|
|
|
bool found = false;
|
|
|
|
|
for_all<providers>(
|
|
|
|
|
owner,
|
2023-09-22 12:02:32 +10:00
|
|
|
[&](const AttributeIDRef &other_attribute_id, const AttributeMetaData & /*meta_data*/) {
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
if (attribute_id == other_attribute_id) {
|
|
|
|
|
found = true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
return found;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<const ComponentAttributeProviders &providers>
|
|
|
|
|
inline std::optional<AttributeMetaData> lookup_meta_data(const void *owner,
|
|
|
|
|
const AttributeIDRef &attribute_id)
|
|
|
|
|
{
|
|
|
|
|
std::optional<AttributeMetaData> meta_data;
|
|
|
|
|
for_all<providers>(
|
|
|
|
|
owner,
|
|
|
|
|
[&](const AttributeIDRef &other_attribute_id, const AttributeMetaData &other_meta_data) {
|
|
|
|
|
if (attribute_id == other_attribute_id) {
|
|
|
|
|
meta_data = other_meta_data;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
return meta_data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<const ComponentAttributeProviders &providers>
|
|
|
|
|
inline GAttributeWriter lookup_for_write(void *owner, const AttributeIDRef &attribute_id)
|
|
|
|
|
{
|
2023-01-05 14:05:30 +01:00
|
|
|
if (!attribute_id.is_anonymous()) {
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
const StringRef name = attribute_id.name();
|
|
|
|
|
if (const BuiltinAttributeProvider *provider =
|
|
|
|
|
providers.builtin_attribute_providers().lookup_default_as(name, nullptr))
|
|
|
|
|
{
|
|
|
|
|
return provider->try_get_for_write(owner);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) {
|
|
|
|
|
GAttributeWriter attribute = provider->try_get_for_write(owner, attribute_id);
|
|
|
|
|
if (attribute) {
|
|
|
|
|
return attribute;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<const ComponentAttributeProviders &providers>
|
|
|
|
|
inline bool remove(void *owner, const AttributeIDRef &attribute_id)
|
|
|
|
|
{
|
2023-01-05 14:05:30 +01:00
|
|
|
if (!attribute_id.is_anonymous()) {
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
const StringRef name = attribute_id.name();
|
|
|
|
|
if (const BuiltinAttributeProvider *provider =
|
|
|
|
|
providers.builtin_attribute_providers().lookup_default_as(name, nullptr))
|
|
|
|
|
{
|
|
|
|
|
return provider->try_delete(owner);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) {
|
2022-11-22 13:46:50 -06:00
|
|
|
if (provider->try_delete(owner, attribute_id)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
}
|
2022-11-22 13:46:50 -06:00
|
|
|
return false;
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<const ComponentAttributeProviders &providers>
|
|
|
|
|
inline bool add(void *owner,
|
|
|
|
|
const AttributeIDRef &attribute_id,
|
|
|
|
|
eAttrDomain domain,
|
|
|
|
|
eCustomDataType data_type,
|
|
|
|
|
const AttributeInit &initializer)
|
|
|
|
|
{
|
|
|
|
|
if (contains<providers>(owner, attribute_id)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-01-05 14:05:30 +01:00
|
|
|
if (!attribute_id.is_anonymous()) {
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
const StringRef name = attribute_id.name();
|
|
|
|
|
if (const BuiltinAttributeProvider *provider =
|
|
|
|
|
providers.builtin_attribute_providers().lookup_default_as(name, nullptr))
|
|
|
|
|
{
|
|
|
|
|
if (provider->domain() != domain) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (provider->data_type() != data_type) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return provider->try_create(owner, initializer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) {
|
|
|
|
|
if (provider->try_create(owner, attribute_id, domain, data_type, initializer)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<const ComponentAttributeProviders &providers>
|
|
|
|
|
inline AttributeAccessorFunctions accessor_functions_for_providers()
|
|
|
|
|
{
|
|
|
|
|
return AttributeAccessorFunctions{contains<providers>,
|
|
|
|
|
lookup_meta_data<providers>,
|
|
|
|
|
nullptr,
|
|
|
|
|
nullptr,
|
|
|
|
|
is_builtin<providers>,
|
|
|
|
|
lookup<providers>,
|
|
|
|
|
nullptr,
|
|
|
|
|
for_all<providers>,
|
2022-09-17 14:38:30 -05:00
|
|
|
lookup_validator<providers>,
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
lookup_for_write<providers>,
|
|
|
|
|
remove<providers>,
|
|
|
|
|
add<providers>};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace attribute_accessor_functions
|
|
|
|
|
|
2021-03-17 11:50:13 +01:00
|
|
|
} // namespace blender::bke
|