Blender V4.3
abc_customdata.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2016 Kévin Dietrich. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "abc_customdata.h"
10#include "abc_axis_conversion.h"
11
12#include <Alembic/Abc/ICompoundProperty.h>
13#include <Alembic/Abc/ISampleSelector.h>
14#include <Alembic/Abc/OCompoundProperty.h>
15#include <Alembic/Abc/TypedArraySample.h>
16#include <Alembic/AbcCoreAbstract/PropertyHeader.h>
17#include <Alembic/AbcGeom/GeometryScope.h>
18#include <Alembic/AbcGeom/IGeomParam.h>
19#include <Alembic/AbcGeom/OGeomParam.h>
20
22#include "DNA_mesh_types.h"
23#include "DNA_meshdata_types.h"
24
25#include "BLI_math_base.h"
26#include "BLI_math_vector.h"
28#include "BLI_utildefines.h"
29
30#include "BKE_attribute.hh"
31#include "BKE_customdata.hh"
32#include "BKE_mesh.hh"
33
34/* NOTE: for now only UVs and Vertex Colors are supported for streaming.
35 * Although Alembic only allows for a single UV layer per {I|O}Schema, and does
36 * not have a vertex color concept, there is a convention between DCCs to write
37 * such data in a way that lets other DCC know what they are for. See comments
38 * in the write code for the conventions. */
39
40using Alembic::AbcGeom::kFacevaryingScope;
41using Alembic::AbcGeom::kVaryingScope;
42using Alembic::AbcGeom::kVertexScope;
43
44using Alembic::Abc::C4fArraySample;
45using Alembic::Abc::UInt32ArraySample;
46using Alembic::Abc::V2fArraySample;
47
48using Alembic::AbcGeom::OC4fGeomParam;
49using Alembic::AbcGeom::OV2fGeomParam;
50using Alembic::AbcGeom::OV3fGeomParam;
51namespace blender::io::alembic {
52
53/* ORCO, Generated Coordinates, and Reference Points ("Pref") are all terms for the same thing.
54 * Other applications (Maya, Houdini) write these to a property called "Pref". */
55static const std::string propNameOriginalCoordinates("Pref");
56
57static void get_uvs(const CDStreamConfig &config,
58 std::vector<Imath::V2f> &uvs,
59 std::vector<uint32_t> &uvidx,
60 const void *cd_data)
61{
62 const float2 *mloopuv_array = static_cast<const float2 *>(cd_data);
63
64 if (!mloopuv_array) {
65 return;
66 }
67
68 const OffsetIndices faces = config.mesh->faces();
69 int *corner_verts = config.corner_verts;
70
71 if (!config.pack_uvs) {
72 int count = 0;
73 uvidx.resize(config.totloop);
74 uvs.resize(config.totloop);
75
76 /* Iterate in reverse order to match exported polygons. */
77 for (const int i : faces.index_range()) {
78 const IndexRange face = faces[i];
79 const float2 *loopuv = mloopuv_array + face.start() + face.size();
80
81 for (int j = 0; j < face.size(); j++, count++) {
82 loopuv--;
83
84 uvidx[count] = count;
85 uvs[count][0] = (*loopuv)[0];
86 uvs[count][1] = (*loopuv)[1];
87 }
88 }
89 }
90 else {
91 /* Mapping for indexed UVs, deduplicating UV coordinates at vertices. */
92 std::vector<std::vector<uint32_t>> idx_map(config.totvert);
93 int idx_count = 0;
94
95 for (const int i : faces.index_range()) {
96 const IndexRange face = faces[i];
97 int *face_verts = corner_verts + face.start() + face.size();
98 const float2 *loopuv = mloopuv_array + face.start() + face.size();
99
100 for (int j = 0; j < face.size(); j++) {
101 face_verts--;
102 loopuv--;
103
104 Imath::V2f uv((*loopuv)[0], (*loopuv)[1]);
105 bool found_same = false;
106
107 /* Find UV already in uvs array. */
108 for (uint32_t uv_idx : idx_map[*face_verts]) {
109 if (uvs[uv_idx] == uv) {
110 found_same = true;
111 uvidx.push_back(uv_idx);
112 break;
113 }
114 }
115
116 /* UV doesn't exists for this vertex, add it. */
117 if (!found_same) {
118 uint32_t uv_idx = idx_count++;
119 idx_map[*face_verts].push_back(uv_idx);
120 uvidx.push_back(uv_idx);
121 uvs.push_back(uv);
122 }
123 }
124 }
125 }
126}
127
128const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, CustomData *data)
129{
130 const int active_uvlayer = CustomData_get_active_layer(data, CD_PROP_FLOAT2);
131
132 if (active_uvlayer < 0) {
133 return "";
134 }
135
136 const void *cd_data = CustomData_get_layer_n(data, CD_PROP_FLOAT2, active_uvlayer);
137
138 get_uvs(config, sample.uvs, sample.indices, cd_data);
139
140 return CustomData_get_layer_name(data, CD_PROP_FLOAT2, active_uvlayer);
141}
142
143/* Convention to write UVs:
144 * - V2fGeomParam on the arbGeomParam
145 * - set scope as face varying
146 * - (optional due to its behavior) tag as UV using Alembic::AbcGeom::SetIsUV
147 */
148static void write_uv(const OCompoundProperty &prop,
149 CDStreamConfig &config,
150 const void *data,
151 const char *name)
152{
153 std::vector<uint32_t> indices;
154 std::vector<Imath::V2f> uvs;
155
156 get_uvs(config, uvs, indices, data);
157
158 if (indices.empty() || uvs.empty()) {
159 return;
160 }
161
162 std::string uv_map_name(name);
163 OV2fGeomParam param = config.abc_uv_maps[uv_map_name];
164
165 if (!param.valid()) {
166 param = OV2fGeomParam(prop, name, true, kFacevaryingScope, 1);
167 }
168 OV2fGeomParam::Sample sample(V2fArraySample(&uvs.front(), uvs.size()),
169 UInt32ArraySample(&indices.front(), indices.size()),
170 kFacevaryingScope);
171 param.set(sample);
172 param.setTimeSampling(config.timesample_index);
173
174 config.abc_uv_maps[uv_map_name] = param;
175}
176
177static void get_cols(const CDStreamConfig &config,
178 std::vector<Imath::C4f> &buffer,
179 std::vector<uint32_t> &uvidx,
180 const void *cd_data)
181{
182 const float cscale = 1.0f / 255.0f;
183 const OffsetIndices faces = config.mesh->faces();
184 const MCol *cfaces = static_cast<const MCol *>(cd_data);
185
186 buffer.reserve(config.totvert);
187 uvidx.reserve(config.totvert);
188
189 Imath::C4f col;
190
191 for (const int i : faces.index_range()) {
192 const IndexRange face = faces[i];
193 const MCol *cface = &cfaces[face.start() + face.size()];
194
195 for (int j = 0; j < face.size(); j++) {
196 cface--;
197
198 col[0] = cface->a * cscale;
199 col[1] = cface->r * cscale;
200 col[2] = cface->g * cscale;
201 col[3] = cface->b * cscale;
202
203 buffer.push_back(col);
204 uvidx.push_back(buffer.size() - 1);
205 }
206 }
207}
208
209/* Convention to write Vertex Colors:
210 * - C3fGeomParam/C4fGeomParam on the arbGeomParam
211 * - set scope as vertex varying
212 */
213static void write_mcol(const OCompoundProperty &prop,
214 CDStreamConfig &config,
215 const void *data,
216 const char *name)
217{
218 std::vector<uint32_t> indices;
219 std::vector<Imath::C4f> buffer;
220
221 get_cols(config, buffer, indices, data);
222
223 if (indices.empty() || buffer.empty()) {
224 return;
225 }
226
227 std::string vcol_name(name);
228 OC4fGeomParam param = config.abc_vertex_colors[vcol_name];
229
230 if (!param.valid()) {
231 param = OC4fGeomParam(prop, name, true, kFacevaryingScope, 1);
232 }
233
234 OC4fGeomParam::Sample sample(C4fArraySample(&buffer.front(), buffer.size()),
235 UInt32ArraySample(&indices.front(), indices.size()),
236 kVertexScope);
237
238 param.set(sample);
239 param.setTimeSampling(config.timesample_index);
240
241 config.abc_vertex_colors[vcol_name] = param;
242}
243
244void write_generated_coordinates(const OCompoundProperty &prop, CDStreamConfig &config)
245{
246 Mesh *mesh = config.mesh;
247 const void *customdata = CustomData_get_layer(&mesh->vert_data, CD_ORCO);
248 if (customdata == nullptr) {
249 /* Data not available, so don't even bother creating an Alembic property for it. */
250 return;
251 }
252 const float(*orcodata)[3] = static_cast<const float(*)[3]>(customdata);
253
254 /* Convert 3D vertices from float[3] z=up to V3f y=up. */
255 std::vector<Imath::V3f> coords(config.totvert);
256 float orco_yup[3];
257 for (int vertex_idx = 0; vertex_idx < config.totvert; vertex_idx++) {
258 copy_yup_from_zup(orco_yup, orcodata[vertex_idx]);
259 coords[vertex_idx].setValue(orco_yup[0], orco_yup[1], orco_yup[2]);
260 }
261
262 /* ORCOs are always stored in the normalized 0..1 range in Blender, but Alembic stores them
263 * unnormalized, so we need to unnormalize (invert transform) them. */
265 mesh, reinterpret_cast<float(*)[3]>(coords.data()), mesh->verts_num, true);
266
267 if (!config.abc_orco.valid()) {
268 /* Create the Alembic property and keep a reference so future frames can reuse it. */
269 config.abc_orco = OV3fGeomParam(prop, propNameOriginalCoordinates, false, kVertexScope, 1);
270 }
271
272 OV3fGeomParam::Sample sample(coords, kVertexScope);
273 config.abc_orco.set(sample);
274}
275
276void write_custom_data(const OCompoundProperty &prop,
277 CDStreamConfig &config,
278 CustomData *data,
279 int data_type)
280{
281 eCustomDataType cd_data_type = static_cast<eCustomDataType>(data_type);
282
283 if (!CustomData_has_layer(data, cd_data_type)) {
284 return;
285 }
286
287 const int active_layer = CustomData_get_active_layer(data, cd_data_type);
288 const int tot_layers = CustomData_number_of_layers(data, cd_data_type);
289
290 for (int i = 0; i < tot_layers; i++) {
291 const void *cd_data = CustomData_get_layer_n(data, cd_data_type, i);
292 const char *name = CustomData_get_layer_name(data, cd_data_type, i);
293
294 if (cd_data_type == CD_PROP_FLOAT2) {
295 /* Already exported. */
296 if (i == active_layer) {
297 continue;
298 }
299
300 write_uv(prop, config, cd_data, name);
301 }
302 else if (cd_data_type == CD_PROP_BYTE_COLOR) {
303 write_mcol(prop, config, cd_data, name);
304 }
305 }
306}
307
308/* ************************************************************************** */
309
310using Alembic::Abc::C3fArraySamplePtr;
311using Alembic::Abc::C4fArraySamplePtr;
312using Alembic::Abc::PropertyHeader;
313using Alembic::Abc::UInt32ArraySamplePtr;
314
315using Alembic::AbcGeom::IC3fGeomParam;
316using Alembic::AbcGeom::IC4fGeomParam;
317using Alembic::AbcGeom::IV2fGeomParam;
318using Alembic::AbcGeom::IV3fGeomParam;
319
320static void read_uvs(const CDStreamConfig &config,
321 void *data,
322 const AbcUvScope uv_scope,
323 const Alembic::AbcGeom::V2fArraySamplePtr &uvs,
324 const UInt32ArraySamplePtr &indices)
325{
326 const OffsetIndices faces = config.mesh->faces();
327 const int *corner_verts = config.corner_verts;
328 float2 *mloopuvs = static_cast<float2 *>(data);
329
330 uint uv_index, loop_index, rev_loop_index;
331
332 BLI_assert(uv_scope != ABC_UV_SCOPE_NONE);
333 const bool do_uvs_per_loop = (uv_scope == ABC_UV_SCOPE_LOOP);
334
335 for (const int i : faces.index_range()) {
336 const IndexRange face = faces[i];
337 uint rev_loop_offset = face.start() + face.size() - 1;
338
339 for (int f = 0; f < face.size(); f++) {
340 rev_loop_index = rev_loop_offset - f;
341 loop_index = do_uvs_per_loop ? face.start() + f : corner_verts[rev_loop_index];
342 uv_index = (*indices)[loop_index];
343 const Imath::V2f &uv = (*uvs)[uv_index];
344
345 float2 &loopuv = mloopuvs[rev_loop_index];
346 loopuv[0] = uv[0];
347 loopuv[1] = uv[1];
348 }
349 }
350}
351
352static size_t mcols_out_of_bounds_check(const size_t color_index,
353 const size_t array_size,
354 const std::string &iobject_full_name,
355 const PropertyHeader &prop_header,
356 bool &r_is_out_of_bounds,
357 bool &r_bounds_warning_given)
358{
359 if (color_index < array_size) {
360 return color_index;
361 }
362
363 if (!r_bounds_warning_given) {
364 std::cerr << "Alembic: color index out of bounds "
365 "reading face colors for object "
366 << iobject_full_name << ", property " << prop_header.getName() << std::endl;
367 r_bounds_warning_given = true;
368 }
369 r_is_out_of_bounds = true;
370 return 0;
371}
372
373static void read_custom_data_mcols(const std::string &iobject_full_name,
374 const ICompoundProperty &arbGeomParams,
375 const PropertyHeader &prop_header,
376 const CDStreamConfig &config,
377 const Alembic::Abc::ISampleSelector &iss)
378{
379 C3fArraySamplePtr c3f_ptr = C3fArraySamplePtr();
380 C4fArraySamplePtr c4f_ptr = C4fArraySamplePtr();
381 Alembic::Abc::UInt32ArraySamplePtr indices;
382 bool use_c3f_ptr;
383 bool is_facevarying;
384
385 /* Find the correct interpretation of the data */
386 if (IC3fGeomParam::matches(prop_header)) {
387 IC3fGeomParam color_param(arbGeomParams, prop_header.getName());
388 IC3fGeomParam::Sample sample;
389 BLI_assert(STREQ("rgb", color_param.getInterpretation()));
390
391 color_param.getIndexed(sample, iss);
392 is_facevarying = sample.getScope() == kFacevaryingScope &&
393 config.totloop == sample.getIndices()->size();
394
395 c3f_ptr = sample.getVals();
396 indices = sample.getIndices();
397 use_c3f_ptr = true;
398 }
399 else if (IC4fGeomParam::matches(prop_header)) {
400 IC4fGeomParam color_param(arbGeomParams, prop_header.getName());
401 IC4fGeomParam::Sample sample;
402 BLI_assert(STREQ("rgba", color_param.getInterpretation()));
403
404 color_param.getIndexed(sample, iss);
405 is_facevarying = sample.getScope() == kFacevaryingScope &&
406 config.totloop == sample.getIndices()->size();
407
408 c4f_ptr = sample.getVals();
409 indices = sample.getIndices();
410 use_c3f_ptr = false;
411 }
412 else {
413 /* this won't happen due to the checks in read_custom_data() */
414 return;
415 }
416 BLI_assert(c3f_ptr || c4f_ptr);
417
418 /* Read the vertex colors */
419 void *cd_data = config.add_customdata_cb(
420 config.mesh, prop_header.getName().c_str(), CD_PROP_BYTE_COLOR);
421 MCol *cfaces = static_cast<MCol *>(cd_data);
422 const OffsetIndices faces = config.mesh->faces();
423 const int *corner_verts = config.corner_verts;
424
425 size_t face_index = 0;
426 size_t color_index;
427 bool bounds_warning_given = false;
428
429 /* The colors can go through two layers of indexing. Often the 'indices'
430 * array doesn't do anything (i.e. indices[n] = n), but when it does, it's
431 * important. Blender 2.79 writes indices incorrectly (see #53745), which
432 * is why we have to check for indices->size() > 0 */
433 bool use_dual_indexing = is_facevarying && indices->size() > 0;
434
435 for (const int i : faces.index_range()) {
436 const IndexRange face = faces[i];
437 MCol *cface = &cfaces[face.start() + face.size()];
438 const int *face_verts = &corner_verts[face.start() + face.size()];
439
440 for (int j = 0; j < face.size(); j++, face_index++) {
441 cface--;
442 face_verts--;
443
444 color_index = is_facevarying ? face_index : *face_verts;
445 if (use_dual_indexing) {
446 color_index = (*indices)[color_index];
447 }
448 if (use_c3f_ptr) {
449 bool is_mcols_out_of_bounds = false;
450 color_index = mcols_out_of_bounds_check(color_index,
451 c3f_ptr->size(),
452 iobject_full_name,
453 prop_header,
454 is_mcols_out_of_bounds,
455 bounds_warning_given);
456 if (is_mcols_out_of_bounds) {
457 continue;
458 }
459 const Imath::C3f &color = (*c3f_ptr)[color_index];
460 cface->a = unit_float_to_uchar_clamp(color[0]);
461 cface->r = unit_float_to_uchar_clamp(color[1]);
462 cface->g = unit_float_to_uchar_clamp(color[2]);
463 cface->b = 255;
464 }
465 else {
466 bool is_mcols_out_of_bounds = false;
467 color_index = mcols_out_of_bounds_check(color_index,
468 c4f_ptr->size(),
469 iobject_full_name,
470 prop_header,
471 is_mcols_out_of_bounds,
472 bounds_warning_given);
473 if (is_mcols_out_of_bounds) {
474 continue;
475 }
476 const Imath::C4f &color = (*c4f_ptr)[color_index];
477 cface->a = unit_float_to_uchar_clamp(color[0]);
478 cface->r = unit_float_to_uchar_clamp(color[1]);
479 cface->g = unit_float_to_uchar_clamp(color[2]);
480 cface->b = unit_float_to_uchar_clamp(color[3]);
481 }
482 }
483 }
484}
485
486static void read_custom_data_uvs(const ICompoundProperty &prop,
487 const PropertyHeader &prop_header,
488 const CDStreamConfig &config,
489 const Alembic::Abc::ISampleSelector &iss)
490{
491 IV2fGeomParam uv_param(prop, prop_header.getName());
492
493 if (!uv_param.isIndexed()) {
494 return;
495 }
496
497 IV2fGeomParam::Sample sample;
498 uv_param.getIndexed(sample, iss);
499
500 UInt32ArraySamplePtr uvs_indices = sample.getIndices();
501
502 const AbcUvScope uv_scope = get_uv_scope(uv_param.getScope(), config, uvs_indices);
503
504 if (uv_scope == ABC_UV_SCOPE_NONE) {
505 return;
506 }
507
508 void *cd_data = config.add_customdata_cb(
509 config.mesh, prop_header.getName().c_str(), CD_PROP_FLOAT2);
510
511 read_uvs(config, cd_data, uv_scope, sample.getVals(), uvs_indices);
512}
513
514void read_velocity(const V3fArraySamplePtr &velocities,
515 const CDStreamConfig &config,
516 const float velocity_scale)
517{
518 const int num_velocity_vectors = int(velocities->size());
519 if (num_velocity_vectors != config.mesh->verts_num) {
520 /* Files containing videogrammetry data may be malformed and export velocity data on missing
521 * frames (most likely by copying the last valid data). */
522 return;
523 }
524
526 CustomDataLayer *velocity_layer = BKE_attribute_new(
527 owner, "velocity", CD_PROP_FLOAT3, bke::AttrDomain::Point, nullptr);
528 float(*velocity)[3] = (float(*)[3])velocity_layer->data;
529
530 for (int i = 0; i < num_velocity_vectors; i++) {
531 const Imath::V3f &vel_in = (*velocities)[i];
532 copy_zup_from_yup(velocity[i], vel_in.getValue());
533 mul_v3_fl(velocity[i], velocity_scale);
534 }
535}
536
537void read_generated_coordinates(const ICompoundProperty &prop,
538 const CDStreamConfig &config,
539 const Alembic::Abc::ISampleSelector &iss)
540{
541 if (!prop.valid() || prop.getPropertyHeader(propNameOriginalCoordinates) == nullptr) {
542 /* The ORCO property isn't there, so don't bother trying to process it. */
543 return;
544 }
545
546 IV3fGeomParam param(prop, propNameOriginalCoordinates);
547 if (!param.valid() || param.isIndexed()) {
548 /* Invalid or indexed coordinates aren't supported. */
549 return;
550 }
551 if (param.getScope() != kVertexScope) {
552 /* These are original vertex coordinates, so must be vertex-scoped. */
553 return;
554 }
555
556 IV3fGeomParam::Sample sample = param.getExpandedValue(iss);
557 Alembic::AbcGeom::V3fArraySamplePtr abc_orco = sample.getVals();
558 const size_t totvert = abc_orco.get()->size();
559 Mesh *mesh = config.mesh;
560
561 if (totvert != mesh->verts_num) {
562 /* Either the data is somehow corrupted, or we have a dynamic simulation where only the ORCOs
563 * for the first frame were exported. */
564 return;
565 }
566
567 void *cd_data;
568 if (CustomData_has_layer(&mesh->vert_data, CD_ORCO)) {
569 cd_data = CustomData_get_layer_for_write(&mesh->vert_data, CD_ORCO, mesh->verts_num);
570 }
571 else {
572 cd_data = CustomData_add_layer(&mesh->vert_data, CD_ORCO, CD_CONSTRUCT, totvert);
573 }
574
575 float(*orcodata)[3] = static_cast<float(*)[3]>(cd_data);
576 for (int vertex_idx = 0; vertex_idx < totvert; ++vertex_idx) {
577 const Imath::V3f &abc_coords = (*abc_orco)[vertex_idx];
578 copy_zup_from_yup(orcodata[vertex_idx], abc_coords.getValue());
579 }
580
581 /* ORCOs are always stored in the normalized 0..1 range in Blender, but Alembic stores them
582 * unnormalized, so we need to normalize them. */
583 BKE_mesh_orco_verts_transform(mesh, orcodata, mesh->verts_num, false);
584}
585
586void read_custom_data(const std::string &iobject_full_name,
587 const ICompoundProperty &prop,
588 const CDStreamConfig &config,
589 const Alembic::Abc::ISampleSelector &iss)
590{
591 if (!prop.valid()) {
592 return;
593 }
594
595 int num_uvs = 0;
596
597 const size_t num_props = prop.getNumProperties();
598
599 for (size_t i = 0; i < num_props; i++) {
600 const Alembic::Abc::PropertyHeader &prop_header = prop.getPropertyHeader(i);
601
602 /* Read UVs according to convention. */
603 if (IV2fGeomParam::matches(prop_header) && Alembic::AbcGeom::isUV(prop_header)) {
604 if (++num_uvs > MAX_MTFACE) {
605 continue;
606 }
607
608 read_custom_data_uvs(prop, prop_header, config, iss);
609 continue;
610 }
611
612 /* Read vertex colors according to convention. */
613 if (IC3fGeomParam::matches(prop_header) || IC4fGeomParam::matches(prop_header)) {
614 read_custom_data_mcols(iobject_full_name, prop, prop_header, config, iss);
615 continue;
616 }
617 }
618}
619
620AbcUvScope get_uv_scope(const Alembic::AbcGeom::GeometryScope scope,
621 const CDStreamConfig &config,
622 const Alembic::AbcGeom::UInt32ArraySamplePtr &indices)
623{
624 if (scope == kFacevaryingScope && indices->size() == config.totloop) {
625 return ABC_UV_SCOPE_LOOP;
626 }
627
628 /* kVaryingScope is sometimes used for vertex scopes as the values vary across the vertices. To
629 * be sure, one has to check the size of the data against the number of vertices, as it could
630 * also be a varying attribute across the faces (i.e. one value per face). */
631 if (ELEM(scope, kVaryingScope, kVertexScope) && indices->size() == config.totvert) {
632 return ABC_UV_SCOPE_VERTEX;
633 }
634
635 return ABC_UV_SCOPE_NONE;
636}
637
638} // namespace blender::io::alembic
struct CustomDataLayer * BKE_attribute_new(AttributeOwner &owner, const char *name, eCustomDataType type, blender::bke::AttrDomain domain, struct ReportList *reports)
CustomData interface, see also DNA_customdata_types.h.
const void * CustomData_get_layer_n(const CustomData *data, eCustomDataType type, int n)
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
@ CD_CONSTRUCT
const char * CustomData_get_layer_name(const CustomData *data, eCustomDataType type, int n)
int CustomData_get_active_layer(const CustomData *data, eCustomDataType type)
void * CustomData_get_layer_for_write(CustomData *data, eCustomDataType type, int totelem)
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
void * CustomData_add_layer(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem)
int CustomData_number_of_layers(const CustomData *data, eCustomDataType type)
void BKE_mesh_orco_verts_transform(Mesh *mesh, blender::MutableSpan< blender::float3 > orco, bool invert)
#define BLI_assert(a)
Definition BLI_assert.h:50
MINLINE void mul_v3_fl(float r[3], float f)
unsigned int uint
#define ELEM(...)
#define STREQ(a, b)
@ CD_PROP_BYTE_COLOR
@ CD_PROP_FLOAT3
@ CD_PROP_FLOAT2
#define MAX_MTFACE
static AttributeOwner from_id(ID *id)
Definition attribute.cc:43
constexpr int64_t start() const
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
static ushort indices[]
uint col
int count
#define unit_float_to_uchar_clamp(val)
AbcUvScope get_uv_scope(const Alembic::AbcGeom::GeometryScope scope, const CDStreamConfig &config, const Alembic::AbcGeom::UInt32ArraySamplePtr &indices)
BLI_INLINE void copy_yup_from_zup(float yup[3], const float zup[3])
const char * get_uv_sample(UVSample &sample, const CDStreamConfig &config, CustomData *data)
static void write_uv(const OCompoundProperty &prop, CDStreamConfig &config, const void *data, const char *name)
void read_velocity(const V3fArraySamplePtr &velocities, const CDStreamConfig &config, const float velocity_scale)
static void read_custom_data_mcols(const std::string &iobject_full_name, const ICompoundProperty &arbGeomParams, const PropertyHeader &prop_header, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss)
void write_custom_data(const OCompoundProperty &prop, CDStreamConfig &config, CustomData *data, int data_type)
static void write_mcol(const OCompoundProperty &prop, CDStreamConfig &config, const void *data, const char *name)
BLI_INLINE void copy_zup_from_yup(float zup[3], const float yup[3])
void read_custom_data(const std::string &iobject_full_name, const ICompoundProperty &prop, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss)
static void get_uvs(const CDStreamConfig &config, std::vector< Imath::V2f > &uvs, std::vector< uint32_t > &uvidx, const void *cd_data)
static const std::string propNameOriginalCoordinates("Pref")
static void read_custom_data_uvs(const ICompoundProperty &prop, const PropertyHeader &prop_header, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss)
void read_generated_coordinates(const ICompoundProperty &prop, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss)
static size_t mcols_out_of_bounds_check(const size_t color_index, const size_t array_size, const std::string &iobject_full_name, const PropertyHeader &prop_header, bool &r_is_out_of_bounds, bool &r_bounds_warning_given)
void write_generated_coordinates(const OCompoundProperty &prop, CDStreamConfig &config)
static void get_cols(const CDStreamConfig &config, std::vector< Imath::C4f > &buffer, std::vector< uint32_t > &uvidx, const void *cd_data)
static void read_uvs(const CDStreamConfig &config, void *data, const AbcUvScope uv_scope, const Alembic::AbcGeom::V2fArraySamplePtr &uvs, const UInt32ArraySamplePtr &indices)
unsigned int uint32_t
Definition stdint.h:80
unsigned char r
unsigned char a
unsigned char g
unsigned char b
int verts_num
std::map< std::string, Alembic::AbcGeom::OC4fGeomParam > abc_vertex_colors
void *(* add_customdata_cb)(Mesh *mesh, const char *name, int data_type)
Alembic::AbcGeom::OV3fGeomParam abc_orco
std::map< std::string, Alembic::AbcGeom::OV2fGeomParam > abc_uv_maps