Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/attribute.cc')
-rw-r--r--source/blender/blenkernel/intern/attribute.cc233
1 files changed, 147 insertions, 86 deletions
diff --git a/source/blender/blenkernel/intern/attribute.cc b/source/blender/blenkernel/intern/attribute.cc
index 7c09b4a4ce3..f66a1f9ee93 100644
--- a/source/blender/blenkernel/intern/attribute.cc
+++ b/source/blender/blenkernel/intern/attribute.cc
@@ -8,6 +8,7 @@
*/
#include <cstring>
+#include <optional>
#include "MEM_guardedalloc.h"
@@ -19,12 +20,15 @@
#include "DNA_pointcloud_types.h"
#include "BLI_index_range.hh"
+#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_string_utils.h"
+#include "BLT_translation.h"
+
#include "BKE_attribute.h"
-#include "BKE_attribute_access.hh"
-#include "BKE_curves.h"
+#include "BKE_attribute.hh"
+#include "BKE_curves.hh"
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_pointcloud.h"
@@ -89,6 +93,36 @@ static void get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
}
}
+namespace blender::bke {
+
+static std::optional<blender::bke::MutableAttributeAccessor> get_attribute_accessor_for_write(
+ ID &id)
+{
+ switch (GS(id.name)) {
+ case ID_ME: {
+ Mesh &mesh = reinterpret_cast<Mesh &>(id);
+ /* The attribute API isn't implemented for BMesh, so edit mode meshes are not supported. */
+ BLI_assert(mesh.edit_mesh == nullptr);
+ return mesh.attributes_for_write();
+ }
+ case ID_PT: {
+ PointCloud &pointcloud = reinterpret_cast<PointCloud &>(id);
+ return pointcloud.attributes_for_write();
+ }
+ case ID_CV: {
+ Curves &curves_id = reinterpret_cast<Curves &>(id);
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
+ return curves.attributes_for_write();
+ }
+ default: {
+ BLI_assert_unreachable();
+ return {};
+ }
+ }
+}
+
+} // namespace blender::bke
+
bool BKE_id_attributes_supported(const ID *id)
{
DomainInfo info[ATTR_DOMAIN_NUM];
@@ -115,6 +149,13 @@ bool BKE_id_attribute_rename(ID *id,
BLI_assert_msg(0, "Required attribute name is not editable");
return false;
}
+ if (STREQ(new_name, "")) {
+ BKE_report(reports, RPT_ERROR, "Attribute name can not be empty");
+ return false;
+ }
+ if (STREQ(old_name, new_name)) {
+ return false;
+ }
CustomDataLayer *layer = BKE_id_attribute_search(
id, old_name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
@@ -146,9 +187,9 @@ static bool unique_name_cb(void *arg, const char *name)
continue;
}
- CustomData *cdata = info[domain].customdata;
+ const CustomData *cdata = info[domain].customdata;
for (int i = 0; i < cdata->totlayer; i++) {
- CustomDataLayer *layer = cdata->layers + i;
+ const CustomDataLayer *layer = cdata->layers + i;
if (STREQ(layer->name, name)) {
return true;
@@ -163,7 +204,14 @@ bool BKE_id_attribute_calc_unique_name(ID *id, const char *name, char *outname)
{
AttrUniqueData data{id};
- BLI_strncpy_utf8(outname, name, MAX_CUSTOMDATA_LAYER_NAME);
+ /* Set default name if none specified.
+ * NOTE: We only call IFACE_() if needed to avoid locale lookup overhead. */
+ if (!name || name[0] == '\0') {
+ BLI_strncpy(outname, IFACE_("Attribute"), MAX_CUSTOMDATA_LAYER_NAME);
+ }
+ else {
+ BLI_strncpy_utf8(outname, name, MAX_CUSTOMDATA_LAYER_NAME);
+ }
return BLI_uniquename_cb(
unique_name_cb, &data, nullptr, '.', outname, MAX_CUSTOMDATA_LAYER_NAME);
@@ -172,6 +220,7 @@ bool BKE_id_attribute_calc_unique_name(ID *id, const char *name, char *outname)
CustomDataLayer *BKE_id_attribute_new(
ID *id, const char *name, const int type, const eAttrDomain domain, ReportList *reports)
{
+ using namespace blender::bke;
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
@@ -184,64 +233,65 @@ CustomDataLayer *BKE_id_attribute_new(
char uniquename[MAX_CUSTOMDATA_LAYER_NAME];
BKE_id_attribute_calc_unique_name(id, name, uniquename);
- switch (GS(id->name)) {
- case ID_ME: {
- Mesh *me = (Mesh *)id;
- BMEditMesh *em = me->edit_mesh;
- if (em != nullptr) {
- BM_data_layer_add_named(em->bm, customdata, type, uniquename);
- }
- else {
- CustomData_add_layer_named(
- customdata, type, CD_DEFAULT, nullptr, info[domain].length, uniquename);
- }
- break;
- }
- default: {
- CustomData_add_layer_named(
- customdata, type, CD_DEFAULT, nullptr, info[domain].length, uniquename);
- break;
+ if (GS(id->name) == ID_ME) {
+ Mesh *mesh = reinterpret_cast<Mesh *>(id);
+ if (BMEditMesh *em = mesh->edit_mesh) {
+ BM_data_layer_add_named(em->bm, customdata, type, uniquename);
+ const int index = CustomData_get_named_layer_index(customdata, type, uniquename);
+ return (index == -1) ? nullptr : &(customdata->layers[index]);
}
}
+ std::optional<MutableAttributeAccessor> attributes = get_attribute_accessor_for_write(*id);
+ if (!attributes) {
+ return nullptr;
+ }
+
+ attributes->add(uniquename, domain, eCustomDataType(type), AttributeInitDefaultValue());
+
const int index = CustomData_get_named_layer_index(customdata, type, uniquename);
return (index == -1) ? nullptr : &(customdata->layers[index]);
}
CustomDataLayer *BKE_id_attribute_duplicate(ID *id, const char *name, ReportList *reports)
{
- const CustomDataLayer *src_layer = BKE_id_attribute_search(
- id, name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
- if (src_layer == nullptr) {
- BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry");
- return nullptr;
- }
-
- const eCustomDataType type = (eCustomDataType)src_layer->type;
- const eAttrDomain domain = BKE_id_attribute_domain(id, src_layer);
+ using namespace blender::bke;
+ char uniquename[MAX_CUSTOMDATA_LAYER_NAME];
+ BKE_id_attribute_calc_unique_name(id, name, uniquename);
- /* Make a copy of name in case CustomData API reallocates the layers. */
- const std::string name_copy = name;
+ if (GS(id->name) == ID_ME) {
+ Mesh *mesh = reinterpret_cast<Mesh *>(id);
+ if (BMEditMesh *em = mesh->edit_mesh) {
+ BLI_assert_unreachable();
+ UNUSED_VARS(em);
+ return nullptr;
+ }
+ }
- DomainInfo info[ATTR_DOMAIN_NUM];
- get_domains(id, info);
- CustomData *customdata = info[domain].customdata;
+ std::optional<MutableAttributeAccessor> attributes = get_attribute_accessor_for_write(*id);
+ if (!attributes) {
+ return nullptr;
+ }
- CustomDataLayer *new_layer = BKE_id_attribute_new(id, name_copy.c_str(), type, domain, reports);
- if (new_layer == nullptr) {
+ GAttributeReader src = attributes->lookup(name);
+ if (!src) {
+ BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry");
return nullptr;
}
- const int from_index = CustomData_get_named_layer_index(customdata, type, name_copy.c_str());
- const int to_index = CustomData_get_named_layer_index(customdata, type, new_layer->name);
- CustomData_copy_data_layer(
- customdata, customdata, from_index, to_index, 0, 0, info[domain].length);
+ const eCustomDataType type = cpp_type_to_custom_data_type(src.varray.type());
+ attributes->add(uniquename, src.domain, type, AttributeInitVArray(src.varray));
- return new_layer;
+ return BKE_id_attribute_search(id, uniquename, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
}
bool BKE_id_attribute_remove(ID *id, const char *name, ReportList *reports)
{
+ using namespace blender::bke;
+ if (!name || name[0] == '\0') {
+ BKE_report(reports, RPT_ERROR, "The attribute name must not be empty");
+ return false;
+ }
if (BKE_id_attribute_required(id, name)) {
BKE_report(reports, RPT_ERROR, "Attribute is required and can't be removed");
return false;
@@ -250,31 +300,26 @@ bool BKE_id_attribute_remove(ID *id, const char *name, ReportList *reports)
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
- switch (GS(id->name)) {
- case ID_ME: {
- Mesh *mesh = reinterpret_cast<Mesh *>(id);
- if (BMEditMesh *em = mesh->edit_mesh) {
- for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
- if (CustomData *data = info[domain].customdata) {
- if (BM_data_layer_free_named(em->bm, data, name)) {
- return true;
- }
- }
- }
- return false;
- }
- ATTR_FALLTHROUGH;
- }
- default:
+ if (GS(id->name) == ID_ME) {
+ Mesh *mesh = reinterpret_cast<Mesh *>(id);
+ if (BMEditMesh *em = mesh->edit_mesh) {
for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
if (CustomData *data = info[domain].customdata) {
- if (CustomData_free_layer_named(data, name, info[domain].length)) {
+ if (BM_data_layer_free_named(em->bm, data, name)) {
return true;
}
}
}
return false;
+ }
+ }
+
+ std::optional<MutableAttributeAccessor> attributes = get_attribute_accessor_for_write(*id);
+ if (!attributes) {
+ return false;
}
+
+ return attributes->remove(name);
}
CustomDataLayer *BKE_id_attribute_find(const ID *id,
@@ -338,9 +383,12 @@ int BKE_id_attributes_length(const ID *id, eAttrDomainMask domain_mask, eCustomD
int length = 0;
for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
- CustomData *customdata = info[domain].customdata;
+ const CustomData *customdata = info[domain].customdata;
+ if (customdata == nullptr) {
+ continue;
+ }
- if (customdata && ((1 << (int)domain) & domain_mask)) {
+ if ((1 << (int)domain) & domain_mask) {
length += CustomData_number_of_layers_typemask(customdata, mask);
}
}
@@ -354,9 +402,11 @@ eAttrDomain BKE_id_attribute_domain(const ID *id, const CustomDataLayer *layer)
get_domains(id, info);
for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
- CustomData *customdata = info[domain].customdata;
- if (customdata &&
- ARRAY_HAS_ITEM((CustomDataLayer *)layer, customdata->layers, customdata->totlayer)) {
+ const CustomData *customdata = info[domain].customdata;
+ if (customdata == nullptr) {
+ continue;
+ }
+ if (ARRAY_HAS_ITEM((CustomDataLayer *)layer, customdata->layers, customdata->totlayer)) {
return static_cast<eAttrDomain>(domain);
}
}
@@ -376,6 +426,7 @@ int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer)
if (mesh->edit_mesh != nullptr) {
return 0;
}
+ break;
}
default:
break;
@@ -385,9 +436,11 @@ int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer)
get_domains(id, info);
for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
- CustomData *customdata = info[domain].customdata;
- if (customdata &&
- ARRAY_HAS_ITEM((CustomDataLayer *)layer, customdata->layers, customdata->totlayer)) {
+ const CustomData *customdata = info[domain].customdata;
+ if (customdata == nullptr) {
+ continue;
+ }
+ if (ARRAY_HAS_ITEM((CustomDataLayer *)layer, customdata->layers, customdata->totlayer)) {
return info[domain].length;
}
}
@@ -424,15 +477,19 @@ CustomDataLayer *BKE_id_attributes_active_get(ID *id)
for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
CustomData *customdata = info[domain].customdata;
- if (customdata) {
- for (int i = 0; i < customdata->totlayer; i++) {
- CustomDataLayer *layer = &customdata->layers[i];
- if (CD_MASK_PROP_ALL & CD_TYPE_AS_MASK(layer->type)) {
- if (index == active_index) {
+ if (customdata == nullptr) {
+ continue;
+ }
+ for (int i = 0; i < customdata->totlayer; i++) {
+ CustomDataLayer *layer = &customdata->layers[i];
+ if (CD_MASK_PROP_ALL & CD_TYPE_AS_MASK(layer->type)) {
+ if (index == active_index) {
+ if (BKE_attribute_allow_procedural_access(layer->name)) {
return layer;
}
- index++;
+ return nullptr;
}
+ index++;
}
}
}
@@ -448,17 +505,18 @@ void BKE_id_attributes_active_set(ID *id, CustomDataLayer *active_layer)
int index = 0;
for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
- CustomData *customdata = info[domain].customdata;
- if (customdata) {
- for (int i = 0; i < customdata->totlayer; i++) {
- CustomDataLayer *layer = &customdata->layers[i];
- if (layer == active_layer) {
- *BKE_id_attributes_active_index_p(id) = index;
- return;
- }
- if (CD_MASK_PROP_ALL & CD_TYPE_AS_MASK(layer->type)) {
- index++;
- }
+ const CustomData *customdata = info[domain].customdata;
+ if (customdata == nullptr) {
+ continue;
+ }
+ for (int i = 0; i < customdata->totlayer; i++) {
+ const CustomDataLayer *layer = &customdata->layers[i];
+ if (layer == active_layer) {
+ *BKE_id_attributes_active_index_p(id) = index;
+ return;
+ }
+ if (CD_MASK_PROP_ALL & CD_TYPE_AS_MASK(layer->type)) {
+ index++;
}
}
}
@@ -490,7 +548,10 @@ CustomData *BKE_id_attributes_iterator_next_domain(ID *id, CustomDataLayer *laye
for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
CustomData *customdata = info[domain].customdata;
- if (customdata && customdata->layers && customdata->totlayer) {
+ if (customdata == nullptr) {
+ continue;
+ }
+ if (customdata->layers && customdata->totlayer) {
if (customdata->layers == layers) {
use_next = true;
}