Blender  V2.93
attribute.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2006 Blender Foundation.
17  * All rights reserved.
18  *
19  * Implementation of generic geometry attributes management. This is built
20  * on top of CustomData, which manages individual domains.
21  */
22 
27 #include <string.h>
28 
29 #include "MEM_guardedalloc.h"
30 
31 #include "DNA_ID.h"
32 #include "DNA_customdata_types.h"
33 #include "DNA_hair_types.h"
34 #include "DNA_mesh_types.h"
35 #include "DNA_meshdata_types.h"
36 #include "DNA_pointcloud_types.h"
37 
38 #include "BLI_string_utf8.h"
39 
40 #include "BKE_attribute.h"
41 #include "BKE_customdata.h"
42 #include "BKE_hair.h"
43 #include "BKE_pointcloud.h"
44 #include "BKE_report.h"
45 
46 #include "RNA_access.h"
47 
48 typedef struct DomainInfo {
50  int length;
52 
53 static void get_domains(ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
54 {
55  memset(info, 0, sizeof(DomainInfo) * ATTR_DOMAIN_NUM);
56 
57  switch (GS(id->name)) {
58  case ID_PT: {
59  PointCloud *pointcloud = (PointCloud *)id;
60  info[ATTR_DOMAIN_POINT].customdata = &pointcloud->pdata;
61  info[ATTR_DOMAIN_POINT].length = pointcloud->totpoint;
62  break;
63  }
64  case ID_ME: {
65  Mesh *mesh = (Mesh *)id;
66  info[ATTR_DOMAIN_POINT].customdata = &mesh->vdata;
67  info[ATTR_DOMAIN_POINT].length = mesh->totvert;
68  info[ATTR_DOMAIN_EDGE].customdata = &mesh->edata;
69  info[ATTR_DOMAIN_EDGE].length = mesh->totedge;
70  info[ATTR_DOMAIN_CORNER].customdata = &mesh->ldata;
71  info[ATTR_DOMAIN_CORNER].length = mesh->totloop;
72  info[ATTR_DOMAIN_FACE].customdata = &mesh->pdata;
73  info[ATTR_DOMAIN_FACE].length = mesh->totpoly;
74  break;
75  }
76  case ID_HA: {
77  Hair *hair = (Hair *)id;
78  info[ATTR_DOMAIN_POINT].customdata = &hair->pdata;
79  info[ATTR_DOMAIN_POINT].length = hair->totpoint;
80  info[ATTR_DOMAIN_CURVE].customdata = &hair->cdata;
81  info[ATTR_DOMAIN_CURVE].length = hair->totcurve;
82  break;
83  }
84  default:
85  break;
86  }
87 }
88 
90 {
92  get_domains(id, info);
93 
94  for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
95  CustomData *customdata = info[domain].customdata;
96  if (customdata && ARRAY_HAS_ITEM(layer, customdata->layers, customdata->totlayer)) {
97  return customdata;
98  }
99  }
100 
101  return NULL;
102 }
103 
105 {
107  get_domains(id, info);
108  for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
109  if (info[domain].customdata) {
110  return true;
111  }
112  }
113  return false;
114 }
115 
117  CustomDataLayer *layer,
118  const char *new_name,
119  ReportList *reports)
120 {
121  if (BKE_id_attribute_required(id, layer)) {
122  BLI_assert(!"Required attribute name is not editable");
123  return false;
124  }
125 
126  CustomData *customdata = attribute_customdata_find(id, layer);
127  if (customdata == NULL) {
128  BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry");
129  return false;
130  }
131 
132  BLI_strncpy_utf8(layer->name, new_name, sizeof(layer->name));
133  CustomData_set_layer_unique_name(customdata, layer - customdata->layers);
134  return true;
135 }
136 
138  ID *id, const char *name, const int type, const AttributeDomain domain, ReportList *reports)
139 {
141  get_domains(id, info);
142 
143  CustomData *customdata = info[domain].customdata;
144  if (customdata == NULL) {
145  BKE_report(reports, RPT_ERROR, "Attribute domain not supported by this geometry type");
146  return NULL;
147  }
148 
149  CustomData_add_layer_named(customdata, type, CD_DEFAULT, NULL, info[domain].length, name);
150  const int index = CustomData_get_named_layer_index(customdata, type, name);
151  return (index == -1) ? NULL : &(customdata->layers[index]);
152 }
153 
155 {
156  CustomData *customdata = attribute_customdata_find(id, layer);
157  const int index = (customdata) ?
158  CustomData_get_named_layer_index(customdata, layer->type, layer->name) :
159  -1;
160 
161  if (index == -1) {
162  BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry");
163  return false;
164  }
165 
166  if (BKE_id_attribute_required(id, layer)) {
167  BKE_report(reports, RPT_ERROR, "Attribute is required and can't be removed");
168  return false;
169  }
170 
171  const int length = BKE_id_attribute_data_length(id, layer);
172  CustomData_free_layer(customdata, layer->type, length, index);
173  return true;
174 }
175 
177 {
179  get_domains(id, info);
180 
181  int length = 0;
182 
183  for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
184  CustomData *customdata = info[domain].customdata;
185  if (customdata) {
187  }
188  }
189 
190  return length;
191 }
192 
194 {
196  get_domains(id, info);
197 
198  for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
199  CustomData *customdata = info[domain].customdata;
200  if (customdata && ARRAY_HAS_ITEM(layer, customdata->layers, customdata->totlayer)) {
201  return domain;
202  }
203  }
204 
205  BLI_assert(!"Custom data layer not found in geometry");
206  return ATTR_DOMAIN_NUM;
207 }
208 
210 {
212  get_domains(id, info);
213 
214  for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
215  CustomData *customdata = info[domain].customdata;
216  if (customdata && ARRAY_HAS_ITEM(layer, customdata->layers, customdata->totlayer)) {
217  return info[domain].length;
218  }
219  }
220 
221  BLI_assert(!"Custom data layer not found in geometry");
222  return 0;
223 }
224 
226 {
227  switch (GS(id->name)) {
228  case ID_PT: {
229  return BKE_pointcloud_customdata_required((PointCloud *)id, layer);
230  }
231  case ID_HA: {
232  return BKE_hair_customdata_required((Hair *)id, layer);
233  }
234  default:
235  return false;
236  }
237 }
238 
240 {
241  int active_index = *BKE_id_attributes_active_index_p(id);
242  if (active_index > BKE_id_attributes_length(id, CD_MASK_PROP_ALL)) {
243  active_index = 0;
244  }
245 
247  get_domains(id, info);
248 
249  int index = 0;
250 
251  for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
252  CustomData *customdata = info[domain].customdata;
253  if (customdata) {
254  for (int i = 0; i < customdata->totlayer; i++) {
255  CustomDataLayer *layer = &customdata->layers[i];
256  if (CD_MASK_PROP_ALL & CD_TYPE_AS_MASK(layer->type)) {
257  if (index == active_index) {
258  return layer;
259  }
260  index++;
261  }
262  }
263  }
264  }
265 
266  return NULL;
267 }
268 
270 {
272  get_domains(id, info);
273 
274  int index = 0;
275 
276  for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
277  CustomData *customdata = info[domain].customdata;
278  if (customdata) {
279  for (int i = 0; i < customdata->totlayer; i++) {
280  CustomDataLayer *layer = &customdata->layers[i];
281  if (layer == active_layer) {
283  return;
284  }
285  if (CD_MASK_PROP_ALL & CD_TYPE_AS_MASK(layer->type)) {
286  index++;
287  }
288  }
289  }
290  }
291 }
292 
294 {
295  switch (GS(id->name)) {
296  case ID_PT: {
297  return &((PointCloud *)id)->attributes_active_index;
298  }
299  case ID_ME: {
300  return &((Mesh *)id)->attributes_active_index;
301  }
302  case ID_HA: {
303  return &((Hair *)id)->attributes_active_index;
304  }
305  default:
306  return NULL;
307  }
308 }
309 
311 {
313  get_domains(id, info);
314 
315  bool use_next = (layers == NULL);
316 
317  for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
318  CustomData *customdata = info[domain].customdata;
319  if (customdata && customdata->layers) {
320  if (customdata->layers == layers) {
321  use_next = true;
322  }
323  else if (use_next) {
324  return customdata;
325  }
326  }
327  }
328 
329  return NULL;
330 }
Generic geometry attributes built on CustomData.
AttributeDomain
Definition: BKE_attribute.h:41
@ ATTR_DOMAIN_NUM
Definition: BKE_attribute.h:49
@ ATTR_DOMAIN_CURVE
Definition: BKE_attribute.h:47
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:43
@ ATTR_DOMAIN_FACE
Definition: BKE_attribute.h:46
@ ATTR_DOMAIN_CORNER
Definition: BKE_attribute.h:45
@ ATTR_DOMAIN_EDGE
Definition: BKE_attribute.h:44
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_free_layer(struct CustomData *data, int type, int totelem, int index)
Definition: customdata.c:2655
@ CD_DEFAULT
uint64_t CustomDataMask
int CustomData_get_named_layer_index(const struct CustomData *data, int type, const char *name)
void CustomData_set_layer_unique_name(struct CustomData *data, int index)
Definition: customdata.c:4361
void * CustomData_add_layer_named(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem, const char *name)
Definition: customdata.c:2637
int CustomData_number_of_layers_typemask(const struct CustomData *data, CustomDataMask mask)
#define CD_TYPE_AS_MASK(_type)
General operations for hairs.
bool BKE_hair_customdata_required(struct Hair *hair, struct CustomDataLayer *layer)
General operations for point-clouds.
bool BKE_pointcloud_customdata_required(struct PointCloud *pointcloud, struct CustomDataLayer *layer)
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
#define BLI_assert(a)
Definition: BLI_assert.h:58
char * BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string_utf8.c:258
#define ARRAY_HAS_ITEM(arr_item, arr_start, arr_len)
ID and Library types, which are fundamental for sdna.
@ ID_HA
Definition: DNA_ID_enums.h:93
@ ID_ME
Definition: DNA_ID_enums.h:60
@ ID_PT
Definition: DNA_ID_enums.h:94
#define CD_MASK_PROP_ALL
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Read Guarded memory(de)allocation.
static void get_domains(ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
Definition: attribute.c:53
static CustomData * attribute_customdata_find(ID *id, CustomDataLayer *layer)
Definition: attribute.c:89
bool BKE_id_attributes_supported(struct ID *id)
Definition: attribute.c:104
int BKE_id_attributes_length(ID *id, const CustomDataMask mask)
Definition: attribute.c:176
CustomDataLayer * BKE_id_attribute_new(ID *id, const char *name, const int type, const AttributeDomain domain, ReportList *reports)
Definition: attribute.c:137
bool BKE_id_attribute_rename(ID *id, CustomDataLayer *layer, const char *new_name, ReportList *reports)
Definition: attribute.c:116
int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer)
Definition: attribute.c:209
CustomDataLayer * BKE_id_attributes_active_get(ID *id)
Definition: attribute.c:239
bool BKE_id_attribute_required(ID *id, CustomDataLayer *layer)
Definition: attribute.c:225
struct DomainInfo DomainInfo
AttributeDomain BKE_id_attribute_domain(ID *id, CustomDataLayer *layer)
Definition: attribute.c:193
int * BKE_id_attributes_active_index_p(ID *id)
Definition: attribute.c:293
void BKE_id_attributes_active_set(ID *id, CustomDataLayer *active_layer)
Definition: attribute.c:269
CustomData * BKE_id_attributes_iterator_next_domain(ID *id, CustomDataLayer *layers)
Definition: attribute.c:310
bool BKE_id_attribute_remove(ID *id, CustomDataLayer *layer, ReportList *reports)
Definition: attribute.c:154
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
Definition: btQuaternion.h:895
#define GS(x)
Definition: iris.c:241
CustomDataLayer * layers
CustomData * customdata
Definition: attribute.c:49
int length
Definition: attribute.c:50
struct CustomData pdata
int totcurve
int totpoint
struct CustomData cdata
Definition: DNA_ID.h:273
char name[66]
Definition: DNA_ID.h:283
struct CustomData pdata ldata
int totedge
int totvert
int totpoly
int totloop
struct CustomData pdata
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)