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 20 /** \file 21 * \ingroup bke 22 * \brief CustomData interface, see also DNA_customdata_types.h. 23 */ 24 25 #pragma once 26 27 #include "BLI_sys_types.h" 28 #include "BLI_utildefines.h" 29 30 #include "DNA_customdata_types.h" 31 32 #ifdef __cplusplus 33 extern "C" { 34 #endif 35 36 struct BMesh; 37 struct BlendDataReader; 38 struct BlendWriter; 39 struct CustomData; 40 struct CustomData_MeshMasks; 41 struct ID; 42 typedef uint64_t CustomDataMask; 43 44 /*a data type large enough to hold 1 element from any customdata layer type*/ 45 typedef struct { 46 unsigned char data[64]; 47 } CDBlockBytes; 48 49 extern const CustomData_MeshMasks CD_MASK_BAREMESH; 50 extern const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX; 51 extern const CustomData_MeshMasks CD_MASK_MESH; 52 extern const CustomData_MeshMasks CD_MASK_EDITMESH; 53 extern const CustomData_MeshMasks CD_MASK_DERIVEDMESH; 54 extern const CustomData_MeshMasks CD_MASK_BMESH; 55 extern const CustomData_MeshMasks CD_MASK_FACECORNERS; 56 extern const CustomData_MeshMasks CD_MASK_EVERYTHING; 57 58 /* for ORIGINDEX layer type, indicates no original index for this element */ 59 #define ORIGINDEX_NONE -1 60 61 /* initializes a CustomData object with the same layer setup as source and 62 * memory space for totelem elements. mask must be an array of length 63 * CD_NUMTYPES elements, that indicate if a layer can be copied. */ 64 65 /** Add/copy/merge allocation types. */ 66 typedef enum eCDAllocType { 67 /** Use the data pointer. */ 68 CD_ASSIGN = 0, 69 /** Allocate blank memory. */ 70 CD_CALLOC = 1, 71 /** Allocate and set to default. */ 72 CD_DEFAULT = 2, 73 /** Use data pointers, set layer flag NOFREE. */ 74 CD_REFERENCE = 3, 75 /** Do a full copy of all layers, only allowed if source has same number of elements. */ 76 CD_DUPLICATE = 4, 77 } eCDAllocType; 78 79 #define CD_TYPE_AS_MASK(_type) (CustomDataMask)((CustomDataMask)1 << (CustomDataMask)(_type)) 80 81 void customData_mask_layers__print(const struct CustomData_MeshMasks *mask); 82 83 typedef void (*cd_interp)( 84 const void **sources, const float *weights, const float *sub_weights, int count, void *dest); 85 typedef void (*cd_copy)(const void *source, void *dest, int count); 86 typedef bool (*cd_validate)(void *item, const uint totitems, const bool do_fixes); 87 88 void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst, 89 const CustomData_MeshMasks *mask_src); 90 bool CustomData_MeshMasks_are_matching(const CustomData_MeshMasks *mask_ref, 91 const CustomData_MeshMasks *mask_required); 92 93 /** 94 * Checks if the layer at physical offset \a layer_n (in data->layers) support math 95 * the below operations. 96 */ 97 bool CustomData_layer_has_math(const struct CustomData *data, int layer_n); 98 bool CustomData_layer_has_interp(const struct CustomData *data, int layer_n); 99 100 /** 101 * Checks if any of the customdata layers has math. 102 */ 103 bool CustomData_has_math(const struct CustomData *data); 104 bool CustomData_has_interp(const struct CustomData *data); 105 bool CustomData_bmesh_has_free(const struct CustomData *data); 106 107 /** 108 * Checks if any of the customdata layers is referenced. 109 */ 110 bool CustomData_has_referenced(const struct CustomData *data); 111 112 /* copies the "value" (e.g. mloopuv uv or mloopcol colors) from one block to 113 * another, while not overwriting anything else (e.g. flags). probably only 114 * implemented for mloopuv/mloopcol, for now.*/ 115 void CustomData_data_copy_value(int type, const void *source, void *dest); 116 117 /* Same as above, but doing advanced mixing. 118 * Only available for a few types of data (like colors...). */ 119 void CustomData_data_mix_value( 120 int type, const void *source, void *dest, const int mixmode, const float mixfactor); 121 122 /* compares if data1 is equal to data2. type is a valid CustomData type 123 * enum (e.g. CD_MLOOPUV). the layer type's equal function is used to compare 124 * the data, if it exists, otherwise memcmp is used.*/ 125 bool CustomData_data_equals(int type, const void *data1, const void *data2); 126 void CustomData_data_initminmax(int type, void *min, void *max); 127 void CustomData_data_dominmax(int type, const void *data, void *min, void *max); 128 void CustomData_data_multiply(int type, void *data, float fac); 129 void CustomData_data_add(int type, void *data1, const void *data2); 130 131 /* initializes a CustomData object with the same layer setup as source. 132 * mask is a bitfield where (mask & (1 << (layer type))) indicates 133 * if a layer should be copied or not. alloctype must be one of the above. */ 134 void CustomData_copy(const struct CustomData *source, 135 struct CustomData *dest, 136 CustomDataMask mask, 137 eCDAllocType alloctype, 138 int totelem); 139 140 /* BMESH_TODO, not really a public function but readfile.c needs it */ 141 void CustomData_update_typemap(struct CustomData *data); 142 143 /* same as the above, except that this will preserve existing layers, and only 144 * add the layers that were not there yet */ 145 bool CustomData_merge(const struct CustomData *source, 146 struct CustomData *dest, 147 CustomDataMask mask, 148 eCDAllocType alloctype, 149 int totelem); 150 151 /* Reallocate custom data to a new element count. 152 * Only affects on data layers which are owned by the CustomData itself, 153 * referenced data is kept unchanged, 154 * 155 * NOTE: Take care of referenced layers by yourself! 156 */ 157 void CustomData_realloc(struct CustomData *data, int totelem); 158 159 /* bmesh version of CustomData_merge; merges the layouts of source and dest, 160 * then goes through the mesh and makes sure all the customdata blocks are 161 * consistent with the new layout.*/ 162 bool CustomData_bmesh_merge(const struct CustomData *source, 163 struct CustomData *dest, 164 CustomDataMask mask, 165 eCDAllocType alloctype, 166 struct BMesh *bm, 167 const char htype); 168 169 /** NULL's all members and resets the typemap. */ 170 void CustomData_reset(struct CustomData *data); 171 172 /** 173 * Frees data associated with a CustomData object (doesn't free the object itself, though). 174 */ 175 void CustomData_free(struct CustomData *data, int totelem); 176 177 /* same as above, but only frees layers which matches the given mask. */ 178 void CustomData_free_typemask(struct CustomData *data, int totelem, CustomDataMask mask); 179 180 /* frees all layers with CD_FLAG_TEMPORARY */ 181 void CustomData_free_temporary(struct CustomData *data, int totelem); 182 183 /* adds a data layer of the given type to the CustomData object, optionally 184 * backed by an external data array. the different allocation types are 185 * defined above. returns the data of the layer. 186 */ 187 void *CustomData_add_layer( 188 struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem); 189 /*same as above but accepts a name */ 190 void *CustomData_add_layer_named(struct CustomData *data, 191 int type, 192 eCDAllocType alloctype, 193 void *layer, 194 int totelem, 195 const char *name); 196 197 /* frees the active or first data layer with the give type. 198 * returns 1 on success, 0 if no layer with the given type is found 199 * 200 * in editmode, use EDBM_data_layer_free instead of this function 201 */ 202 bool CustomData_free_layer(struct CustomData *data, int type, int totelem, int index); 203 204 /* frees the layer index with the give type. 205 * returns 1 on success, 0 if no layer with the given type is found 206 * 207 * in editmode, use EDBM_data_layer_free instead of this function 208 */ 209 bool CustomData_free_layer_active(struct CustomData *data, int type, int totelem); 210 211 /* same as above, but free all layers with type */ 212 void CustomData_free_layers(struct CustomData *data, int type, int totelem); 213 214 /* returns 1 if a layer with the specified type exists */ 215 bool CustomData_has_layer(const struct CustomData *data, int type); 216 217 /* returns the number of layers with this type */ 218 int CustomData_number_of_layers(const struct CustomData *data, int type); 219 int CustomData_number_of_layers_typemask(const struct CustomData *data, CustomDataMask mask); 220 221 /* duplicate data of a layer with flag NOFREE, and remove that flag. 222 * returns the layer data */ 223 void *CustomData_duplicate_referenced_layer(struct CustomData *data, 224 const int type, 225 const int totelem); 226 void *CustomData_duplicate_referenced_layer_n(struct CustomData *data, 227 const int type, 228 const int n, 229 const int totelem); 230 void *CustomData_duplicate_referenced_layer_named(struct CustomData *data, 231 const int type, 232 const char *name, 233 const int totelem); 234 bool CustomData_is_referenced_layer(struct CustomData *data, int type); 235 236 /* set the CD_FLAG_NOCOPY flag in custom data layers where the mask is 237 * zero for the layer type, so only layer types specified by the mask 238 * will be copied 239 */ 240 void CustomData_set_only_copy(const struct CustomData *data, CustomDataMask mask); 241 242 /* copies data from one CustomData object to another 243 * objects need not be compatible, each source layer is copied to the 244 * first dest layer of correct type (if there is none, the layer is skipped) 245 * return 1 on success, 0 on failure 246 */ 247 void CustomData_copy_data(const struct CustomData *source, 248 struct CustomData *dest, 249 int source_index, 250 int dest_index, 251 int count); 252 void CustomData_copy_data_named(const struct CustomData *source, 253 struct CustomData *dest, 254 int source_index, 255 int dest_index, 256 int count); 257 void CustomData_copy_elements(int type, void *src_data_ofs, void *dst_data_ofs, int count); 258 void CustomData_bmesh_copy_data(const struct CustomData *source, 259 struct CustomData *dest, 260 void *src_block, 261 void **dest_block); 262 void CustomData_bmesh_copy_data_exclude_by_type(const struct CustomData *source, 263 struct CustomData *dest, 264 void *src_block, 265 void **dest_block, 266 const CustomDataMask mask_exclude); 267 268 /* Copies data of a single layer of a given type. */ 269 void CustomData_copy_layer_type_data(const struct CustomData *source, 270 struct CustomData *destination, 271 int type, 272 int source_index, 273 int destination_index, 274 int count); 275 276 /* frees data in a CustomData object 277 * return 1 on success, 0 on failure 278 */ 279 void CustomData_free_elem(struct CustomData *data, int index, int count); 280 281 /* interpolates data from one CustomData object to another 282 * objects need not be compatible, each source layer is interpolated to the 283 * first dest layer of correct type (if there is none, the layer is skipped) 284 * if weights == NULL or sub_weights == NULL, they default to all 1's 285 * 286 * src_indices gives the source elements to interpolate from 287 * weights gives the weight for each source element 288 * sub_weights is an array of matrices of weights for sub-elements (matrices 289 * should be source->subElems * source->subElems in size) 290 * count gives the number of source elements to interpolate from 291 * dest_index gives the dest element to write the interpolated value to 292 */ 293 void CustomData_interp(const struct CustomData *source, 294 struct CustomData *dest, 295 const int *src_indices, 296 const float *weights, 297 const float *sub_weights, 298 int count, 299 int dest_index); 300 void CustomData_bmesh_interp_n(struct CustomData *data, 301 const void **src_blocks, 302 const float *weights, 303 const float *sub_weights, 304 int count, 305 void *dst_block_ofs, 306 int n); 307 void CustomData_bmesh_interp(struct CustomData *data, 308 const void **src_blocks, 309 const float *weights, 310 const float *sub_weights, 311 int count, 312 void *dst_block); 313 314 /* swaps the data in the element corners, to new corners with indices as 315 * specified in corner_indices. for edges this is an array of length 2, for 316 * faces an array of length 4 */ 317 void CustomData_swap_corners(struct CustomData *data, int index, const int *corner_indices); 318 319 void CustomData_swap(struct CustomData *data, const int index_a, const int index_b); 320 321 /* gets a pointer to the data element at index from the first layer of type 322 * returns NULL if there is no layer of type 323 */ 324 void *CustomData_get(const struct CustomData *data, int index, int type); 325 void *CustomData_get_n(const struct CustomData *data, int type, int index, int n); 326 void *CustomData_bmesh_get(const struct CustomData *data, void *block, int type); 327 void *CustomData_bmesh_get_n(const struct CustomData *data, void *block, int type, int n); 328 329 /* gets the layer at physical index n, with no type checking. 330 */ 331 void *CustomData_bmesh_get_layer_n(const struct CustomData *data, void *block, int n); 332 333 bool CustomData_set_layer_name(const struct CustomData *data, int type, int n, const char *name); 334 const char *CustomData_get_layer_name(const struct CustomData *data, int type, int n); 335 336 /* gets a pointer to the active or first layer of type 337 * returns NULL if there is no layer of type 338 */ 339 void *CustomData_get_layer(const struct CustomData *data, int type); 340 void *CustomData_get_layer_n(const struct CustomData *data, int type, int n); 341 void *CustomData_get_layer_named(const struct CustomData *data, int type, const char *name); 342 int CustomData_get_offset(const struct CustomData *data, int type); 343 int CustomData_get_n_offset(const struct CustomData *data, int type, int n); 344 345 int CustomData_get_layer_index(const struct CustomData *data, int type); 346 int CustomData_get_layer_index_n(const struct CustomData *data, int type, int n); 347 int CustomData_get_named_layer_index(const struct CustomData *data, int type, const char *name); 348 int CustomData_get_active_layer_index(const struct CustomData *data, int type); 349 int CustomData_get_render_layer_index(const struct CustomData *data, int type); 350 int CustomData_get_clone_layer_index(const struct CustomData *data, int type); 351 int CustomData_get_stencil_layer_index(const struct CustomData *data, int type); 352 int CustomData_get_named_layer(const struct CustomData *data, int type, const char *name); 353 int CustomData_get_active_layer(const struct CustomData *data, int type); 354 int CustomData_get_render_layer(const struct CustomData *data, int type); 355 int CustomData_get_clone_layer(const struct CustomData *data, int type); 356 int CustomData_get_stencil_layer(const struct CustomData *data, int type); 357 358 /* copies the data from source to the data element at index in the first 359 * layer of type 360 * no effect if there is no layer of type 361 */ 362 void CustomData_set(const struct CustomData *data, int index, int type, const void *source); 363 364 void CustomData_bmesh_set(const struct CustomData *data, 365 void *block, 366 int type, 367 const void *source); 368 369 void CustomData_bmesh_set_n( 370 struct CustomData *data, void *block, int type, int n, const void *source); 371 /* sets the data of the block at physical layer n. no real type checking 372 * is performed. 373 */ 374 void CustomData_bmesh_set_layer_n(struct CustomData *data, void *block, int n, const void *source); 375 376 /* set the pointer of to the first layer of type. the old data is not freed. 377 * returns the value of ptr if the layer is found, NULL otherwise 378 */ 379 void *CustomData_set_layer(const struct CustomData *data, int type, void *ptr); 380 void *CustomData_set_layer_n(const struct CustomData *data, int type, int n, void *ptr); 381 382 /* sets the nth layer of type as active */ 383 void CustomData_set_layer_active(struct CustomData *data, int type, int n); 384 void CustomData_set_layer_render(struct CustomData *data, int type, int n); 385 void CustomData_set_layer_clone(struct CustomData *data, int type, int n); 386 void CustomData_set_layer_stencil(struct CustomData *data, int type, int n); 387 388 /* same as above but works with an index from CustomData_get_layer_index */ 389 void CustomData_set_layer_active_index(struct CustomData *data, int type, int n); 390 void CustomData_set_layer_render_index(struct CustomData *data, int type, int n); 391 void CustomData_set_layer_clone_index(struct CustomData *data, int type, int n); 392 void CustomData_set_layer_stencil_index(struct CustomData *data, int type, int n); 393 394 /* adds flag to the layer flags */ 395 void CustomData_set_layer_flag(struct CustomData *data, int type, int flag); 396 void CustomData_clear_layer_flag(struct CustomData *data, int type, int flag); 397 398 void CustomData_bmesh_set_default(struct CustomData *data, void **block); 399 void CustomData_bmesh_free_block(struct CustomData *data, void **block); 400 void CustomData_bmesh_free_block_data(struct CustomData *data, void *block); 401 void CustomData_bmesh_free_block_data_exclude_by_type(struct CustomData *data, 402 void *block, 403 const CustomDataMask mask_exclude); 404 405 /* copy custom data to/from layers as in mesh/derivedmesh, to editmesh 406 * blocks of data. the CustomData's must not be compatible */ 407 void CustomData_to_bmesh_block(const struct CustomData *source, 408 struct CustomData *dest, 409 int src_index, 410 void **dest_block, 411 bool use_default_init); 412 void CustomData_from_bmesh_block(const struct CustomData *source, 413 struct CustomData *dest, 414 void *src_block, 415 int dest_index); 416 417 /* query info over types */ 418 void CustomData_file_write_info(int type, const char **r_struct_name, int *r_struct_num); 419 int CustomData_sizeof(int type); 420 421 /* get the name of a layer type */ 422 const char *CustomData_layertype_name(int type); 423 bool CustomData_layertype_is_singleton(int type); 424 int CustomData_layertype_layers_max(const int type); 425 426 /* make sure the name of layer at index is unique */ 427 void CustomData_set_layer_unique_name(struct CustomData *data, int index); 428 429 void CustomData_validate_layer_name(const struct CustomData *data, 430 int type, 431 const char *name, 432 char *outname); 433 434 /* for file reading compatibility, returns false if the layer was freed, 435 * only after this test passes, layer->data should be assigned */ 436 bool CustomData_verify_versions(struct CustomData *data, int index); 437 438 /*BMesh specific customdata stuff*/ 439 void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *ldata, int totloop); 440 void CustomData_from_bmeshpoly(struct CustomData *fdata, struct CustomData *ldata, int total); 441 void CustomData_bmesh_update_active_layers(struct CustomData *fdata, struct CustomData *ldata); 442 void CustomData_bmesh_do_versions_update_active_layers(struct CustomData *fdata, 443 struct CustomData *ldata); 444 void CustomData_bmesh_init_pool(struct CustomData *data, int totelem, const char htype); 445 446 #ifndef NDEBUG 447 bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *ldata, bool fallback); 448 #endif 449 450 /* Layer data validation. */ 451 bool CustomData_layer_validate(struct CustomDataLayer *layer, 452 const uint totitems, 453 const bool do_fixes); 454 void CustomData_layers__print(struct CustomData *data); 455 456 /* External file storage */ 457 458 void CustomData_external_add( 459 struct CustomData *data, struct ID *id, int type, int totelem, const char *filename); 460 void CustomData_external_remove(struct CustomData *data, struct ID *id, int type, int totelem); 461 bool CustomData_external_test(struct CustomData *data, int type); 462 463 void CustomData_external_write( 464 struct CustomData *data, struct ID *id, CustomDataMask mask, int totelem, int free); 465 void CustomData_external_read(struct CustomData *data, 466 struct ID *id, 467 CustomDataMask mask, 468 int totelem); 469 void CustomData_external_reload(struct CustomData *data, 470 struct ID *id, 471 CustomDataMask mask, 472 int totelem); 473 474 /* Mesh-to-mesh transfer data. */ 475 476 struct CustomDataTransferLayerMap; 477 struct MeshPairRemap; 478 479 typedef void (*cd_datatransfer_interp)(const struct CustomDataTransferLayerMap *laymap, 480 void *dest, 481 const void **sources, 482 const float *weights, 483 const int count, 484 const float mix_factor); 485 486 /** 487 * Fake CD_LAYERS (those are actually 'real' data stored directly into elements' structs, 488 * or otherwise not (directly) accessible to usual CDLayer system). */ 489 enum { 490 CD_FAKE = 1 << 8, 491 492 /* Vertices. */ 493 CD_FAKE_MDEFORMVERT = CD_FAKE | CD_MDEFORMVERT, /* *sigh* due to how vgroups are stored :( . */ 494 CD_FAKE_SHAPEKEY = CD_FAKE | 495 CD_SHAPEKEY, /* Not available as real CD layer in non-bmesh context. */ 496 497 /* Edges. */ 498 CD_FAKE_SEAM = CD_FAKE | 100, /* UV seam flag for edges. */ 499 CD_FAKE_CREASE = CD_FAKE | CD_CREASE, /* *sigh*. */ 500 501 /* Multiple types of mesh elements... */ 502 CD_FAKE_BWEIGHT = CD_FAKE | CD_BWEIGHT, /* *sigh*. */ 503 CD_FAKE_UV = CD_FAKE | 504 CD_MLOOPUV, /* UV flag, because we handle both loop's UVs and poly's textures. */ 505 506 CD_FAKE_LNOR = CD_FAKE | 507 CD_CUSTOMLOOPNORMAL, /* Because we play with clnor and temp lnor layers here. */ 508 509 CD_FAKE_SHARP = CD_FAKE | 200, /* Sharp flag for edges, smooth flag for faces. */ 510 }; 511 512 enum { 513 ME_VERT = 1 << 0, 514 ME_EDGE = 1 << 1, 515 ME_POLY = 1 << 2, 516 ME_LOOP = 1 << 3, 517 }; 518 519 /** 520 * How to filter out some elements (to leave untouched). 521 * Note those options are highly dependent on type of transferred data! */ 522 enum { 523 CDT_MIX_NOMIX = -1, /* Special case, only used because we abuse 'copy' CD callback. */ 524 CDT_MIX_TRANSFER = 0, 525 CDT_MIX_REPLACE_ABOVE_THRESHOLD = 1, 526 CDT_MIX_REPLACE_BELOW_THRESHOLD = 2, 527 CDT_MIX_MIX = 16, 528 CDT_MIX_ADD = 17, 529 CDT_MIX_SUB = 18, 530 CDT_MIX_MUL = 19, 531 /* etc. etc. */ 532 }; 533 534 typedef struct CustomDataTransferLayerMap { 535 struct CustomDataTransferLayerMap *next, *prev; 536 537 int data_type; 538 int mix_mode; 539 float mix_factor; 540 /** If non-NULL, array of weights, one for each dest item, replaces mix_factor. */ 541 const float *mix_weights; 542 543 /** Data source array (can be regular CD data, vertices/edges/etc., keyblocks...). */ 544 const void *data_src; 545 /** Data dest array (same type as dat_src). */ 546 void *data_dst; 547 /** Index to affect in data_src (used e.g. for vgroups). */ 548 int data_src_n; 549 /** Index to affect in data_dst (used e.g. for vgroups). */ 550 int data_dst_n; 551 /** Size of one element of data_src/data_dst. */ 552 size_t elem_size; 553 554 /** Size of actual data we transfer. */ 555 size_t data_size; 556 /** Offset of actual data we transfer (in element contained in data_src/dst). */ 557 size_t data_offset; 558 /** For bitflag transfer, flag(s) to affect in transferred data. */ 559 uint64_t data_flag; 560 561 /** Opaque pointer, to be used by specific interp callback (e.g. transformspace for normals). */ 562 void *interp_data; 563 564 cd_datatransfer_interp interp; 565 } CustomDataTransferLayerMap; 566 567 /* Those functions assume src_n and dst_n layers of given type exist in resp. src and dst. */ 568 void CustomData_data_transfer(const struct MeshPairRemap *me_remap, 569 const CustomDataTransferLayerMap *laymap); 570 571 /* .blend file I/O */ 572 void CustomData_blend_write_prepare(struct CustomData *data, 573 struct CustomDataLayer **r_write_layers, 574 struct CustomDataLayer *write_layers_buff, 575 size_t write_layers_size); 576 577 void CustomData_blend_write(struct BlendWriter *writer, 578 struct CustomData *data, 579 CustomDataLayer *layers, 580 int count, 581 CustomDataMask cddata_mask, 582 struct ID *id); 583 void CustomData_blend_read(struct BlendDataReader *reader, struct CustomData *data, int count); 584 585 #ifdef __cplusplus 586 } 587 #endif 588