Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/attribute.c
| Show All 33 Lines | |||||
| #include "DNA_mesh_types.h" | #include "DNA_mesh_types.h" | ||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | ||||
| #include "DNA_pointcloud_types.h" | #include "DNA_pointcloud_types.h" | ||||
| #include "BLI_string_utf8.h" | #include "BLI_string_utf8.h" | ||||
| #include "BKE_attribute.h" | #include "BKE_attribute.h" | ||||
| #include "BKE_customdata.h" | #include "BKE_customdata.h" | ||||
| #include "BKE_editmesh.h" | |||||
| #include "BKE_hair.h" | #include "BKE_hair.h" | ||||
| #include "BKE_pointcloud.h" | #include "BKE_pointcloud.h" | ||||
| #include "BKE_report.h" | #include "BKE_report.h" | ||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| typedef struct DomainInfo { | typedef struct DomainInfo { | ||||
| CustomData *customdata; | CustomData *customdata; | ||||
| int length; | int length; | ||||
| } DomainInfo; | } DomainInfo; | ||||
| static void get_domains(ID *id, DomainInfo info[ATTR_DOMAIN_NUM]) | static void get_domains(ID *id, DomainInfo info[ATTR_DOMAIN_NUM]) | ||||
| { | { | ||||
| memset(info, 0, sizeof(DomainInfo) * ATTR_DOMAIN_NUM); | memset(info, 0, sizeof(DomainInfo) * ATTR_DOMAIN_NUM); | ||||
| switch (GS(id->name)) { | switch (GS(id->name)) { | ||||
| case ID_PT: { | case ID_PT: { | ||||
| PointCloud *pointcloud = (PointCloud *)id; | PointCloud *pointcloud = (PointCloud *)id; | ||||
| info[ATTR_DOMAIN_POINT].customdata = &pointcloud->pdata; | info[ATTR_DOMAIN_POINT].customdata = &pointcloud->pdata; | ||||
| info[ATTR_DOMAIN_POINT].length = pointcloud->totpoint; | info[ATTR_DOMAIN_POINT].length = pointcloud->totpoint; | ||||
| break; | break; | ||||
| } | } | ||||
| case ID_ME: { | case ID_ME: { | ||||
| Mesh *mesh = (Mesh *)id; | Mesh *mesh = (Mesh *)id; | ||||
| BMEditMesh *em = mesh->edit_mesh; | |||||
| if (em != NULL) { | |||||
| BMesh *bm = em->bm; | |||||
| info[ATTR_DOMAIN_POINT].customdata = &bm->vdata; | |||||
| info[ATTR_DOMAIN_POINT].length = bm->totvert; | |||||
| info[ATTR_DOMAIN_EDGE].customdata = &bm->edata; | |||||
| info[ATTR_DOMAIN_EDGE].length = bm->totedge; | |||||
| info[ATTR_DOMAIN_CORNER].customdata = &bm->ldata; | |||||
| info[ATTR_DOMAIN_CORNER].length = bm->totloop; | |||||
| info[ATTR_DOMAIN_FACE].customdata = &bm->pdata; | |||||
| info[ATTR_DOMAIN_FACE].length = bm->totface; | |||||
| } | |||||
| else { | |||||
| info[ATTR_DOMAIN_POINT].customdata = &mesh->vdata; | info[ATTR_DOMAIN_POINT].customdata = &mesh->vdata; | ||||
| info[ATTR_DOMAIN_POINT].length = mesh->totvert; | info[ATTR_DOMAIN_POINT].length = mesh->totvert; | ||||
| info[ATTR_DOMAIN_EDGE].customdata = &mesh->edata; | info[ATTR_DOMAIN_EDGE].customdata = &mesh->edata; | ||||
| info[ATTR_DOMAIN_EDGE].length = mesh->totedge; | info[ATTR_DOMAIN_EDGE].length = mesh->totedge; | ||||
| info[ATTR_DOMAIN_CORNER].customdata = &mesh->ldata; | info[ATTR_DOMAIN_CORNER].customdata = &mesh->ldata; | ||||
| info[ATTR_DOMAIN_CORNER].length = mesh->totloop; | info[ATTR_DOMAIN_CORNER].length = mesh->totloop; | ||||
| info[ATTR_DOMAIN_FACE].customdata = &mesh->pdata; | info[ATTR_DOMAIN_FACE].customdata = &mesh->pdata; | ||||
| info[ATTR_DOMAIN_FACE].length = mesh->totpoly; | info[ATTR_DOMAIN_FACE].length = mesh->totpoly; | ||||
| } | |||||
| break; | break; | ||||
| } | } | ||||
| case ID_HA: { | case ID_HA: { | ||||
| Hair *hair = (Hair *)id; | Hair *hair = (Hair *)id; | ||||
| info[ATTR_DOMAIN_POINT].customdata = &hair->pdata; | info[ATTR_DOMAIN_POINT].customdata = &hair->pdata; | ||||
| info[ATTR_DOMAIN_POINT].length = hair->totpoint; | info[ATTR_DOMAIN_POINT].length = hair->totpoint; | ||||
| info[ATTR_DOMAIN_CURVE].customdata = &hair->cdata; | info[ATTR_DOMAIN_CURVE].customdata = &hair->cdata; | ||||
| info[ATTR_DOMAIN_CURVE].length = hair->totcurve; | info[ATTR_DOMAIN_CURVE].length = hair->totcurve; | ||||
| Show All 32 Lines | |||||
| } | } | ||||
| bool BKE_id_attribute_rename(ID *id, | bool BKE_id_attribute_rename(ID *id, | ||||
| CustomDataLayer *layer, | CustomDataLayer *layer, | ||||
| const char *new_name, | const char *new_name, | ||||
| ReportList *reports) | ReportList *reports) | ||||
| { | { | ||||
| if (BKE_id_attribute_required(id, layer)) { | if (BKE_id_attribute_required(id, layer)) { | ||||
| BLI_assert(!"Required attribute name is not editable"); | BLI_assert_msg(0, "Required attribute name is not editable"); | ||||
| return false; | return false; | ||||
| } | } | ||||
| CustomData *customdata = attribute_customdata_find(id, layer); | CustomData *customdata = attribute_customdata_find(id, layer); | ||||
| if (customdata == NULL) { | if (customdata == NULL) { | ||||
| BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry"); | BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry"); | ||||
| return false; | return false; | ||||
| } | } | ||||
| Show All 10 Lines | CustomDataLayer *BKE_id_attribute_new( | ||||
| get_domains(id, info); | get_domains(id, info); | ||||
| CustomData *customdata = info[domain].customdata; | CustomData *customdata = info[domain].customdata; | ||||
| if (customdata == NULL) { | if (customdata == NULL) { | ||||
| BKE_report(reports, RPT_ERROR, "Attribute domain not supported by this geometry type"); | BKE_report(reports, RPT_ERROR, "Attribute domain not supported by this geometry type"); | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| switch (GS(id->name)) { | |||||
| case ID_ME: { | |||||
| Mesh *me = (Mesh *)id; | |||||
| BMEditMesh *em = me->edit_mesh; | |||||
| if (em != NULL) { | |||||
| BM_data_layer_add_named(em->bm, customdata, type, name); | |||||
| } | |||||
| else { | |||||
| CustomData_add_layer_named(customdata, type, CD_DEFAULT, NULL, info[domain].length, name); | CustomData_add_layer_named(customdata, type, CD_DEFAULT, NULL, info[domain].length, name); | ||||
| } | |||||
| break; | |||||
| } | |||||
| default: { | |||||
| CustomData_add_layer_named(customdata, type, CD_DEFAULT, NULL, info[domain].length, name); | |||||
| break; | |||||
| } | |||||
| } | |||||
| const int index = CustomData_get_named_layer_index(customdata, type, name); | const int index = CustomData_get_named_layer_index(customdata, type, name); | ||||
| return (index == -1) ? NULL : &(customdata->layers[index]); | return (index == -1) ? NULL : &(customdata->layers[index]); | ||||
| } | } | ||||
| bool BKE_id_attribute_remove(ID *id, CustomDataLayer *layer, ReportList *reports) | bool BKE_id_attribute_remove(ID *id, CustomDataLayer *layer, ReportList *reports) | ||||
| { | { | ||||
| CustomData *customdata = attribute_customdata_find(id, layer); | CustomData *customdata = attribute_customdata_find(id, layer); | ||||
| const int index = (customdata) ? | const int index = (customdata) ? | ||||
| CustomData_get_named_layer_index(customdata, layer->type, layer->name) : | CustomData_get_named_layer_index(customdata, layer->type, layer->name) : | ||||
| -1; | -1; | ||||
| if (index == -1) { | if (index == -1) { | ||||
| BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry"); | BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry"); | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (BKE_id_attribute_required(id, layer)) { | if (BKE_id_attribute_required(id, layer)) { | ||||
| BKE_report(reports, RPT_ERROR, "Attribute is required and can't be removed"); | BKE_report(reports, RPT_ERROR, "Attribute is required and can't be removed"); | ||||
| return false; | return false; | ||||
| } | } | ||||
| switch (GS(id->name)) { | |||||
| case ID_ME: { | |||||
| Mesh *me = (Mesh *)id; | |||||
| BMEditMesh *em = me->edit_mesh; | |||||
| if (em != NULL) { | |||||
| BM_data_layer_free(em->bm, customdata, layer->type); | |||||
| } | |||||
| else { | |||||
| const int length = BKE_id_attribute_data_length(id, layer); | |||||
| CustomData_free_layer(customdata, layer->type, length, index); | |||||
| } | |||||
| break; | |||||
| } | |||||
| default: { | |||||
| const int length = BKE_id_attribute_data_length(id, layer); | const int length = BKE_id_attribute_data_length(id, layer); | ||||
| CustomData_free_layer(customdata, layer->type, length, index); | CustomData_free_layer(customdata, layer->type, length, index); | ||||
| break; | |||||
| } | |||||
| } | |||||
| return true; | return true; | ||||
| } | } | ||||
| int BKE_id_attributes_length(ID *id, const CustomDataMask mask) | int BKE_id_attributes_length(ID *id, const CustomDataMask mask) | ||||
| { | { | ||||
| DomainInfo info[ATTR_DOMAIN_NUM]; | DomainInfo info[ATTR_DOMAIN_NUM]; | ||||
| get_domains(id, info); | get_domains(id, info); | ||||
| Show All 16 Lines | AttributeDomain BKE_id_attribute_domain(ID *id, CustomDataLayer *layer) | ||||
| for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) { | for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) { | ||||
| CustomData *customdata = info[domain].customdata; | CustomData *customdata = info[domain].customdata; | ||||
| if (customdata && ARRAY_HAS_ITEM(layer, customdata->layers, customdata->totlayer)) { | if (customdata && ARRAY_HAS_ITEM(layer, customdata->layers, customdata->totlayer)) { | ||||
| return domain; | return domain; | ||||
| } | } | ||||
| } | } | ||||
| BLI_assert(!"Custom data layer not found in geometry"); | BLI_assert_msg(0, "Custom data layer not found in geometry"); | ||||
| return ATTR_DOMAIN_NUM; | return ATTR_DOMAIN_NUM; | ||||
| } | } | ||||
| int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer) | int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer) | ||||
| { | { | ||||
| DomainInfo info[ATTR_DOMAIN_NUM]; | DomainInfo info[ATTR_DOMAIN_NUM]; | ||||
| get_domains(id, info); | get_domains(id, info); | ||||
| for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) { | for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) { | ||||
| CustomData *customdata = info[domain].customdata; | CustomData *customdata = info[domain].customdata; | ||||
| if (customdata && ARRAY_HAS_ITEM(layer, customdata->layers, customdata->totlayer)) { | if (customdata && ARRAY_HAS_ITEM(layer, customdata->layers, customdata->totlayer)) { | ||||
| return info[domain].length; | return info[domain].length; | ||||
| } | } | ||||
| } | } | ||||
| BLI_assert(!"Custom data layer not found in geometry"); | BLI_assert_msg(0, "Custom data layer not found in geometry"); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| bool BKE_id_attribute_required(ID *id, CustomDataLayer *layer) | bool BKE_id_attribute_required(ID *id, CustomDataLayer *layer) | ||||
| { | { | ||||
| switch (GS(id->name)) { | switch (GS(id->name)) { | ||||
| case ID_PT: { | case ID_PT: { | ||||
| return BKE_pointcloud_customdata_required((PointCloud *)id, layer); | return BKE_pointcloud_customdata_required((PointCloud *)id, layer); | ||||
| ▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| DomainInfo info[ATTR_DOMAIN_NUM]; | DomainInfo info[ATTR_DOMAIN_NUM]; | ||||
| get_domains(id, info); | get_domains(id, info); | ||||
| bool use_next = (layers == NULL); | bool use_next = (layers == NULL); | ||||
| for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) { | for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) { | ||||
| CustomData *customdata = info[domain].customdata; | CustomData *customdata = info[domain].customdata; | ||||
| if (customdata && customdata->layers) { | if (customdata && customdata->layers && customdata->totlayer) { | ||||
| if (customdata->layers == layers) { | if (customdata->layers == layers) { | ||||
| use_next = true; | use_next = true; | ||||
| } | } | ||||
| else if (use_next) { | else if (use_next) { | ||||
| return customdata; | return customdata; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||