2022-02-11 09:07:11 +11: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"
|
|
|
|
|
#include "BKE_mesh.h"
|
|
|
|
|
#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"
|
BLI: Refactor vector types & functions to use templates
This patch implements the vector types (i.e:`float2`) by making heavy
usage of templating. All vector functions are now outside of the vector
classes (inside the `blender::math` namespace) and are not vector size
dependent for the most part.
In the ongoing effort to make shaders less GL centric, we are aiming
to share more code between GLSL and C++ to avoid code duplication.
####Motivations:
- We are aiming to share UBO and SSBO structures between GLSL and C++.
This means we will use many of the existing vector types and others
we currently don't have (uintX, intX). All these variations were
asking for many more code duplication.
- Deduplicate existing code which is duplicated for each vector size.
- We also want to share small functions. Which means that vector
functions should be static and not in the class namespace.
- Reduce friction to use these types in new projects due to their
incompleteness.
- The current state of the `BLI_(float|double|mpq)(2|3|4).hh` is a
bit of a let down. Most clases are incomplete, out of sync with each
others with different codestyles, and some functions that should be
static are not (i.e: `float3::reflect()`).
####Upsides:
- Still support `.x, .y, .z, .w` for readability.
- Compact, readable and easilly extendable.
- All of the vector functions are available for all the vectors types
and can be restricted to certain types. Also template specialization
let us define exception for special class (like mpq).
- With optimization ON, the compiler unroll the loops and performance
is the same.
####Downsides:
- Might impact debugability. Though I would arge that the bugs are
rarelly caused by the vector class itself (since the operations are
quite trivial) but by the type conversions.
- Might impact compile time. I did not saw a significant impact since
the usage is not really widespread.
- Functions needs to be rewritten to support arbitrary vector length.
For instance, one can't call `len_squared_v3v3` in
`math::length_squared()` and call it a day.
- Type cast does not work with the template version of the `math::`
vector functions. Meaning you need to manually cast `float *` and
`(float *)[3]` to `float3` for the function calls.
i.e: `math::distance_squared(float3(nearest.co), positions[i]);`
- Some parts might loose in readability:
`float3::dot(v1.normalized(), v2.normalized())`
becoming
`math::dot(math::normalize(v1), math::normalize(v2))`
But I propose, when appropriate, to use
`using namespace blender::math;` on function local or file scope to
increase readability.
`dot(normalize(v1), normalize(v2))`
####Consideration:
- Include back `.length()` method. It is quite handy and is more C++
oriented.
- I considered the GLM library as a candidate for replacement. It felt
like too much for what we need and would be difficult to extend / modify
to our needs.
- I used Macros to reduce code in operators declaration and potential
copy paste bugs. This could reduce debugability and could be reverted.
- This touches `delaunay_2d.cc` and the intersection code. I would like
to know @howardt opinion on the matter.
- The `noexcept` on the copy constructor of `mpq(2|3)` is being removed.
But according to @JacquesLucke it is not a real problem for now.
I would like to give a huge thanks to @JacquesLucke who helped during this
and pushed me to reduce the duplication further.
Reviewed By: brecht, sergey, JacquesLucke
Differential Revision: https://developer.blender.org/D13791
2022-01-12 12:57:07 +01:00
|
|
|
#include "BLI_math_vec_types.hh"
|
2020-12-02 13:25:25 +01:00
|
|
|
#include "BLI_span.hh"
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
if (attribute_id.is_named()) {
|
|
|
|
|
stream << attribute_id.name();
|
|
|
|
|
}
|
|
|
|
|
else if (attribute_id.is_anonymous()) {
|
|
|
|
|
const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id();
|
|
|
|
|
stream << "<" << BKE_anonymous_attribute_id_debug_name(&anonymous_id) << ">";
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
stream << "<none>";
|
|
|
|
|
}
|
|
|
|
|
return stream;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-31 13:20:16 +02:00
|
|
|
const char *no_procedural_access_message =
|
|
|
|
|
"This attribute can not be accessed in a procedural context";
|
|
|
|
|
|
|
|
|
|
bool allow_procedural_attribute_access(StringRef attribute_name)
|
|
|
|
|
{
|
Mesh: Move selection flags to generic attributes
Using the attribute name semantics from T97452, this patch moves the
selection status of mesh elements from the `SELECT` of vertices, and
edges, and the `ME_FACE_SEL` of faces to generic boolean attribute
Storing this data as generic attributes can significantly simplify and
improve code, as described in T95965.
The attributes are called `.select_vert`, `.select_edge`, and
`.select_poly`. The `.` prefix means they are "UI attributes",so they
still contain original data edited by users, but they aren't meant to
be accessed procedurally by the user in arbitrary situations. They are
also be hidden in the spreadsheet and the attribute list.
Until 4.0, the attributes are still written to and read from the mesh
in the old way, so neither forward nor backward compatibility are
affected. This means memory requirements will be increased by one byte
per element when selection is used. When the flags are removed
completely, requirements will decrease.
Further notes:
* The `MVert` flag is empty at runtime now, so it can be ignored.
* `BMesh` is unchanged, otherwise the change would be much larger.
* Many tests have slightly different results, since the selection
attribute uses more generic propagation. Previously you couldn't
really rely on edit mode selections being propagated procedurally.
Now it mostly works as expected.
Similar to 2480b55f216c
Ref T95965
Differential Revision: https://developer.blender.org/D15795
2022-09-23 09:38:37 -05:00
|
|
|
return !attribute_name.startswith(".sculpt") && !attribute_name.startswith(".select") &&
|
2022-09-17 15:12:56 +10:00
|
|
|
!attribute_name.startswith(".hide");
|
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;
|
2022-02-04 10:29:11 -06:00
|
|
|
case CD_PROP_FLOAT2:
|
2021-03-08 16:31:51 -05:00
|
|
|
return 4;
|
2022-02-04 10:29:11 -06:00
|
|
|
case CD_PROP_FLOAT3:
|
2021-03-08 16:31:51 -05:00
|
|
|
return 5;
|
2022-04-21 16:11:26 +02:00
|
|
|
case CD_PROP_BYTE_COLOR:
|
2022-02-04 10:29:11 -06:00
|
|
|
return 6;
|
2022-04-21 16:11:26 +02:00
|
|
|
case CD_PROP_COLOR:
|
|
|
|
|
return 7;
|
2021-03-08 16:31:51 -05:00
|
|
|
#if 0 /* These attribute types are not supported yet. */
|
|
|
|
|
case CD_PROP_STRING:
|
|
|
|
|
return 6;
|
|
|
|
|
#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;
|
2021-11-19 17:53:48 +01:00
|
|
|
case ATTR_DOMAIN_CURVE:
|
2021-03-08 16:31:51 -05:00
|
|
|
return 1;
|
2021-11-19 17:53:48 +01:00
|
|
|
case ATTR_DOMAIN_FACE:
|
2021-03-08 16:31:51 -05:00
|
|
|
return 2;
|
2021-11-19 17:53:48 +01:00
|
|
|
case ATTR_DOMAIN_EDGE:
|
2021-03-08 16:31:51 -05:00
|
|
|
return 3;
|
2021-11-19 17:53:48 +01:00
|
|
|
case ATTR_DOMAIN_POINT:
|
2021-03-08 16:31:51 -05:00
|
|
|
return 4;
|
2021-11-19 17:53:48 +01:00
|
|
|
case ATTR_DOMAIN_CORNER:
|
|
|
|
|
return 5;
|
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) {
|
|
|
|
|
return layer.anonymous_id;
|
|
|
|
|
}
|
|
|
|
|
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: {
|
|
|
|
|
void *data = CustomData_add_layer(
|
|
|
|
|
&custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num);
|
|
|
|
|
return data != nullptr;
|
|
|
|
|
}
|
|
|
|
|
case AttributeInit::Type::DefaultValue: {
|
|
|
|
|
void *data = CustomData_add_layer(
|
|
|
|
|
&custom_data, data_type, CD_SET_DEFAULT, nullptr, domain_num);
|
2021-10-18 12:22:44 -05:00
|
|
|
return data != nullptr;
|
|
|
|
|
}
|
|
|
|
|
case AttributeInit::Type::VArray: {
|
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
|
|
|
void *data = CustomData_add_layer(
|
|
|
|
|
&custom_data, data_type, CD_CONSTRUCT, nullptr, 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: {
|
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
|
|
|
void *source_data = static_cast<const AttributeInitMoveArray &>(initializer).data;
|
2021-10-18 12:22:44 -05:00
|
|
|
void *data = CustomData_add_layer(
|
2022-05-11 12:59:58 +10:00
|
|
|
&custom_data, data_type, CD_ASSIGN, source_data, domain_num);
|
2021-10-18 12:22:44 -05:00
|
|
|
if (data == nullptr) {
|
|
|
|
|
MEM_freeN(source_data);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
void *layer_data,
|
2022-05-11 12:59:58 +10:00
|
|
|
const int domain_num,
|
2021-10-18 12:22:44 -05:00
|
|
|
const AttributeIDRef &attribute_id)
|
|
|
|
|
{
|
|
|
|
|
if (attribute_id.is_named()) {
|
|
|
|
|
char attribute_name_c[MAX_NAME];
|
|
|
|
|
attribute_id.name().copy(attribute_name_c);
|
|
|
|
|
return CustomData_add_layer_named(
|
2022-05-11 12:59:58 +10:00
|
|
|
&custom_data, data_type, alloctype, layer_data, domain_num, attribute_name_c);
|
2021-10-18 12:22:44 -05:00
|
|
|
}
|
|
|
|
|
const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id();
|
|
|
|
|
return CustomData_add_layer_anonymous(
|
2022-05-11 12:59:58 +10:00
|
|
|
&custom_data, data_type, alloctype, layer_data, domain_num, &anonymous_id);
|
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(
|
|
|
|
|
custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num, attribute_id);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case AttributeInit::Type::DefaultValue: {
|
2022-07-27 18:20:22 +02:00
|
|
|
add_generic_custom_data_layer(
|
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
|
|
|
custom_data, data_type, CD_SET_DEFAULT, nullptr, 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(
|
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
|
|
|
custom_data, data_type, CD_CONSTRUCT, nullptr, 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: {
|
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
|
|
|
void *source_data = static_cast<const AttributeInitMoveArray &>(initializer).data;
|
2021-10-18 12:22:44 -05:00
|
|
|
void *data = add_generic_custom_data_layer(
|
2022-05-11 12:59:58 +10:00
|
|
|
custom_data, data_type, CD_ASSIGN, source_data, domain_num, attribute_id);
|
2022-07-27 18:20:22 +02:00
|
|
|
if (source_data != nullptr && data == nullptr) {
|
2021-10-18 12:22:44 -05:00
|
|
|
MEM_freeN(source_data);
|
|
|
|
|
}
|
2022-07-27 18:20:22 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
if (attribute_id.is_anonymous()) {
|
|
|
|
|
return layer.anonymous_id == &attribute_id.anonymous_id();
|
|
|
|
|
}
|
|
|
|
|
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_);
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
GVArray 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. */
|
|
|
|
|
const int element_num = custom_data_access_.get_element_num(owner);
|
|
|
|
|
if (element_num == 0) {
|
|
|
|
|
if (this->layer_exists(*custom_data)) {
|
|
|
|
|
return as_read_attribute_(nullptr, 0);
|
2022-07-27 18:20:22 +02:00
|
|
|
}
|
2022-09-06 13:20:03 -05:00
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const void *data = nullptr;
|
|
|
|
|
if (stored_as_named_attribute_) {
|
|
|
|
|
data = CustomData_get_layer_named(custom_data, stored_type_, name_.c_str());
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
data = CustomData_get_layer(custom_data, stored_type_);
|
2021-10-20 10:54:54 -05:00
|
|
|
}
|
2022-09-06 13:20:03 -05:00
|
|
|
if (data == nullptr) {
|
2021-03-08 16:31:51 -05:00
|
|
|
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
|
|
|
return as_read_attribute_(data, element_num);
|
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
|
|
|
{
|
2021-03-08 16:31:51 -05:00
|
|
|
if (writable_ != Writable) {
|
|
|
|
|
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
|
|
|
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. */
|
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)) {
|
|
|
|
|
return {as_write_attribute_(nullptr, 0), domain_, std::move(tag_modified_fn)};
|
|
|
|
|
}
|
|
|
|
|
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_) {
|
|
|
|
|
data = CustomData_duplicate_referenced_layer_named(
|
|
|
|
|
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 {
|
|
|
|
|
data = CustomData_duplicate_referenced_layer(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
|
|
|
}
|
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 {as_write_attribute_(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_) {
|
|
|
|
|
if (CustomData_get_layer_named(custom_data, data_type_, name_.c_str())) {
|
|
|
|
|
/* 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_) {
|
|
|
|
|
return CustomData_get_layer_named(custom_data, stored_type_, name_.c_str()) != nullptr;
|
|
|
|
|
}
|
|
|
|
|
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};
|
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 {GVArray::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
|
|
|
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;
|
|
|
|
|
}
|
2021-09-09 12:54:20 +02:00
|
|
|
if (attribute_id.is_named()) {
|
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_duplicate_referenced_layer_named(
|
|
|
|
|
custom_data, layer.type, layer.name, element_num);
|
2021-09-09 12:54:20 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
CustomData_duplicate_referenced_layer_anonymous(
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
custom_data, layer.type, &attribute_id.anonymous_id(), element_num);
|
2021-09-09 12:54:20 +02:00
|
|
|
}
|
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
|
|
|
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)) {
|
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_free_layer(custom_data, 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
|
|
|
}
|
|
|
|
|
|
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 NamedLegacyCustomDataProvider::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 {};
|
|
|
|
|
}
|
|
|
|
|
for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
|
|
|
|
|
if (layer.type == stored_type_) {
|
2021-09-09 12:54:20 +02:00
|
|
|
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
const int domain_num = custom_data_access_.get_element_num(owner);
|
2022-05-11 12:59:58 +10:00
|
|
|
return {as_read_attribute_(layer.data, domain_num), 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
|
|
|
GAttributeWriter NamedLegacyCustomDataProvider::try_get_for_write(
|
|
|
|
|
void *owner, const AttributeIDRef &attribute_id) const
|
2020-12-02 13:25:25 +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 {};
|
|
|
|
|
}
|
|
|
|
|
for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
|
|
|
|
|
if (layer.type == stored_type_) {
|
2021-09-09 12:54:20 +02:00
|
|
|
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
const int element_num = custom_data_access_.get_element_num(owner);
|
2022-09-06 09:43:32 -05:00
|
|
|
void *data = CustomData_duplicate_referenced_layer_named(
|
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
|
|
|
custom_data, stored_type_, layer.name, element_num);
|
2022-09-06 09:43:32 -05:00
|
|
|
return {as_write_attribute_(data, element_num), domain_};
|
2021-03-08 16:31:51 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return {};
|
2021-02-09 11:24:28 +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 NamedLegacyCustomDataProvider::try_delete(void *owner,
|
2021-09-09 12:54:20 +02:00
|
|
|
const AttributeIDRef &attribute_id) const
|
2021-02-09 11:24:28 +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;
|
|
|
|
|
}
|
|
|
|
|
for (const int i : IndexRange(custom_data->totlayer)) {
|
|
|
|
|
const CustomDataLayer &layer = custom_data->layers[i];
|
|
|
|
|
if (layer.type == stored_type_) {
|
2021-09-09 12:54:20 +02:00
|
|
|
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
const int element_num = custom_data_access_.get_element_num(owner);
|
|
|
|
|
CustomData_free_layer(custom_data, stored_type_, element_num, i);
|
2021-03-08 16:31:51 -05:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2021-02-09 11:24:28 +01:00
|
|
|
}
|
|
|
|
|
|
2021-03-08 16:31:51 -05:00
|
|
|
bool NamedLegacyCustomDataProvider::foreach_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 void *owner, const AttributeForeachCallback callback) const
|
2021-02-09 11:24:28 +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)) {
|
|
|
|
|
if (layer.type == stored_type_) {
|
|
|
|
|
AttributeMetaData meta_data{domain_, attribute_type_};
|
|
|
|
|
if (!callback(layer.name, meta_data)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
2021-03-08 16:31:51 -05:00
|
|
|
}
|
|
|
|
|
return true;
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
|
2021-03-17 11:50:13 +01:00
|
|
|
void NamedLegacyCustomDataProvider::foreach_domain(
|
2022-06-01 14:38:06 +10:00
|
|
|
const FunctionRef<void(eAttrDomain)> callback) const
|
2020-12-02 13:25:25 +01:00
|
|
|
{
|
2021-03-17 11:50:13 +01:00
|
|
|
callback(domain_);
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
|
2021-05-19 13:22:09 -04:00
|
|
|
CustomDataAttributes::CustomDataAttributes()
|
|
|
|
|
{
|
|
|
|
|
CustomData_reset(&data);
|
|
|
|
|
size_ = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CustomDataAttributes::~CustomDataAttributes()
|
|
|
|
|
{
|
|
|
|
|
CustomData_free(&data, size_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CustomDataAttributes::CustomDataAttributes(const CustomDataAttributes &other)
|
|
|
|
|
{
|
|
|
|
|
size_ = other.size_;
|
|
|
|
|
CustomData_copy(&other.data, &data, CD_MASK_ALL, CD_DUPLICATE, size_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CustomDataAttributes::CustomDataAttributes(CustomDataAttributes &&other)
|
|
|
|
|
{
|
|
|
|
|
size_ = other.size_;
|
|
|
|
|
data = other.data;
|
|
|
|
|
CustomData_reset(&other.data);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-09 15:54:26 -05:00
|
|
|
CustomDataAttributes &CustomDataAttributes::operator=(const CustomDataAttributes &other)
|
|
|
|
|
{
|
|
|
|
|
if (this != &other) {
|
|
|
|
|
CustomData_copy(&other.data, &data, CD_MASK_ALL, CD_DUPLICATE, other.size_);
|
|
|
|
|
size_ = other.size_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-09 12:54:20 +02:00
|
|
|
std::optional<GSpan> CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id) const
|
2021-05-19 13:22:09 -04:00
|
|
|
{
|
|
|
|
|
for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
|
2021-09-09 12:54:20 +02:00
|
|
|
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
|
2022-06-01 14:38:06 +10:00
|
|
|
const CPPType *cpp_type = custom_data_type_to_cpp_type((eCustomDataType)layer.type);
|
2021-05-19 13:22:09 -04:00
|
|
|
BLI_assert(cpp_type != nullptr);
|
|
|
|
|
return GSpan(*cpp_type, layer.data, size_);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
GVArray CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id,
|
2022-06-01 14:38:06 +10:00
|
|
|
const eCustomDataType data_type,
|
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 void *default_value) const
|
2021-06-02 08:24:42 -04:00
|
|
|
{
|
|
|
|
|
const CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
|
|
|
|
|
|
2021-09-09 12:54:20 +02:00
|
|
|
std::optional<GSpan> attribute = this->get_for_read(attribute_id);
|
2021-06-02 08:24:42 -04:00
|
|
|
if (!attribute) {
|
2022-05-11 12:59:58 +10:00
|
|
|
const int domain_num = this->size_;
|
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 GVArray::ForSingle(
|
2022-05-11 12:59:58 +10:00
|
|
|
*type, domain_num, (default_value == nullptr) ? type->default_value() : default_value);
|
2021-06-02 08:24:42 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (attribute->type() == *type) {
|
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 GVArray::ForSpan(*attribute);
|
2021-06-02 08:24:42 -04:00
|
|
|
}
|
2021-12-07 15:21:59 +01:00
|
|
|
const blender::bke::DataTypeConversions &conversions =
|
|
|
|
|
blender::bke::get_implicit_type_conversions();
|
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 conversions.try_convert(GVArray::ForSpan(*attribute), *type);
|
2021-06-02 08:24:42 -04:00
|
|
|
}
|
|
|
|
|
|
2021-09-09 12:54:20 +02:00
|
|
|
std::optional<GMutableSpan> CustomDataAttributes::get_for_write(const AttributeIDRef &attribute_id)
|
2021-05-19 13:22:09 -04:00
|
|
|
{
|
|
|
|
|
for (CustomDataLayer &layer : MutableSpan(data.layers, data.totlayer)) {
|
2021-09-09 12:54:20 +02:00
|
|
|
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
|
2022-06-01 14:38:06 +10:00
|
|
|
const CPPType *cpp_type = custom_data_type_to_cpp_type((eCustomDataType)layer.type);
|
2021-05-19 13:22:09 -04:00
|
|
|
BLI_assert(cpp_type != nullptr);
|
|
|
|
|
return GMutableSpan(*cpp_type, layer.data, size_);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-09 12:54:20 +02:00
|
|
|
bool CustomDataAttributes::create(const AttributeIDRef &attribute_id,
|
2022-06-01 14:38:06 +10:00
|
|
|
const eCustomDataType data_type)
|
2021-05-19 13:22:09 -04:00
|
|
|
{
|
2021-09-09 12:54:20 +02:00
|
|
|
void *result = add_generic_custom_data_layer(
|
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
|
|
|
data, data_type, CD_SET_DEFAULT, nullptr, size_, attribute_id);
|
2021-05-19 13:22:09 -04:00
|
|
|
return result != nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-09 12:54:20 +02:00
|
|
|
bool CustomDataAttributes::create_by_move(const AttributeIDRef &attribute_id,
|
2022-06-01 14:38:06 +10:00
|
|
|
const eCustomDataType data_type,
|
2021-05-19 13:22:09 -04:00
|
|
|
void *buffer)
|
|
|
|
|
{
|
2021-09-09 12:54:20 +02:00
|
|
|
void *result = add_generic_custom_data_layer(
|
|
|
|
|
data, data_type, CD_ASSIGN, buffer, size_, attribute_id);
|
2021-05-19 13:22:09 -04:00
|
|
|
return result != nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-09 12:54:20 +02:00
|
|
|
bool CustomDataAttributes::remove(const AttributeIDRef &attribute_id)
|
2021-05-19 13:22:09 -04:00
|
|
|
{
|
|
|
|
|
for (const int i : IndexRange(data.totlayer)) {
|
|
|
|
|
const CustomDataLayer &layer = data.layers[i];
|
2021-09-09 12:54:20 +02:00
|
|
|
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
|
2021-05-19 13:22:09 -04:00
|
|
|
CustomData_free_layer(&data, layer.type, size_, i);
|
2022-04-14 13:04:16 -05:00
|
|
|
return true;
|
2021-05-19 13:22:09 -04:00
|
|
|
}
|
|
|
|
|
}
|
2022-04-14 13:04:16 -05:00
|
|
|
return false;
|
2021-05-19 13:22:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CustomDataAttributes::reallocate(const int size)
|
|
|
|
|
{
|
2022-09-12 11:35:33 -05:00
|
|
|
const int old_size = size_;
|
2021-05-19 13:22:09 -04:00
|
|
|
size_ = size;
|
2022-09-12 11:35:33 -05:00
|
|
|
CustomData_realloc(&data, old_size, size_);
|
|
|
|
|
if (size_ > old_size) {
|
|
|
|
|
/* Fill default new values. */
|
|
|
|
|
const int new_elements_num = size_ - old_size;
|
|
|
|
|
this->foreach_attribute(
|
|
|
|
|
[&](const bke::AttributeIDRef &id, const bke::AttributeMetaData /*meta_data*/) {
|
|
|
|
|
GMutableSpan new_data = this->get_for_write(id)->take_back(new_elements_num);
|
|
|
|
|
const CPPType &type = new_data.type();
|
|
|
|
|
type.fill_assign_n(type.default_value(), new_data.data(), new_data.size());
|
|
|
|
|
return true;
|
|
|
|
|
},
|
|
|
|
|
/* Dummy. */
|
|
|
|
|
ATTR_DOMAIN_POINT);
|
|
|
|
|
}
|
2021-05-19 13:22:09 -04:00
|
|
|
}
|
|
|
|
|
|
2021-11-30 10:59:11 -05:00
|
|
|
void CustomDataAttributes::clear()
|
|
|
|
|
{
|
|
|
|
|
CustomData_free(&data, size_);
|
|
|
|
|
size_ = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-19 13:22:09 -04:00
|
|
|
bool CustomDataAttributes::foreach_attribute(const AttributeForeachCallback callback,
|
2022-06-01 14:38:06 +10:00
|
|
|
const eAttrDomain domain) const
|
2021-05-19 13:22:09 -04:00
|
|
|
{
|
|
|
|
|
for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
|
2022-06-01 14:38:06 +10:00
|
|
|
AttributeMetaData meta_data{domain, (eCustomDataType)layer.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-05-19 13:22:09 -04:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
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
|
|
|
GVArray AttributeAccessor::lookup(const AttributeIDRef &attribute_id,
|
|
|
|
|
const std::optional<eAttrDomain> domain,
|
|
|
|
|
const std::optional<eCustomDataType> data_type) const
|
|
|
|
|
{
|
|
|
|
|
GAttributeReader attribute = this->lookup(attribute_id);
|
|
|
|
|
if (!attribute) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
GVArray varray = std::move(attribute.varray);
|
|
|
|
|
if (domain.has_value()) {
|
|
|
|
|
if (attribute.domain != domain) {
|
|
|
|
|
varray = this->adapt_domain(varray, attribute.domain, *domain);
|
|
|
|
|
if (!varray) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (data_type.has_value()) {
|
|
|
|
|
const CPPType &type = *custom_data_type_to_cpp_type(*data_type);
|
|
|
|
|
if (varray.type() != type) {
|
|
|
|
|
varray = try_adapt_data_type(std::move(varray), type);
|
|
|
|
|
if (!varray) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return varray;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GVArray AttributeAccessor::lookup_or_default(const AttributeIDRef &attribute_id,
|
|
|
|
|
const eAttrDomain domain,
|
|
|
|
|
const eCustomDataType data_type,
|
|
|
|
|
const void *default_value) const
|
|
|
|
|
{
|
|
|
|
|
GVArray varray = this->lookup(attribute_id, domain, data_type);
|
|
|
|
|
if (varray) {
|
|
|
|
|
return varray;
|
|
|
|
|
}
|
|
|
|
|
const CPPType &type = *custom_data_type_to_cpp_type(data_type);
|
|
|
|
|
const int64_t domain_size = this->domain_size(domain);
|
|
|
|
|
if (default_value == nullptr) {
|
|
|
|
|
return GVArray::ForSingleRef(type, domain_size, type.default_value());
|
|
|
|
|
}
|
|
|
|
|
return GVArray::ForSingle(type, domain_size, default_value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Set<AttributeIDRef> AttributeAccessor::all_ids() const
|
|
|
|
|
{
|
|
|
|
|
Set<AttributeIDRef> ids;
|
|
|
|
|
this->for_all(
|
|
|
|
|
[&](const AttributeIDRef &attribute_id, const AttributeMetaData & /* meta_data */) {
|
|
|
|
|
ids.add(attribute_id);
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
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()) {
|
|
|
|
|
this->remove(anonymous_ids.pop_last());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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>();
|
|
|
|
|
if (attribute_id.is_named()) {
|
|
|
|
|
checker->name = attribute_id.name();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
checker->name = BKE_anonymous_attribute_id_debug_name(&attribute_id.anonymous_id());
|
|
|
|
|
}
|
|
|
|
|
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 {};
|
|
|
|
|
}
|
|
|
|
|
|
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,
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
if (id.is_named() && skip.contains(id.name())) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (!id.should_be_kept()) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GVArray src = src_attributes.lookup(id, meta_data.domain);
|
|
|
|
|
BLI_assert(src);
|
|
|
|
|
bke::GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
|
|
|
|
|
id, meta_data.domain, meta_data.data_type);
|
|
|
|
|
BLI_assert(dst);
|
|
|
|
|
attributes.append({std::move(src), meta_data, std::move(dst)});
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
return attributes;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-13 11:36:14 -05:00
|
|
|
void copy_attribute_domain(const AttributeAccessor src_attributes,
|
|
|
|
|
MutableAttributeAccessor dst_attributes,
|
|
|
|
|
const IndexMask selection,
|
|
|
|
|
const eAttrDomain domain,
|
|
|
|
|
const Set<std::string> &skip)
|
|
|
|
|
{
|
|
|
|
|
src_attributes.for_all(
|
|
|
|
|
[&](const bke::AttributeIDRef &id, const bke::AttributeMetaData &meta_data) {
|
|
|
|
|
if (meta_data.domain != domain) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (id.is_named() && skip.contains(id.name())) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (!id.should_be_kept()) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const GVArray src = src_attributes.lookup(id, meta_data.domain);
|
|
|
|
|
BLI_assert(src);
|
|
|
|
|
|
|
|
|
|
/* Copy attribute. */
|
|
|
|
|
GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
|
|
|
|
|
id, domain, meta_data.data_type);
|
|
|
|
|
array_utils::copy(src, selection, dst.span);
|
|
|
|
|
dst.finish();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-09 12:54:20 +02:00
|
|
|
} // namespace blender::bke
|
2021-12-14 15:49:31 +11:00
|
|
|
|
|
|
|
|
/** \} */
|