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 */
|
2020-12-02 13:25:25 +01:00
|
|
|
|
|
|
|
|
#include <utility>
|
|
|
|
|
|
2021-02-09 11:44:58 +01:00
|
|
|
#include "BKE_attribute_math.hh"
|
2020-12-02 13:25:25 +01:00
|
|
|
#include "BKE_customdata.h"
|
|
|
|
|
#include "BKE_deform.h"
|
|
|
|
|
#include "BKE_geometry_set.hh"
|
2023-03-12 22:29:15 +01:00
|
|
|
#include "BKE_mesh.hh"
|
2020-12-02 13:25:25 +01:00
|
|
|
#include "BKE_pointcloud.h"
|
2021-12-07 15:21:59 +01:00
|
|
|
#include "BKE_type_conversions.hh"
|
2020-12-02 13:25:25 +01:00
|
|
|
|
|
|
|
|
#include "DNA_mesh_types.h"
|
|
|
|
|
#include "DNA_meshdata_types.h"
|
|
|
|
|
#include "DNA_pointcloud_types.h"
|
|
|
|
|
|
2022-09-13 11:36:14 -05:00
|
|
|
#include "BLI_array_utils.hh"
|
2020-12-02 13:25:25 +01:00
|
|
|
#include "BLI_color.hh"
|
2023-01-04 00:14:55 +01:00
|
|
|
#include "BLI_math_vector_types.hh"
|
2020-12-02 13:25:25 +01:00
|
|
|
#include "BLI_span.hh"
|
|
|
|
|
|
2022-09-17 01:50:55 +02:00
|
|
|
#include "BLT_translation.h"
|
|
|
|
|
|
2022-09-17 14:38:30 -05:00
|
|
|
#include "FN_field.hh"
|
|
|
|
|
|
2021-09-11 13:05:20 +02:00
|
|
|
#include "BLT_translation.h"
|
|
|
|
|
|
2020-12-02 13:25:25 +01:00
|
|
|
#include "CLG_log.h"
|
|
|
|
|
|
2021-03-08 16:31:51 -05:00
|
|
|
#include "attribute_access_intern.hh"
|
|
|
|
|
|
2020-12-02 13:25:25 +01:00
|
|
|
using blender::float3;
|
2022-03-19 08:26:29 +01:00
|
|
|
using blender::GMutableSpan;
|
|
|
|
|
using blender::GSpan;
|
|
|
|
|
using blender::GVArrayImpl_For_GSpan;
|
2020-12-02 13:25:25 +01:00
|
|
|
using blender::Set;
|
|
|
|
|
using blender::StringRef;
|
2021-01-14 15:52:08 +01:00
|
|
|
using blender::StringRefNull;
|
2021-09-09 12:54:20 +02:00
|
|
|
using blender::bke::AttributeIDRef;
|
2020-12-02 13:25:25 +01:00
|
|
|
|
|
|
|
|
namespace blender::bke {
|
|
|
|
|
|
2021-09-23 13:46:13 +02:00
|
|
|
std::ostream &operator<<(std::ostream &stream, const AttributeIDRef &attribute_id)
|
|
|
|
|
{
|
2023-01-05 14:05:30 +01:00
|
|
|
if (attribute_id) {
|
2021-09-23 13:46:13 +02:00
|
|
|
stream << attribute_id.name();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
stream << "<none>";
|
|
|
|
|
}
|
|
|
|
|
return stream;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-17 01:50:55 +02:00
|
|
|
const char *no_procedural_access_message = N_(
|
|
|
|
|
"This attribute can not be accessed in a procedural context");
|
2022-05-31 13:20:16 +02:00
|
|
|
|
|
|
|
|
bool allow_procedural_attribute_access(StringRef attribute_name)
|
|
|
|
|
{
|
2023-03-21 18:28:05 -04:00
|
|
|
if (attribute_name.startswith(".corner")) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
Mesh: Move edges to a generic attribute
Implements #95966, as the final step of #95965.
This commit changes the storage of mesh edge vertex indices from the
`MEdge` type to the generic `int2` attribute type. This follows the
general design for geometry and the attribute system, where the data
storage type and the usage semantics are separated.
The main benefit of the change is reduced memory usage-- the
requirements of storing mesh edges is reduced by 1/3. For example,
this saves 8MB on a 1 million vertex grid. This also gives performance
benefits to any memory-bound mesh processing algorithm that uses edges.
Another benefit is that all of the edge's vertex indices are
contiguous. In a few cases, it's helpful to process all of them as
`Span<int>` rather than `Span<int2>`. Similarly, the type is more
likely to match a generic format used by a library, or code that
shouldn't know about specific Blender `Mesh` types.
Various Notes:
- The `.edge_verts` name is used to reflect a mapping between domains,
similar to `.corner_verts`, etc. The period means that it the data
shouldn't change arbitrarily by the user or procedural operations.
- `edge[0]` is now used instead of `edge.v1`
- Signed integers are used instead of unsigned to reduce the mixing
of signed-ness, which can be error prone.
- All of the previously used core mesh data types (`MVert`, `MEdge`,
`MLoop`, `MPoly` are now deprecated. Only generic types are used).
- The `vec2i` DNA type is used in the few C files where necessary.
Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
|
|
|
if (attribute_name.startswith(".edge")) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
if (attribute_name.startswith(".select")) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (attribute_name.startswith(".sculpt")) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (attribute_name.startswith(".hide")) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-03-08 11:41:18 -05:00
|
|
|
if (attribute_name.startswith(".uv")) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
if (attribute_name.startswith("." UV_VERTSEL_NAME ".")) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (attribute_name.startswith("." UV_EDGESEL_NAME ".")) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (attribute_name.startswith("." UV_PINNED_NAME ".")) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2022-05-31 13:20:16 +02:00
|
|
|
}
|
|
|
|
|
|
2022-06-01 14:38:06 +10:00
|
|
|
static int attribute_data_type_complexity(const eCustomDataType data_type)
|
2021-02-09 11:24:28 +01:00
|
|
|
{
|
2021-03-08 16:31:51 -05:00
|
|
|
switch (data_type) {
|
|
|
|
|
case CD_PROP_BOOL:
|
|
|
|
|
return 0;
|
2022-02-04 10:29:11 -06:00
|
|
|
case CD_PROP_INT8:
|
2021-03-08 16:31:51 -05:00
|
|
|
return 1;
|
2022-02-04 10:29:11 -06:00
|
|
|
case CD_PROP_INT32:
|
2021-03-08 16:31:51 -05:00
|
|
|
return 2;
|
2022-02-04 10:29:11 -06:00
|
|
|
case CD_PROP_FLOAT:
|
2021-03-08 16:31:51 -05:00
|
|
|
return 3;
|
2023-04-14 16:08:05 +02:00
|
|
|
case CD_PROP_INT32_2D:
|
2021-03-08 16:31:51 -05:00
|
|
|
return 4;
|
2023-04-14 16:08:05 +02:00
|
|
|
case CD_PROP_FLOAT2:
|
2021-03-08 16:31:51 -05:00
|
|
|
return 5;
|
2023-04-14 16:08:05 +02:00
|
|
|
case CD_PROP_FLOAT3:
|
2022-02-04 10:29:11 -06:00
|
|
|
return 6;
|
2023-04-14 16:08:05 +02:00
|
|
|
case CD_PROP_BYTE_COLOR:
|
2022-04-21 16:11:26 +02:00
|
|
|
return 7;
|
2023-06-12 15:49:50 +02:00
|
|
|
case CD_PROP_QUATERNION:
|
2023-04-14 16:08:05 +02:00
|
|
|
return 8;
|
2023-06-12 15:49:50 +02:00
|
|
|
case CD_PROP_COLOR:
|
|
|
|
|
return 9;
|
2021-03-08 16:31:51 -05:00
|
|
|
#if 0 /* These attribute types are not supported yet. */
|
|
|
|
|
case CD_PROP_STRING:
|
2023-06-12 15:49:50 +02:00
|
|
|
return 10;
|
2021-03-08 16:31:51 -05:00
|
|
|
#endif
|
|
|
|
|
default:
|
|
|
|
|
/* Only accept "generic" custom data types used by the attribute system. */
|
2021-03-23 16:49:47 +01:00
|
|
|
BLI_assert_unreachable();
|
2021-03-08 16:31:51 -05:00
|
|
|
return 0;
|
|
|
|
|
}
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
|
2022-06-01 14:38:06 +10:00
|
|
|
eCustomDataType attribute_data_type_highest_complexity(Span<eCustomDataType> data_types)
|
2020-12-02 13:25:25 +01:00
|
|
|
{
|
2021-03-08 16:31:51 -05:00
|
|
|
int highest_complexity = INT_MIN;
|
2022-06-01 14:38:06 +10:00
|
|
|
eCustomDataType most_complex_type = CD_PROP_COLOR;
|
2020-12-02 13:25:25 +01:00
|
|
|
|
2022-06-01 14:38:06 +10:00
|
|
|
for (const eCustomDataType data_type : data_types) {
|
2021-03-08 16:31:51 -05:00
|
|
|
const int complexity = attribute_data_type_complexity(data_type);
|
|
|
|
|
if (complexity > highest_complexity) {
|
|
|
|
|
highest_complexity = complexity;
|
|
|
|
|
most_complex_type = data_type;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return most_complex_type;
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
|
2021-03-08 16:31:51 -05:00
|
|
|
/**
|
|
|
|
|
* \note Generally the order should mirror the order of the domains
|
|
|
|
|
* established in each component's ComponentAttributeProviders.
|
|
|
|
|
*/
|
2022-06-01 14:38:06 +10:00
|
|
|
static int attribute_domain_priority(const eAttrDomain domain)
|
2021-02-12 11:31:15 +01:00
|
|
|
{
|
2021-03-08 16:31:51 -05:00
|
|
|
switch (domain) {
|
2021-11-19 17:53:48 +01:00
|
|
|
case ATTR_DOMAIN_INSTANCE:
|
2021-03-08 16:31:51 -05:00
|
|
|
return 0;
|
2023-10-12 13:54:32 +02:00
|
|
|
case ATTR_DOMAIN_LAYER:
|
2021-03-08 16:31:51 -05:00
|
|
|
return 1;
|
2023-10-10 16:49:30 +02:00
|
|
|
case ATTR_DOMAIN_CURVE:
|
2021-03-08 16:31:51 -05:00
|
|
|
return 2;
|
2023-10-10 16:49:30 +02:00
|
|
|
case ATTR_DOMAIN_FACE:
|
2021-03-08 16:31:51 -05:00
|
|
|
return 3;
|
2023-10-10 16:49:30 +02:00
|
|
|
case ATTR_DOMAIN_EDGE:
|
2021-03-08 16:31:51 -05:00
|
|
|
return 4;
|
2023-10-10 16:49:30 +02:00
|
|
|
case ATTR_DOMAIN_POINT:
|
2021-11-19 17:53:48 +01:00
|
|
|
return 5;
|
2023-10-10 16:49:30 +02:00
|
|
|
case ATTR_DOMAIN_CORNER:
|
|
|
|
|
return 6;
|
2021-03-08 16:31:51 -05:00
|
|
|
default:
|
|
|
|
|
/* Domain not supported in nodes yet. */
|
2021-03-23 16:49:47 +01:00
|
|
|
BLI_assert_unreachable();
|
2021-03-08 16:31:51 -05:00
|
|
|
return 0;
|
2021-02-12 11:31:15 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-01 14:38:06 +10:00
|
|
|
eAttrDomain attribute_domain_highest_priority(Span<eAttrDomain> domains)
|
2021-02-17 08:30:15 -06:00
|
|
|
{
|
2021-03-08 16:31:51 -05:00
|
|
|
int highest_priority = INT_MIN;
|
2022-06-01 14:38:06 +10:00
|
|
|
eAttrDomain highest_priority_domain = ATTR_DOMAIN_CORNER;
|
2021-02-17 08:30:15 -06:00
|
|
|
|
2022-06-01 14:38:06 +10:00
|
|
|
for (const eAttrDomain domain : domains) {
|
2021-03-08 16:31:51 -05:00
|
|
|
const int priority = attribute_domain_priority(domain);
|
|
|
|
|
if (priority > highest_priority) {
|
|
|
|
|
highest_priority = priority;
|
|
|
|
|
highest_priority_domain = domain;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-02-17 08:30:15 -06:00
|
|
|
|
2021-03-08 16:31:51 -05:00
|
|
|
return highest_priority_domain;
|
2021-02-17 08:30:15 -06:00
|
|
|
}
|
|
|
|
|
|
2021-11-02 13:43:54 -05:00
|
|
|
static AttributeIDRef attribute_id_from_custom_data_layer(const CustomDataLayer &layer)
|
|
|
|
|
{
|
|
|
|
|
if (layer.anonymous_id != nullptr) {
|
2023-01-05 14:05:30 +01:00
|
|
|
return *layer.anonymous_id;
|
2021-11-02 13:43:54 -05:00
|
|
|
}
|
|
|
|
|
return layer.name;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-18 12:22:44 -05:00
|
|
|
static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data,
|
2022-06-01 14:38:06 +10:00
|
|
|
const eCustomDataType data_type,
|
2022-05-11 12:59:58 +10:00
|
|
|
const int domain_num,
|
2021-10-18 12:22:44 -05:00
|
|
|
const AttributeInit &initializer)
|
|
|
|
|
{
|
|
|
|
|
switch (initializer.type) {
|
Attributes: Improve custom data initialization options
When allocating new `CustomData` layers, often we do redundant
initialization of arrays. For example, it's common that values are
allocated, set to their default value, and then set to some other
value. This is wasteful, and it negates the benefits of optimizations
to the allocator like D15082. There are two reasons for this. The
first is array-of-structs storage that makes it annoying to initialize
values manually, and the second is confusing options in the Custom Data
API. This patch addresses the latter.
The `CustomData` "alloc type" options are rearranged. Now, besides
the options that use existing layers, there are two remaining:
* `CD_SET_DEFAULT` sets the default value.
* Usually zeroes, but for colors this is white (how it was before).
* Should be used when you add the layer but don't set all values.
* `CD_CONSTRUCT` refers to the "default construct" C++ term.
* Only necessary or defined for non-trivial types like vertex groups.
* Doesn't do anything for trivial types like `int` or `float3`.
* Should be used every other time, when all values will be set.
The attribute API's `AttributeInit` types are updated as well.
To update code, replace `CD_CALLOC` with `CD_SET_DEFAULT` and
`CD_DEFAULT` with `CD_CONSTRUCT`. This doesn't cause any functional
changes yet. Follow-up commits will change to avoid initializing
new layers where the correctness is clear.
Differential Revision: https://developer.blender.org/D15617
2022-08-30 14:54:53 -05:00
|
|
|
case AttributeInit::Type::Construct: {
|
2023-03-14 15:30:26 +01:00
|
|
|
void *data = CustomData_add_layer(&custom_data, data_type, CD_CONSTRUCT, domain_num);
|
Attributes: Improve custom data initialization options
When allocating new `CustomData` layers, often we do redundant
initialization of arrays. For example, it's common that values are
allocated, set to their default value, and then set to some other
value. This is wasteful, and it negates the benefits of optimizations
to the allocator like D15082. There are two reasons for this. The
first is array-of-structs storage that makes it annoying to initialize
values manually, and the second is confusing options in the Custom Data
API. This patch addresses the latter.
The `CustomData` "alloc type" options are rearranged. Now, besides
the options that use existing layers, there are two remaining:
* `CD_SET_DEFAULT` sets the default value.
* Usually zeroes, but for colors this is white (how it was before).
* Should be used when you add the layer but don't set all values.
* `CD_CONSTRUCT` refers to the "default construct" C++ term.
* Only necessary or defined for non-trivial types like vertex groups.
* Doesn't do anything for trivial types like `int` or `float3`.
* Should be used every other time, when all values will be set.
The attribute API's `AttributeInit` types are updated as well.
To update code, replace `CD_CALLOC` with `CD_SET_DEFAULT` and
`CD_DEFAULT` with `CD_CONSTRUCT`. This doesn't cause any functional
changes yet. Follow-up commits will change to avoid initializing
new layers where the correctness is clear.
Differential Revision: https://developer.blender.org/D15617
2022-08-30 14:54:53 -05:00
|
|
|
return data != nullptr;
|
|
|
|
|
}
|
|
|
|
|
case AttributeInit::Type::DefaultValue: {
|
2023-03-14 15:30:26 +01:00
|
|
|
void *data = CustomData_add_layer(&custom_data, data_type, CD_SET_DEFAULT, domain_num);
|
2021-10-18 12:22:44 -05:00
|
|
|
return data != nullptr;
|
|
|
|
|
}
|
|
|
|
|
case AttributeInit::Type::VArray: {
|
2023-03-14 15:30:26 +01:00
|
|
|
void *data = CustomData_add_layer(&custom_data, data_type, CD_CONSTRUCT, domain_num);
|
2021-10-18 12:22:44 -05:00
|
|
|
if (data == nullptr) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
Geometry Nodes: refactor virtual array system
Goals of this refactor:
* Simplify creating virtual arrays.
* Simplify passing virtual arrays around.
* Simplify converting between typed and generic virtual arrays.
* Reduce memory allocations.
As a quick reminder, a virtual arrays is a data structure that behaves like an
array (i.e. it can be accessed using an index). However, it may not actually
be stored as array internally. The two most important implementations
of virtual arrays are those that correspond to an actual plain array and those
that have the same value for every index. However, many more
implementations exist for various reasons (interfacing with legacy attributes,
unified iterator over all points in multiple splines, ...).
With this refactor the core types (`VArray`, `GVArray`, `VMutableArray` and
`GVMutableArray`) can be used like "normal values". They typically live
on the stack. Before, they were usually inside a `std::unique_ptr`. This makes
passing them around much easier. Creation of new virtual arrays is also
much simpler now due to some constructors. Memory allocations are
reduced by making use of small object optimization inside the core types.
Previously, `VArray` was a class with virtual methods that had to be overridden
to change the behavior of a the virtual array. Now,`VArray` has a fixed size
and has no virtual methods. Instead it contains a `VArrayImpl` that is
similar to the old `VArray`. `VArrayImpl` should rarely ever be used directly,
unless a new virtual array implementation is added.
To support the small object optimization for many `VArrayImpl` classes,
a new `blender::Any` type is added. It is similar to `std::any` with two
additional features. It has an adjustable inline buffer size and alignment.
The inline buffer size of `std::any` can't be relied on and is usually too
small for our use case here. Furthermore, `blender::Any` can store
additional user-defined type information without increasing the
stack size.
Differential Revision: https://developer.blender.org/D12986
2021-11-16 10:15:51 +01:00
|
|
|
const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray;
|
|
|
|
|
varray.materialize_to_uninitialized(varray.index_range(), data);
|
2021-10-18 12:22:44 -05:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case AttributeInit::Type::MoveArray: {
|
2023-04-13 14:57:57 +02:00
|
|
|
void *src_data = static_cast<const AttributeInitMoveArray &>(initializer).data;
|
|
|
|
|
const void *stored_data = CustomData_add_layer_with_data(
|
|
|
|
|
&custom_data, data_type, src_data, domain_num, nullptr);
|
|
|
|
|
if (stored_data == nullptr) {
|
2021-10-18 12:22:44 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
2023-04-13 14:57:57 +02:00
|
|
|
if (stored_data != src_data) {
|
|
|
|
|
MEM_freeN(src_data);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2021-10-18 12:22:44 -05:00
|
|
|
return true;
|
|
|
|
|
}
|
2023-04-19 11:21:06 +02:00
|
|
|
case AttributeInit::Type::Shared: {
|
|
|
|
|
const AttributeInitShared &init = static_cast<const AttributeInitShared &>(initializer);
|
|
|
|
|
const void *stored_data = CustomData_add_layer_with_data(
|
|
|
|
|
&custom_data, data_type, const_cast<void *>(init.data), domain_num, init.sharing_info);
|
|
|
|
|
return stored_data != nullptr;
|
|
|
|
|
}
|
2021-10-18 12:22:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BLI_assert_unreachable();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void *add_generic_custom_data_layer(CustomData &custom_data,
|
2022-06-01 14:38:06 +10:00
|
|
|
const eCustomDataType data_type,
|
2021-10-18 12:22:44 -05:00
|
|
|
const eCDAllocType alloctype,
|
2023-03-14 15:30:26 +01:00
|
|
|
const int domain_size,
|
2021-10-18 12:22:44 -05:00
|
|
|
const AttributeIDRef &attribute_id)
|
|
|
|
|
{
|
2023-01-05 14:05:30 +01:00
|
|
|
if (!attribute_id.is_anonymous()) {
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
char attribute_name_c[MAX_CUSTOMDATA_LAYER_NAME];
|
2021-10-18 12:22:44 -05:00
|
|
|
attribute_id.name().copy(attribute_name_c);
|
|
|
|
|
return CustomData_add_layer_named(
|
2023-03-14 15:30:26 +01:00
|
|
|
&custom_data, data_type, alloctype, domain_size, attribute_name_c);
|
2021-10-18 12:22:44 -05:00
|
|
|
}
|
|
|
|
|
const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id();
|
|
|
|
|
return CustomData_add_layer_anonymous(
|
2023-04-13 14:57:57 +02:00
|
|
|
&custom_data, data_type, alloctype, domain_size, &anonymous_id);
|
2023-03-14 15:30:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const void *add_generic_custom_data_layer_with_existing_data(
|
|
|
|
|
CustomData &custom_data,
|
|
|
|
|
const eCustomDataType data_type,
|
2023-04-13 14:57:57 +02:00
|
|
|
const AttributeIDRef &attribute_id,
|
2023-03-14 15:30:26 +01:00
|
|
|
const int domain_size,
|
2023-04-13 14:57:57 +02:00
|
|
|
void *layer_data,
|
|
|
|
|
const ImplicitSharingInfo *sharing_info)
|
2023-03-14 15:30:26 +01:00
|
|
|
{
|
2023-04-13 14:57:57 +02:00
|
|
|
if (attribute_id.is_anonymous()) {
|
|
|
|
|
const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id();
|
|
|
|
|
return CustomData_add_layer_anonymous_with_data(
|
|
|
|
|
&custom_data, data_type, &anonymous_id, domain_size, layer_data, sharing_info);
|
2023-03-14 15:30:26 +01:00
|
|
|
}
|
2023-04-13 14:57:57 +02:00
|
|
|
char attribute_name_c[MAX_CUSTOMDATA_LAYER_NAME];
|
|
|
|
|
attribute_id.name().copy(attribute_name_c);
|
|
|
|
|
return CustomData_add_layer_named_with_data(
|
|
|
|
|
&custom_data, data_type, layer_data, domain_size, attribute_name_c, sharing_info);
|
2021-10-18 12:22:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attribute_id,
|
|
|
|
|
CustomData &custom_data,
|
2022-06-01 14:38:06 +10:00
|
|
|
const eCustomDataType data_type,
|
2022-05-11 12:59:58 +10:00
|
|
|
const int domain_num,
|
2021-10-18 12:22:44 -05:00
|
|
|
const AttributeInit &initializer)
|
|
|
|
|
{
|
2022-07-27 18:20:22 +02:00
|
|
|
const int old_layer_num = custom_data.totlayer;
|
2021-10-18 12:22:44 -05:00
|
|
|
switch (initializer.type) {
|
Attributes: Improve custom data initialization options
When allocating new `CustomData` layers, often we do redundant
initialization of arrays. For example, it's common that values are
allocated, set to their default value, and then set to some other
value. This is wasteful, and it negates the benefits of optimizations
to the allocator like D15082. There are two reasons for this. The
first is array-of-structs storage that makes it annoying to initialize
values manually, and the second is confusing options in the Custom Data
API. This patch addresses the latter.
The `CustomData` "alloc type" options are rearranged. Now, besides
the options that use existing layers, there are two remaining:
* `CD_SET_DEFAULT` sets the default value.
* Usually zeroes, but for colors this is white (how it was before).
* Should be used when you add the layer but don't set all values.
* `CD_CONSTRUCT` refers to the "default construct" C++ term.
* Only necessary or defined for non-trivial types like vertex groups.
* Doesn't do anything for trivial types like `int` or `float3`.
* Should be used every other time, when all values will be set.
The attribute API's `AttributeInit` types are updated as well.
To update code, replace `CD_CALLOC` with `CD_SET_DEFAULT` and
`CD_DEFAULT` with `CD_CONSTRUCT`. This doesn't cause any functional
changes yet. Follow-up commits will change to avoid initializing
new layers where the correctness is clear.
Differential Revision: https://developer.blender.org/D15617
2022-08-30 14:54:53 -05:00
|
|
|
case AttributeInit::Type::Construct: {
|
|
|
|
|
add_generic_custom_data_layer(
|
2023-03-14 15:30:26 +01:00
|
|
|
custom_data, data_type, CD_CONSTRUCT, domain_num, attribute_id);
|
Attributes: Improve custom data initialization options
When allocating new `CustomData` layers, often we do redundant
initialization of arrays. For example, it's common that values are
allocated, set to their default value, and then set to some other
value. This is wasteful, and it negates the benefits of optimizations
to the allocator like D15082. There are two reasons for this. The
first is array-of-structs storage that makes it annoying to initialize
values manually, and the second is confusing options in the Custom Data
API. This patch addresses the latter.
The `CustomData` "alloc type" options are rearranged. Now, besides
the options that use existing layers, there are two remaining:
* `CD_SET_DEFAULT` sets the default value.
* Usually zeroes, but for colors this is white (how it was before).
* Should be used when you add the layer but don't set all values.
* `CD_CONSTRUCT` refers to the "default construct" C++ term.
* Only necessary or defined for non-trivial types like vertex groups.
* Doesn't do anything for trivial types like `int` or `float3`.
* Should be used every other time, when all values will be set.
The attribute API's `AttributeInit` types are updated as well.
To update code, replace `CD_CALLOC` with `CD_SET_DEFAULT` and
`CD_DEFAULT` with `CD_CONSTRUCT`. This doesn't cause any functional
changes yet. Follow-up commits will change to avoid initializing
new layers where the correctness is clear.
Differential Revision: https://developer.blender.org/D15617
2022-08-30 14:54:53 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case AttributeInit::Type::DefaultValue: {
|
2022-07-27 18:20:22 +02:00
|
|
|
add_generic_custom_data_layer(
|
2023-03-14 15:30:26 +01:00
|
|
|
custom_data, data_type, CD_SET_DEFAULT, domain_num, attribute_id);
|
2022-07-27 18:20:22 +02:00
|
|
|
break;
|
2021-10-18 12:22:44 -05:00
|
|
|
}
|
|
|
|
|
case AttributeInit::Type::VArray: {
|
|
|
|
|
void *data = add_generic_custom_data_layer(
|
2023-03-14 15:30:26 +01:00
|
|
|
custom_data, data_type, CD_CONSTRUCT, domain_num, attribute_id);
|
2022-07-27 18:20:22 +02:00
|
|
|
if (data != nullptr) {
|
|
|
|
|
const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray;
|
|
|
|
|
varray.materialize_to_uninitialized(varray.index_range(), data);
|
2021-10-18 12:22:44 -05:00
|
|
|
}
|
2022-07-27 18:20:22 +02:00
|
|
|
break;
|
2021-10-18 12:22:44 -05:00
|
|
|
}
|
|
|
|
|
case AttributeInit::Type::MoveArray: {
|
2023-04-13 14:57:57 +02:00
|
|
|
void *data = static_cast<const AttributeInitMoveArray &>(initializer).data;
|
2023-03-14 15:30:26 +01:00
|
|
|
add_generic_custom_data_layer_with_existing_data(
|
2023-04-13 14:57:57 +02:00
|
|
|
custom_data, data_type, attribute_id, domain_num, data, nullptr);
|
2022-07-27 18:20:22 +02:00
|
|
|
break;
|
2021-10-18 12:22:44 -05:00
|
|
|
}
|
2023-04-19 11:21:06 +02:00
|
|
|
case AttributeInit::Type::Shared: {
|
|
|
|
|
const AttributeInitShared &init = static_cast<const AttributeInitShared &>(initializer);
|
|
|
|
|
add_generic_custom_data_layer_with_existing_data(custom_data,
|
|
|
|
|
data_type,
|
|
|
|
|
attribute_id,
|
|
|
|
|
domain_num,
|
|
|
|
|
const_cast<void *>(init.data),
|
|
|
|
|
init.sharing_info);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-10-18 12:22:44 -05:00
|
|
|
}
|
2022-07-27 18:20:22 +02:00
|
|
|
return old_layer_num < custom_data.totlayer;
|
2021-10-18 12:22:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool custom_data_layer_matches_attribute_id(const CustomDataLayer &layer,
|
|
|
|
|
const AttributeIDRef &attribute_id)
|
|
|
|
|
{
|
|
|
|
|
if (!attribute_id) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return layer.name == attribute_id.name();
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-06 13:20:03 -05:00
|
|
|
bool BuiltinCustomDataLayerProvider::layer_exists(const CustomData &custom_data) const
|
|
|
|
|
{
|
|
|
|
|
if (stored_as_named_attribute_) {
|
|
|
|
|
return CustomData_get_named_layer_index(&custom_data, stored_type_, name_.c_str()) != -1;
|
|
|
|
|
}
|
|
|
|
|
return CustomData_has_layer(&custom_data, stored_type_);
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-19 11:21:06 +02:00
|
|
|
GAttributeReader BuiltinCustomDataLayerProvider::try_get_for_read(const void *owner) const
|
2021-02-17 08:30:15 -06: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
|
|
|
const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
|
2021-03-08 16:31:51 -05:00
|
|
|
if (custom_data == nullptr) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
2021-02-17 08:30:15 -06:00
|
|
|
|
2022-09-06 13:20:03 -05:00
|
|
|
/* When the number of elements is zero, layers might have null data but still exist. */
|
2023-04-18 17:13:38 +02:00
|
|
|
const CPPType &type = *custom_data_type_to_cpp_type(data_type_);
|
2022-09-06 13:20:03 -05:00
|
|
|
const int element_num = custom_data_access_.get_element_num(owner);
|
|
|
|
|
if (element_num == 0) {
|
|
|
|
|
if (this->layer_exists(*custom_data)) {
|
2023-04-19 11:21:06 +02:00
|
|
|
return {GVArray::ForSpan({type, nullptr, 0}), domain_, nullptr};
|
2022-07-27 18:20:22 +02:00
|
|
|
}
|
2022-09-06 13:20:03 -05:00
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-19 11:21:06 +02:00
|
|
|
int index;
|
2022-09-06 13:20:03 -05:00
|
|
|
if (stored_as_named_attribute_) {
|
2023-04-19 11:21:06 +02:00
|
|
|
index = CustomData_get_named_layer_index(custom_data, stored_type_, name_.c_str());
|
2022-09-06 13:20:03 -05:00
|
|
|
}
|
|
|
|
|
else {
|
2023-04-19 11:21:06 +02:00
|
|
|
index = CustomData_get_layer_index(custom_data, stored_type_);
|
2021-10-20 10:54:54 -05:00
|
|
|
}
|
2023-04-19 11:21:06 +02:00
|
|
|
if (index == -1) {
|
2021-03-08 16:31:51 -05:00
|
|
|
return {};
|
|
|
|
|
}
|
2023-04-19 11:21:06 +02:00
|
|
|
const CustomDataLayer &layer = custom_data->layers[index];
|
|
|
|
|
return {GVArray::ForSpan({type, layer.data, element_num}), domain_, layer.sharing_info};
|
2021-03-05 15:16:25 -06: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 BuiltinCustomDataLayerProvider::try_get_for_write(void *owner) const
|
2021-03-05 15:16:25 -06: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
|
|
|
CustomData *custom_data = custom_data_access_.get_custom_data(owner);
|
2021-03-08 16:31:51 -05:00
|
|
|
if (custom_data == nullptr) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
2022-09-06 13:20:03 -05:00
|
|
|
|
|
|
|
|
std::function<void()> tag_modified_fn;
|
|
|
|
|
if (update_on_change_ != nullptr) {
|
|
|
|
|
tag_modified_fn = [owner, update = update_on_change_]() { update(owner); };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* When the number of elements is zero, layers might have null data but still exist. */
|
2023-04-18 17:13:38 +02:00
|
|
|
const CPPType &type = *custom_data_type_to_cpp_type(data_type_);
|
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 int element_num = custom_data_access_.get_element_num(owner);
|
2022-09-06 13:20:03 -05:00
|
|
|
if (element_num == 0) {
|
|
|
|
|
if (this->layer_exists(*custom_data)) {
|
2023-04-18 17:13:38 +02:00
|
|
|
return {GVMutableArray::ForSpan({type, nullptr, 0}), domain_, std::move(tag_modified_fn)};
|
2022-09-06 13:20:03 -05:00
|
|
|
}
|
|
|
|
|
return {};
|
|
|
|
|
}
|
2021-10-20 13:15:37 -05:00
|
|
|
|
2022-07-27 18:20:22 +02:00
|
|
|
void *data = nullptr;
|
2022-09-06 09:43:32 -05:00
|
|
|
if (stored_as_named_attribute_) {
|
2023-01-13 17:21:20 -06:00
|
|
|
data = CustomData_get_layer_named_for_write(
|
2022-09-06 09:43:32 -05:00
|
|
|
custom_data, stored_type_, name_.c_str(), element_num);
|
2021-10-20 13:15:37 -05:00
|
|
|
}
|
2022-09-06 09:43:32 -05:00
|
|
|
else {
|
2023-01-13 17:21:20 -06:00
|
|
|
data = CustomData_get_layer_for_write(custom_data, stored_type_, element_num);
|
2021-03-08 16:31:51 -05:00
|
|
|
}
|
2022-09-06 09:43:32 -05:00
|
|
|
if (data == nullptr) {
|
|
|
|
|
return {};
|
2021-03-08 16:31:51 -05:00
|
|
|
}
|
2023-04-18 17:13:38 +02:00
|
|
|
return {GVMutableArray::ForSpan({type, data, element_num}), domain_, std::move(tag_modified_fn)};
|
2021-03-05 15:16:25 -06: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 BuiltinCustomDataLayerProvider::try_delete(void *owner) const
|
2021-03-05 15:16:25 -06:00
|
|
|
{
|
2021-03-08 16:31:51 -05:00
|
|
|
if (deletable_ != Deletable) {
|
|
|
|
|
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
|
|
|
CustomData *custom_data = custom_data_access_.get_custom_data(owner);
|
2021-03-08 16:31:51 -05:00
|
|
|
if (custom_data == nullptr) {
|
|
|
|
|
return {};
|
2021-03-05 15:16:25 -06:00
|
|
|
}
|
|
|
|
|
|
2022-07-23 19:59:59 -05:00
|
|
|
auto update = [&]() {
|
|
|
|
|
if (update_on_change_ != nullptr) {
|
|
|
|
|
update_on_change_(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
|
|
|
const int element_num = custom_data_access_.get_element_num(owner);
|
2021-10-20 10:54:54 -05:00
|
|
|
if (stored_as_named_attribute_) {
|
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 (CustomData_free_layer_named(custom_data, name_.c_str(), element_num)) {
|
2022-07-23 19:59:59 -05:00
|
|
|
update();
|
2022-06-22 09:06:29 -05:00
|
|
|
return true;
|
2021-10-20 10:54:54 -05:00
|
|
|
}
|
2022-06-22 09:06:29 -05:00
|
|
|
return false;
|
2021-10-20 10:54:54 -05:00
|
|
|
}
|
|
|
|
|
|
2022-06-22 09:06:29 -05:00
|
|
|
const int layer_index = CustomData_get_layer_index(custom_data, stored_type_);
|
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 (CustomData_free_layer(custom_data, stored_type_, element_num, layer_index)) {
|
2022-07-23 19:59:59 -05:00
|
|
|
update();
|
2022-06-22 09:06:29 -05:00
|
|
|
return true;
|
2021-03-05 15:16:25 -06:00
|
|
|
}
|
2022-07-23 19:59:59 -05:00
|
|
|
|
2022-06-22 09:06:29 -05:00
|
|
|
return false;
|
2021-03-05 15:16:25 -06: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 BuiltinCustomDataLayerProvider::try_create(void *owner,
|
2021-04-22 09:20:03 -05:00
|
|
|
const AttributeInit &initializer) const
|
2021-02-18 10:24:02 +01:00
|
|
|
{
|
2021-03-08 16:31:51 -05:00
|
|
|
if (createable_ != Creatable) {
|
|
|
|
|
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
|
|
|
CustomData *custom_data = custom_data_access_.get_custom_data(owner);
|
2021-03-08 16:31:51 -05:00
|
|
|
if (custom_data == nullptr) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2021-04-22 09:20:03 -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
|
|
|
const int element_num = custom_data_access_.get_element_num(owner);
|
2021-10-20 10:54:54 -05:00
|
|
|
if (stored_as_named_attribute_) {
|
2023-05-17 16:16:54 -04:00
|
|
|
if (CustomData_has_layer_named(custom_data, data_type_, name_.c_str())) {
|
2021-10-20 10:54:54 -05:00
|
|
|
/* Exists already. */
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-09-06 09:43:32 -05:00
|
|
|
return add_custom_data_layer_from_attribute_init(
|
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
|
|
|
name_, *custom_data, stored_type_, element_num, initializer);
|
2021-10-20 10:54:54 -05:00
|
|
|
}
|
2022-09-06 09:43:32 -05:00
|
|
|
|
|
|
|
|
if (CustomData_get_layer(custom_data, stored_type_) != nullptr) {
|
|
|
|
|
/* Exists already. */
|
|
|
|
|
return false;
|
2021-03-08 16:31:51 -05:00
|
|
|
}
|
2022-09-06 09:43:32 -05:00
|
|
|
return add_builtin_type_custom_data_layer_from_init(
|
|
|
|
|
*custom_data, stored_type_, element_num, initializer);
|
2021-02-18 10:24:02 +01: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 BuiltinCustomDataLayerProvider::exists(const void *owner) const
|
2021-02-18 10:24:02 +01: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
|
|
|
const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
|
2021-03-08 16:31:51 -05:00
|
|
|
if (custom_data == nullptr) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2021-10-20 10:54:54 -05:00
|
|
|
if (stored_as_named_attribute_) {
|
2023-05-17 16:16:54 -04:00
|
|
|
return CustomData_has_layer_named(custom_data, stored_type_, name_.c_str());
|
2021-10-20 10:54:54 -05:00
|
|
|
}
|
|
|
|
|
return CustomData_get_layer(custom_data, stored_type_) != nullptr;
|
2021-02-18 10:24:02 +01: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
|
|
|
GAttributeReader CustomDataAttributeProvider::try_get_for_read(
|
|
|
|
|
const void *owner, const AttributeIDRef &attribute_id) const
|
2021-02-18 10:24:02 +01: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
|
|
|
const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
|
2021-03-08 16:31:51 -05:00
|
|
|
if (custom_data == nullptr) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
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 int element_num = custom_data_access_.get_element_num(owner);
|
2021-03-08 16:31:51 -05:00
|
|
|
for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
|
2021-09-09 12:54:20 +02:00
|
|
|
if (!custom_data_layer_matches_attribute_id(layer, attribute_id)) {
|
2021-03-08 16:31:51 -05:00
|
|
|
continue;
|
|
|
|
|
}
|
2022-06-01 14:38:06 +10:00
|
|
|
const CPPType *type = custom_data_type_to_cpp_type((eCustomDataType)layer.type);
|
2021-10-18 10:08:57 -05:00
|
|
|
if (type == nullptr) {
|
|
|
|
|
continue;
|
2021-03-08 16:31:51 -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
|
|
|
GSpan data{*type, layer.data, element_num};
|
2023-04-19 11:21:06 +02:00
|
|
|
return {GVArray::ForSpan(data), domain_, layer.sharing_info};
|
2021-03-08 16:31:51 -05:00
|
|
|
}
|
|
|
|
|
return {};
|
2021-02-18 10:24:02 +01: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 CustomDataAttributeProvider::try_get_for_write(
|
|
|
|
|
void *owner, const AttributeIDRef &attribute_id) const
|
2021-02-18 10:24:02 +01: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
|
|
|
CustomData *custom_data = custom_data_access_.get_custom_data(owner);
|
2021-03-08 16:31:51 -05:00
|
|
|
if (custom_data == nullptr) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
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 int element_num = custom_data_access_.get_element_num(owner);
|
2021-03-08 16:31:51 -05:00
|
|
|
for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
|
2021-09-09 12:54:20 +02:00
|
|
|
if (!custom_data_layer_matches_attribute_id(layer, attribute_id)) {
|
2021-03-08 16:31:51 -05:00
|
|
|
continue;
|
|
|
|
|
}
|
2023-03-29 17:10:49 +02:00
|
|
|
CustomData_get_layer_named_for_write(
|
|
|
|
|
custom_data, eCustomDataType(layer.type), layer.name, element_num);
|
2023-01-05 14:05:30 +01:00
|
|
|
|
2023-03-29 17:10:49 +02:00
|
|
|
const CPPType *type = custom_data_type_to_cpp_type(eCustomDataType(layer.type));
|
2021-10-18 10:08:57 -05:00
|
|
|
if (type == nullptr) {
|
|
|
|
|
continue;
|
2021-03-08 16:31:51 -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
|
|
|
GMutableSpan data{*type, layer.data, element_num};
|
Geometry Nodes: refactor virtual array system
Goals of this refactor:
* Simplify creating virtual arrays.
* Simplify passing virtual arrays around.
* Simplify converting between typed and generic virtual arrays.
* Reduce memory allocations.
As a quick reminder, a virtual arrays is a data structure that behaves like an
array (i.e. it can be accessed using an index). However, it may not actually
be stored as array internally. The two most important implementations
of virtual arrays are those that correspond to an actual plain array and those
that have the same value for every index. However, many more
implementations exist for various reasons (interfacing with legacy attributes,
unified iterator over all points in multiple splines, ...).
With this refactor the core types (`VArray`, `GVArray`, `VMutableArray` and
`GVMutableArray`) can be used like "normal values". They typically live
on the stack. Before, they were usually inside a `std::unique_ptr`. This makes
passing them around much easier. Creation of new virtual arrays is also
much simpler now due to some constructors. Memory allocations are
reduced by making use of small object optimization inside the core types.
Previously, `VArray` was a class with virtual methods that had to be overridden
to change the behavior of a the virtual array. Now,`VArray` has a fixed size
and has no virtual methods. Instead it contains a `VArrayImpl` that is
similar to the old `VArray`. `VArrayImpl` should rarely ever be used directly,
unless a new virtual array implementation is added.
To support the small object optimization for many `VArrayImpl` classes,
a new `blender::Any` type is added. It is similar to `std::any` with two
additional features. It has an adjustable inline buffer size and alignment.
The inline buffer size of `std::any` can't be relied on and is usually too
small for our use case here. Furthermore, `blender::Any` can store
additional user-defined type information without increasing the
stack size.
Differential Revision: https://developer.blender.org/D12986
2021-11-16 10:15:51 +01:00
|
|
|
return {GVMutableArray::ForSpan(data), domain_};
|
2021-03-08 16:31:51 -05:00
|
|
|
}
|
|
|
|
|
return {};
|
2021-02-18 10:24:02 +01: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 CustomDataAttributeProvider::try_delete(void *owner, const AttributeIDRef &attribute_id) const
|
2021-02-18 10:24:02 +01: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
|
|
|
CustomData *custom_data = custom_data_access_.get_custom_data(owner);
|
2021-03-08 16:31:51 -05:00
|
|
|
if (custom_data == nullptr) {
|
|
|
|
|
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
|
|
|
const int element_num = custom_data_access_.get_element_num(owner);
|
|
|
|
|
;
|
2021-03-08 16:31:51 -05:00
|
|
|
for (const int i : IndexRange(custom_data->totlayer)) {
|
|
|
|
|
const CustomDataLayer &layer = custom_data->layers[i];
|
2022-06-01 14:38:06 +10:00
|
|
|
if (this->type_is_supported((eCustomDataType)layer.type) &&
|
2021-09-09 12:54:20 +02:00
|
|
|
custom_data_layer_matches_attribute_id(layer, attribute_id))
|
|
|
|
|
{
|
2023-03-29 17:10:49 +02:00
|
|
|
CustomData_free_layer(custom_data, eCustomDataType(layer.type), element_num, i);
|
2021-03-08 16:31:51 -05:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2021-02-18 10:24:02 +01: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 CustomDataAttributeProvider::try_create(void *owner,
|
2021-09-09 12:54:20 +02:00
|
|
|
const AttributeIDRef &attribute_id,
|
2022-06-01 14:38:06 +10:00
|
|
|
const eAttrDomain domain,
|
|
|
|
|
const eCustomDataType data_type,
|
2021-04-22 09:20:03 -05:00
|
|
|
const AttributeInit &initializer) const
|
2021-02-18 10:24:02 +01:00
|
|
|
{
|
2021-03-08 16:31:51 -05:00
|
|
|
if (domain_ != domain) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!this->type_is_supported(data_type)) {
|
|
|
|
|
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
|
|
|
CustomData *custom_data = custom_data_access_.get_custom_data(owner);
|
2021-03-08 16:31:51 -05:00
|
|
|
if (custom_data == nullptr) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
|
2021-09-09 12:54:20 +02:00
|
|
|
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
|
2021-03-08 16:31:51 -05: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
|
|
|
const int element_num = custom_data_access_.get_element_num(owner);
|
2021-09-09 12:54:20 +02:00
|
|
|
add_custom_data_layer_from_attribute_init(
|
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
|
|
|
attribute_id, *custom_data, data_type, element_num, initializer);
|
2021-03-08 16:31:51 -05:00
|
|
|
return true;
|
2021-02-18 10:24:02 +01: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 CustomDataAttributeProvider::foreach_attribute(const void *owner,
|
2021-03-08 16:31:51 -05:00
|
|
|
const AttributeForeachCallback callback) const
|
2021-02-18 10:24:02 +01: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
|
|
|
const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
|
2021-03-08 16:31:51 -05:00
|
|
|
if (custom_data == nullptr) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
|
2022-06-01 14:38:06 +10:00
|
|
|
const eCustomDataType data_type = (eCustomDataType)layer.type;
|
2021-03-08 16:31:51 -05:00
|
|
|
if (this->type_is_supported(data_type)) {
|
|
|
|
|
AttributeMetaData meta_data{domain_, data_type};
|
2021-11-02 13:43:54 -05:00
|
|
|
const AttributeIDRef attribute_id = attribute_id_from_custom_data_layer(layer);
|
2021-09-09 12:54:20 +02:00
|
|
|
if (!callback(attribute_id, meta_data)) {
|
2021-03-08 16:31:51 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2021-02-18 10:24:02 +01:00
|
|
|
}
|
|
|
|
|
|
2020-12-02 13:25:25 +01:00
|
|
|
/* -------------------------------------------------------------------- */
|
Geometry Nodes: Use separate field context for each geometry type
Using the same `GeometryComponentFieldContext` for all situations,
even when only one geometry type is supported is misleading, and mixes
too many different abstraction levels into code that could be simpler.
With the attribute API moved out of geometry components recently,
the "component" system is just getting in the way here.
This commit adds specific field contexts for geometry types: meshes,
curves, point clouds, and instances. There are also separate field input
helper classes, to help reduce boilerplate for fields that only support
specific geometry types.
Another benefit of this change is that it separates geometry components
from fields, which makes it easier to see the purpose of the two concepts,
and how they relate.
Because we want to be able to evaluate a field on just `CurvesGeometry`
rather than the full `Curves` data-block, the generic "geometry context"
had to be changed to avoid using `GeometryComponent`, since there is
no corresponding geometry component type. The resulting void pointer
is ugly, but only turns up in three places in practice. When Apple clang
supports `std::variant`, that could be used instead.
Differential Revision: https://developer.blender.org/D15519
2022-08-30 11:08:27 -05:00
|
|
|
/** \name Attribute API
|
2020-12-02 13:25:25 +01:00
|
|
|
* \{ */
|
|
|
|
|
|
2022-03-19 08:26:29 +01:00
|
|
|
static blender::GVArray try_adapt_data_type(blender::GVArray varray,
|
|
|
|
|
const blender::CPPType &to_type)
|
2020-12-02 13:25:25 +01:00
|
|
|
{
|
2021-12-07 15:21:59 +01:00
|
|
|
const blender::bke::DataTypeConversions &conversions =
|
|
|
|
|
blender::bke::get_implicit_type_conversions();
|
Geometry Nodes: use virtual arrays in internal attribute api
A virtual array is a data structure that is similar to a normal array
in that its elements can be accessed by an index. However, a virtual
array does not have to be a contiguous array internally. Instead, its
elements can be layed out arbitrarily while element access happens
through a virtual function call. However, the virtual array data
structures are designed so that the virtual function call can be avoided
in cases where it could become a bottleneck.
Most commonly, a virtual array is backed by an actual array/span or
is a single value internally, that is the same for every index.
Besides those, there are many more specialized virtual arrays like the
ones that provides vertex positions based on the `MVert` struct or
vertex group weights.
Not all attributes used by geometry nodes are stored in simple contiguous
arrays. To provide uniform access to all kinds of attributes, the attribute
API has to provide virtual array functionality that hides the implementation
details of attributes.
Before this refactor, the attribute API provided its own virtual array
implementation as part of the `ReadAttribute` and `WriteAttribute` types.
That resulted in unnecessary code duplication with the virtual array system.
Even worse, it bound many algorithms used by geometry nodes to the specifics
of the attribute API, even though they could also use different data sources
(such as data from sockets, default values, later results of expressions, ...).
This refactor removes the `ReadAttribute` and `WriteAttribute` types and
replaces them with `GVArray` and `GVMutableArray` respectively. The `GV`
stands for "generic virtual". The "generic" means that the data type contained
in those virtual arrays is only known at run-time. There are the corresponding
statically typed types `VArray<T>` and `VMutableArray<T>` as well.
No regressions are expected from this refactor. It does come with one
improvement for users. The attribute API can convert the data type
on write now. This is especially useful when writing to builtin attributes
like `material_index` with e.g. the Attribute Math node (which usually
just writes to float attributes, while `material_index` is an integer attribute).
Differential Revision: https://developer.blender.org/D10994
2021-04-17 16:41:03 +02:00
|
|
|
return conversions.try_convert(std::move(varray), to_type);
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
|
2023-04-19 11:21:06 +02:00
|
|
|
GAttributeReader AttributeAccessor::lookup(const AttributeIDRef &attribute_id,
|
|
|
|
|
const std::optional<eAttrDomain> domain,
|
|
|
|
|
const std::optional<eCustomDataType> data_type) const
|
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 attribute = this->lookup(attribute_id);
|
|
|
|
|
if (!attribute) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
if (domain.has_value()) {
|
|
|
|
|
if (attribute.domain != domain) {
|
2023-04-19 11:21:06 +02:00
|
|
|
attribute.varray = this->adapt_domain(attribute.varray, attribute.domain, *domain);
|
|
|
|
|
attribute.domain = *domain;
|
|
|
|
|
attribute.sharing_info = nullptr;
|
|
|
|
|
if (!attribute.varray) {
|
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 {};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (data_type.has_value()) {
|
|
|
|
|
const CPPType &type = *custom_data_type_to_cpp_type(*data_type);
|
2023-04-19 11:21:06 +02:00
|
|
|
if (attribute.varray.type() != type) {
|
|
|
|
|
attribute.varray = try_adapt_data_type(std::move(attribute.varray), type);
|
|
|
|
|
attribute.sharing_info = nullptr;
|
|
|
|
|
if (!attribute.varray) {
|
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 {};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-04-19 11:21:06 +02:00
|
|
|
return attribute;
|
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-04-19 11:21:06 +02:00
|
|
|
GAttributeReader AttributeAccessor::lookup_or_default(const AttributeIDRef &attribute_id,
|
|
|
|
|
const eAttrDomain domain,
|
|
|
|
|
const eCustomDataType data_type,
|
|
|
|
|
const void *default_value) const
|
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-04-19 11:21:06 +02:00
|
|
|
GAttributeReader attribute = this->lookup(attribute_id, domain, data_type);
|
|
|
|
|
if (attribute) {
|
|
|
|
|
return attribute;
|
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 CPPType &type = *custom_data_type_to_cpp_type(data_type);
|
|
|
|
|
const int64_t domain_size = this->domain_size(domain);
|
|
|
|
|
if (default_value == nullptr) {
|
2023-04-19 11:21:06 +02:00
|
|
|
return {GVArray::ForSingleRef(type, domain_size, type.default_value()), domain, nullptr};
|
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-04-19 11:21:06 +02:00
|
|
|
return {GVArray::ForSingle(type, domain_size, default_value), domain, nullptr};
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Set<AttributeIDRef> AttributeAccessor::all_ids() const
|
|
|
|
|
{
|
|
|
|
|
Set<AttributeIDRef> ids;
|
2023-09-22 12:02:32 +10:00
|
|
|
this->for_all([&](const AttributeIDRef &attribute_id, const AttributeMetaData & /*meta_data*/) {
|
|
|
|
|
ids.add(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
|
|
|
return ids;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MutableAttributeAccessor::remove_anonymous()
|
|
|
|
|
{
|
|
|
|
|
Vector<const AnonymousAttributeID *> anonymous_ids;
|
|
|
|
|
for (const AttributeIDRef &id : this->all_ids()) {
|
|
|
|
|
if (id.is_anonymous()) {
|
|
|
|
|
anonymous_ids.append(&id.anonymous_id());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (!anonymous_ids.is_empty()) {
|
2023-01-05 14:05:30 +01:00
|
|
|
this->remove(*anonymous_ids.pop_last());
|
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-07-21 12:47:44 +02:00
|
|
|
/**
|
|
|
|
|
* Debug utility that checks whether the #finish function of an #AttributeWriter has been called.
|
|
|
|
|
*/
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
struct FinishCallChecker {
|
|
|
|
|
std::string name;
|
|
|
|
|
bool finish_called = false;
|
|
|
|
|
std::function<void()> real_finish_fn;
|
|
|
|
|
|
|
|
|
|
~FinishCallChecker()
|
|
|
|
|
{
|
|
|
|
|
if (!this->finish_called) {
|
|
|
|
|
std::cerr << "Forgot to call `finish()` for '" << this->name << "'.\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
GAttributeWriter MutableAttributeAccessor::lookup_for_write(const AttributeIDRef &attribute_id)
|
|
|
|
|
{
|
|
|
|
|
GAttributeWriter attribute = fn_->lookup_for_write(owner_, attribute_id);
|
|
|
|
|
/* Check that the #finish method is called in debug builds. */
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
if (attribute) {
|
|
|
|
|
auto checker = std::make_shared<FinishCallChecker>();
|
2023-01-05 14:05:30 +01:00
|
|
|
checker->name = attribute_id.name();
|
2022-07-21 12:47:44 +02:00
|
|
|
checker->real_finish_fn = attribute.tag_modified_fn;
|
|
|
|
|
attribute.tag_modified_fn = [checker]() {
|
|
|
|
|
if (checker->real_finish_fn) {
|
|
|
|
|
checker->real_finish_fn();
|
|
|
|
|
}
|
|
|
|
|
checker->finish_called = true;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
return attribute;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-12 10:36:56 -05:00
|
|
|
GSpanAttributeWriter MutableAttributeAccessor::lookup_for_write_span(
|
|
|
|
|
const AttributeIDRef &attribute_id)
|
|
|
|
|
{
|
|
|
|
|
GAttributeWriter attribute = this->lookup_for_write(attribute_id);
|
|
|
|
|
if (attribute) {
|
|
|
|
|
return GSpanAttributeWriter{std::move(attribute), true};
|
|
|
|
|
}
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
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 MutableAttributeAccessor::lookup_or_add_for_write(
|
|
|
|
|
const AttributeIDRef &attribute_id,
|
|
|
|
|
const eAttrDomain domain,
|
|
|
|
|
const eCustomDataType data_type,
|
|
|
|
|
const AttributeInit &initializer)
|
|
|
|
|
{
|
|
|
|
|
std::optional<AttributeMetaData> meta_data = this->lookup_meta_data(attribute_id);
|
|
|
|
|
if (meta_data.has_value()) {
|
|
|
|
|
if (meta_data->domain == domain && meta_data->data_type == data_type) {
|
|
|
|
|
return this->lookup_for_write(attribute_id);
|
|
|
|
|
}
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
if (this->add(attribute_id, domain, data_type, initializer)) {
|
|
|
|
|
return this->lookup_for_write(attribute_id);
|
|
|
|
|
}
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GSpanAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write_span(
|
|
|
|
|
const AttributeIDRef &attribute_id,
|
|
|
|
|
const eAttrDomain domain,
|
|
|
|
|
const eCustomDataType data_type,
|
|
|
|
|
const AttributeInit &initializer)
|
|
|
|
|
{
|
|
|
|
|
GAttributeWriter attribute = this->lookup_or_add_for_write(
|
|
|
|
|
attribute_id, domain, data_type, initializer);
|
|
|
|
|
if (attribute) {
|
|
|
|
|
return GSpanAttributeWriter{std::move(attribute), true};
|
|
|
|
|
}
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GSpanAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write_only_span(
|
|
|
|
|
const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type)
|
|
|
|
|
{
|
2022-08-30 16:44:47 -05:00
|
|
|
GAttributeWriter attribute = this->lookup_or_add_for_write(
|
|
|
|
|
attribute_id, domain, data_type, AttributeInitConstruct());
|
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) {
|
|
|
|
|
return GSpanAttributeWriter{std::move(attribute), false};
|
|
|
|
|
}
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-27 09:54:40 -04:00
|
|
|
bool MutableAttributeAccessor::rename(const AttributeIDRef &old_attribute_id,
|
|
|
|
|
const AttributeIDRef &new_attribute_id)
|
|
|
|
|
{
|
|
|
|
|
if (old_attribute_id == new_attribute_id) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (this->contains(new_attribute_id)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
const GAttributeReader old_attribute = this->lookup(old_attribute_id);
|
|
|
|
|
if (!old_attribute) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
const eCustomDataType type = cpp_type_to_custom_data_type(old_attribute.varray.type());
|
|
|
|
|
if (old_attribute.sharing_info != nullptr && old_attribute.varray.is_span()) {
|
|
|
|
|
if (!this->add(new_attribute_id,
|
|
|
|
|
old_attribute.domain,
|
|
|
|
|
type,
|
|
|
|
|
AttributeInitShared{old_attribute.varray.get_internal_span().data(),
|
|
|
|
|
*old_attribute.sharing_info}))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (!this->add(new_attribute_id,
|
|
|
|
|
old_attribute.domain,
|
|
|
|
|
type,
|
|
|
|
|
AttributeInitVArray{old_attribute.varray}))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
this->remove(old_attribute_id);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-17 14:38:30 -05:00
|
|
|
fn::GField AttributeValidator::validate_field_if_necessary(const fn::GField &field) const
|
|
|
|
|
{
|
|
|
|
|
if (function) {
|
|
|
|
|
auto validate_op = fn::FieldOperation::Create(*function, {field});
|
|
|
|
|
return fn::GField(validate_op);
|
|
|
|
|
}
|
|
|
|
|
return field;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-19 18:50:27 -05:00
|
|
|
Vector<AttributeTransferData> retrieve_attributes_for_transfer(
|
2022-07-20 16:40:05 -05:00
|
|
|
const bke::AttributeAccessor src_attributes,
|
|
|
|
|
bke::MutableAttributeAccessor dst_attributes,
|
2022-07-19 18:50:27 -05:00
|
|
|
const eAttrDomainMask domain_mask,
|
2023-01-05 14:05:30 +01:00
|
|
|
const AnonymousAttributePropagationInfo &propagation_info,
|
2022-07-19 18:50:27 -05:00
|
|
|
const Set<std::string> &skip)
|
|
|
|
|
{
|
|
|
|
|
Vector<AttributeTransferData> attributes;
|
|
|
|
|
src_attributes.for_all(
|
|
|
|
|
[&](const bke::AttributeIDRef &id, const bke::AttributeMetaData meta_data) {
|
|
|
|
|
if (!(ATTR_DOMAIN_AS_MASK(meta_data.domain) & domain_mask)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2023-01-05 14:05:30 +01:00
|
|
|
if (id.is_anonymous() && !propagation_info.propagate(id.anonymous_id())) {
|
2022-07-19 18:50:27 -05:00
|
|
|
return true;
|
|
|
|
|
}
|
2023-01-05 14:05:30 +01:00
|
|
|
if (skip.contains(id.name())) {
|
2022-07-19 18:50:27 -05:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-26 15:04:07 -04:00
|
|
|
const GVArray src = *src_attributes.lookup(id, meta_data.domain);
|
2022-07-19 18:50:27 -05:00
|
|
|
bke::GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
|
|
|
|
|
id, meta_data.domain, meta_data.data_type);
|
|
|
|
|
attributes.append({std::move(src), meta_data, std::move(dst)});
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
return attributes;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-14 15:49:31 +11:00
|
|
|
/** \} */
|
2023-04-19 08:40:23 +10:00
|
|
|
|
2023-05-26 13:15:31 -04:00
|
|
|
void gather_attributes(const AttributeAccessor src_attributes,
|
|
|
|
|
const eAttrDomain domain,
|
|
|
|
|
const AnonymousAttributePropagationInfo &propagation_info,
|
2023-05-26 15:04:07 -04:00
|
|
|
const Set<std::string> &skip,
|
2023-05-26 13:15:31 -04:00
|
|
|
const IndexMask &selection,
|
|
|
|
|
MutableAttributeAccessor dst_attributes)
|
|
|
|
|
{
|
|
|
|
|
const int src_size = src_attributes.domain_size(domain);
|
|
|
|
|
src_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
|
|
|
|
|
if (meta_data.domain != domain) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (id.is_anonymous() && !propagation_info.propagate(id.anonymous_id())) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2023-05-26 15:04:07 -04:00
|
|
|
if (skip.contains(id.name())) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2023-05-26 13:15:31 -04:00
|
|
|
const bke::GAttributeReader src = src_attributes.lookup(id, domain);
|
|
|
|
|
if (selection.size() == src_size && src.sharing_info && src.varray.is_span()) {
|
|
|
|
|
const bke::AttributeInitShared init(src.varray.get_internal_span().data(),
|
|
|
|
|
*src.sharing_info);
|
2023-05-26 15:04:07 -04:00
|
|
|
if (dst_attributes.add(id, domain, meta_data.data_type, init)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2023-05-26 13:15:31 -04:00
|
|
|
}
|
2023-05-26 15:04:07 -04:00
|
|
|
bke::GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
|
|
|
|
|
id, domain, meta_data.data_type);
|
2023-06-14 13:59:38 +02:00
|
|
|
if (!dst) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2023-05-26 15:04:07 -04:00
|
|
|
array_utils::gather(src.varray, selection, dst.span);
|
|
|
|
|
dst.finish();
|
2023-05-26 13:15:31 -04:00
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-29 20:12:47 +02:00
|
|
|
static bool indices_are_range(const Span<int> indices, const IndexRange range)
|
|
|
|
|
{
|
|
|
|
|
if (indices.size() != range.size()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return threading::parallel_reduce(
|
|
|
|
|
range,
|
|
|
|
|
4096,
|
|
|
|
|
true,
|
|
|
|
|
[&](const IndexRange range, const bool init) {
|
|
|
|
|
if (!init) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
for (const int i : range) {
|
|
|
|
|
if (indices[i] != i) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
},
|
|
|
|
|
[](const bool a, const bool b) { return a && b; });
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-29 16:52:20 +02:00
|
|
|
void gather_attributes(const AttributeAccessor src_attributes,
|
|
|
|
|
const eAttrDomain domain,
|
|
|
|
|
const AnonymousAttributePropagationInfo &propagation_info,
|
|
|
|
|
const Set<std::string> &skip,
|
|
|
|
|
const Span<int> indices,
|
|
|
|
|
MutableAttributeAccessor dst_attributes)
|
|
|
|
|
{
|
2023-08-29 20:12:47 +02:00
|
|
|
if (indices_are_range(indices, IndexRange(src_attributes.domain_size(domain)))) {
|
|
|
|
|
copy_attributes(src_attributes, domain, propagation_info, skip, dst_attributes);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
src_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
|
|
|
|
|
if (meta_data.domain != domain) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (id.is_anonymous() && !propagation_info.propagate(id.anonymous_id())) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (skip.contains(id.name())) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
const bke::GAttributeReader src = src_attributes.lookup(id, domain);
|
|
|
|
|
bke::GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
|
|
|
|
|
id, domain, meta_data.data_type);
|
|
|
|
|
if (!dst) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
attribute_math::gather(src.varray, indices, dst.span);
|
|
|
|
|
dst.finish();
|
2023-08-29 16:52:20 +02:00
|
|
|
return true;
|
2023-08-29 20:12:47 +02:00
|
|
|
});
|
|
|
|
|
}
|
2023-08-29 16:52:20 +02:00
|
|
|
}
|
|
|
|
|
|
2023-06-01 14:55:21 +02:00
|
|
|
template<typename T>
|
|
|
|
|
static void gather_group_to_group(const OffsetIndices<int> src_offsets,
|
|
|
|
|
const OffsetIndices<int> dst_offsets,
|
|
|
|
|
const IndexMask &selection,
|
|
|
|
|
const Span<T> src,
|
|
|
|
|
MutableSpan<T> dst)
|
|
|
|
|
{
|
|
|
|
|
selection.foreach_index(GrainSize(512), [&](const int64_t src_i, const int64_t dst_i) {
|
|
|
|
|
dst.slice(dst_offsets[dst_i]).copy_from(src.slice(src_offsets[src_i]));
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void gather_group_to_group(const OffsetIndices<int> src_offsets,
|
|
|
|
|
const OffsetIndices<int> dst_offsets,
|
|
|
|
|
const IndexMask &selection,
|
|
|
|
|
const GSpan src,
|
|
|
|
|
GMutableSpan dst)
|
|
|
|
|
{
|
|
|
|
|
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
|
|
|
|
|
using T = decltype(dummy);
|
|
|
|
|
gather_group_to_group(src_offsets, dst_offsets, selection, src.typed<T>(), dst.typed<T>());
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void gather_attributes_group_to_group(const AttributeAccessor src_attributes,
|
|
|
|
|
const eAttrDomain domain,
|
|
|
|
|
const AnonymousAttributePropagationInfo &propagation_info,
|
|
|
|
|
const Set<std::string> &skip,
|
|
|
|
|
const OffsetIndices<int> src_offsets,
|
|
|
|
|
const OffsetIndices<int> dst_offsets,
|
|
|
|
|
const IndexMask &selection,
|
|
|
|
|
MutableAttributeAccessor dst_attributes)
|
|
|
|
|
{
|
|
|
|
|
src_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
|
|
|
|
|
if (meta_data.domain != domain) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (id.is_anonymous() && !propagation_info.propagate(id.anonymous_id())) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (skip.contains(id.name())) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
const GVArraySpan src = *src_attributes.lookup(id, domain);
|
|
|
|
|
bke::GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
|
|
|
|
|
id, domain, meta_data.data_type);
|
2023-06-14 13:59:38 +02:00
|
|
|
if (!dst) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2023-06-01 14:55:21 +02:00
|
|
|
gather_group_to_group(src_offsets, dst_offsets, selection, src, dst.span);
|
|
|
|
|
dst.finish();
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-26 15:04:07 -04:00
|
|
|
void copy_attributes(const AttributeAccessor src_attributes,
|
|
|
|
|
const eAttrDomain domain,
|
|
|
|
|
const AnonymousAttributePropagationInfo &propagation_info,
|
|
|
|
|
const Set<std::string> &skip,
|
|
|
|
|
MutableAttributeAccessor dst_attributes)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(src_attributes.domain_size(domain) == dst_attributes.domain_size(domain));
|
|
|
|
|
return gather_attributes(src_attributes,
|
|
|
|
|
domain,
|
|
|
|
|
propagation_info,
|
|
|
|
|
skip,
|
|
|
|
|
IndexMask(src_attributes.domain_size(domain)),
|
|
|
|
|
dst_attributes);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 15:23:35 +02:00
|
|
|
void copy_attributes_group_to_group(const AttributeAccessor src_attributes,
|
|
|
|
|
const eAttrDomain domain,
|
|
|
|
|
const AnonymousAttributePropagationInfo &propagation_info,
|
|
|
|
|
const Set<std::string> &skip,
|
|
|
|
|
const OffsetIndices<int> src_offsets,
|
|
|
|
|
const OffsetIndices<int> dst_offsets,
|
|
|
|
|
const IndexMask &selection,
|
|
|
|
|
MutableAttributeAccessor dst_attributes)
|
|
|
|
|
{
|
|
|
|
|
if (selection.is_empty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
src_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
|
|
|
|
|
if (meta_data.domain != domain) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (id.is_anonymous() && !propagation_info.propagate(id.anonymous_id())) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (skip.contains(id.name())) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
const GVArraySpan src = *src_attributes.lookup(id, domain);
|
|
|
|
|
bke::GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
|
|
|
|
|
id, domain, meta_data.data_type);
|
|
|
|
|
if (!dst) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
array_utils::copy_group_to_group(src_offsets, dst_offsets, selection, src, dst.span);
|
|
|
|
|
dst.finish();
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-19 08:40:23 +10:00
|
|
|
} // namespace blender::bke
|