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