Compare commits
7 Commits
temp-geome
...
temp-geome
Author | SHA1 | Date | |
---|---|---|---|
fb0d5124f2 | |||
6146a679c9 | |||
65a1ec89ba | |||
ef9fbf258b | |||
a448949f25 | |||
e3232f987a | |||
c42ceef040 |
37
source/blender/blenkernel/BKE_anonymous_attribute.h
Normal file
37
source/blender/blenkernel/BKE_anonymous_attribute.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct AnonymousAttributeID AnonymousAttributeID;
|
||||
|
||||
AnonymousAttributeID *BKE_anonymous_attribute_id_new_weak(const char *debug_name);
|
||||
AnonymousAttributeID *BKE_anonymous_attribute_id_new_strong(const char *debug_name);
|
||||
bool BKE_anonymous_attribute_id_has_strong_references(const AnonymousAttributeID *anonymous_id);
|
||||
void BKE_anonymous_attribute_id_increment_weak(const AnonymousAttributeID *anonymous_id);
|
||||
void BKE_anonymous_attribute_id_increment_strong(const AnonymousAttributeID *anonymous_id);
|
||||
void BKE_anonymous_attribute_id_decrement_weak(const AnonymousAttributeID *anonymous_id);
|
||||
void BKE_anonymous_attribute_id_decrement_strong(const AnonymousAttributeID *anonymous_id);
|
||||
const char *BKE_anonymous_attribute_id_debug_name(const AnonymousAttributeID *anonymous_id);
|
||||
const char *BKE_anonymous_attribute_id_internal_name(const AnonymousAttributeID *anonymous_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
223
source/blender/blenkernel/BKE_anonymous_attribute.hh
Normal file
223
source/blender/blenkernel/BKE_anonymous_attribute.hh
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
|
||||
#include "BLI_hash.hh"
|
||||
#include "BLI_string_ref.hh"
|
||||
|
||||
#include "BKE_anonymous_attribute.h"
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
template<bool IsStrongReference> class OwnedAnonymousAttributeID {
|
||||
private:
|
||||
const AnonymousAttributeID *data_ = nullptr;
|
||||
|
||||
public:
|
||||
OwnedAnonymousAttributeID() = default;
|
||||
|
||||
explicit OwnedAnonymousAttributeID(StringRefNull debug_name)
|
||||
{
|
||||
if constexpr (IsStrongReference) {
|
||||
data_ = BKE_anonymous_attribute_id_new_strong(debug_name.c_str());
|
||||
}
|
||||
else {
|
||||
data_ = BKE_anonymous_attribute_id_new_weak(debug_name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/* This transfers ownership, so no incref is necessary. */
|
||||
explicit OwnedAnonymousAttributeID(const AnonymousAttributeID *anonymous_id)
|
||||
: data_(anonymous_id)
|
||||
{
|
||||
}
|
||||
|
||||
template<bool OtherIsStrong>
|
||||
OwnedAnonymousAttributeID(const OwnedAnonymousAttributeID<OtherIsStrong> &other)
|
||||
{
|
||||
data_ = other.data_;
|
||||
this->incref();
|
||||
}
|
||||
|
||||
template<bool OtherIsStrong>
|
||||
OwnedAnonymousAttributeID(OwnedAnonymousAttributeID<OtherIsStrong> &&other)
|
||||
{
|
||||
data_ = other.data_;
|
||||
this->incref();
|
||||
other.decref();
|
||||
other.data_ = nullptr;
|
||||
}
|
||||
|
||||
~OwnedAnonymousAttributeID()
|
||||
{
|
||||
this->decref();
|
||||
}
|
||||
|
||||
template<bool OtherIsStrong>
|
||||
OwnedAnonymousAttributeID &operator=(const OwnedAnonymousAttributeID<OtherIsStrong> &other)
|
||||
{
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
this->~OwnedAnonymousAttributeID();
|
||||
new (this) OwnedAnonymousAttributeID(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<bool OtherIsStrong>
|
||||
OwnedAnonymousAttributeID &operator=(OwnedAnonymousAttributeID<OtherIsStrong> &&other)
|
||||
{
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
this->~OwnedAnonymousAttributeID();
|
||||
new (this) OwnedAnonymousAttributeID(std::move(other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return data_ != nullptr;
|
||||
}
|
||||
|
||||
StringRefNull debug_name() const
|
||||
{
|
||||
BLI_assert(data_ != nullptr);
|
||||
return BKE_anonymous_attribute_id_debug_name(data_);
|
||||
}
|
||||
|
||||
bool has_strong_references() const
|
||||
{
|
||||
BLI_assert(data_ != nullptr);
|
||||
return BKE_anonymous_attribute_id_has_strong_references(data_);
|
||||
}
|
||||
|
||||
const AnonymousAttributeID *extract()
|
||||
{
|
||||
const AnonymousAttributeID *extracted_data = data_;
|
||||
/* Don't decref because the caller becomes the new owner. */
|
||||
data_ = nullptr;
|
||||
return extracted_data;
|
||||
}
|
||||
|
||||
const AnonymousAttributeID *get()
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
private:
|
||||
void incref()
|
||||
{
|
||||
if (data_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
if constexpr (IsStrongReference) {
|
||||
BKE_anonymous_attribute_id_increment_strong(data_);
|
||||
}
|
||||
else {
|
||||
BKE_anonymous_attribute_id_increment_weak(data_);
|
||||
}
|
||||
}
|
||||
|
||||
void decref()
|
||||
{
|
||||
if (data_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
if constexpr (IsStrongReference) {
|
||||
BKE_anonymous_attribute_id_decrement_strong(data_);
|
||||
}
|
||||
else {
|
||||
BKE_anonymous_attribute_id_decrement_weak(data_);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using StrongAnonymousAttributeID = OwnedAnonymousAttributeID<true>;
|
||||
using WeakAnonymousAttributeID = OwnedAnonymousAttributeID<false>;
|
||||
|
||||
class AttributeIDRef {
|
||||
private:
|
||||
StringRef name_;
|
||||
const AnonymousAttributeID *anonymous_id_ = nullptr;
|
||||
|
||||
public:
|
||||
AttributeIDRef() = default;
|
||||
|
||||
AttributeIDRef(StringRef name) : name_(name)
|
||||
{
|
||||
}
|
||||
|
||||
AttributeIDRef(StringRefNull name) : name_(name)
|
||||
{
|
||||
}
|
||||
|
||||
AttributeIDRef(const char *name) : name_(name)
|
||||
{
|
||||
}
|
||||
|
||||
AttributeIDRef(const std::string &name) : name_(name)
|
||||
{
|
||||
}
|
||||
|
||||
/* The anonymous id is only borrowed, the caller has to keep a reference to it. */
|
||||
AttributeIDRef(const AnonymousAttributeID *anonymous_id) : anonymous_id_(anonymous_id)
|
||||
{
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return this->is_named() || this->is_anonymous();
|
||||
}
|
||||
|
||||
friend bool operator==(const AttributeIDRef &a, const AttributeIDRef &b)
|
||||
{
|
||||
return a.anonymous_id_ == b.anonymous_id_ && a.name_ == b.name_;
|
||||
}
|
||||
|
||||
uint64_t hash() const
|
||||
{
|
||||
return get_default_hash_2(name_, anonymous_id_);
|
||||
}
|
||||
|
||||
bool is_named() const
|
||||
{
|
||||
return !name_.is_empty();
|
||||
}
|
||||
|
||||
bool is_anonymous() const
|
||||
{
|
||||
return anonymous_id_ != nullptr;
|
||||
}
|
||||
|
||||
StringRef name() const
|
||||
{
|
||||
BLI_assert(this->is_named());
|
||||
return name_;
|
||||
}
|
||||
|
||||
const AnonymousAttributeID &anonymous_id() const
|
||||
{
|
||||
BLI_assert(this->is_anonymous());
|
||||
return *anonymous_id_;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::bke
|
@@ -22,6 +22,7 @@
|
||||
#include "FN_generic_span.hh"
|
||||
#include "FN_generic_virtual_array.hh"
|
||||
|
||||
#include "BKE_anonymous_attribute.hh"
|
||||
#include "BKE_attribute.h"
|
||||
|
||||
#include "BLI_color.hh"
|
||||
@@ -104,8 +105,8 @@ struct AttributeInitMove : public AttributeInit {
|
||||
};
|
||||
|
||||
/* Returns false when the iteration should be stopped. */
|
||||
using AttributeForeachCallback = blender::FunctionRef<bool(blender::StringRefNull attribute_name,
|
||||
const AttributeMetaData &meta_data)>;
|
||||
using AttributeForeachCallback = blender::FunctionRef<bool(
|
||||
const blender::bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data)>;
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
@@ -333,26 +334,30 @@ class CustomDataAttributes {
|
||||
|
||||
void reallocate(const int size);
|
||||
|
||||
std::optional<blender::fn::GSpan> get_for_read(const blender::StringRef name) const;
|
||||
std::optional<blender::fn::GSpan> get_for_read(
|
||||
const blender::bke::AttributeIDRef &attribute_id) const;
|
||||
|
||||
blender::fn::GVArrayPtr get_for_read(const StringRef name,
|
||||
blender::fn::GVArrayPtr get_for_read(const AttributeIDRef &attribute_id,
|
||||
const CustomDataType data_type,
|
||||
const void *default_value) const;
|
||||
|
||||
template<typename T>
|
||||
blender::fn::GVArray_Typed<T> get_for_read(const blender::StringRef name,
|
||||
blender::fn::GVArray_Typed<T> get_for_read(const blender::bke::AttributeIDRef &attribute_id,
|
||||
const T &default_value) const
|
||||
{
|
||||
const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
|
||||
const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
|
||||
GVArrayPtr varray = this->get_for_read(name, type, &default_value);
|
||||
GVArrayPtr varray = this->get_for_read(attribute_id, type, &default_value);
|
||||
return blender::fn::GVArray_Typed<T>(std::move(varray));
|
||||
}
|
||||
|
||||
std::optional<blender::fn::GMutableSpan> get_for_write(const blender::StringRef name);
|
||||
bool create(const blender::StringRef name, const CustomDataType data_type);
|
||||
bool create_by_move(const blender::StringRef name, const CustomDataType data_type, void *buffer);
|
||||
bool remove(const blender::StringRef name);
|
||||
std::optional<blender::fn::GMutableSpan> get_for_write(
|
||||
const blender::bke::AttributeIDRef &attribute_id);
|
||||
bool create(const blender::bke::AttributeIDRef &attribute_id, const CustomDataType data_type);
|
||||
bool create_by_move(const blender::bke::AttributeIDRef &attribute_id,
|
||||
const CustomDataType data_type,
|
||||
void *buffer);
|
||||
bool remove(const blender::bke::AttributeIDRef &attribute_id);
|
||||
|
||||
bool foreach_attribute(const AttributeForeachCallback callback,
|
||||
const AttributeDomain domain) const;
|
||||
|
@@ -33,6 +33,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct AnonymousAttributeID;
|
||||
struct BMesh;
|
||||
struct BlendDataReader;
|
||||
struct BlendWriter;
|
||||
@@ -193,6 +194,12 @@ void *CustomData_add_layer_named(struct CustomData *data,
|
||||
void *layer,
|
||||
int totelem,
|
||||
const char *name);
|
||||
void *CustomData_add_layer_anonymous(struct CustomData *data,
|
||||
int type,
|
||||
eCDAllocType alloctype,
|
||||
void *layer,
|
||||
int totelem,
|
||||
const struct AnonymousAttributeID *anonymous_id);
|
||||
|
||||
/* frees the active or first data layer with the give type.
|
||||
* returns 1 on success, 0 if no layer with the given type is found
|
||||
@@ -231,6 +238,11 @@ void *CustomData_duplicate_referenced_layer_named(struct CustomData *data,
|
||||
const int type,
|
||||
const char *name,
|
||||
const int totelem);
|
||||
void *CustomData_duplicate_referenced_layer_anonymous(
|
||||
CustomData *data,
|
||||
const int type,
|
||||
const struct AnonymousAttributeID *anonymous_id,
|
||||
const int totelem);
|
||||
bool CustomData_is_referenced_layer(struct CustomData *data, int type);
|
||||
|
||||
/* Duplicate all the layers with flag NOFREE, and remove the flag from duplicated layers. */
|
||||
|
@@ -31,6 +31,7 @@
|
||||
#include "BLI_user_counter.hh"
|
||||
#include "BLI_vector_set.hh"
|
||||
|
||||
#include "BKE_anonymous_attribute.hh"
|
||||
#include "BKE_attribute_access.hh"
|
||||
#include "BKE_geometry_set.h"
|
||||
|
||||
@@ -88,11 +89,11 @@ class GeometryComponent {
|
||||
GeometryComponentType type() const;
|
||||
|
||||
/* Return true when any attribute with this name exists, including built in attributes. */
|
||||
bool attribute_exists(const blender::StringRef attribute_name) const;
|
||||
bool attribute_exists(const blender::bke::AttributeIDRef &attribute_id) const;
|
||||
|
||||
/* Return the data type and domain of an attribute with the given name if it exists. */
|
||||
std::optional<AttributeMetaData> attribute_get_meta_data(
|
||||
const blender::StringRef attribute_name) const;
|
||||
const blender::bke::AttributeIDRef &attribute_id) const;
|
||||
|
||||
/* Returns true when the geometry component supports this attribute domain. */
|
||||
bool attribute_domain_supported(const AttributeDomain domain) const;
|
||||
@@ -104,12 +105,12 @@ class GeometryComponent {
|
||||
/* Get read-only access to the highest priority attribute with the given name.
|
||||
* Returns null if the attribute does not exist. */
|
||||
blender::bke::ReadAttributeLookup attribute_try_get_for_read(
|
||||
const blender::StringRef attribute_name) const;
|
||||
const blender::bke::AttributeIDRef &attribute_id) const;
|
||||
|
||||
/* Get read and write access to the highest priority attribute with the given name.
|
||||
* Returns null if the attribute does not exist. */
|
||||
blender::bke::WriteAttributeLookup attribute_try_get_for_write(
|
||||
const blender::StringRef attribute_name);
|
||||
const blender::bke::AttributeIDRef &attribute_id);
|
||||
|
||||
/* Get a read-only attribute for the domain based on the given attribute. This can be used to
|
||||
* interpolate from one domain to another.
|
||||
@@ -120,10 +121,10 @@ class GeometryComponent {
|
||||
const AttributeDomain to_domain) const;
|
||||
|
||||
/* Returns true when the attribute has been deleted. */
|
||||
bool attribute_try_delete(const blender::StringRef attribute_name);
|
||||
bool attribute_try_delete(const blender::bke::AttributeIDRef &attribute_id);
|
||||
|
||||
/* Returns true when the attribute has been created. */
|
||||
bool attribute_try_create(const blender::StringRef attribute_name,
|
||||
bool attribute_try_create(const blender::bke::AttributeIDRef &attribute_id,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const AttributeInit &initializer);
|
||||
@@ -133,7 +134,7 @@ class GeometryComponent {
|
||||
bool attribute_try_create_builtin(const blender::StringRef attribute_name,
|
||||
const AttributeInit &initializer);
|
||||
|
||||
blender::Set<std::string> attribute_names() const;
|
||||
blender::Set<blender::bke::AttributeIDRef> attribute_ids() const;
|
||||
bool attribute_foreach(const AttributeForeachCallback callback) const;
|
||||
|
||||
virtual bool is_empty() const;
|
||||
@@ -142,7 +143,7 @@ class GeometryComponent {
|
||||
* Returns null when the attribute does not exist or cannot be converted to the requested domain
|
||||
* and data type. */
|
||||
std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read(
|
||||
const blender::StringRef attribute_name,
|
||||
const blender::bke::AttributeIDRef &attribute_id,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type) const;
|
||||
|
||||
@@ -150,18 +151,18 @@ class GeometryComponent {
|
||||
* left unchanged. Returns null when the attribute does not exist or cannot be adapted to the
|
||||
* requested domain. */
|
||||
std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read(
|
||||
const blender::StringRef attribute_name, const AttributeDomain domain) const;
|
||||
const blender::bke::AttributeIDRef &attribute_id, const AttributeDomain domain) const;
|
||||
|
||||
/* Get a virtual array to read data of an attribute with the given data type. The domain is
|
||||
* left unchanged. Returns null when the attribute does not exist or cannot be converted to the
|
||||
* requested data type. */
|
||||
blender::bke::ReadAttributeLookup attribute_try_get_for_read(
|
||||
const blender::StringRef attribute_name, const CustomDataType data_type) const;
|
||||
const blender::bke::AttributeIDRef &attribute_id, const CustomDataType data_type) const;
|
||||
|
||||
/* Get a virtual array to read the data of an attribute. If that is not possible, the returned
|
||||
* virtual array will contain a default value. This never returns null. */
|
||||
std::unique_ptr<blender::fn::GVArray> attribute_get_for_read(
|
||||
const blender::StringRef attribute_name,
|
||||
const blender::bke::AttributeIDRef &attribute_id,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const void *default_value = nullptr) const;
|
||||
@@ -169,14 +170,15 @@ class GeometryComponent {
|
||||
/* Should be used instead of the method above when the requested data type is known at compile
|
||||
* time for better type safety. */
|
||||
template<typename T>
|
||||
blender::fn::GVArray_Typed<T> attribute_get_for_read(const blender::StringRef attribute_name,
|
||||
const AttributeDomain domain,
|
||||
const T &default_value) const
|
||||
blender::fn::GVArray_Typed<T> attribute_get_for_read(
|
||||
const blender::bke::AttributeIDRef &attribute_id,
|
||||
const AttributeDomain domain,
|
||||
const T &default_value) const
|
||||
{
|
||||
const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
|
||||
const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
|
||||
std::unique_ptr varray = this->attribute_get_for_read(
|
||||
attribute_name, domain, type, &default_value);
|
||||
attribute_id, domain, type, &default_value);
|
||||
return blender::fn::GVArray_Typed<T>(std::move(varray));
|
||||
}
|
||||
|
||||
@@ -191,7 +193,7 @@ class GeometryComponent {
|
||||
* is created that will overwrite the existing attribute in the end.
|
||||
*/
|
||||
blender::bke::OutputAttribute attribute_try_get_for_output(
|
||||
const blender::StringRef attribute_name,
|
||||
const blender::bke::AttributeIDRef &attribute_id,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const void *default_value = nullptr);
|
||||
@@ -200,28 +202,30 @@ class GeometryComponent {
|
||||
* attributes are not read, i.e. the attribute is used only for output. Since values are not read
|
||||
* from this attribute, no default value is necessary. */
|
||||
blender::bke::OutputAttribute attribute_try_get_for_output_only(
|
||||
const blender::StringRef attribute_name,
|
||||
const blender::bke::AttributeIDRef &attribute_id,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type);
|
||||
|
||||
/* Statically typed method corresponding to the equally named generic one. */
|
||||
template<typename T>
|
||||
blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output(
|
||||
const blender::StringRef attribute_name, const AttributeDomain domain, const T default_value)
|
||||
const blender::bke::AttributeIDRef &attribute_id,
|
||||
const AttributeDomain domain,
|
||||
const T default_value)
|
||||
{
|
||||
const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
|
||||
const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
|
||||
return this->attribute_try_get_for_output(attribute_name, domain, data_type, &default_value);
|
||||
return this->attribute_try_get_for_output(attribute_id, domain, data_type, &default_value);
|
||||
}
|
||||
|
||||
/* Statically typed method corresponding to the equally named generic one. */
|
||||
template<typename T>
|
||||
blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output_only(
|
||||
const blender::StringRef attribute_name, const AttributeDomain domain)
|
||||
const blender::bke::AttributeIDRef &attribute_id, const AttributeDomain domain)
|
||||
{
|
||||
const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
|
||||
const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
|
||||
return this->attribute_try_get_for_output_only(attribute_name, domain, data_type);
|
||||
return this->attribute_try_get_for_output_only(attribute_id, domain, data_type);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@@ -59,9 +59,10 @@ struct AttributeKind {
|
||||
* will contain the highest complexity data type and the highest priority domain among every
|
||||
* attribute with the given name on all of the input components.
|
||||
*/
|
||||
void geometry_set_gather_instances_attribute_info(Span<GeometryInstanceGroup> set_groups,
|
||||
Span<GeometryComponentType> component_types,
|
||||
const Set<std::string> &ignored_attributes,
|
||||
Map<std::string, AttributeKind> &r_attributes);
|
||||
void geometry_set_gather_instances_attribute_info(
|
||||
Span<GeometryInstanceGroup> set_groups,
|
||||
Span<GeometryComponentType> component_types,
|
||||
const Set<std::string> &ignored_attributes,
|
||||
Map<AttributeIDRef, AttributeKind> &r_attributes);
|
||||
|
||||
} // namespace blender::bke
|
||||
|
@@ -76,6 +76,7 @@ set(SRC
|
||||
intern/anim_path.c
|
||||
intern/anim_sys.c
|
||||
intern/anim_visualization.c
|
||||
intern/anonymous_attribute.cc
|
||||
intern/appdir.c
|
||||
intern/armature.c
|
||||
intern/armature_selection.cc
|
||||
@@ -295,6 +296,8 @@ set(SRC
|
||||
BKE_anim_path.h
|
||||
BKE_anim_visualization.h
|
||||
BKE_animsys.h
|
||||
BKE_anonymous_attribute.h
|
||||
BKE_anonymous_attribute.hh
|
||||
BKE_appdir.h
|
||||
BKE_armature.h
|
||||
BKE_armature.hh
|
||||
|
92
source/blender/blenkernel/intern/anonymous_attribute.cc
Normal file
92
source/blender/blenkernel/intern/anonymous_attribute.cc
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "BKE_anonymous_attribute.hh"
|
||||
|
||||
using namespace blender::bke;
|
||||
|
||||
struct AnonymousAttributeID {
|
||||
mutable std::atomic<int> refcount_weak = 0;
|
||||
mutable std::atomic<int> refcount_strong = 0;
|
||||
std::string debug_name;
|
||||
std::string internal_name;
|
||||
};
|
||||
|
||||
static std::string get_new_internal_name()
|
||||
{
|
||||
static std::atomic<int> index = 0;
|
||||
const int next_index = index.fetch_add(1);
|
||||
return "anonymous_attribute_" + std::to_string(next_index);
|
||||
}
|
||||
|
||||
AnonymousAttributeID *BKE_anonymous_attribute_id_new_weak(const char *debug_name)
|
||||
{
|
||||
AnonymousAttributeID *anonymous_id = new AnonymousAttributeID();
|
||||
anonymous_id->debug_name = debug_name;
|
||||
anonymous_id->internal_name = get_new_internal_name();
|
||||
anonymous_id->refcount_weak.store(1);
|
||||
return anonymous_id;
|
||||
}
|
||||
|
||||
AnonymousAttributeID *BKE_anonymous_attribute_id_new_strong(const char *debug_name)
|
||||
{
|
||||
AnonymousAttributeID *anonymous_id = new AnonymousAttributeID();
|
||||
anonymous_id->debug_name = debug_name;
|
||||
anonymous_id->internal_name = get_new_internal_name();
|
||||
anonymous_id->refcount_weak.store(1);
|
||||
anonymous_id->refcount_strong.store(1);
|
||||
return anonymous_id;
|
||||
}
|
||||
|
||||
bool BKE_anonymous_attribute_id_has_strong_references(const AnonymousAttributeID *anonymous_id)
|
||||
{
|
||||
return anonymous_id->refcount_strong.load() >= 1;
|
||||
}
|
||||
|
||||
void BKE_anonymous_attribute_id_increment_weak(const AnonymousAttributeID *anonymous_id)
|
||||
{
|
||||
anonymous_id->refcount_weak.fetch_add(1);
|
||||
}
|
||||
|
||||
void BKE_anonymous_attribute_id_increment_strong(const AnonymousAttributeID *anonymous_id)
|
||||
{
|
||||
anonymous_id->refcount_weak.fetch_add(1);
|
||||
anonymous_id->refcount_strong.fetch_add(1);
|
||||
}
|
||||
|
||||
void BKE_anonymous_attribute_id_decrement_weak(const AnonymousAttributeID *anonymous_id)
|
||||
{
|
||||
const int new_refcount = anonymous_id->refcount_weak.fetch_sub(1) - 1;
|
||||
if (new_refcount == 0) {
|
||||
delete anonymous_id;
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_anonymous_attribute_id_decrement_strong(const AnonymousAttributeID *anonymous_id)
|
||||
{
|
||||
anonymous_id->refcount_strong.fetch_sub(1);
|
||||
BKE_anonymous_attribute_id_decrement_weak(anonymous_id);
|
||||
}
|
||||
|
||||
const char *BKE_anonymous_attribute_id_debug_name(const AnonymousAttributeID *anonymous_id)
|
||||
{
|
||||
return anonymous_id->debug_name.c_str();
|
||||
}
|
||||
|
||||
const char *BKE_anonymous_attribute_id_internal_name(const AnonymousAttributeID *anonymous_id)
|
||||
{
|
||||
return anonymous_id->internal_name.c_str();
|
||||
}
|
@@ -334,8 +334,20 @@ bool BuiltinCustomDataLayerProvider::exists(const GeometryComponent &component)
|
||||
return data != nullptr;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read(
|
||||
const GeometryComponent &component, const StringRef attribute_name) const
|
||||
const GeometryComponent &component, const AttributeIDRef &attribute_id) const
|
||||
{
|
||||
const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
|
||||
if (custom_data == nullptr) {
|
||||
@@ -343,7 +355,7 @@ ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read(
|
||||
}
|
||||
const int domain_size = component.attribute_domain_size(domain_);
|
||||
for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
|
||||
if (layer.name != attribute_name) {
|
||||
if (!custom_data_layer_matches_attribute_id(layer, attribute_id)) {
|
||||
continue;
|
||||
}
|
||||
const CustomDataType data_type = (CustomDataType)layer.type;
|
||||
@@ -368,7 +380,7 @@ ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read(
|
||||
}
|
||||
|
||||
WriteAttributeLookup CustomDataAttributeProvider::try_get_for_write(
|
||||
GeometryComponent &component, const StringRef attribute_name) const
|
||||
GeometryComponent &component, const AttributeIDRef &attribute_id) const
|
||||
{
|
||||
CustomData *custom_data = custom_data_access_.get_custom_data(component);
|
||||
if (custom_data == nullptr) {
|
||||
@@ -376,10 +388,17 @@ WriteAttributeLookup CustomDataAttributeProvider::try_get_for_write(
|
||||
}
|
||||
const int domain_size = component.attribute_domain_size(domain_);
|
||||
for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
|
||||
if (layer.name != attribute_name) {
|
||||
if (!custom_data_layer_matches_attribute_id(layer, attribute_id)) {
|
||||
continue;
|
||||
}
|
||||
CustomData_duplicate_referenced_layer_named(custom_data, layer.type, layer.name, domain_size);
|
||||
if (attribute_id.is_named()) {
|
||||
CustomData_duplicate_referenced_layer_named(
|
||||
custom_data, layer.type, layer.name, domain_size);
|
||||
}
|
||||
else {
|
||||
CustomData_duplicate_referenced_layer_anonymous(
|
||||
custom_data, layer.type, &attribute_id.anonymous_id(), domain_size);
|
||||
}
|
||||
const CustomDataType data_type = (CustomDataType)layer.type;
|
||||
switch (data_type) {
|
||||
case CD_PROP_FLOAT:
|
||||
@@ -402,7 +421,7 @@ WriteAttributeLookup CustomDataAttributeProvider::try_get_for_write(
|
||||
}
|
||||
|
||||
bool CustomDataAttributeProvider::try_delete(GeometryComponent &component,
|
||||
const StringRef attribute_name) const
|
||||
const AttributeIDRef &attribute_id) const
|
||||
{
|
||||
CustomData *custom_data = custom_data_access_.get_custom_data(component);
|
||||
if (custom_data == nullptr) {
|
||||
@@ -411,7 +430,8 @@ bool CustomDataAttributeProvider::try_delete(GeometryComponent &component,
|
||||
const int domain_size = component.attribute_domain_size(domain_);
|
||||
for (const int i : IndexRange(custom_data->totlayer)) {
|
||||
const CustomDataLayer &layer = custom_data->layers[i];
|
||||
if (this->type_is_supported((CustomDataType)layer.type) && layer.name == attribute_name) {
|
||||
if (this->type_is_supported((CustomDataType)layer.type) &&
|
||||
custom_data_layer_matches_attribute_id(layer, attribute_id)) {
|
||||
CustomData_free_layer(custom_data, layer.type, domain_size, i);
|
||||
return true;
|
||||
}
|
||||
@@ -419,24 +439,39 @@ bool CustomDataAttributeProvider::try_delete(GeometryComponent &component,
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool add_named_custom_data_layer_from_attribute_init(const StringRef attribute_name,
|
||||
CustomData &custom_data,
|
||||
const CustomDataType data_type,
|
||||
const int domain_size,
|
||||
const AttributeInit &initializer)
|
||||
static void *add_generic_custom_data_layer(CustomData &custom_data,
|
||||
const CustomDataType data_type,
|
||||
const eCDAllocType alloctype,
|
||||
void *layer_data,
|
||||
const int domain_size,
|
||||
const AttributeIDRef &attribute_id)
|
||||
{
|
||||
char attribute_name_c[MAX_NAME];
|
||||
attribute_name.copy(attribute_name_c);
|
||||
if (attribute_id.is_named()) {
|
||||
char attribute_name_c[MAX_NAME];
|
||||
attribute_id.name().copy(attribute_name_c);
|
||||
return CustomData_add_layer_named(
|
||||
&custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c);
|
||||
}
|
||||
const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id();
|
||||
return CustomData_add_layer_anonymous(
|
||||
&custom_data, data_type, alloctype, layer_data, domain_size, &anonymous_id);
|
||||
}
|
||||
|
||||
static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attribute_id,
|
||||
CustomData &custom_data,
|
||||
const CustomDataType data_type,
|
||||
const int domain_size,
|
||||
const AttributeInit &initializer)
|
||||
{
|
||||
switch (initializer.type) {
|
||||
case AttributeInit::Type::Default: {
|
||||
void *data = CustomData_add_layer_named(
|
||||
&custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c);
|
||||
void *data = add_generic_custom_data_layer(
|
||||
custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_id);
|
||||
return data != nullptr;
|
||||
}
|
||||
case AttributeInit::Type::VArray: {
|
||||
void *data = CustomData_add_layer_named(
|
||||
&custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c);
|
||||
void *data = add_generic_custom_data_layer(
|
||||
custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_id);
|
||||
if (data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
@@ -446,8 +481,8 @@ static bool add_named_custom_data_layer_from_attribute_init(const StringRef attr
|
||||
}
|
||||
case AttributeInit::Type::MoveArray: {
|
||||
void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
|
||||
void *data = CustomData_add_layer_named(
|
||||
&custom_data, data_type, CD_ASSIGN, source_data, domain_size, attribute_name_c);
|
||||
void *data = add_generic_custom_data_layer(
|
||||
custom_data, data_type, CD_ASSIGN, source_data, domain_size, attribute_id);
|
||||
if (data == nullptr) {
|
||||
MEM_freeN(source_data);
|
||||
return false;
|
||||
@@ -461,7 +496,7 @@ static bool add_named_custom_data_layer_from_attribute_init(const StringRef attr
|
||||
}
|
||||
|
||||
bool CustomDataAttributeProvider::try_create(GeometryComponent &component,
|
||||
const StringRef attribute_name,
|
||||
const AttributeIDRef &attribute_id,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const AttributeInit &initializer) const
|
||||
@@ -477,13 +512,13 @@ bool CustomDataAttributeProvider::try_create(GeometryComponent &component,
|
||||
return false;
|
||||
}
|
||||
for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
|
||||
if (layer.name == attribute_name) {
|
||||
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const int domain_size = component.attribute_domain_size(domain_);
|
||||
add_named_custom_data_layer_from_attribute_init(
|
||||
attribute_name, *custom_data, data_type, domain_size, initializer);
|
||||
add_custom_data_layer_from_attribute_init(
|
||||
attribute_id, *custom_data, data_type, domain_size, initializer);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -498,7 +533,14 @@ bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &com
|
||||
const CustomDataType data_type = (CustomDataType)layer.type;
|
||||
if (this->type_is_supported(data_type)) {
|
||||
AttributeMetaData meta_data{domain_, data_type};
|
||||
if (!callback(layer.name, meta_data)) {
|
||||
AttributeIDRef attribute_id;
|
||||
if (layer.anonymous_id != nullptr) {
|
||||
attribute_id = layer.anonymous_id;
|
||||
}
|
||||
else {
|
||||
attribute_id = layer.name;
|
||||
}
|
||||
if (!callback(attribute_id, meta_data)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -507,7 +549,7 @@ bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &com
|
||||
}
|
||||
|
||||
ReadAttributeLookup NamedLegacyCustomDataProvider::try_get_for_read(
|
||||
const GeometryComponent &component, const StringRef attribute_name) const
|
||||
const GeometryComponent &component, const AttributeIDRef &attribute_id) const
|
||||
{
|
||||
const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
|
||||
if (custom_data == nullptr) {
|
||||
@@ -515,7 +557,7 @@ ReadAttributeLookup NamedLegacyCustomDataProvider::try_get_for_read(
|
||||
}
|
||||
for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
|
||||
if (layer.type == stored_type_) {
|
||||
if (layer.name == attribute_name) {
|
||||
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
|
||||
const int domain_size = component.attribute_domain_size(domain_);
|
||||
return {as_read_attribute_(layer.data, domain_size), domain_};
|
||||
}
|
||||
@@ -525,7 +567,7 @@ ReadAttributeLookup NamedLegacyCustomDataProvider::try_get_for_read(
|
||||
}
|
||||
|
||||
WriteAttributeLookup NamedLegacyCustomDataProvider::try_get_for_write(
|
||||
GeometryComponent &component, const StringRef attribute_name) const
|
||||
GeometryComponent &component, const AttributeIDRef &attribute_id) const
|
||||
{
|
||||
CustomData *custom_data = custom_data_access_.get_custom_data(component);
|
||||
if (custom_data == nullptr) {
|
||||
@@ -533,7 +575,7 @@ WriteAttributeLookup NamedLegacyCustomDataProvider::try_get_for_write(
|
||||
}
|
||||
for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
|
||||
if (layer.type == stored_type_) {
|
||||
if (layer.name == attribute_name) {
|
||||
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
|
||||
const int domain_size = component.attribute_domain_size(domain_);
|
||||
void *data_old = layer.data;
|
||||
void *data_new = CustomData_duplicate_referenced_layer_named(
|
||||
@@ -549,7 +591,7 @@ WriteAttributeLookup NamedLegacyCustomDataProvider::try_get_for_write(
|
||||
}
|
||||
|
||||
bool NamedLegacyCustomDataProvider::try_delete(GeometryComponent &component,
|
||||
const StringRef attribute_name) const
|
||||
const AttributeIDRef &attribute_id) const
|
||||
{
|
||||
CustomData *custom_data = custom_data_access_.get_custom_data(component);
|
||||
if (custom_data == nullptr) {
|
||||
@@ -558,7 +600,7 @@ bool NamedLegacyCustomDataProvider::try_delete(GeometryComponent &component,
|
||||
for (const int i : IndexRange(custom_data->totlayer)) {
|
||||
const CustomDataLayer &layer = custom_data->layers[i];
|
||||
if (layer.type == stored_type_) {
|
||||
if (layer.name == attribute_name) {
|
||||
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
|
||||
const int domain_size = component.attribute_domain_size(domain_);
|
||||
CustomData_free_layer(custom_data, stored_type_, domain_size, i);
|
||||
custom_data_access_.update_custom_data_pointers(component);
|
||||
@@ -627,11 +669,11 @@ CustomDataAttributes &CustomDataAttributes::operator=(const CustomDataAttributes
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::optional<GSpan> CustomDataAttributes::get_for_read(const StringRef name) const
|
||||
std::optional<GSpan> CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id) const
|
||||
{
|
||||
BLI_assert(size_ != 0);
|
||||
for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
|
||||
if (layer.name == name) {
|
||||
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
|
||||
const CPPType *cpp_type = custom_data_type_to_cpp_type((CustomDataType)layer.type);
|
||||
BLI_assert(cpp_type != nullptr);
|
||||
return GSpan(*cpp_type, layer.data, size_);
|
||||
@@ -645,13 +687,13 @@ std::optional<GSpan> CustomDataAttributes::get_for_read(const StringRef name) co
|
||||
* value if the attribute doesn't exist. If no default value is provided, the default value for the
|
||||
* type will be used.
|
||||
*/
|
||||
GVArrayPtr CustomDataAttributes::get_for_read(const StringRef name,
|
||||
GVArrayPtr CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id,
|
||||
const CustomDataType data_type,
|
||||
const void *default_value) const
|
||||
{
|
||||
const CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
|
||||
|
||||
std::optional<GSpan> attribute = this->get_for_read(name);
|
||||
std::optional<GSpan> attribute = this->get_for_read(attribute_id);
|
||||
if (!attribute) {
|
||||
const int domain_size = this->size_;
|
||||
return std::make_unique<GVArray_For_SingleValue>(
|
||||
@@ -666,12 +708,12 @@ GVArrayPtr CustomDataAttributes::get_for_read(const StringRef name,
|
||||
return conversions.try_convert(std::make_unique<GVArray_For_GSpan>(*attribute), *type);
|
||||
}
|
||||
|
||||
std::optional<GMutableSpan> CustomDataAttributes::get_for_write(const StringRef name)
|
||||
std::optional<GMutableSpan> CustomDataAttributes::get_for_write(const AttributeIDRef &attribute_id)
|
||||
{
|
||||
/* If this assert hits, it most likely means that #reallocate was not called at some point. */
|
||||
BLI_assert(size_ != 0);
|
||||
for (CustomDataLayer &layer : MutableSpan(data.layers, data.totlayer)) {
|
||||
if (layer.name == name) {
|
||||
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
|
||||
const CPPType *cpp_type = custom_data_type_to_cpp_type((CustomDataType)layer.type);
|
||||
BLI_assert(cpp_type != nullptr);
|
||||
return GMutableSpan(*cpp_type, layer.data, size_);
|
||||
@@ -680,30 +722,29 @@ std::optional<GMutableSpan> CustomDataAttributes::get_for_write(const StringRef
|
||||
return {};
|
||||
}
|
||||
|
||||
bool CustomDataAttributes::create(const StringRef name, const CustomDataType data_type)
|
||||
bool CustomDataAttributes::create(const AttributeIDRef &attribute_id,
|
||||
const CustomDataType data_type)
|
||||
{
|
||||
char name_c[MAX_NAME];
|
||||
name.copy(name_c);
|
||||
void *result = CustomData_add_layer_named(&data, data_type, CD_DEFAULT, nullptr, size_, name_c);
|
||||
void *result = add_generic_custom_data_layer(
|
||||
data, data_type, CD_DEFAULT, nullptr, size_, attribute_id);
|
||||
return result != nullptr;
|
||||
}
|
||||
|
||||
bool CustomDataAttributes::create_by_move(const blender::StringRef name,
|
||||
bool CustomDataAttributes::create_by_move(const blender::bke::AttributeIDRef &attribute_id,
|
||||
const CustomDataType data_type,
|
||||
void *buffer)
|
||||
{
|
||||
char name_c[MAX_NAME];
|
||||
name.copy(name_c);
|
||||
void *result = CustomData_add_layer_named(&data, data_type, CD_ASSIGN, buffer, size_, name_c);
|
||||
void *result = add_generic_custom_data_layer(
|
||||
data, data_type, CD_ASSIGN, buffer, size_, attribute_id);
|
||||
return result != nullptr;
|
||||
}
|
||||
|
||||
bool CustomDataAttributes::remove(const blender::StringRef name)
|
||||
bool CustomDataAttributes::remove(const blender::bke::AttributeIDRef &attribute_id)
|
||||
{
|
||||
bool result = false;
|
||||
for (const int i : IndexRange(data.totlayer)) {
|
||||
const CustomDataLayer &layer = data.layers[i];
|
||||
if (layer.name == name) {
|
||||
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
|
||||
CustomData_free_layer(&data, layer.type, size_, i);
|
||||
result = true;
|
||||
}
|
||||
@@ -722,7 +763,14 @@ bool CustomDataAttributes::foreach_attribute(const AttributeForeachCallback call
|
||||
{
|
||||
for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
|
||||
AttributeMetaData meta_data{domain, (CustomDataType)layer.type};
|
||||
if (!callback(layer.name, meta_data)) {
|
||||
AttributeIDRef attribute_id;
|
||||
if (layer.anonymous_id != nullptr) {
|
||||
attribute_id = layer.anonymous_id;
|
||||
}
|
||||
else {
|
||||
attribute_id = layer.name;
|
||||
}
|
||||
if (!callback(attribute_id, meta_data)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -766,21 +814,23 @@ bool GeometryComponent::attribute_is_builtin(const blender::StringRef attribute_
|
||||
}
|
||||
|
||||
blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
|
||||
const StringRef attribute_name) const
|
||||
const blender::bke::AttributeIDRef &attribute_id) const
|
||||
{
|
||||
using namespace blender::bke;
|
||||
const ComponentAttributeProviders *providers = this->get_attribute_providers();
|
||||
if (providers == nullptr) {
|
||||
return {};
|
||||
}
|
||||
const BuiltinAttributeProvider *builtin_provider =
|
||||
providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
|
||||
if (builtin_provider != nullptr) {
|
||||
return {builtin_provider->try_get_for_read(*this), builtin_provider->domain()};
|
||||
if (attribute_id.is_named()) {
|
||||
const BuiltinAttributeProvider *builtin_provider =
|
||||
providers->builtin_attribute_providers().lookup_default_as(attribute_id.name(), nullptr);
|
||||
if (builtin_provider != nullptr) {
|
||||
return {builtin_provider->try_get_for_read(*this), builtin_provider->domain()};
|
||||
}
|
||||
}
|
||||
for (const DynamicAttributesProvider *dynamic_provider :
|
||||
providers->dynamic_attribute_providers()) {
|
||||
ReadAttributeLookup attribute = dynamic_provider->try_get_for_read(*this, attribute_name);
|
||||
ReadAttributeLookup attribute = dynamic_provider->try_get_for_read(*this, attribute_id);
|
||||
if (attribute) {
|
||||
return attribute;
|
||||
}
|
||||
@@ -800,21 +850,23 @@ std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_adapt_dom
|
||||
}
|
||||
|
||||
blender::bke::WriteAttributeLookup GeometryComponent::attribute_try_get_for_write(
|
||||
const StringRef attribute_name)
|
||||
const blender::bke::AttributeIDRef &attribute_id)
|
||||
{
|
||||
using namespace blender::bke;
|
||||
const ComponentAttributeProviders *providers = this->get_attribute_providers();
|
||||
if (providers == nullptr) {
|
||||
return {};
|
||||
}
|
||||
const BuiltinAttributeProvider *builtin_provider =
|
||||
providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
|
||||
if (builtin_provider != nullptr) {
|
||||
return {builtin_provider->try_get_for_write(*this), builtin_provider->domain()};
|
||||
if (attribute_id.is_named()) {
|
||||
const BuiltinAttributeProvider *builtin_provider =
|
||||
providers->builtin_attribute_providers().lookup_default_as(attribute_id.name(), nullptr);
|
||||
if (builtin_provider != nullptr) {
|
||||
return {builtin_provider->try_get_for_write(*this), builtin_provider->domain()};
|
||||
}
|
||||
}
|
||||
for (const DynamicAttributesProvider *dynamic_provider :
|
||||
providers->dynamic_attribute_providers()) {
|
||||
WriteAttributeLookup attribute = dynamic_provider->try_get_for_write(*this, attribute_name);
|
||||
WriteAttributeLookup attribute = dynamic_provider->try_get_for_write(*this, attribute_id);
|
||||
if (attribute) {
|
||||
return attribute;
|
||||
}
|
||||
@@ -822,53 +874,57 @@ blender::bke::WriteAttributeLookup GeometryComponent::attribute_try_get_for_writ
|
||||
return {};
|
||||
}
|
||||
|
||||
bool GeometryComponent::attribute_try_delete(const StringRef attribute_name)
|
||||
bool GeometryComponent::attribute_try_delete(const blender::bke::AttributeIDRef &attribute_id)
|
||||
{
|
||||
using namespace blender::bke;
|
||||
const ComponentAttributeProviders *providers = this->get_attribute_providers();
|
||||
if (providers == nullptr) {
|
||||
return {};
|
||||
}
|
||||
const BuiltinAttributeProvider *builtin_provider =
|
||||
providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
|
||||
if (builtin_provider != nullptr) {
|
||||
return builtin_provider->try_delete(*this);
|
||||
if (attribute_id.is_named()) {
|
||||
const BuiltinAttributeProvider *builtin_provider =
|
||||
providers->builtin_attribute_providers().lookup_default_as(attribute_id.name(), nullptr);
|
||||
if (builtin_provider != nullptr) {
|
||||
return builtin_provider->try_delete(*this);
|
||||
}
|
||||
}
|
||||
bool success = false;
|
||||
for (const DynamicAttributesProvider *dynamic_provider :
|
||||
providers->dynamic_attribute_providers()) {
|
||||
success = dynamic_provider->try_delete(*this, attribute_name) || success;
|
||||
success = dynamic_provider->try_delete(*this, attribute_id) || success;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool GeometryComponent::attribute_try_create(const StringRef attribute_name,
|
||||
bool GeometryComponent::attribute_try_create(const blender::bke::AttributeIDRef &attribute_id,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const AttributeInit &initializer)
|
||||
{
|
||||
using namespace blender::bke;
|
||||
if (attribute_name.is_empty()) {
|
||||
if (!attribute_id) {
|
||||
return false;
|
||||
}
|
||||
const ComponentAttributeProviders *providers = this->get_attribute_providers();
|
||||
if (providers == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const BuiltinAttributeProvider *builtin_provider =
|
||||
providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
|
||||
if (builtin_provider != nullptr) {
|
||||
if (builtin_provider->domain() != domain) {
|
||||
return false;
|
||||
if (attribute_id.is_named()) {
|
||||
const BuiltinAttributeProvider *builtin_provider =
|
||||
providers->builtin_attribute_providers().lookup_default_as(attribute_id.name(), nullptr);
|
||||
if (builtin_provider != nullptr) {
|
||||
if (builtin_provider->domain() != domain) {
|
||||
return false;
|
||||
}
|
||||
if (builtin_provider->data_type() != data_type) {
|
||||
return false;
|
||||
}
|
||||
return builtin_provider->try_create(*this, initializer);
|
||||
}
|
||||
if (builtin_provider->data_type() != data_type) {
|
||||
return false;
|
||||
}
|
||||
return builtin_provider->try_create(*this, initializer);
|
||||
}
|
||||
for (const DynamicAttributesProvider *dynamic_provider :
|
||||
providers->dynamic_attribute_providers()) {
|
||||
if (dynamic_provider->try_create(*this, attribute_name, domain, data_type, initializer)) {
|
||||
if (dynamic_provider->try_create(*this, attribute_id, domain, data_type, initializer)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -894,11 +950,12 @@ bool GeometryComponent::attribute_try_create_builtin(const blender::StringRef at
|
||||
return builtin_provider->try_create(*this, initializer);
|
||||
}
|
||||
|
||||
Set<std::string> GeometryComponent::attribute_names() const
|
||||
Set<blender::bke::AttributeIDRef> GeometryComponent::attribute_ids() const
|
||||
{
|
||||
Set<std::string> attributes;
|
||||
this->attribute_foreach([&](StringRefNull name, const AttributeMetaData &UNUSED(meta_data)) {
|
||||
attributes.add(name);
|
||||
Set<blender::bke::AttributeIDRef> attributes;
|
||||
this->attribute_foreach([&](const blender::bke::AttributeIDRef &attribute_id,
|
||||
const AttributeMetaData &UNUSED(meta_data)) {
|
||||
attributes.add(attribute_id);
|
||||
return true;
|
||||
});
|
||||
return attributes;
|
||||
@@ -931,9 +988,9 @@ bool GeometryComponent::attribute_foreach(const AttributeForeachCallback callbac
|
||||
}
|
||||
for (const DynamicAttributesProvider *provider : providers->dynamic_attribute_providers()) {
|
||||
const bool continue_loop = provider->foreach_attribute(
|
||||
*this, [&](StringRefNull name, const AttributeMetaData &meta_data) {
|
||||
if (handled_attribute_names.add(name)) {
|
||||
return callback(name, meta_data);
|
||||
*this, [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
|
||||
if (attribute_id.is_anonymous() || handled_attribute_names.add(attribute_id.name())) {
|
||||
return callback(attribute_id, meta_data);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
@@ -945,9 +1002,9 @@ bool GeometryComponent::attribute_foreach(const AttributeForeachCallback callbac
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GeometryComponent::attribute_exists(const blender::StringRef attribute_name) const
|
||||
bool GeometryComponent::attribute_exists(const blender::bke::AttributeIDRef &attribute_id) const
|
||||
{
|
||||
blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name);
|
||||
blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_id);
|
||||
if (attribute) {
|
||||
return true;
|
||||
}
|
||||
@@ -955,11 +1012,12 @@ bool GeometryComponent::attribute_exists(const blender::StringRef attribute_name
|
||||
}
|
||||
|
||||
std::optional<AttributeMetaData> GeometryComponent::attribute_get_meta_data(
|
||||
const StringRef attribute_name) const
|
||||
const blender::bke::AttributeIDRef &attribute_id) const
|
||||
{
|
||||
std::optional<AttributeMetaData> result{std::nullopt};
|
||||
this->attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) {
|
||||
if (attribute_name == name) {
|
||||
this->attribute_foreach([&](const blender::bke::AttributeIDRef ¤t_attribute_id,
|
||||
const AttributeMetaData &meta_data) {
|
||||
if (attribute_id == current_attribute_id) {
|
||||
result = meta_data;
|
||||
return false;
|
||||
}
|
||||
@@ -977,11 +1035,11 @@ static std::unique_ptr<blender::fn::GVArray> try_adapt_data_type(
|
||||
}
|
||||
|
||||
std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_read(
|
||||
const StringRef attribute_name,
|
||||
const blender::bke::AttributeIDRef &attribute_id,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type) const
|
||||
{
|
||||
blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name);
|
||||
blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_id);
|
||||
if (!attribute) {
|
||||
return {};
|
||||
}
|
||||
@@ -1007,13 +1065,13 @@ std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_r
|
||||
}
|
||||
|
||||
std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_try_get_for_read(
|
||||
const StringRef attribute_name, const AttributeDomain domain) const
|
||||
const blender::bke::AttributeIDRef &attribute_id, const AttributeDomain domain) const
|
||||
{
|
||||
if (!this->attribute_domain_supported(domain)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name);
|
||||
blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_id);
|
||||
if (!attribute) {
|
||||
return {};
|
||||
}
|
||||
@@ -1026,9 +1084,9 @@ std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_try_get_for_
|
||||
}
|
||||
|
||||
blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
|
||||
const blender::StringRef attribute_name, const CustomDataType data_type) const
|
||||
const blender::bke::AttributeIDRef &attribute_id, const CustomDataType data_type) const
|
||||
{
|
||||
blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name);
|
||||
blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_id);
|
||||
if (!attribute) {
|
||||
return {};
|
||||
}
|
||||
@@ -1043,13 +1101,13 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
|
||||
}
|
||||
|
||||
std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_get_for_read(
|
||||
const StringRef attribute_name,
|
||||
const blender::bke::AttributeIDRef &attribute_id,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const void *default_value) const
|
||||
{
|
||||
std::unique_ptr<blender::bke::GVArray> varray = this->attribute_try_get_for_read(
|
||||
attribute_name, domain, data_type);
|
||||
attribute_id, domain, data_type);
|
||||
if (varray) {
|
||||
return varray;
|
||||
}
|
||||
@@ -1065,15 +1123,22 @@ class GVMutableAttribute_For_OutputAttribute
|
||||
: public blender::fn::GVMutableArray_For_GMutableSpan {
|
||||
public:
|
||||
GeometryComponent *component;
|
||||
std::string final_name;
|
||||
std::string attribute_name;
|
||||
blender::bke::WeakAnonymousAttributeID anonymous_attribute_id;
|
||||
|
||||
GVMutableAttribute_For_OutputAttribute(GMutableSpan data,
|
||||
GeometryComponent &component,
|
||||
std::string final_name)
|
||||
: blender::fn::GVMutableArray_For_GMutableSpan(data),
|
||||
component(&component),
|
||||
final_name(std::move(final_name))
|
||||
const blender::bke::AttributeIDRef &attribute_id)
|
||||
: blender::fn::GVMutableArray_For_GMutableSpan(data), component(&component)
|
||||
{
|
||||
if (attribute_id.is_named()) {
|
||||
this->attribute_name = attribute_id.name();
|
||||
}
|
||||
else {
|
||||
const AnonymousAttributeID *anonymous_id = &attribute_id.anonymous_id();
|
||||
BKE_anonymous_attribute_id_increment_weak(anonymous_id);
|
||||
this->anonymous_attribute_id = blender::bke::WeakAnonymousAttributeID{anonymous_id};
|
||||
}
|
||||
}
|
||||
|
||||
~GVMutableAttribute_For_OutputAttribute() override
|
||||
@@ -1093,21 +1158,28 @@ static void save_output_attribute(blender::bke::OutputAttribute &output_attribut
|
||||
dynamic_cast<GVMutableAttribute_For_OutputAttribute &>(output_attribute.varray());
|
||||
|
||||
GeometryComponent &component = *varray.component;
|
||||
const StringRefNull name = varray.final_name;
|
||||
AttributeIDRef attribute_id;
|
||||
if (!varray.attribute_name.empty()) {
|
||||
attribute_id = varray.attribute_name;
|
||||
}
|
||||
else {
|
||||
attribute_id = varray.anonymous_attribute_id.extract();
|
||||
}
|
||||
const AttributeDomain domain = output_attribute.domain();
|
||||
const CustomDataType data_type = output_attribute.custom_data_type();
|
||||
const CPPType &cpp_type = output_attribute.cpp_type();
|
||||
|
||||
component.attribute_try_delete(name);
|
||||
if (!component.attribute_try_create(
|
||||
varray.final_name, domain, data_type, AttributeInitDefault())) {
|
||||
CLOG_WARN(&LOG,
|
||||
"Could not create the '%s' attribute with type '%s'.",
|
||||
name.c_str(),
|
||||
cpp_type.name().c_str());
|
||||
component.attribute_try_delete(attribute_id);
|
||||
if (!component.attribute_try_create(attribute_id, domain, data_type, AttributeInitDefault())) {
|
||||
if (!varray.attribute_name.empty()) {
|
||||
CLOG_WARN(&LOG,
|
||||
"Could not create the '%s' attribute with type '%s'.",
|
||||
varray.attribute_name.c_str(),
|
||||
cpp_type.name().c_str());
|
||||
}
|
||||
return;
|
||||
}
|
||||
WriteAttributeLookup write_attribute = component.attribute_try_get_for_write(name);
|
||||
WriteAttributeLookup write_attribute = component.attribute_try_get_for_write(attribute_id);
|
||||
BUFFER_FOR_CPP_TYPE_VALUE(varray.type(), buffer);
|
||||
for (const int i : IndexRange(varray.size())) {
|
||||
varray.get(i, buffer);
|
||||
@@ -1117,7 +1189,7 @@ static void save_output_attribute(blender::bke::OutputAttribute &output_attribut
|
||||
|
||||
static blender::bke::OutputAttribute create_output_attribute(
|
||||
GeometryComponent &component,
|
||||
const blender::StringRef attribute_name,
|
||||
const blender::bke::AttributeIDRef &attribute_id,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const bool ignore_old_values,
|
||||
@@ -1127,7 +1199,7 @@ static blender::bke::OutputAttribute create_output_attribute(
|
||||
using namespace blender::fn;
|
||||
using namespace blender::bke;
|
||||
|
||||
if (attribute_name.is_empty()) {
|
||||
if (!attribute_id) {
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -1135,7 +1207,8 @@ static blender::bke::OutputAttribute create_output_attribute(
|
||||
BLI_assert(cpp_type != nullptr);
|
||||
const nodes::DataTypeConversions &conversions = nodes::get_implicit_type_conversions();
|
||||
|
||||
if (component.attribute_is_builtin(attribute_name)) {
|
||||
if (attribute_id.is_named() && component.attribute_is_builtin(attribute_id.name())) {
|
||||
const StringRef attribute_name = attribute_id.name();
|
||||
WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name);
|
||||
if (!attribute) {
|
||||
if (default_value) {
|
||||
@@ -1169,18 +1242,18 @@ static blender::bke::OutputAttribute create_output_attribute(
|
||||
|
||||
const int domain_size = component.attribute_domain_size(domain);
|
||||
|
||||
WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name);
|
||||
WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_id);
|
||||
if (!attribute) {
|
||||
if (default_value) {
|
||||
const GVArray_For_SingleValueRef default_varray{*cpp_type, domain_size, default_value};
|
||||
component.attribute_try_create(
|
||||
attribute_name, domain, data_type, AttributeInitVArray(&default_varray));
|
||||
attribute_id, domain, data_type, AttributeInitVArray(&default_varray));
|
||||
}
|
||||
else {
|
||||
component.attribute_try_create(attribute_name, domain, data_type, AttributeInitDefault());
|
||||
component.attribute_try_create(attribute_id, domain, data_type, AttributeInitDefault());
|
||||
}
|
||||
|
||||
attribute = component.attribute_try_get_for_write(attribute_name);
|
||||
attribute = component.attribute_try_get_for_write(attribute_id);
|
||||
if (!attribute) {
|
||||
/* Can't create the attribute. */
|
||||
return {};
|
||||
@@ -1202,28 +1275,28 @@ static blender::bke::OutputAttribute create_output_attribute(
|
||||
else {
|
||||
/* Fill the temporary array with values from the existing attribute. */
|
||||
GVArrayPtr old_varray = component.attribute_get_for_read(
|
||||
attribute_name, domain, data_type, default_value);
|
||||
attribute_id, domain, data_type, default_value);
|
||||
old_varray->materialize_to_uninitialized(IndexRange(domain_size), data);
|
||||
}
|
||||
GVMutableArrayPtr varray = std::make_unique<GVMutableAttribute_For_OutputAttribute>(
|
||||
GMutableSpan{*cpp_type, data, domain_size}, component, attribute_name);
|
||||
GMutableSpan{*cpp_type, data, domain_size}, component, attribute_id);
|
||||
|
||||
return OutputAttribute(std::move(varray), domain, save_output_attribute, true);
|
||||
}
|
||||
|
||||
blender::bke::OutputAttribute GeometryComponent::attribute_try_get_for_output(
|
||||
const StringRef attribute_name,
|
||||
const blender::bke::AttributeIDRef &attribute_id,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const void *default_value)
|
||||
{
|
||||
return create_output_attribute(*this, attribute_name, domain, data_type, false, default_value);
|
||||
return create_output_attribute(*this, attribute_id, domain, data_type, false, default_value);
|
||||
}
|
||||
|
||||
blender::bke::OutputAttribute GeometryComponent::attribute_try_get_for_output_only(
|
||||
const blender::StringRef attribute_name,
|
||||
const blender::bke::AttributeIDRef &attribute_id,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type)
|
||||
{
|
||||
return create_output_attribute(*this, attribute_name, domain, data_type, true, nullptr);
|
||||
return create_output_attribute(*this, attribute_id, domain, data_type, true, nullptr);
|
||||
}
|
||||
|
@@ -116,12 +116,13 @@ class BuiltinAttributeProvider {
|
||||
class DynamicAttributesProvider {
|
||||
public:
|
||||
virtual ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
|
||||
const StringRef attribute_name) const = 0;
|
||||
const AttributeIDRef &attribute_id) const = 0;
|
||||
virtual WriteAttributeLookup try_get_for_write(GeometryComponent &component,
|
||||
const StringRef attribute_name) const = 0;
|
||||
virtual bool try_delete(GeometryComponent &component, const StringRef attribute_name) const = 0;
|
||||
const AttributeIDRef &attribute_id) const = 0;
|
||||
virtual bool try_delete(GeometryComponent &component,
|
||||
const AttributeIDRef &attribute_id) const = 0;
|
||||
virtual bool try_create(GeometryComponent &UNUSED(component),
|
||||
const StringRef UNUSED(attribute_name),
|
||||
const AttributeIDRef &UNUSED(attribute_id),
|
||||
const AttributeDomain UNUSED(domain),
|
||||
const CustomDataType UNUSED(data_type),
|
||||
const AttributeInit &UNUSED(initializer)) const
|
||||
@@ -154,15 +155,15 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
|
||||
}
|
||||
|
||||
ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
|
||||
const StringRef attribute_name) const final;
|
||||
const AttributeIDRef &attribute_id) const final;
|
||||
|
||||
WriteAttributeLookup try_get_for_write(GeometryComponent &component,
|
||||
const StringRef attribute_name) const final;
|
||||
const AttributeIDRef &attribute_id) const final;
|
||||
|
||||
bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final;
|
||||
bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final;
|
||||
|
||||
bool try_create(GeometryComponent &component,
|
||||
const StringRef attribute_name,
|
||||
const AttributeIDRef &attribute_id,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const AttributeInit &initializer) const final;
|
||||
@@ -231,10 +232,10 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
|
||||
}
|
||||
|
||||
ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
|
||||
const StringRef attribute_name) const final;
|
||||
const AttributeIDRef &attribute_id) const final;
|
||||
WriteAttributeLookup try_get_for_write(GeometryComponent &component,
|
||||
const StringRef attribute_name) const final;
|
||||
bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final;
|
||||
const AttributeIDRef &attribute_id) const final;
|
||||
bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final;
|
||||
bool foreach_attribute(const GeometryComponent &component,
|
||||
const AttributeForeachCallback callback) const final;
|
||||
void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const final;
|
||||
|
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "DNA_curve_types.h"
|
||||
|
||||
#include "BKE_anonymous_attribute.hh"
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_spline.hh"
|
||||
|
||||
@@ -330,13 +331,13 @@ void CurveEval::assert_valid_point_attributes() const
|
||||
return;
|
||||
}
|
||||
const int layer_len = splines_.first()->attributes.data.totlayer;
|
||||
Map<StringRefNull, AttributeMetaData> map;
|
||||
Map<blender::bke::AttributeIDRef, AttributeMetaData> map;
|
||||
for (const SplinePtr &spline : splines_) {
|
||||
BLI_assert(spline->attributes.data.totlayer == layer_len);
|
||||
spline->attributes.foreach_attribute(
|
||||
[&](StringRefNull name, const AttributeMetaData &meta_data) {
|
||||
[&](const blender::bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
|
||||
map.add_or_modify(
|
||||
name,
|
||||
attribute_id,
|
||||
[&](AttributeMetaData *map_data) {
|
||||
/* All unique attribute names should be added on the first spline. */
|
||||
BLI_assert(spline == splines_.first());
|
||||
|
@@ -46,6 +46,7 @@
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "BKE_anonymous_attribute.h"
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_customdata_file.h"
|
||||
#include "BKE_deform.h"
|
||||
@@ -2127,6 +2128,10 @@ bool CustomData_merge(const struct CustomData *source,
|
||||
if (flag & CD_FLAG_NOCOPY) {
|
||||
continue;
|
||||
}
|
||||
if (layer->anonymous_id &&
|
||||
!BKE_anonymous_attribute_id_has_strong_references(layer->anonymous_id)) {
|
||||
continue;
|
||||
}
|
||||
if (!(mask & CD_TYPE_AS_MASK(type))) {
|
||||
continue;
|
||||
}
|
||||
@@ -2166,6 +2171,11 @@ bool CustomData_merge(const struct CustomData *source,
|
||||
newlayer->active_mask = lastmask;
|
||||
newlayer->flag |= flag & (CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY);
|
||||
changed = true;
|
||||
|
||||
if (layer->anonymous_id != NULL) {
|
||||
BKE_anonymous_attribute_id_increment_weak(layer->anonymous_id);
|
||||
newlayer->anonymous_id = layer->anonymous_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2206,6 +2216,10 @@ static void customData_free_layer__internal(CustomDataLayer *layer, int totelem)
|
||||
{
|
||||
const LayerTypeInfo *typeInfo;
|
||||
|
||||
if (layer->anonymous_id != NULL) {
|
||||
BKE_anonymous_attribute_id_decrement_weak(layer->anonymous_id);
|
||||
layer->anonymous_id = NULL;
|
||||
}
|
||||
if (!(layer->flag & CD_FLAG_NOFREE) && layer->data) {
|
||||
typeInfo = layerType_getInfo(layer->type);
|
||||
|
||||
@@ -2649,6 +2663,27 @@ void *CustomData_add_layer_named(CustomData *data,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *CustomData_add_layer_anonymous(struct CustomData *data,
|
||||
int type,
|
||||
eCDAllocType alloctype,
|
||||
void *layerdata,
|
||||
int totelem,
|
||||
const AnonymousAttributeID *anonymous_id)
|
||||
{
|
||||
const char *name = BKE_anonymous_attribute_id_internal_name(anonymous_id);
|
||||
CustomDataLayer *layer = customData_add_layer__internal(
|
||||
data, type, alloctype, layerdata, totelem, name);
|
||||
CustomData_update_typemap(data);
|
||||
|
||||
if (layer == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BKE_anonymous_attribute_id_increment_weak(anonymous_id);
|
||||
layer->anonymous_id = anonymous_id;
|
||||
return layer->data;
|
||||
}
|
||||
|
||||
bool CustomData_free_layer(CustomData *data, int type, int totelem, int index)
|
||||
{
|
||||
const int index_first = CustomData_get_layer_index(data, type);
|
||||
@@ -2812,6 +2847,20 @@ void *CustomData_duplicate_referenced_layer_named(CustomData *data,
|
||||
return customData_duplicate_referenced_layer_index(data, layer_index, totelem);
|
||||
}
|
||||
|
||||
void *CustomData_duplicate_referenced_layer_anonymous(CustomData *data,
|
||||
const int type,
|
||||
const AnonymousAttributeID *anonymous_id,
|
||||
const int totelem)
|
||||
{
|
||||
for (int i = 0; i < data->totlayer; i++) {
|
||||
if (data->layers[i].anonymous_id == anonymous_id) {
|
||||
return customData_duplicate_referenced_layer_index(data, i, totelem);
|
||||
}
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CustomData_duplicate_referenced_layers(CustomData *data, int totelem)
|
||||
{
|
||||
for (int i = 0; i < data->totlayer; i++) {
|
||||
@@ -4244,7 +4293,8 @@ void CustomData_blend_write_prepare(CustomData *data,
|
||||
|
||||
for (i = 0, j = 0; i < totlayer; i++) {
|
||||
CustomDataLayer *layer = &data->layers[i];
|
||||
if (layer->flag & CD_FLAG_NOCOPY) { /* Layers with this flag set are not written to file. */
|
||||
/* Layers with this flag set are not written to file. */
|
||||
if ((layer->flag & CD_FLAG_NOCOPY) || layer->anonymous_id != NULL) {
|
||||
data->totlayer--;
|
||||
// CLOG_WARN(&LOG, "skipping layer %p (%s)", layer, layer->name);
|
||||
}
|
||||
|
@@ -892,7 +892,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
|
||||
|
||||
public:
|
||||
ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
|
||||
const StringRef attribute_name) const final
|
||||
const AttributeIDRef &attribute_id) const final
|
||||
{
|
||||
const CurveEval *curve = get_curve_from_component_for_read(component);
|
||||
if (curve == nullptr || curve->splines().size() == 0) {
|
||||
@@ -902,13 +902,13 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
|
||||
Span<SplinePtr> splines = curve->splines();
|
||||
Vector<GSpan> spans; /* GSpan has no default constructor. */
|
||||
spans.reserve(splines.size());
|
||||
std::optional<GSpan> first_span = splines[0]->attributes.get_for_read(attribute_name);
|
||||
std::optional<GSpan> first_span = splines[0]->attributes.get_for_read(attribute_id);
|
||||
if (!first_span) {
|
||||
return {};
|
||||
}
|
||||
spans.append(*first_span);
|
||||
for (const int i : IndexRange(1, splines.size() - 1)) {
|
||||
std::optional<GSpan> span = splines[i]->attributes.get_for_read(attribute_name);
|
||||
std::optional<GSpan> span = splines[i]->attributes.get_for_read(attribute_id);
|
||||
if (!span) {
|
||||
/* All splines should have the same set of data layers. It would be possible to recover
|
||||
* here and return partial data instead, but that would add a lot of complexity for a
|
||||
@@ -945,7 +945,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
|
||||
|
||||
/* This function is almost the same as #try_get_for_read, but without const. */
|
||||
WriteAttributeLookup try_get_for_write(GeometryComponent &component,
|
||||
const StringRef attribute_name) const final
|
||||
const AttributeIDRef &attribute_id) const final
|
||||
{
|
||||
CurveEval *curve = get_curve_from_component_for_write(component);
|
||||
if (curve == nullptr || curve->splines().size() == 0) {
|
||||
@@ -955,13 +955,13 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
|
||||
MutableSpan<SplinePtr> splines = curve->splines();
|
||||
Vector<GMutableSpan> spans; /* GMutableSpan has no default constructor. */
|
||||
spans.reserve(splines.size());
|
||||
std::optional<GMutableSpan> first_span = splines[0]->attributes.get_for_write(attribute_name);
|
||||
std::optional<GMutableSpan> first_span = splines[0]->attributes.get_for_write(attribute_id);
|
||||
if (!first_span) {
|
||||
return {};
|
||||
}
|
||||
spans.append(*first_span);
|
||||
for (const int i : IndexRange(1, splines.size() - 1)) {
|
||||
std::optional<GMutableSpan> span = splines[i]->attributes.get_for_write(attribute_name);
|
||||
std::optional<GMutableSpan> span = splines[i]->attributes.get_for_write(attribute_id);
|
||||
if (!span) {
|
||||
/* All splines should have the same set of data layers. It would be possible to recover
|
||||
* here and return partial data instead, but that would add a lot of complexity for a
|
||||
@@ -996,7 +996,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
|
||||
return attribute;
|
||||
}
|
||||
|
||||
bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final
|
||||
bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final
|
||||
{
|
||||
CurveEval *curve = get_curve_from_component_for_write(component);
|
||||
if (curve == nullptr) {
|
||||
@@ -1006,7 +1006,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
|
||||
/* Reuse the boolean for all splines; we expect all splines to have the same attributes. */
|
||||
bool layer_freed = false;
|
||||
for (SplinePtr &spline : curve->splines()) {
|
||||
layer_freed = spline->attributes.remove(attribute_name);
|
||||
layer_freed = spline->attributes.remove(attribute_id);
|
||||
}
|
||||
return layer_freed;
|
||||
}
|
||||
@@ -1034,7 +1034,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
|
||||
}
|
||||
|
||||
bool try_create(GeometryComponent &component,
|
||||
const StringRef attribute_name,
|
||||
const AttributeIDRef &attribute_id,
|
||||
const AttributeDomain domain,
|
||||
const CustomDataType data_type,
|
||||
const AttributeInit &initializer) const final
|
||||
@@ -1053,7 +1053,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
|
||||
/* First check the one case that allows us to avoid copying the input data. */
|
||||
if (splines.size() == 1 && initializer.type == AttributeInit::Type::MoveArray) {
|
||||
void *source_data = static_cast<const AttributeInitMove &>(initializer).data;
|
||||
if (!splines[0]->attributes.create_by_move(attribute_name, data_type, source_data)) {
|
||||
if (!splines[0]->attributes.create_by_move(attribute_id, data_type, source_data)) {
|
||||
MEM_freeN(source_data);
|
||||
return false;
|
||||
}
|
||||
@@ -1062,7 +1062,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
|
||||
|
||||
/* Otherwise just create a custom data layer on each of the splines. */
|
||||
for (const int i : splines.index_range()) {
|
||||
if (!splines[i]->attributes.create(attribute_name, data_type)) {
|
||||
if (!splines[i]->attributes.create(attribute_id, data_type)) {
|
||||
/* If attribute creation fails on one of the splines, we cannot leave the custom data
|
||||
* layers in the previous splines around, so delete them before returning. However,
|
||||
* this is not an expected case. */
|
||||
@@ -1076,7 +1076,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
|
||||
return true;
|
||||
}
|
||||
|
||||
WriteAttributeLookup write_attribute = this->try_get_for_write(component, attribute_name);
|
||||
WriteAttributeLookup write_attribute = this->try_get_for_write(component, attribute_id);
|
||||
/* We just created the attribute, it should exist. */
|
||||
BLI_assert(write_attribute);
|
||||
|
||||
|
@@ -818,16 +818,20 @@ class VArray_For_VertexWeights final : public VArray<float> {
|
||||
class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
|
||||
public:
|
||||
ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
|
||||
const StringRef attribute_name) const final
|
||||
const AttributeIDRef &attribute_id) const final
|
||||
{
|
||||
BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
|
||||
if (!attribute_id.is_named()) {
|
||||
return {};
|
||||
}
|
||||
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
|
||||
const Mesh *mesh = mesh_component.get_for_read();
|
||||
if (mesh == nullptr) {
|
||||
return {};
|
||||
}
|
||||
std::string name = attribute_id.name();
|
||||
const int vertex_group_index = BLI_findstringindex(
|
||||
&mesh->vertex_group_names, attribute_name.data(), offsetof(bDeformGroup, name));
|
||||
&mesh->vertex_group_names, name.c_str(), offsetof(bDeformGroup, name));
|
||||
if (vertex_group_index < 0) {
|
||||
return {};
|
||||
}
|
||||
@@ -843,17 +847,21 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
|
||||
}
|
||||
|
||||
WriteAttributeLookup try_get_for_write(GeometryComponent &component,
|
||||
const StringRef attribute_name) const final
|
||||
const AttributeIDRef &attribute_id) const final
|
||||
{
|
||||
BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
|
||||
if (!attribute_id.is_named()) {
|
||||
return {};
|
||||
}
|
||||
MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
|
||||
Mesh *mesh = mesh_component.get_for_write();
|
||||
if (mesh == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const std::string name = attribute_id.name();
|
||||
const int vertex_group_index = BLI_findstringindex(
|
||||
&mesh->vertex_group_names, attribute_name.data(), offsetof(bDeformGroup, name));
|
||||
&mesh->vertex_group_names, name.c_str(), offsetof(bDeformGroup, name));
|
||||
if (vertex_group_index < 0) {
|
||||
return {};
|
||||
}
|
||||
@@ -872,17 +880,21 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
|
||||
ATTR_DOMAIN_POINT};
|
||||
}
|
||||
|
||||
bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final
|
||||
bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final
|
||||
{
|
||||
BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
|
||||
if (!attribute_id.is_named()) {
|
||||
return false;
|
||||
}
|
||||
MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
|
||||
Mesh *mesh = mesh_component.get_for_write();
|
||||
if (mesh == nullptr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::string name = attribute_id.name();
|
||||
const int vertex_group_index = BLI_findstringindex(
|
||||
&mesh->vertex_group_names, attribute_name.data(), offsetof(bDeformGroup, name));
|
||||
&mesh->vertex_group_names, name.c_str(), offsetof(bDeformGroup, name));
|
||||
if (vertex_group_index < 0) {
|
||||
return false;
|
||||
}
|
||||
|
@@ -319,7 +319,7 @@ void geometry_set_instances_attribute_foreach(const GeometrySet &geometry_set,
|
||||
void geometry_set_gather_instances_attribute_info(Span<GeometryInstanceGroup> set_groups,
|
||||
Span<GeometryComponentType> component_types,
|
||||
const Set<std::string> &ignored_attributes,
|
||||
Map<std::string, AttributeKind> &r_attributes)
|
||||
Map<AttributeIDRef, AttributeKind> &r_attributes)
|
||||
{
|
||||
for (const GeometryInstanceGroup &set_group : set_groups) {
|
||||
const GeometrySet &set = set_group.geometry_set;
|
||||
@@ -329,23 +329,24 @@ void geometry_set_gather_instances_attribute_info(Span<GeometryInstanceGroup> se
|
||||
}
|
||||
const GeometryComponent &component = *set.get_component_for_read(component_type);
|
||||
|
||||
component.attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) {
|
||||
if (ignored_attributes.contains(name)) {
|
||||
return true;
|
||||
}
|
||||
auto add_info = [&](AttributeKind *attribute_kind) {
|
||||
attribute_kind->domain = meta_data.domain;
|
||||
attribute_kind->data_type = meta_data.data_type;
|
||||
};
|
||||
auto modify_info = [&](AttributeKind *attribute_kind) {
|
||||
attribute_kind->domain = meta_data.domain; /* TODO: Use highest priority domain. */
|
||||
attribute_kind->data_type = bke::attribute_data_type_highest_complexity(
|
||||
{attribute_kind->data_type, meta_data.data_type});
|
||||
};
|
||||
component.attribute_foreach(
|
||||
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
|
||||
if (attribute_id.is_named() && ignored_attributes.contains(attribute_id.name())) {
|
||||
return true;
|
||||
}
|
||||
auto add_info = [&](AttributeKind *attribute_kind) {
|
||||
attribute_kind->domain = meta_data.domain;
|
||||
attribute_kind->data_type = meta_data.data_type;
|
||||
};
|
||||
auto modify_info = [&](AttributeKind *attribute_kind) {
|
||||
attribute_kind->domain = meta_data.domain; /* TODO: Use highest priority domain. */
|
||||
attribute_kind->data_type = bke::attribute_data_type_highest_complexity(
|
||||
{attribute_kind->data_type, meta_data.data_type});
|
||||
};
|
||||
|
||||
r_attributes.add_or_modify(name, add_info, modify_info);
|
||||
return true;
|
||||
});
|
||||
r_attributes.add_or_modify(attribute_id, add_info, modify_info);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -500,11 +501,11 @@ static Mesh *join_mesh_topology_and_builtin_attributes(Span<GeometryInstanceGrou
|
||||
|
||||
static void join_attributes(Span<GeometryInstanceGroup> set_groups,
|
||||
Span<GeometryComponentType> component_types,
|
||||
const Map<std::string, AttributeKind> &attribute_info,
|
||||
const Map<AttributeIDRef, AttributeKind> &attribute_info,
|
||||
GeometryComponent &result)
|
||||
{
|
||||
for (Map<std::string, AttributeKind>::Item entry : attribute_info.items()) {
|
||||
StringRef name = entry.key;
|
||||
for (Map<AttributeIDRef, AttributeKind>::Item entry : attribute_info.items()) {
|
||||
const AttributeIDRef attribute_id = entry.key;
|
||||
const AttributeDomain domain_output = entry.value.domain;
|
||||
const CustomDataType data_type_output = entry.value.data_type;
|
||||
const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(data_type_output);
|
||||
@@ -512,7 +513,7 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups,
|
||||
|
||||
result.attribute_try_create(
|
||||
entry.key, domain_output, data_type_output, AttributeInitDefault());
|
||||
WriteAttributeLookup write_attribute = result.attribute_try_get_for_write(name);
|
||||
WriteAttributeLookup write_attribute = result.attribute_try_get_for_write(attribute_id);
|
||||
if (!write_attribute || &write_attribute.varray->type() != cpp_type ||
|
||||
write_attribute.domain != domain_output) {
|
||||
continue;
|
||||
@@ -531,7 +532,7 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups,
|
||||
continue; /* Domain size is 0, so no need to increment the offset. */
|
||||
}
|
||||
GVArrayPtr source_attribute = component.attribute_try_get_for_read(
|
||||
name, domain_output, data_type_output);
|
||||
attribute_id, domain_output, data_type_output);
|
||||
|
||||
if (source_attribute) {
|
||||
fn::GVArray_GSpan src_span{*source_attribute};
|
||||
@@ -641,7 +642,7 @@ static void join_instance_groups_mesh(Span<GeometryInstanceGroup> set_groups,
|
||||
}
|
||||
|
||||
/* Don't copy attributes that are stored directly in the mesh data structs. */
|
||||
Map<std::string, AttributeKind> attributes;
|
||||
Map<AttributeIDRef, AttributeKind> attributes;
|
||||
geometry_set_gather_instances_attribute_info(
|
||||
set_groups,
|
||||
component_types,
|
||||
@@ -662,7 +663,7 @@ static void join_instance_groups_pointcloud(Span<GeometryInstanceGroup> set_grou
|
||||
PointCloudComponent &dst_component = result.get_component_for_write<PointCloudComponent>();
|
||||
dst_component.replace(new_pointcloud);
|
||||
|
||||
Map<std::string, AttributeKind> attributes;
|
||||
Map<AttributeIDRef, AttributeKind> attributes;
|
||||
geometry_set_gather_instances_attribute_info(
|
||||
set_groups, {GEO_COMPONENT_TYPE_POINT_CLOUD}, {"position"}, attributes);
|
||||
join_attributes(set_groups,
|
||||
@@ -696,7 +697,7 @@ static void join_instance_groups_curve(Span<GeometryInstanceGroup> set_groups, G
|
||||
CurveComponent &dst_component = result.get_component_for_write<CurveComponent>();
|
||||
dst_component.replace(curve);
|
||||
|
||||
Map<std::string, AttributeKind> attributes;
|
||||
Map<AttributeIDRef, AttributeKind> attributes;
|
||||
geometry_set_gather_instances_attribute_info(
|
||||
set_groups,
|
||||
{GEO_COMPONENT_TYPE_CURVE},
|
||||
|
@@ -45,15 +45,20 @@ namespace blender::ed::spreadsheet {
|
||||
void GeometryDataSource::foreach_default_column_ids(
|
||||
FunctionRef<void(const SpreadsheetColumnID &)> fn) const
|
||||
{
|
||||
component_->attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) {
|
||||
if (meta_data.domain != domain_) {
|
||||
return true;
|
||||
}
|
||||
SpreadsheetColumnID column_id;
|
||||
column_id.name = (char *)name.c_str();
|
||||
fn(column_id);
|
||||
return true;
|
||||
});
|
||||
component_->attribute_foreach(
|
||||
[&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
|
||||
if (meta_data.domain != domain_) {
|
||||
return true;
|
||||
}
|
||||
if (attribute_id.is_anonymous()) {
|
||||
return true;
|
||||
}
|
||||
SpreadsheetColumnID column_id;
|
||||
std::string name = attribute_id.name();
|
||||
column_id.name = (char *)name.c_str();
|
||||
fn(column_id);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
|
||||
|
@@ -31,6 +31,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct AnonymousAttributeID;
|
||||
|
||||
/** Descriptor and storage for a custom data layer. */
|
||||
typedef struct CustomDataLayer {
|
||||
/** Type of data in layer. */
|
||||
@@ -53,6 +55,9 @@ typedef struct CustomDataLayer {
|
||||
char name[64];
|
||||
/** Layer data. */
|
||||
void *data;
|
||||
/** Run-time identifier for this layer. If no
|
||||
* one has a strong reference to this id anymore, the layer can be removed. */
|
||||
const struct AnonymousAttributeID *anonymous_id;
|
||||
} CustomDataLayer;
|
||||
|
||||
#define MAX_CUSTOMDATA_LAYER_NAME 64
|
||||
|
@@ -32,10 +32,13 @@ struct ModifierData;
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
using bke::AttributeIDRef;
|
||||
using bke::geometry_set_realize_instances;
|
||||
using bke::OutputAttribute;
|
||||
using bke::OutputAttribute_Typed;
|
||||
using bke::ReadAttributeLookup;
|
||||
using bke::StrongAnonymousAttributeID;
|
||||
using bke::WeakAnonymousAttributeID;
|
||||
using bke::WriteAttributeLookup;
|
||||
using fn::CPPType;
|
||||
using fn::GMutablePointer;
|
||||
|
@@ -76,7 +76,7 @@ struct CurveToPointsResults {
|
||||
MutableSpan<float> radii;
|
||||
MutableSpan<float> tilts;
|
||||
|
||||
Map<std::string, GMutableSpan> point_attributes;
|
||||
Map<AttributeIDRef, GMutableSpan> point_attributes;
|
||||
|
||||
MutableSpan<float3> tangents;
|
||||
MutableSpan<float3> normals;
|
||||
|
@@ -60,25 +60,26 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component,
|
||||
Span<int> offsets,
|
||||
PointCloudComponent &points)
|
||||
{
|
||||
curve_component.attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) {
|
||||
if (meta_data.domain != ATTR_DOMAIN_CURVE) {
|
||||
return true;
|
||||
}
|
||||
GVArrayPtr spline_attribute = curve_component.attribute_get_for_read(
|
||||
name, ATTR_DOMAIN_CURVE, meta_data.data_type);
|
||||
curve_component.attribute_foreach(
|
||||
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
|
||||
if (meta_data.domain != ATTR_DOMAIN_CURVE) {
|
||||
return true;
|
||||
}
|
||||
GVArrayPtr spline_attribute = curve_component.attribute_get_for_read(
|
||||
attribute_id, ATTR_DOMAIN_CURVE, meta_data.data_type);
|
||||
|
||||
OutputAttribute result_attribute = points.attribute_try_get_for_output_only(
|
||||
name, ATTR_DOMAIN_POINT, meta_data.data_type);
|
||||
GMutableSpan result = result_attribute.as_span();
|
||||
OutputAttribute result_attribute = points.attribute_try_get_for_output_only(
|
||||
attribute_id, ATTR_DOMAIN_POINT, meta_data.data_type);
|
||||
GMutableSpan result = result_attribute.as_span();
|
||||
|
||||
/* Only copy the attributes of splines in the offsets. */
|
||||
for (const int i : offsets.index_range()) {
|
||||
spline_attribute->get(offsets[i], result[i]);
|
||||
}
|
||||
/* Only copy the attributes of splines in the offsets. */
|
||||
for (const int i : offsets.index_range()) {
|
||||
spline_attribute->get(offsets[i], result[i]);
|
||||
}
|
||||
|
||||
result_attribute.save();
|
||||
return true;
|
||||
});
|
||||
result_attribute.save();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,20 +129,20 @@ static void copy_endpoint_attributes(Span<SplinePtr> splines,
|
||||
|
||||
/* Copy the point attribute data over. */
|
||||
for (const auto &item : start_data.point_attributes.items()) {
|
||||
const StringRef name = item.key;
|
||||
const AttributeIDRef attribute_id = item.key;
|
||||
GMutableSpan point_span = item.value;
|
||||
|
||||
BLI_assert(spline.attributes.get_for_read(name));
|
||||
GSpan spline_span = *spline.attributes.get_for_read(name);
|
||||
BLI_assert(spline.attributes.get_for_read(attribute_id));
|
||||
GSpan spline_span = *spline.attributes.get_for_read(attribute_id);
|
||||
blender::fn::GVArray_For_GSpan(spline_span).get(0, point_span[i]);
|
||||
}
|
||||
|
||||
for (const auto &item : end_data.point_attributes.items()) {
|
||||
const StringRef name = item.key;
|
||||
const AttributeIDRef attribute_id = item.key;
|
||||
GMutableSpan point_span = item.value;
|
||||
|
||||
BLI_assert(spline.attributes.get_for_read(name));
|
||||
GSpan spline_span = *spline.attributes.get_for_read(name);
|
||||
BLI_assert(spline.attributes.get_for_read(attribute_id));
|
||||
GSpan spline_span = *spline.attributes.get_for_read(attribute_id);
|
||||
blender::fn::GVArray_For_GSpan(spline_span).get(spline.size() - 1, point_span[i]);
|
||||
}
|
||||
}
|
||||
|
@@ -88,14 +88,14 @@ static SplinePtr resample_spline(const Spline &input_spline, const int count)
|
||||
input_spline.radii().first());
|
||||
output_spline->attributes.reallocate(1);
|
||||
input_spline.attributes.foreach_attribute(
|
||||
[&](StringRefNull name, const AttributeMetaData &meta_data) {
|
||||
std::optional<GSpan> src = input_spline.attributes.get_for_read(name);
|
||||
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
|
||||
std::optional<GSpan> src = input_spline.attributes.get_for_read(attribute_id);
|
||||
BLI_assert(src);
|
||||
if (!output_spline->attributes.create(name, meta_data.data_type)) {
|
||||
if (!output_spline->attributes.create(attribute_id, meta_data.data_type)) {
|
||||
BLI_assert_unreachable();
|
||||
return false;
|
||||
}
|
||||
std::optional<GMutableSpan> dst = output_spline->attributes.get_for_write(name);
|
||||
std::optional<GMutableSpan> dst = output_spline->attributes.get_for_write(attribute_id);
|
||||
if (!dst) {
|
||||
BLI_assert_unreachable();
|
||||
return false;
|
||||
@@ -126,15 +126,15 @@ static SplinePtr resample_spline(const Spline &input_spline, const int count)
|
||||
|
||||
output_spline->attributes.reallocate(count);
|
||||
input_spline.attributes.foreach_attribute(
|
||||
[&](StringRefNull name, const AttributeMetaData &meta_data) {
|
||||
std::optional<GSpan> input_attribute = input_spline.attributes.get_for_read(name);
|
||||
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
|
||||
std::optional<GSpan> input_attribute = input_spline.attributes.get_for_read(attribute_id);
|
||||
BLI_assert(input_attribute);
|
||||
if (!output_spline->attributes.create(name, meta_data.data_type)) {
|
||||
if (!output_spline->attributes.create(attribute_id, meta_data.data_type)) {
|
||||
BLI_assert_unreachable();
|
||||
return false;
|
||||
}
|
||||
std::optional<GMutableSpan> output_attribute = output_spline->attributes.get_for_write(
|
||||
name);
|
||||
attribute_id);
|
||||
if (!output_attribute) {
|
||||
BLI_assert_unreachable();
|
||||
return false;
|
||||
|
@@ -87,9 +87,9 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params)
|
||||
reverse_data<float>(splines[i]->tilts());
|
||||
|
||||
splines[i]->attributes.foreach_attribute(
|
||||
[&](StringRefNull name, const AttributeMetaData &meta_data) {
|
||||
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
|
||||
std::optional<blender::fn::GMutableSpan> output_attribute =
|
||||
splines[i]->attributes.get_for_write(name);
|
||||
splines[i]->attributes.get_for_write(attribute_id);
|
||||
if (!output_attribute) {
|
||||
BLI_assert_unreachable();
|
||||
return false;
|
||||
|
@@ -78,14 +78,14 @@ template<typename CopyFn>
|
||||
static void copy_attributes(const Spline &input_spline, Spline &output_spline, CopyFn copy_fn)
|
||||
{
|
||||
input_spline.attributes.foreach_attribute(
|
||||
[&](StringRefNull name, const AttributeMetaData &meta_data) {
|
||||
std::optional<GSpan> src = input_spline.attributes.get_for_read(name);
|
||||
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
|
||||
std::optional<GSpan> src = input_spline.attributes.get_for_read(attribute_id);
|
||||
BLI_assert(src);
|
||||
if (!output_spline.attributes.create(name, meta_data.data_type)) {
|
||||
if (!output_spline.attributes.create(attribute_id, meta_data.data_type)) {
|
||||
BLI_assert_unreachable();
|
||||
return false;
|
||||
}
|
||||
std::optional<GMutableSpan> dst = output_spline.attributes.get_for_write(name);
|
||||
std::optional<GMutableSpan> dst = output_spline.attributes.get_for_write(attribute_id);
|
||||
if (!dst) {
|
||||
BLI_assert_unreachable();
|
||||
return false;
|
||||
|
@@ -287,16 +287,16 @@ static void subdivide_dynamic_attributes(const Spline &src_spline,
|
||||
{
|
||||
const bool is_cyclic = src_spline.is_cyclic();
|
||||
src_spline.attributes.foreach_attribute(
|
||||
[&](StringRefNull name, const AttributeMetaData &meta_data) {
|
||||
std::optional<GSpan> src = src_spline.attributes.get_for_read(name);
|
||||
[&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
|
||||
std::optional<GSpan> src = src_spline.attributes.get_for_read(attribute_id);
|
||||
BLI_assert(src);
|
||||
|
||||
if (!dst_spline.attributes.create(name, meta_data.data_type)) {
|
||||
if (!dst_spline.attributes.create(attribute_id, meta_data.data_type)) {
|
||||
/* Since the source spline of the same type had the attribute, adding it should work. */
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
std::optional<GMutableSpan> dst = dst_spline.attributes.get_for_write(name);
|
||||
std::optional<GMutableSpan> dst = dst_spline.attributes.get_for_write(attribute_id);
|
||||
BLI_assert(dst);
|
||||
|
||||
attribute_math::convert_to_static_type(dst->type(), [&](auto dummy) {
|
||||
|
@@ -119,21 +119,21 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams ¶ms,
|
||||
}
|
||||
|
||||
static GMutableSpan create_attribute_and_retrieve_span(PointCloudComponent &points,
|
||||
const StringRef name,
|
||||
const AttributeIDRef &attribute_id,
|
||||
const CustomDataType data_type)
|
||||
{
|
||||
points.attribute_try_create(name, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault());
|
||||
WriteAttributeLookup attribute = points.attribute_try_get_for_write(name);
|
||||
points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault());
|
||||
WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id);
|
||||
BLI_assert(attribute);
|
||||
return attribute.varray->get_internal_span();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static MutableSpan<T> create_attribute_and_retrieve_span(PointCloudComponent &points,
|
||||
const StringRef name)
|
||||
const AttributeIDRef &attribute_id)
|
||||
{
|
||||
GMutableSpan attribute = create_attribute_and_retrieve_span(
|
||||
points, name, bke::cpp_type_to_custom_data_type(CPPType::get<T>()));
|
||||
points, attribute_id, bke::cpp_type_to_custom_data_type(CPPType::get<T>()));
|
||||
return attribute.typed<T>();
|
||||
}
|
||||
|
||||
@@ -151,9 +151,10 @@ CurveToPointsResults curve_to_points_create_result_attributes(PointCloudComponen
|
||||
/* Because of the invariants of the curve component, we use the attributes of the
|
||||
* first spline as a representative for the attribute meta data all splines. */
|
||||
curve.splines().first()->attributes.foreach_attribute(
|
||||
[&](StringRefNull name, const AttributeMetaData &meta_data) {
|
||||
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
|
||||
attributes.point_attributes.add_new(
|
||||
name, create_attribute_and_retrieve_span(points, name, meta_data.data_type));
|
||||
attribute_id,
|
||||
create_attribute_and_retrieve_span(points, attribute_id, meta_data.data_type));
|
||||
return true;
|
||||
},
|
||||
ATTR_DOMAIN_POINT);
|
||||
@@ -183,12 +184,12 @@ static void copy_evaluated_point_attributes(Span<SplinePtr> splines,
|
||||
spline.interpolate_to_evaluated(spline.radii())->materialize(data.radii.slice(offset, size));
|
||||
spline.interpolate_to_evaluated(spline.tilts())->materialize(data.tilts.slice(offset, size));
|
||||
|
||||
for (const Map<std::string, GMutableSpan>::Item &item : data.point_attributes.items()) {
|
||||
const StringRef name = item.key;
|
||||
for (const Map<AttributeIDRef, GMutableSpan>::Item &item : data.point_attributes.items()) {
|
||||
const AttributeIDRef attribute_id = item.key;
|
||||
GMutableSpan point_span = item.value;
|
||||
|
||||
BLI_assert(spline.attributes.get_for_read(name));
|
||||
GSpan spline_span = *spline.attributes.get_for_read(name);
|
||||
BLI_assert(spline.attributes.get_for_read(attribute_id));
|
||||
GSpan spline_span = *spline.attributes.get_for_read(attribute_id);
|
||||
|
||||
spline.interpolate_to_evaluated(spline_span)
|
||||
->materialize(point_span.slice(offset, size).data());
|
||||
@@ -226,12 +227,12 @@ static void copy_uniform_sample_point_attributes(Span<SplinePtr> splines,
|
||||
uniform_samples,
|
||||
data.tilts.slice(offset, size));
|
||||
|
||||
for (const Map<std::string, GMutableSpan>::Item &item : data.point_attributes.items()) {
|
||||
const StringRef name = item.key;
|
||||
for (const Map<AttributeIDRef, GMutableSpan>::Item &item : data.point_attributes.items()) {
|
||||
const AttributeIDRef attribute_id = item.key;
|
||||
GMutableSpan point_span = item.value;
|
||||
|
||||
BLI_assert(spline.attributes.get_for_read(name));
|
||||
GSpan spline_span = *spline.attributes.get_for_read(name);
|
||||
BLI_assert(spline.attributes.get_for_read(attribute_id));
|
||||
GSpan spline_span = *spline.attributes.get_for_read(attribute_id);
|
||||
|
||||
spline.sample_with_index_factors(*spline.interpolate_to_evaluated(spline_span),
|
||||
uniform_samples,
|
||||
@@ -261,31 +262,32 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component,
|
||||
Span<int> offsets,
|
||||
PointCloudComponent &points)
|
||||
{
|
||||
curve_component.attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) {
|
||||
if (meta_data.domain != ATTR_DOMAIN_CURVE) {
|
||||
return true;
|
||||
}
|
||||
GVArrayPtr spline_attribute = curve_component.attribute_get_for_read(
|
||||
name, ATTR_DOMAIN_CURVE, meta_data.data_type);
|
||||
const CPPType &type = spline_attribute->type();
|
||||
curve_component.attribute_foreach(
|
||||
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
|
||||
if (meta_data.domain != ATTR_DOMAIN_CURVE) {
|
||||
return true;
|
||||
}
|
||||
GVArrayPtr spline_attribute = curve_component.attribute_get_for_read(
|
||||
attribute_id, ATTR_DOMAIN_CURVE, meta_data.data_type);
|
||||
const CPPType &type = spline_attribute->type();
|
||||
|
||||
OutputAttribute result_attribute = points.attribute_try_get_for_output_only(
|
||||
name, ATTR_DOMAIN_POINT, meta_data.data_type);
|
||||
GMutableSpan result = result_attribute.as_span();
|
||||
OutputAttribute result_attribute = points.attribute_try_get_for_output_only(
|
||||
attribute_id, ATTR_DOMAIN_POINT, meta_data.data_type);
|
||||
GMutableSpan result = result_attribute.as_span();
|
||||
|
||||
for (const int i : IndexRange(spline_attribute->size())) {
|
||||
const int offset = offsets[i];
|
||||
const int size = offsets[i + 1] - offsets[i];
|
||||
if (size != 0) {
|
||||
BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
|
||||
spline_attribute->get(i, buffer);
|
||||
type.fill_assign_n(buffer, result[offset], size);
|
||||
}
|
||||
}
|
||||
for (const int i : IndexRange(spline_attribute->size())) {
|
||||
const int offset = offsets[i];
|
||||
const int size = offsets[i + 1] - offsets[i];
|
||||
if (size != 0) {
|
||||
BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
|
||||
spline_attribute->get(i, buffer);
|
||||
type.fill_assign_n(buffer, result[offset], size);
|
||||
}
|
||||
}
|
||||
|
||||
result_attribute.save();
|
||||
return true;
|
||||
});
|
||||
result_attribute.save();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void curve_create_default_rotation_attribute(Span<float3> tangents,
|
||||
|
@@ -162,8 +162,8 @@ static void trim_poly_spline(Spline &spline,
|
||||
linear_trim_data<float>(start, end, spline.tilts());
|
||||
|
||||
spline.attributes.foreach_attribute(
|
||||
[&](StringRefNull name, const AttributeMetaData &UNUSED(meta_data)) {
|
||||
std::optional<GMutableSpan> src = spline.attributes.get_for_write(name);
|
||||
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &UNUSED(meta_data)) {
|
||||
std::optional<GMutableSpan> src = spline.attributes.get_for_write(attribute_id);
|
||||
BLI_assert(src);
|
||||
attribute_math::convert_to_static_type(src->type(), [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
@@ -197,14 +197,14 @@ static PolySpline trim_nurbs_spline(const Spline &spline,
|
||||
|
||||
/* Copy generic attribute data. */
|
||||
spline.attributes.foreach_attribute(
|
||||
[&](StringRefNull name, const AttributeMetaData &meta_data) {
|
||||
std::optional<GSpan> src = spline.attributes.get_for_read(name);
|
||||
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
|
||||
std::optional<GSpan> src = spline.attributes.get_for_read(attribute_id);
|
||||
BLI_assert(src);
|
||||
if (!new_spline.attributes.create(name, meta_data.data_type)) {
|
||||
if (!new_spline.attributes.create(attribute_id, meta_data.data_type)) {
|
||||
BLI_assert_unreachable();
|
||||
return false;
|
||||
}
|
||||
std::optional<GMutableSpan> dst = new_spline.attributes.get_for_write(name);
|
||||
std::optional<GMutableSpan> dst = new_spline.attributes.get_for_write(attribute_id);
|
||||
BLI_assert(dst);
|
||||
|
||||
attribute_math::convert_to_static_type(src->type(), [&](auto dummy) {
|
||||
@@ -253,8 +253,8 @@ static void trim_bezier_spline(Spline &spline,
|
||||
linear_trim_data<float>(start, end, bezier_spline.radii());
|
||||
linear_trim_data<float>(start, end, bezier_spline.tilts());
|
||||
spline.attributes.foreach_attribute(
|
||||
[&](StringRefNull name, const AttributeMetaData &UNUSED(meta_data)) {
|
||||
std::optional<GMutableSpan> src = spline.attributes.get_for_write(name);
|
||||
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &UNUSED(meta_data)) {
|
||||
std::optional<GMutableSpan> src = spline.attributes.get_for_write(attribute_id);
|
||||
BLI_assert(src);
|
||||
attribute_math::convert_to_static_type(src->type(), [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
|
@@ -97,16 +97,16 @@ static void copy_dynamic_attributes(const CustomDataAttributes &src,
|
||||
const IndexMask mask)
|
||||
{
|
||||
src.foreach_attribute(
|
||||
[&](StringRefNull name, const AttributeMetaData &meta_data) {
|
||||
std::optional<GSpan> src_attribute = src.get_for_read(name);
|
||||
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
|
||||
std::optional<GSpan> src_attribute = src.get_for_read(attribute_id);
|
||||
BLI_assert(src_attribute);
|
||||
|
||||
if (!dst.create(name, meta_data.data_type)) {
|
||||
if (!dst.create(attribute_id, meta_data.data_type)) {
|
||||
/* Since the source spline of the same type had the attribute, adding it should work. */
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
std::optional<GMutableSpan> new_attribute = dst.get_for_write(name);
|
||||
std::optional<GMutableSpan> new_attribute = dst.get_for_write(attribute_id);
|
||||
BLI_assert(new_attribute);
|
||||
|
||||
attribute_math::convert_to_static_type(new_attribute->type(), [&](auto dummy) {
|
||||
|
@@ -161,34 +161,35 @@ static Array<const GeometryComponent *> to_base_components(Span<const Component
|
||||
return components;
|
||||
}
|
||||
|
||||
static Map<std::string, AttributeMetaData> get_final_attribute_info(
|
||||
static Map<AttributeIDRef, AttributeMetaData> get_final_attribute_info(
|
||||
Span<const GeometryComponent *> components, Span<StringRef> ignored_attributes)
|
||||
{
|
||||
Map<std::string, AttributeMetaData> info;
|
||||
Map<AttributeIDRef, AttributeMetaData> info;
|
||||
|
||||
for (const GeometryComponent *component : components) {
|
||||
component->attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) {
|
||||
if (ignored_attributes.contains(name)) {
|
||||
return true;
|
||||
}
|
||||
info.add_or_modify(
|
||||
name,
|
||||
[&](AttributeMetaData *meta_data_final) { *meta_data_final = meta_data; },
|
||||
[&](AttributeMetaData *meta_data_final) {
|
||||
meta_data_final->data_type = blender::bke::attribute_data_type_highest_complexity(
|
||||
{meta_data_final->data_type, meta_data.data_type});
|
||||
meta_data_final->domain = blender::bke::attribute_domain_highest_priority(
|
||||
{meta_data_final->domain, meta_data.domain});
|
||||
});
|
||||
return true;
|
||||
});
|
||||
component->attribute_foreach(
|
||||
[&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
|
||||
if (attribute_id.is_named() && ignored_attributes.contains(attribute_id.name())) {
|
||||
return true;
|
||||
}
|
||||
info.add_or_modify(
|
||||
attribute_id,
|
||||
[&](AttributeMetaData *meta_data_final) { *meta_data_final = meta_data; },
|
||||
[&](AttributeMetaData *meta_data_final) {
|
||||
meta_data_final->data_type = blender::bke::attribute_data_type_highest_complexity(
|
||||
{meta_data_final->data_type, meta_data.data_type});
|
||||
meta_data_final->domain = blender::bke::attribute_domain_highest_priority(
|
||||
{meta_data_final->domain, meta_data.domain});
|
||||
});
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static void fill_new_attribute(Span<const GeometryComponent *> src_components,
|
||||
StringRef attribute_name,
|
||||
const AttributeIDRef &attribute_id,
|
||||
const CustomDataType data_type,
|
||||
const AttributeDomain domain,
|
||||
GMutableSpan dst_span)
|
||||
@@ -203,7 +204,7 @@ static void fill_new_attribute(Span<const GeometryComponent *> src_components,
|
||||
continue;
|
||||
}
|
||||
GVArrayPtr read_attribute = component->attribute_get_for_read(
|
||||
attribute_name, domain, data_type, nullptr);
|
||||
attribute_id, domain, data_type, nullptr);
|
||||
|
||||
GVArray_GSpan src_span{*read_attribute};
|
||||
const void *src_buffer = src_span.data();
|
||||
@@ -218,20 +219,21 @@ static void join_attributes(Span<const GeometryComponent *> src_components,
|
||||
GeometryComponent &result,
|
||||
Span<StringRef> ignored_attributes = {})
|
||||
{
|
||||
const Map<std::string, AttributeMetaData> info = get_final_attribute_info(src_components,
|
||||
ignored_attributes);
|
||||
const Map<AttributeIDRef, AttributeMetaData> info = get_final_attribute_info(src_components,
|
||||
ignored_attributes);
|
||||
|
||||
for (const Map<std::string, AttributeMetaData>::Item &item : info.items()) {
|
||||
const StringRef name = item.key;
|
||||
for (const Map<AttributeIDRef, AttributeMetaData>::Item &item : info.items()) {
|
||||
const AttributeIDRef attribute_id = item.key;
|
||||
const AttributeMetaData &meta_data = item.value;
|
||||
|
||||
OutputAttribute write_attribute = result.attribute_try_get_for_output_only(
|
||||
name, meta_data.domain, meta_data.data_type);
|
||||
attribute_id, meta_data.domain, meta_data.data_type);
|
||||
if (!write_attribute) {
|
||||
continue;
|
||||
}
|
||||
GMutableSpan dst_span = write_attribute.as_span();
|
||||
fill_new_attribute(src_components, name, meta_data.data_type, meta_data.domain, dst_span);
|
||||
fill_new_attribute(
|
||||
src_components, attribute_id, meta_data.data_type, meta_data.domain, dst_span);
|
||||
write_attribute.save();
|
||||
}
|
||||
}
|
||||
@@ -306,7 +308,7 @@ static void join_components(Span<const VolumeComponent *> src_components, Geomet
|
||||
* \note This takes advantage of the fact that creating attributes on joined curves never
|
||||
* changes a point attribute into a spline attribute; it is always the other way around.
|
||||
*/
|
||||
static void ensure_control_point_attribute(const StringRef name,
|
||||
static void ensure_control_point_attribute(const AttributeIDRef &attribute_id,
|
||||
const CustomDataType data_type,
|
||||
Span<CurveComponent *> src_components,
|
||||
CurveEval &result)
|
||||
@@ -321,7 +323,7 @@ static void ensure_control_point_attribute(const StringRef name,
|
||||
const CurveEval *current_curve = src_components[src_component_index]->get_for_read();
|
||||
|
||||
for (SplinePtr &spline : splines) {
|
||||
std::optional<GSpan> attribute = spline->attributes.get_for_read(name);
|
||||
std::optional<GSpan> attribute = spline->attributes.get_for_read(attribute_id);
|
||||
|
||||
if (attribute) {
|
||||
if (attribute->type() != type) {
|
||||
@@ -334,22 +336,22 @@ static void ensure_control_point_attribute(const StringRef name,
|
||||
conversions.try_convert(std::make_unique<GVArray_For_GSpan>(*attribute), type)
|
||||
->materialize(converted_buffer);
|
||||
|
||||
spline->attributes.remove(name);
|
||||
spline->attributes.create_by_move(name, data_type, converted_buffer);
|
||||
spline->attributes.remove(attribute_id);
|
||||
spline->attributes.create_by_move(attribute_id, data_type, converted_buffer);
|
||||
}
|
||||
}
|
||||
else {
|
||||
spline->attributes.create(name, data_type);
|
||||
spline->attributes.create(attribute_id, data_type);
|
||||
|
||||
if (current_curve->attributes.get_for_read(name)) {
|
||||
if (current_curve->attributes.get_for_read(attribute_id)) {
|
||||
/* In this case the attribute did not exist, but there is a spline domain attribute
|
||||
* we can retrieve a value from, as a spline to point domain conversion. So fill the
|
||||
* new attribute with the value for this spline. */
|
||||
GVArrayPtr current_curve_attribute = current_curve->attributes.get_for_read(
|
||||
name, data_type, nullptr);
|
||||
attribute_id, data_type, nullptr);
|
||||
|
||||
BLI_assert(spline->attributes.get_for_read(name));
|
||||
std::optional<GMutableSpan> new_attribute = spline->attributes.get_for_write(name);
|
||||
BLI_assert(spline->attributes.get_for_read(attribute_id));
|
||||
std::optional<GMutableSpan> new_attribute = spline->attributes.get_for_write(attribute_id);
|
||||
|
||||
BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
|
||||
current_curve_attribute->get(spline_index_in_component, buffer);
|
||||
@@ -371,15 +373,15 @@ static void ensure_control_point_attribute(const StringRef name,
|
||||
/**
|
||||
* Fill data for an attribute on the new curve based on all source curves.
|
||||
*/
|
||||
static void ensure_spline_attribute(const StringRef name,
|
||||
static void ensure_spline_attribute(const AttributeIDRef &attribute_id,
|
||||
const CustomDataType data_type,
|
||||
Span<CurveComponent *> src_components,
|
||||
CurveEval &result)
|
||||
{
|
||||
const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
|
||||
|
||||
result.attributes.create(name, data_type);
|
||||
GMutableSpan result_attribute = *result.attributes.get_for_write(name);
|
||||
result.attributes.create(attribute_id, data_type);
|
||||
GMutableSpan result_attribute = *result.attributes.get_for_write(attribute_id);
|
||||
|
||||
int offset = 0;
|
||||
for (const CurveComponent *component : src_components) {
|
||||
@@ -388,7 +390,7 @@ static void ensure_spline_attribute(const StringRef name,
|
||||
if (size == 0) {
|
||||
continue;
|
||||
}
|
||||
GVArrayPtr read_attribute = curve.attributes.get_for_read(name, data_type, nullptr);
|
||||
GVArrayPtr read_attribute = curve.attributes.get_for_read(attribute_id, data_type, nullptr);
|
||||
GVArray_GSpan src_span{*read_attribute};
|
||||
|
||||
const void *src_buffer = src_span.data();
|
||||
@@ -406,19 +408,19 @@ static void ensure_spline_attribute(const StringRef name,
|
||||
* \warning Splines have been moved out of the source components at this point, so it
|
||||
* is important to only read curve-level data (spline domain attributes) from them.
|
||||
*/
|
||||
static void join_curve_attributes(const Map<std::string, AttributeMetaData> &info,
|
||||
static void join_curve_attributes(const Map<AttributeIDRef, AttributeMetaData> &info,
|
||||
Span<CurveComponent *> src_components,
|
||||
CurveEval &result)
|
||||
{
|
||||
for (const Map<std::string, AttributeMetaData>::Item &item : info.items()) {
|
||||
const StringRef name = item.key;
|
||||
for (const Map<AttributeIDRef, AttributeMetaData>::Item &item : info.items()) {
|
||||
const AttributeIDRef attribute_id = item.key;
|
||||
const AttributeMetaData meta_data = item.value;
|
||||
|
||||
if (meta_data.domain == ATTR_DOMAIN_CURVE) {
|
||||
ensure_spline_attribute(name, meta_data.data_type, src_components, result);
|
||||
ensure_spline_attribute(attribute_id, meta_data.data_type, src_components, result);
|
||||
}
|
||||
else {
|
||||
ensure_control_point_attribute(name, meta_data.data_type, src_components, result);
|
||||
ensure_control_point_attribute(attribute_id, meta_data.data_type, src_components, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -446,7 +448,7 @@ static void join_curve_components(MutableSpan<GeometrySet> src_geometry_sets, Ge
|
||||
}
|
||||
|
||||
/* Retrieve attribute info before moving the splines out of the input components. */
|
||||
const Map<std::string, AttributeMetaData> info = get_final_attribute_info(
|
||||
const Map<AttributeIDRef, AttributeMetaData> info = get_final_attribute_info(
|
||||
{(const GeometryComponent **)src_components.data(), src_components.size()},
|
||||
{"position", "radius", "tilt", "cyclic", "resolution"});
|
||||
|
||||
|
@@ -56,10 +56,10 @@ static void copy_attributes_to_points(CurveEval &curve,
|
||||
Span<Vector<int>> point_to_vert_maps)
|
||||
{
|
||||
MutableSpan<SplinePtr> splines = curve.splines();
|
||||
Set<std::string> source_attribute_names = mesh_component.attribute_names();
|
||||
Set<AttributeIDRef> source_attribute_ids = mesh_component.attribute_ids();
|
||||
|
||||
/* Copy builtin control point attributes. */
|
||||
if (source_attribute_names.contains_as("tilt")) {
|
||||
if (source_attribute_ids.contains("tilt")) {
|
||||
const GVArray_Typed<float> tilt_attribute = mesh_component.attribute_get_for_read<float>(
|
||||
"tilt", ATTR_DOMAIN_POINT, 0.0f);
|
||||
threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) {
|
||||
@@ -68,9 +68,9 @@ static void copy_attributes_to_points(CurveEval &curve,
|
||||
*tilt_attribute, point_to_vert_maps[i], splines[i]->tilts());
|
||||
}
|
||||
});
|
||||
source_attribute_names.remove_contained_as("tilt");
|
||||
source_attribute_ids.remove_contained("tilt");
|
||||
}
|
||||
if (source_attribute_names.contains_as("radius")) {
|
||||
if (source_attribute_ids.contains("radius")) {
|
||||
const GVArray_Typed<float> radius_attribute = mesh_component.attribute_get_for_read<float>(
|
||||
"radius", ATTR_DOMAIN_POINT, 1.0f);
|
||||
threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) {
|
||||
@@ -79,15 +79,15 @@ static void copy_attributes_to_points(CurveEval &curve,
|
||||
*radius_attribute, point_to_vert_maps[i], splines[i]->radii());
|
||||
}
|
||||
});
|
||||
source_attribute_names.remove_contained_as("radius");
|
||||
source_attribute_ids.remove_contained("radius");
|
||||
}
|
||||
|
||||
/* Don't copy other builtin control point attributes. */
|
||||
source_attribute_names.remove_as("position");
|
||||
source_attribute_ids.remove("position");
|
||||
|
||||
/* Copy dynamic control point attributes. */
|
||||
for (const StringRef name : source_attribute_names) {
|
||||
const GVArrayPtr mesh_attribute = mesh_component.attribute_try_get_for_read(name,
|
||||
for (const AttributeIDRef &attribute_id : source_attribute_ids) {
|
||||
const GVArrayPtr mesh_attribute = mesh_component.attribute_try_get_for_read(attribute_id,
|
||||
ATTR_DOMAIN_POINT);
|
||||
/* Some attributes might not exist if they were builtin attribute on domains that don't
|
||||
* have any elements, i.e. a face attribute on the output of the line primitive node. */
|
||||
@@ -100,8 +100,9 @@ static void copy_attributes_to_points(CurveEval &curve,
|
||||
threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
|
||||
for (const int i : range) {
|
||||
/* Create attribute on the spline points. */
|
||||
splines[i]->attributes.create(name, data_type);
|
||||
std::optional<GMutableSpan> spline_attribute = splines[i]->attributes.get_for_write(name);
|
||||
splines[i]->attributes.create(attribute_id, data_type);
|
||||
std::optional<GMutableSpan> spline_attribute = splines[i]->attributes.get_for_write(
|
||||
attribute_id);
|
||||
BLI_assert(spline_attribute);
|
||||
|
||||
/* Copy attribute based on the map for this spline. */
|
||||
|
@@ -277,17 +277,17 @@ BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
|
||||
BLI_NOINLINE static void interpolate_existing_attributes(
|
||||
Span<GeometryInstanceGroup> set_groups,
|
||||
Span<int> instance_start_offsets,
|
||||
const Map<std::string, AttributeKind> &attributes,
|
||||
const Map<AttributeIDRef, AttributeKind> &attributes,
|
||||
GeometryComponent &component,
|
||||
Span<Vector<float3>> bary_coords_array,
|
||||
Span<Vector<int>> looptri_indices_array)
|
||||
{
|
||||
for (Map<std::string, AttributeKind>::Item entry : attributes.items()) {
|
||||
StringRef attribute_name = entry.key;
|
||||
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
|
||||
const AttributeIDRef attribute_id = entry.key;
|
||||
const CustomDataType output_data_type = entry.value.data_type;
|
||||
/* The output domain is always #ATTR_DOMAIN_POINT, since we are creating a point cloud. */
|
||||
OutputAttribute attribute_out = component.attribute_try_get_for_output_only(
|
||||
attribute_name, ATTR_DOMAIN_POINT, output_data_type);
|
||||
attribute_id, ATTR_DOMAIN_POINT, output_data_type);
|
||||
if (!attribute_out) {
|
||||
continue;
|
||||
}
|
||||
@@ -301,7 +301,7 @@ BLI_NOINLINE static void interpolate_existing_attributes(
|
||||
const Mesh &mesh = *source_component.get_for_read();
|
||||
|
||||
std::optional<AttributeMetaData> attribute_info = component.attribute_get_meta_data(
|
||||
attribute_name);
|
||||
attribute_id);
|
||||
if (!attribute_info) {
|
||||
i_instance += set_group.transforms.size();
|
||||
continue;
|
||||
@@ -309,7 +309,7 @@ BLI_NOINLINE static void interpolate_existing_attributes(
|
||||
|
||||
const AttributeDomain source_domain = attribute_info->domain;
|
||||
GVArrayPtr source_attribute = source_component.attribute_get_for_read(
|
||||
attribute_name, source_domain, output_data_type, nullptr);
|
||||
attribute_id, source_domain, output_data_type, nullptr);
|
||||
if (!source_attribute) {
|
||||
i_instance += set_group.transforms.size();
|
||||
continue;
|
||||
@@ -406,7 +406,7 @@ BLI_NOINLINE static void compute_special_attributes(Span<GeometryInstanceGroup>
|
||||
BLI_NOINLINE static void add_remaining_point_attributes(
|
||||
Span<GeometryInstanceGroup> set_groups,
|
||||
Span<int> instance_start_offsets,
|
||||
const Map<std::string, AttributeKind> &attributes,
|
||||
const Map<AttributeIDRef, AttributeKind> &attributes,
|
||||
GeometryComponent &component,
|
||||
Span<Vector<float3>> bary_coords_array,
|
||||
Span<Vector<int>> looptri_indices_array)
|
||||
@@ -629,7 +629,7 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
|
||||
PointCloudComponent &point_component =
|
||||
geometry_set_out.get_component_for_write<PointCloudComponent>();
|
||||
|
||||
Map<std::string, AttributeKind> attributes;
|
||||
Map<AttributeIDRef, AttributeKind> attributes;
|
||||
bke::geometry_set_gather_instances_attribute_info(
|
||||
set_groups, {GEO_COMPONENT_TYPE_MESH}, {"position", "normal", "id"}, attributes);
|
||||
add_remaining_point_attributes(set_groups,
|
||||
|
@@ -57,8 +57,8 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component,
|
||||
Span<bool> masks,
|
||||
const bool invert)
|
||||
{
|
||||
for (const std::string &name : in_component.attribute_names()) {
|
||||
ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(name);
|
||||
for (const AttributeIDRef &attribute_id : in_component.attribute_ids()) {
|
||||
ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(attribute_id);
|
||||
const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray->type());
|
||||
|
||||
/* Only copy point attributes. Theoretically this could interpolate attributes on other
|
||||
@@ -69,7 +69,7 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component,
|
||||
}
|
||||
|
||||
OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only(
|
||||
name, ATTR_DOMAIN_POINT, data_type);
|
||||
attribute_id, ATTR_DOMAIN_POINT, data_type);
|
||||
|
||||
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
|
@@ -161,8 +161,10 @@ GeometryValueLog::GeometryValueLog(const GeometrySet &geometry_set, bool log_ful
|
||||
{
|
||||
bke::geometry_set_instances_attribute_foreach(
|
||||
geometry_set,
|
||||
[&](StringRefNull attribute_name, const AttributeMetaData &meta_data) {
|
||||
this->attributes_.append({attribute_name, meta_data.domain, meta_data.data_type});
|
||||
[&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
|
||||
if (attribute_id.is_named()) {
|
||||
this->attributes_.append({attribute_id.name(), meta_data.domain, meta_data.data_type});
|
||||
}
|
||||
return true;
|
||||
},
|
||||
8);
|
||||
|
Reference in New Issue
Block a user