Blender  V3.3
abc_reader_mesh.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include "abc_reader_mesh.h"
8 #include "abc_axis_conversion.h"
9 #include "abc_reader_transform.h"
10 #include "abc_util.h"
11 
12 #include <algorithm>
13 
14 #include "MEM_guardedalloc.h"
15 
16 #include "DNA_customdata_types.h"
17 #include "DNA_material_types.h"
18 #include "DNA_mesh_types.h"
19 #include "DNA_meshdata_types.h"
20 #include "DNA_object_types.h"
21 
22 #include "BLI_compiler_compat.h"
23 #include "BLI_edgehash.h"
24 #include "BLI_index_range.hh"
25 #include "BLI_listbase.h"
26 #include "BLI_math_geom.h"
27 
28 #include "BKE_attribute.h"
29 #include "BKE_lib_id.h"
30 #include "BKE_main.h"
31 #include "BKE_material.h"
32 #include "BKE_mesh.h"
33 #include "BKE_modifier.h"
34 #include "BKE_object.h"
35 
36 using Alembic::Abc::FloatArraySamplePtr;
37 using Alembic::Abc::Int32ArraySamplePtr;
38 using Alembic::Abc::IV3fArrayProperty;
39 using Alembic::Abc::P3fArraySamplePtr;
40 using Alembic::Abc::PropertyHeader;
41 using Alembic::Abc::V3fArraySamplePtr;
42 
43 using Alembic::AbcGeom::IC3fGeomParam;
44 using Alembic::AbcGeom::IC4fGeomParam;
45 using Alembic::AbcGeom::IFaceSet;
46 using Alembic::AbcGeom::IFaceSetSchema;
47 using Alembic::AbcGeom::IN3fGeomParam;
48 using Alembic::AbcGeom::IObject;
49 using Alembic::AbcGeom::IPolyMesh;
50 using Alembic::AbcGeom::IPolyMeshSchema;
51 using Alembic::AbcGeom::ISampleSelector;
52 using Alembic::AbcGeom::ISubD;
53 using Alembic::AbcGeom::ISubDSchema;
54 using Alembic::AbcGeom::IV2fGeomParam;
55 using Alembic::AbcGeom::kWrapExisting;
56 using Alembic::AbcGeom::N3fArraySample;
57 using Alembic::AbcGeom::N3fArraySamplePtr;
58 using Alembic::AbcGeom::UInt32ArraySamplePtr;
59 using Alembic::AbcGeom::V2fArraySamplePtr;
60 
61 namespace blender::io::alembic {
62 
63 /* NOTE: Alembic's polygon winding order is clockwise, to match with Renderman. */
64 
65 /* Some helpers for mesh generation */
66 namespace utils {
67 
68 static std::map<std::string, Material *> build_material_map(const Main *bmain)
69 {
70  std::map<std::string, Material *> mat_map;
72  mat_map[material->id.name + 2] = material;
73  }
74  return mat_map;
75 }
76 
77 static void assign_materials(Main *bmain,
78  Object *ob,
79  const std::map<std::string, int> &mat_index_map)
80 {
81  std::map<std::string, int>::const_iterator it;
82  if (mat_index_map.size() > MAXMAT) {
83  return;
84  }
85 
86  std::map<std::string, Material *> matname_to_material = build_material_map(bmain);
87  std::map<std::string, Material *>::iterator mat_iter;
88 
89  for (it = mat_index_map.begin(); it != mat_index_map.end(); ++it) {
90  const std::string mat_name = it->first;
91  const int mat_index = it->second;
92 
93  Material *assigned_mat;
94  mat_iter = matname_to_material.find(mat_name);
95  if (mat_iter == matname_to_material.end()) {
96  assigned_mat = BKE_material_add(bmain, mat_name.c_str());
97  id_us_min(&assigned_mat->id);
98  matname_to_material[mat_name] = assigned_mat;
99  }
100  else {
101  assigned_mat = mat_iter->second;
102  }
103 
104  BKE_object_material_assign_single_obdata(bmain, ob, assigned_mat, mat_index);
105  }
106  if (ob->totcol > 0) {
107  ob->actcol = 1;
108  }
109 }
110 
111 } /* namespace utils */
112 
113 struct AbcMeshData {
114  Int32ArraySamplePtr face_indices;
115  Int32ArraySamplePtr face_counts;
116 
117  P3fArraySamplePtr positions;
118  P3fArraySamplePtr ceil_positions;
119 
121  V2fArraySamplePtr uvs;
122  UInt32ArraySamplePtr uvs_indices;
123 };
124 
125 static void read_mverts_interp(MVert *mverts,
126  const P3fArraySamplePtr &positions,
127  const P3fArraySamplePtr &ceil_positions,
128  const double weight)
129 {
130  float tmp[3];
131  for (int i = 0; i < positions->size(); i++) {
132  MVert &mvert = mverts[i];
133  const Imath::V3f &floor_pos = (*positions)[i];
134  const Imath::V3f &ceil_pos = (*ceil_positions)[i];
135 
136  interp_v3_v3v3(tmp, floor_pos.getValue(), ceil_pos.getValue(), static_cast<float>(weight));
137  copy_zup_from_yup(mvert.co, tmp);
138 
139  mvert.bweight = 0;
140  }
141 }
142 
143 static void read_mverts(CDStreamConfig &config, const AbcMeshData &mesh_data)
144 {
145  MVert *mverts = config.mvert;
146  const P3fArraySamplePtr &positions = mesh_data.positions;
147 
148  if (config.use_vertex_interpolation && config.weight != 0.0f &&
149  mesh_data.ceil_positions != nullptr &&
150  mesh_data.ceil_positions->size() == positions->size()) {
151  read_mverts_interp(mverts, positions, mesh_data.ceil_positions, config.weight);
152  return;
153  }
154 
155  read_mverts(*config.mesh, positions, nullptr);
156 }
157 
158 void read_mverts(Mesh &mesh, const P3fArraySamplePtr positions, const N3fArraySamplePtr normals)
159 {
160  for (int i = 0; i < positions->size(); i++) {
161  MVert &mvert = mesh.mvert[i];
162  Imath::V3f pos_in = (*positions)[i];
163 
164  copy_zup_from_yup(mvert.co, pos_in.getValue());
165 
166  mvert.bweight = 0;
167  }
168  if (normals) {
169  float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(&mesh);
170  for (const int64_t i : IndexRange(normals->size())) {
171  Imath::V3f nor_in = (*normals)[i];
172  copy_zup_from_yup(vert_normals[i], nor_in.getValue());
173  }
175  }
176 }
177 
178 static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
179 {
180  MPoly *mpolys = config.mpoly;
181  MLoop *mloops = config.mloop;
182  MLoopUV *mloopuvs = config.mloopuv;
183 
184  const Int32ArraySamplePtr &face_indices = mesh_data.face_indices;
185  const Int32ArraySamplePtr &face_counts = mesh_data.face_counts;
186  const V2fArraySamplePtr &uvs = mesh_data.uvs;
187  const size_t uvs_size = uvs == nullptr ? 0 : uvs->size();
188 
189  const UInt32ArraySamplePtr &uvs_indices = mesh_data.uvs_indices;
190 
191  const bool do_uvs = (mloopuvs && uvs && uvs_indices);
192  const bool do_uvs_per_loop = do_uvs && mesh_data.uv_scope == ABC_UV_SCOPE_LOOP;
193  BLI_assert(!do_uvs || mesh_data.uv_scope != ABC_UV_SCOPE_NONE);
194  unsigned int loop_index = 0;
195  unsigned int rev_loop_index = 0;
196  unsigned int uv_index = 0;
197  bool seen_invalid_geometry = false;
198 
199  for (int i = 0; i < face_counts->size(); i++) {
200  const int face_size = (*face_counts)[i];
201 
202  MPoly &poly = mpolys[i];
203  poly.loopstart = loop_index;
204  poly.totloop = face_size;
205 
206  /* Polygons are always assumed to be smooth-shaded. If the Alembic mesh should be flat-shaded,
207  * this is encoded in custom loop normals. See T71246. */
208  poly.flag |= ME_SMOOTH;
209 
210  /* NOTE: Alembic data is stored in the reverse order. */
211  rev_loop_index = loop_index + (face_size - 1);
212 
213  uint last_vertex_index = 0;
214  for (int f = 0; f < face_size; f++, loop_index++, rev_loop_index--) {
215  MLoop &loop = mloops[rev_loop_index];
216  loop.v = (*face_indices)[loop_index];
217 
218  if (f > 0 && loop.v == last_vertex_index) {
219  /* This face is invalid, as it has consecutive loops from the same vertex. This is caused
220  * by invalid geometry in the Alembic file, such as in T76514. */
221  seen_invalid_geometry = true;
222  }
223  last_vertex_index = loop.v;
224 
225  if (do_uvs) {
226  MLoopUV &loopuv = mloopuvs[rev_loop_index];
227  uv_index = (*uvs_indices)[do_uvs_per_loop ? loop_index : loop.v];
228 
229  /* Some Alembic files are broken (or at least export UVs in a way we don't expect). */
230  if (uv_index >= uvs_size) {
231  continue;
232  }
233 
234  loopuv.uv[0] = (*uvs)[uv_index][0];
235  loopuv.uv[1] = (*uvs)[uv_index][1];
236  }
237  }
238  }
239 
240  BKE_mesh_calc_edges(config.mesh, false, false);
241  if (seen_invalid_geometry) {
242  if (config.modifier_error_message) {
243  *config.modifier_error_message = "Mesh hash invalid geometry; more details on the console";
244  }
245  BKE_mesh_validate(config.mesh, true, true);
246  }
247 }
248 
249 static void process_no_normals(CDStreamConfig &config)
250 {
251  /* Absence of normals in the Alembic mesh is interpreted as 'smooth'. */
253 }
254 
255 static void process_loop_normals(CDStreamConfig &config, const N3fArraySamplePtr loop_normals_ptr)
256 {
257  size_t loop_count = loop_normals_ptr->size();
258 
259  if (loop_count == 0) {
260  process_no_normals(config);
261  return;
262  }
263 
264  Mesh *mesh = config.mesh;
265  if (loop_count != mesh->totloop) {
266  /* This happens in certain Houdini exports. When a mesh is animated and then replaced by a
267  * fluid simulation, Houdini will still write the original mesh's loop normals, but the mesh
268  * verts/loops/polys are from the simulation. In such cases the normals cannot be mapped to the
269  * mesh, so it's better to ignore them. */
270  process_no_normals(config);
271  return;
272  }
273 
274  float(*lnors)[3] = static_cast<float(*)[3]>(
275  MEM_malloc_arrayN(loop_count, sizeof(float[3]), "ABC::FaceNormals"));
276 
277  MPoly *mpoly = mesh->mpoly;
278  const N3fArraySample &loop_normals = *loop_normals_ptr;
279  int abc_index = 0;
280  for (int i = 0, e = mesh->totpoly; i < e; i++, mpoly++) {
281  /* As usual, ABC orders the loops in reverse. */
282  for (int j = mpoly->totloop - 1; j >= 0; j--, abc_index++) {
283  int blender_index = mpoly->loopstart + j;
284  copy_zup_from_yup(lnors[blender_index], loop_normals[abc_index].getValue());
285  }
286  }
287 
288  mesh->flag |= ME_AUTOSMOOTH;
290 
291  MEM_freeN(lnors);
292 }
293 
295  const N3fArraySamplePtr vertex_normals_ptr)
296 {
297  size_t normals_count = vertex_normals_ptr->size();
298  if (normals_count == 0) {
299  process_no_normals(config);
300  return;
301  }
302 
303  float(*vnors)[3] = static_cast<float(*)[3]>(
304  MEM_malloc_arrayN(normals_count, sizeof(float[3]), "ABC::VertexNormals"));
305 
306  const N3fArraySample &vertex_normals = *vertex_normals_ptr;
307  for (int index = 0; index < normals_count; index++) {
308  copy_zup_from_yup(vnors[index], vertex_normals[index].getValue());
309  }
310 
311  config.mesh->flag |= ME_AUTOSMOOTH;
313  MEM_freeN(vnors);
314 }
315 
316 static void process_normals(CDStreamConfig &config,
317  const IN3fGeomParam &normals,
318  const ISampleSelector &selector)
319 {
320  if (!normals.valid()) {
321  process_no_normals(config);
322  return;
323  }
324 
325  IN3fGeomParam::Sample normsamp = normals.getExpandedValue(selector);
326  Alembic::AbcGeom::GeometryScope scope = normals.getScope();
327 
328  switch (scope) {
329  case Alembic::AbcGeom::kFacevaryingScope: /* 'Vertex Normals' in Houdini. */
330  process_loop_normals(config, normsamp.getVals());
331  break;
332  case Alembic::AbcGeom::kVertexScope:
333  case Alembic::AbcGeom::kVaryingScope: /* 'Point Normals' in Houdini. */
334  process_vertex_normals(config, normsamp.getVals());
335  break;
336  case Alembic::AbcGeom::kConstantScope:
337  case Alembic::AbcGeom::kUniformScope:
338  case Alembic::AbcGeom::kUnknownScope:
339  process_no_normals(config);
340  break;
341  }
342 }
343 
345  AbcMeshData &abc_data,
346  const IV2fGeomParam &uv,
347  const ISampleSelector &selector)
348 {
349  if (!uv.valid()) {
350  return;
351  }
352 
353  IV2fGeomParam::Sample uvsamp;
354  uv.getIndexed(uvsamp, selector);
355 
356  UInt32ArraySamplePtr uvs_indices = uvsamp.getIndices();
357 
358  const AbcUvScope uv_scope = get_uv_scope(uv.getScope(), config, uvs_indices);
359 
360  if (uv_scope == ABC_UV_SCOPE_NONE) {
361  return;
362  }
363 
364  abc_data.uv_scope = uv_scope;
365  abc_data.uvs = uvsamp.getVals();
366  abc_data.uvs_indices = uvs_indices;
367 
368  std::string name = Alembic::Abc::GetSourceName(uv.getMetaData());
369 
370  /* According to the convention, primary UVs should have had their name
371  * set using Alembic::Abc::SetSourceName, but you can't expect everyone
372  * to follow it! :) */
373  if (name.empty()) {
374  name = uv.getName();
375  }
376 
377  void *cd_ptr = config.add_customdata_cb(config.mesh, name.c_str(), CD_MLOOPUV);
378  config.mloopuv = static_cast<MLoopUV *>(cd_ptr);
379 }
380 
381 static void *add_customdata_cb(Mesh *mesh, const char *name, int data_type)
382 {
383  eCustomDataType cd_data_type = static_cast<eCustomDataType>(data_type);
384 
385  /* unsupported custom data type -- don't do anything. */
386  if (!ELEM(cd_data_type, CD_MLOOPUV, CD_PROP_BYTE_COLOR)) {
387  return nullptr;
388  }
389 
390  void *cd_ptr = CustomData_get_layer_named(&mesh->ldata, cd_data_type, name);
391  if (cd_ptr != nullptr) {
392  /* layer already exists, so just return it. */
393  return cd_ptr;
394  }
395 
396  /* Create a new layer. */
397  int numloops = mesh->totloop;
399  &mesh->ldata, cd_data_type, CD_DEFAULT, nullptr, numloops, name);
400  return cd_ptr;
401 }
402 
404  Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling,
405  size_t samples_number)
406 {
407  Alembic::AbcGeom::index_t i0, i1;
408 
409  config.weight = get_weight_and_index(config.time, time_sampling, samples_number, i0, i1);
410 
411  config.index = i0;
412  config.ceil_index = i1;
413 }
414 
415 static V3fArraySamplePtr get_velocity_prop(const ICompoundProperty &schema,
416  const ISampleSelector &selector,
417  const std::string &name)
418 {
419  for (size_t i = 0; i < schema.getNumProperties(); i++) {
420  const PropertyHeader &header = schema.getPropertyHeader(i);
421 
422  if (header.isCompound()) {
423  const ICompoundProperty &prop = ICompoundProperty(schema, header.getName());
424 
425  if (has_property(prop, name)) {
426  /* Header cannot be null here, as its presence is checked via has_property, so it is safe
427  * to dereference. */
428  const PropertyHeader *header = prop.getPropertyHeader(name);
429  if (!IV3fArrayProperty::matches(*header)) {
430  continue;
431  }
432 
433  const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(prop, name, 0);
434  if (velocity_prop) {
435  return velocity_prop.getValue(selector);
436  }
437  }
438  }
439  else if (header.isArray()) {
440  if (header.getName() == name && IV3fArrayProperty::matches(header)) {
441  const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(schema, name, 0);
442  return velocity_prop.getValue(selector);
443  }
444  }
445  }
446 
447  return V3fArraySamplePtr();
448 }
449 
450 static void read_velocity(const V3fArraySamplePtr &velocities,
451  const CDStreamConfig &config,
452  const float velocity_scale)
453 {
454  const int num_velocity_vectors = static_cast<int>(velocities->size());
455  if (num_velocity_vectors != config.mesh->totvert) {
456  /* Files containing videogrammetry data may be malformed and export velocity data on missing
457  * frames (most likely by copying the last valid data). */
458  return;
459  }
460 
461  CustomDataLayer *velocity_layer = BKE_id_attribute_new(
462  &config.mesh->id, "velocity", CD_PROP_FLOAT3, ATTR_DOMAIN_POINT, nullptr);
463  float(*velocity)[3] = (float(*)[3])velocity_layer->data;
464 
465  for (int i = 0; i < num_velocity_vectors; i++) {
466  const Imath::V3f &vel_in = (*velocities)[i];
467  copy_zup_from_yup(velocity[i], vel_in.getValue());
468  mul_v3_fl(velocity[i], velocity_scale);
469  }
470 }
471 
472 static void read_mesh_sample(const std::string &iobject_full_name,
473  ImportSettings *settings,
474  const IPolyMeshSchema &schema,
475  const ISampleSelector &selector,
476  CDStreamConfig &config)
477 {
478  const IPolyMeshSchema::Sample sample = schema.getValue(selector);
479 
480  AbcMeshData abc_mesh_data;
481  abc_mesh_data.face_counts = sample.getFaceCounts();
482  abc_mesh_data.face_indices = sample.getFaceIndices();
483  abc_mesh_data.positions = sample.getPositions();
484 
485  get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples());
486 
487  if (config.weight != 0.0f) {
488  Alembic::AbcGeom::IPolyMeshSchema::Sample ceil_sample;
489  schema.get(ceil_sample, Alembic::Abc::ISampleSelector(config.ceil_index));
490  abc_mesh_data.ceil_positions = ceil_sample.getPositions();
491  }
492 
493  if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) {
494  read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector);
495  }
496 
497  if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) {
498  read_mverts(config, abc_mesh_data);
499  read_generated_coordinates(schema.getArbGeomParams(), config, selector);
500  }
501 
502  if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
503  read_mpolys(config, abc_mesh_data);
504  process_normals(config, schema.getNormalsParam(), selector);
505  }
506 
507  if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
508  read_custom_data(iobject_full_name, schema.getArbGeomParams(), config, selector);
509  }
510 
511  if (!settings->velocity_name.empty() && settings->velocity_scale != 0.0f) {
512  V3fArraySamplePtr velocities = get_velocity_prop(schema, selector, settings->velocity_name);
513  if (velocities) {
514  read_velocity(velocities, config, settings->velocity_scale);
515  }
516  }
517 }
518 
519 CDStreamConfig get_config(Mesh *mesh, const bool use_vertex_interpolation)
520 {
521  CDStreamConfig config;
522 
523  BLI_assert(mesh->mvert || mesh->totvert == 0);
524 
525  config.mesh = mesh;
526  config.mvert = mesh->mvert;
527  config.mloop = mesh->mloop;
528  config.mpoly = mesh->mpoly;
529  config.totvert = mesh->totvert;
530  config.totloop = mesh->totloop;
531  config.totpoly = mesh->totpoly;
532  config.loopdata = &mesh->ldata;
534  config.use_vertex_interpolation = use_vertex_interpolation;
535 
536  return config;
537 }
538 
539 /* ************************************************************************** */
540 
541 AbcMeshReader::AbcMeshReader(const IObject &object, ImportSettings &settings)
542  : AbcObjectReader(object, settings)
543 {
545 
546  IPolyMesh ipoly_mesh(m_iobject, kWrapExisting);
547  m_schema = ipoly_mesh.getSchema();
548 
550 }
551 
553 {
554  return m_schema.valid();
555 }
556 
557 template<class typedGeomParam>
558 bool is_valid_animated(const ICompoundProperty arbGeomParams, const PropertyHeader &prop_header)
559 {
560  if (!typedGeomParam::matches(prop_header)) {
561  return false;
562  }
563 
564  typedGeomParam geom_param(arbGeomParams, prop_header.getName());
565  return geom_param.valid() && !geom_param.isConstant();
566 }
567 
568 static bool has_animated_geom_params(const ICompoundProperty arbGeomParams)
569 {
570  if (!arbGeomParams.valid()) {
571  return false;
572  }
573 
574  const int num_props = arbGeomParams.getNumProperties();
575  for (int i = 0; i < num_props; i++) {
576  const PropertyHeader &prop_header = arbGeomParams.getPropertyHeader(i);
577 
578  /* These are interpreted as vertex colors later (see 'read_custom_data'). */
579  if (is_valid_animated<IC3fGeomParam>(arbGeomParams, prop_header)) {
580  return true;
581  }
582  if (is_valid_animated<IC4fGeomParam>(arbGeomParams, prop_header)) {
583  return true;
584  }
585  }
586 
587  return false;
588 }
589 
590 /* Specialization of #has_animations() as defined in abc_reader_object.h. */
591 template<> bool has_animations(Alembic::AbcGeom::IPolyMeshSchema &schema, ImportSettings *settings)
592 {
593  if (settings->is_sequence || !schema.isConstant()) {
594  return true;
595  }
596 
597  IV2fGeomParam uvsParam = schema.getUVsParam();
598  if (uvsParam.valid() && !uvsParam.isConstant()) {
599  return true;
600  }
601 
602  IN3fGeomParam normalsParam = schema.getNormalsParam();
603  if (normalsParam.valid() && !normalsParam.isConstant()) {
604  return true;
605  }
606 
607  ICompoundProperty arbGeomParams = schema.getArbGeomParams();
608  if (has_animated_geom_params(arbGeomParams)) {
609  return true;
610  }
611 
612  return false;
613 }
614 
615 void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
616 {
617  Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
618 
620  m_object->data = mesh;
621 
622  Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, "", 0.0f, nullptr);
623  if (read_mesh != mesh) {
624  /* XXX FIXME: after 2.80; mesh->flag isn't copied by #BKE_mesh_nomain_to_mesh(). */
625  /* read_mesh can be freed by BKE_mesh_nomain_to_mesh(), so get the flag before that happens. */
626  uint16_t autosmooth = (read_mesh->flag & ME_AUTOSMOOTH);
628  mesh->flag |= autosmooth;
629  }
630 
632  BKE_mesh_validate(mesh, false, false);
633  }
634 
635  readFaceSetsSample(bmain, mesh, sample_sel);
636 
639  }
640 }
641 
643  const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
644  const Object *const ob,
645  const char **err_str) const
646 {
647  if (!Alembic::AbcGeom::IPolyMesh::matches(alembic_header)) {
648  *err_str =
649  "Object type mismatch, Alembic object path pointed to PolyMesh when importing, but not "
650  "any more.";
651  return false;
652  }
653 
654  if (ob->type != OB_MESH) {
655  *err_str = "Object type mismatch, Alembic object path points to PolyMesh.";
656  return false;
657  }
658 
659  return true;
660 }
661 
662 bool AbcMeshReader::topology_changed(const Mesh *existing_mesh, const ISampleSelector &sample_sel)
663 {
664  IPolyMeshSchema::Sample sample;
665  try {
666  sample = m_schema.getValue(sample_sel);
667  }
668  catch (Alembic::Util::Exception &ex) {
669  printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n",
670  m_iobject.getFullName().c_str(),
671  m_schema.getName().c_str(),
672  sample_sel.getRequestedTime(),
673  ex.what());
674  /* A similar error in read_mesh() would just return existing_mesh. */
675  return false;
676  }
677 
678  const P3fArraySamplePtr &positions = sample.getPositions();
679  const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
680  const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
681 
682  return positions->size() != existing_mesh->totvert ||
683  face_counts->size() != existing_mesh->totpoly ||
684  face_indices->size() != existing_mesh->totloop;
685 }
686 
688  const ISampleSelector &sample_sel,
689  const int read_flag,
690  const char *velocity_name,
691  const float velocity_scale,
692  const char **err_str)
693 {
694  IPolyMeshSchema::Sample sample;
695  try {
696  sample = m_schema.getValue(sample_sel);
697  }
698  catch (Alembic::Util::Exception &ex) {
699  if (err_str != nullptr) {
700  *err_str = "Error reading mesh sample; more detail on the console";
701  }
702  printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n",
703  m_iobject.getFullName().c_str(),
704  m_schema.getName().c_str(),
705  sample_sel.getRequestedTime(),
706  ex.what());
707  return existing_mesh;
708  }
709 
710  const P3fArraySamplePtr &positions = sample.getPositions();
711  const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
712  const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
713 
714  /* Do some very minimal mesh validation. */
715  const int poly_count = face_counts->size();
716  const int loop_count = face_indices->size();
717  /* This is the same test as in poly_to_tri_count(). */
718  if (poly_count > 0 && loop_count < poly_count * 2) {
719  if (err_str != nullptr) {
720  *err_str = "Invalid mesh; more detail on the console";
721  }
722  printf("Alembic: invalid mesh sample for '%s/%s' at time %f, less than 2 loops per face\n",
723  m_iobject.getFullName().c_str(),
724  m_schema.getName().c_str(),
725  sample_sel.getRequestedTime());
726  return existing_mesh;
727  }
728 
729  Mesh *new_mesh = nullptr;
730 
731  /* Only read point data when streaming meshes, unless we need to create new ones. */
732  ImportSettings settings;
733  settings.read_flag |= read_flag;
734  settings.velocity_name = velocity_name;
735  settings.velocity_scale = velocity_scale;
736 
737  if (topology_changed(existing_mesh, sample_sel)) {
739  existing_mesh, positions->size(), 0, 0, face_indices->size(), face_counts->size());
740 
741  settings.read_flag |= MOD_MESHSEQ_READ_ALL;
742  }
743  else {
744  /* If the face count changed (e.g. by triangulation), only read points.
745  * This prevents crash from T49813.
746  * TODO(kevin): perhaps find a better way to do this? */
747  if (face_counts->size() != existing_mesh->totpoly ||
748  face_indices->size() != existing_mesh->totloop) {
749  settings.read_flag = MOD_MESHSEQ_READ_VERT;
750 
751  if (err_str) {
752  *err_str =
753  "Topology has changed, perhaps by triangulating the"
754  " mesh. Only vertices will be read!";
755  }
756  }
757  }
758 
759  Mesh *mesh_to_export = new_mesh ? new_mesh : existing_mesh;
760  const bool use_vertex_interpolation = read_flag & MOD_MESHSEQ_INTERPOLATE_VERTICES;
761  CDStreamConfig config = get_config(mesh_to_export, use_vertex_interpolation);
762  config.time = sample_sel.getRequestedTime();
763  config.modifier_error_message = err_str;
764 
765  read_mesh_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config);
766 
767  if (new_mesh) {
768  /* Here we assume that the number of materials doesn't change, i.e. that
769  * the material slots that were created when the object was loaded from
770  * Alembic are still valid now. */
771  size_t num_polys = new_mesh->totpoly;
772  if (num_polys > 0) {
773  std::map<std::string, int> mat_map;
774  assign_facesets_to_mpoly(sample_sel, new_mesh->mpoly, num_polys, mat_map);
775  }
776 
777  return new_mesh;
778  }
779 
780  return existing_mesh;
781 }
782 
783 void AbcMeshReader::assign_facesets_to_mpoly(const ISampleSelector &sample_sel,
784  MPoly *mpoly,
785  int totpoly,
786  std::map<std::string, int> &r_mat_map)
787 {
788  std::vector<std::string> face_sets;
789  m_schema.getFaceSetNames(face_sets);
790 
791  if (face_sets.empty()) {
792  return;
793  }
794 
795  int current_mat = 0;
796 
797  for (const std::string &grp_name : face_sets) {
798  if (r_mat_map.find(grp_name) == r_mat_map.end()) {
799  r_mat_map[grp_name] = ++current_mat;
800  }
801 
802  const int assigned_mat = r_mat_map[grp_name];
803 
804  const IFaceSet faceset = m_schema.getFaceSet(grp_name);
805 
806  if (!faceset.valid()) {
807  std::cerr << " Face set " << grp_name << " invalid for " << m_object_name << "\n";
808  continue;
809  }
810 
811  const IFaceSetSchema face_schem = faceset.getSchema();
812  const IFaceSetSchema::Sample face_sample = face_schem.getValue(sample_sel);
813  const Int32ArraySamplePtr group_faces = face_sample.getFaces();
814  const size_t num_group_faces = group_faces->size();
815 
816  for (size_t l = 0; l < num_group_faces; l++) {
817  size_t pos = (*group_faces)[l];
818 
819  if (pos >= totpoly) {
820  std::cerr << "Faceset overflow on " << faceset.getName() << '\n';
821  break;
822  }
823 
824  MPoly &poly = mpoly[pos];
825  poly.mat_nr = assigned_mat - 1;
826  }
827  }
828 }
829 
830 void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const ISampleSelector &sample_sel)
831 {
832  std::map<std::string, int> mat_map;
833  assign_facesets_to_mpoly(sample_sel, mesh->mpoly, mesh->totpoly, mat_map);
834  utils::assign_materials(bmain, m_object, mat_map);
835 }
836 
837 /* ************************************************************************** */
838 
839 static void read_subd_sample(const std::string &iobject_full_name,
840  ImportSettings *settings,
841  const ISubDSchema &schema,
842  const ISampleSelector &selector,
843  CDStreamConfig &config)
844 {
845  const ISubDSchema::Sample sample = schema.getValue(selector);
846 
847  AbcMeshData abc_mesh_data;
848  abc_mesh_data.face_counts = sample.getFaceCounts();
849  abc_mesh_data.face_indices = sample.getFaceIndices();
850  abc_mesh_data.positions = sample.getPositions();
851 
852  get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples());
853 
854  if (config.weight != 0.0f) {
855  Alembic::AbcGeom::ISubDSchema::Sample ceil_sample;
856  schema.get(ceil_sample, Alembic::Abc::ISampleSelector(config.ceil_index));
857  abc_mesh_data.ceil_positions = ceil_sample.getPositions();
858  }
859 
860  if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) {
861  read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector);
862  }
863 
864  if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) {
865  read_mverts(config, abc_mesh_data);
866  }
867 
868  if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
869  /* Alembic's 'SubD' scheme is used to store subdivision surfaces, i.e. the pre-subdivision
870  * mesh. Currently we don't add a subdivision modifier when we load such data. This code is
871  * assuming that the subdivided surface should be smooth. */
872  read_mpolys(config, abc_mesh_data);
873  process_no_normals(config);
874  }
875 
876  if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
877  read_custom_data(iobject_full_name, schema.getArbGeomParams(), config, selector);
878  }
879 
880  if (!settings->velocity_name.empty() && settings->velocity_scale != 0.0f) {
881  V3fArraySamplePtr velocities = get_velocity_prop(schema, selector, settings->velocity_name);
882  if (velocities) {
883  read_velocity(velocities, config, settings->velocity_scale);
884  }
885  }
886 }
887 
889  const Int32ArraySamplePtr &indices,
890  const FloatArraySamplePtr &sharpnesses)
891 {
892  if (!(indices && sharpnesses && indices->size() == sharpnesses->size() &&
893  indices->size() != 0)) {
894  return;
895  }
896 
897  float *vertex_crease_data = (float *)CustomData_add_layer(
898  &mesh->vdata, CD_CREASE, CD_DEFAULT, nullptr, mesh->totvert);
899  const int totvert = mesh->totvert;
900 
901  for (int i = 0, v = indices->size(); i < v; ++i) {
902  const int idx = (*indices)[i];
903 
904  if (idx >= totvert) {
905  continue;
906  }
907 
908  vertex_crease_data[idx] = (*sharpnesses)[i];
909  }
910 
912 }
913 
915  const Int32ArraySamplePtr &indices,
916  const FloatArraySamplePtr &sharpnesses)
917 {
918  if (!(indices && sharpnesses)) {
919  return;
920  }
921 
922  MEdge *edges = mesh->medge;
923  const int totedge = mesh->totedge;
924 
925  EdgeHash *edge_hash = BLI_edgehash_new_ex(__func__, mesh->totedge);
926 
927  for (int i = 0; i < totedge; i++) {
928  MEdge *edge = &edges[i];
929  BLI_edgehash_insert(edge_hash, edge->v1, edge->v2, edge);
930  }
931 
932  for (int i = 0, s = 0, e = indices->size(); i < e; i += 2, s++) {
933  int v1 = (*indices)[i];
934  int v2 = (*indices)[i + 1];
935 
936  if (v2 < v1) {
937  /* It appears to be common to store edges with the smallest index first, in which case this
938  * prevents us from doing the second search below. */
939  std::swap(v1, v2);
940  }
941 
942  MEdge *edge = static_cast<MEdge *>(BLI_edgehash_lookup(edge_hash, v1, v2));
943  if (edge == nullptr) {
944  edge = static_cast<MEdge *>(BLI_edgehash_lookup(edge_hash, v2, v1));
945  }
946 
947  if (edge) {
948  edge->crease = unit_float_to_uchar_clamp((*sharpnesses)[s]);
949  }
950  }
951 
952  BLI_edgehash_free(edge_hash, nullptr);
953 
955 }
956 
957 /* ************************************************************************** */
958 
959 AbcSubDReader::AbcSubDReader(const IObject &object, ImportSettings &settings)
960  : AbcObjectReader(object, settings)
961 {
963 
964  ISubD isubd_mesh(m_iobject, kWrapExisting);
965  m_schema = isubd_mesh.getSchema();
966 
968 }
969 
971 {
972  return m_schema.valid();
973 }
974 
976  const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
977  const Object *const ob,
978  const char **err_str) const
979 {
980  if (!Alembic::AbcGeom::ISubD::matches(alembic_header)) {
981  *err_str =
982  "Object type mismatch, Alembic object path pointed to SubD when importing, but not any "
983  "more.";
984  return false;
985  }
986 
987  if (ob->type != OB_MESH) {
988  *err_str = "Object type mismatch, Alembic object path points to SubD.";
989  return false;
990  }
991 
992  return true;
993 }
994 
995 void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
996 {
997  Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
998 
1000  m_object->data = mesh;
1001 
1002  Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, "", 0.0f, nullptr);
1003  if (read_mesh != mesh) {
1005  }
1006 
1007  ISubDSchema::Sample sample;
1008  try {
1009  sample = m_schema.getValue(sample_sel);
1010  }
1011  catch (Alembic::Util::Exception &ex) {
1012  printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n",
1013  m_iobject.getFullName().c_str(),
1014  m_schema.getName().c_str(),
1015  sample_sel.getRequestedTime(),
1016  ex.what());
1017  return;
1018  }
1019 
1020  read_edge_creases(mesh, sample.getCreaseIndices(), sample.getCreaseSharpnesses());
1021 
1022  read_vertex_creases(mesh, sample.getCornerIndices(), sample.getCornerSharpnesses());
1023 
1024  if (m_settings->validate_meshes) {
1025  BKE_mesh_validate(mesh, false, false);
1026  }
1027 
1029  addCacheModifier();
1030  }
1031 }
1032 
1034  const ISampleSelector &sample_sel,
1035  const int read_flag,
1036  const char *velocity_name,
1037  const float velocity_scale,
1038  const char **err_str)
1039 {
1040  ISubDSchema::Sample sample;
1041  try {
1042  sample = m_schema.getValue(sample_sel);
1043  }
1044  catch (Alembic::Util::Exception &ex) {
1045  if (err_str != nullptr) {
1046  *err_str = "Error reading mesh sample; more detail on the console";
1047  }
1048  printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n",
1049  m_iobject.getFullName().c_str(),
1050  m_schema.getName().c_str(),
1051  sample_sel.getRequestedTime(),
1052  ex.what());
1053  return existing_mesh;
1054  }
1055 
1056  const P3fArraySamplePtr &positions = sample.getPositions();
1057  const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
1058  const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
1059 
1060  Mesh *new_mesh = nullptr;
1061 
1062  ImportSettings settings;
1063  settings.read_flag |= read_flag;
1064  settings.velocity_name = velocity_name;
1065  settings.velocity_scale = velocity_scale;
1066 
1067  if (existing_mesh->totvert != positions->size()) {
1069  existing_mesh, positions->size(), 0, 0, face_indices->size(), face_counts->size());
1070 
1071  settings.read_flag |= MOD_MESHSEQ_READ_ALL;
1072  }
1073  else {
1074  /* If the face count changed (e.g. by triangulation), only read points.
1075  * This prevents crash from T49813.
1076  * TODO(kevin): perhaps find a better way to do this? */
1077  if (face_counts->size() != existing_mesh->totpoly ||
1078  face_indices->size() != existing_mesh->totloop) {
1079  settings.read_flag = MOD_MESHSEQ_READ_VERT;
1080 
1081  if (err_str) {
1082  *err_str =
1083  "Topology has changed, perhaps by triangulating the"
1084  " mesh. Only vertices will be read!";
1085  }
1086  }
1087  }
1088 
1089  /* Only read point data when streaming meshes, unless we need to create new ones. */
1090  Mesh *mesh_to_export = new_mesh ? new_mesh : existing_mesh;
1091  const bool use_vertex_interpolation = read_flag & MOD_MESHSEQ_INTERPOLATE_VERTICES;
1092  CDStreamConfig config = get_config(mesh_to_export, use_vertex_interpolation);
1093  config.time = sample_sel.getRequestedTime();
1094  read_subd_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config);
1095 
1096  return mesh_to_export;
1097 }
1098 
1099 } // namespace blender::io::alembic
typedef float(TangentPoint)[2]
Generic geometry attributes built on CustomData.
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
struct CustomDataLayer * BKE_id_attribute_new(struct ID *id, const char *name, int type, eAttrDomain domain, struct ReportList *reports)
Definition: attribute.cc:220
const CustomData_MeshMasks CD_MASK_EVERYTHING
Definition: customdata.cc:2101
@ CD_DEFAULT
void * CustomData_add_layer_named(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem, const char *name)
Definition: customdata.cc:2792
void * CustomData_get_layer_named(const struct CustomData *data, int type, const char *name)
void * CustomData_add_layer(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem)
Definition: customdata.cc:2776
void id_us_min(struct ID *id)
Definition: lib_id.c:313
General operations, lookup, etc. for materials.
void BKE_object_material_assign_single_obdata(struct Main *bmain, struct Object *ob, struct Material *ma, short act)
Definition: material.c:1052
struct Material * BKE_material_add(struct Main *bmain, const char *name)
Definition: material.c:289
float(* BKE_mesh_vertex_normals_for_write(struct Mesh *mesh))[3]
struct Mesh * BKE_mesh_new_nomain_from_template(const struct Mesh *me_src, int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
void BKE_mesh_nomain_to_mesh(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct Object *ob, const struct CustomData_MeshMasks *mask, bool take_ownership)
struct Mesh * BKE_mesh_add(struct Main *bmain, const char *name)
Definition: mesh.cc:963
bool BKE_mesh_validate(struct Mesh *me, bool do_verbose, bool cddata_check_mask)
void BKE_mesh_vertex_normals_clear_dirty(struct Mesh *mesh)
void BKE_mesh_set_custom_normals_from_vertices(struct Mesh *mesh, float(*r_custom_vertnors)[3])
void BKE_mesh_normals_tag_dirty(struct Mesh *mesh)
Definition: mesh_normals.cc:95
void BKE_mesh_set_custom_normals(struct Mesh *mesh, float(*r_custom_loopnors)[3])
void BKE_mesh_calc_edges(struct Mesh *mesh, bool keep_existing_edges, bool select_new_edges)
General operations, lookup, etc. for blender objects.
struct Object * BKE_object_add_only_object(struct Main *bmain, int type, const char *name) ATTR_RETURNS_NONNULL
Definition: object.cc:2241
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_INLINE
void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP free_value)
Definition: edgehash.c:230
void BLI_edgehash_insert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val)
Definition: edgehash.c:261
EdgeHash * BLI_edgehash_new_ex(const char *info, unsigned int nentries_reserve)
Definition: edgehash.c:212
void * BLI_edgehash_lookup(const EdgeHash *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT
Definition: edgehash.c:295
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
MINLINE void mul_v3_fl(float r[3], float f)
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition: math_vector.c:29
unsigned int uint
Definition: BLI_sys_types.h:67
#define ELEM(...)
void swap(T &a, T &b)
Definition: Common.h:19
eCustomDataType
@ CD_PROP_BYTE_COLOR
@ CD_PROP_FLOAT3
@ CD_MLOOPUV
#define MAXMAT
@ ME_AUTOSMOOTH
@ ME_CDFLAG_VERT_CREASE
@ ME_CDFLAG_EDGE_CREASE
@ ME_SMOOTH
#define MOD_MESHSEQ_READ_ALL
@ MOD_MESHSEQ_READ_COLOR
@ MOD_MESHSEQ_READ_VERT
@ MOD_MESHSEQ_INTERPOLATE_VERTICES
@ MOD_MESHSEQ_READ_UV
@ MOD_MESHSEQ_READ_POLY
Object is a sort of wrapper for general info.
@ OB_MESH
_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 const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint i1
_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 const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
struct Mesh * read_mesh(struct Mesh *existing_mesh, const Alembic::Abc::ISampleSelector &sample_sel, int read_flag, const char *velocity_name, float velocity_scale, const char **err_str) override
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override
bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, const Object *const ob, const char **err_str) const override
bool topology_changed(const Mesh *existing_mesh, const Alembic::Abc::ISampleSelector &sample_sel) override
AbcMeshReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
struct Mesh * read_mesh(struct Mesh *existing_mesh, const Alembic::Abc::ISampleSelector &sample_sel, int read_flag, const char *velocity_name, float velocity_scale, const char **err_str) override
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override
AbcSubDReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, const Object *const ob, const char **err_str) const override
Material material
uint pos
ccl_gpu_kernel_postfix int ccl_global int * indices
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:34
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
MINLINE unsigned char unit_float_to_uchar_clamp(float val)
static void assign_materials(Main *bmain, Object *ob, const std::map< std::string, int > &mat_index_map)
static std::map< std::string, Material * > build_material_map(const Main *bmain)
AbcUvScope get_uv_scope(const Alembic::AbcGeom::GeometryScope scope, const CDStreamConfig &config, const Alembic::AbcGeom::UInt32ArraySamplePtr &indices)
static void process_normals(CDStreamConfig &config, const IN3fGeomParam &normals, const ISampleSelector &selector)
static void get_weight_and_index(CDStreamConfig &config, Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling, size_t samples_number)
void get_min_max_time(const Alembic::AbcGeom::IObject &object, const Schema &schema, chrono_t &min, chrono_t &max)
Definition: abc_util.h:66
static void read_mverts_interp(MVert *mverts, const P3fArraySamplePtr &positions, const P3fArraySamplePtr &ceil_positions, const double weight)
static void read_mesh_sample(const std::string &iobject_full_name, ImportSettings *settings, const IPolyMeshSchema &schema, const ISampleSelector &selector, CDStreamConfig &config)
BLI_INLINE void read_uvs_params(CDStreamConfig &config, AbcMeshData &abc_data, const IV2fGeomParam &uv, const ISampleSelector &selector)
static void process_loop_normals(CDStreamConfig &config, const N3fArraySamplePtr loop_normals_ptr)
bool is_valid_animated(const ICompoundProperty arbGeomParams, const PropertyHeader &prop_header)
static void read_vertex_creases(Mesh *mesh, const Int32ArraySamplePtr &indices, const FloatArraySamplePtr &sharpnesses)
BLI_INLINE void copy_zup_from_yup(float zup[3], const float yup[3])
static void process_vertex_normals(CDStreamConfig &config, const N3fArraySamplePtr vertex_normals_ptr)
void read_custom_data(const std::string &iobject_full_name, const ICompoundProperty &prop, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss)
static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
CDStreamConfig get_config(Mesh *mesh, const bool use_vertex_interpolation)
static void read_edge_creases(Mesh *mesh, const Int32ArraySamplePtr &indices, const FloatArraySamplePtr &sharpnesses)
static void read_subd_sample(const std::string &iobject_full_name, ImportSettings *settings, const ISubDSchema &schema, const ISampleSelector &selector, CDStreamConfig &config)
static bool has_animated_geom_params(const ICompoundProperty arbGeomParams)
static void read_velocity(const V3fArraySamplePtr &velocities, const CDStreamConfig &config, const float velocity_scale)
void read_generated_coordinates(const ICompoundProperty &prop, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss)
static V3fArraySamplePtr get_velocity_prop(const ICompoundProperty &schema, const ISampleSelector &selector, const std::string &name)
static void process_no_normals(CDStreamConfig &config)
static void read_mverts(CDStreamConfig &config, const AbcMeshData &mesh_data)
bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name)
Definition: abc_util.cc:106
static void * add_customdata_cb(Mesh *mesh, const char *name, int data_type)
bool has_animations(Alembic::AbcGeom::IPolyMeshSchema &schema, ImportSettings *settings)
MutableSpan< float3 > positions
MutableSpan< float3 > normals
unsigned short uint16_t
Definition: stdint.h:79
__int64 int64_t
Definition: stdint.h:89
char name[66]
Definition: DNA_ID.h:378
unsigned int v
short mat_nr
float co[3]
Definition: BKE_main.h:121
ListBase materials
Definition: BKE_main.h:174
struct MEdge * medge
CustomData vdata
struct MVert * mvert
uint16_t flag
int totedge
char cd_flag
int totvert
struct MLoop * mloop
int totpoly
int totloop
struct MPoly * mpoly
CustomData ldata
void * data
Alembic::AbcGeom::index_t index
Alembic::AbcGeom::index_t ceil_index
void *(* add_customdata_cb)(Mesh *mesh, const char *name, int data_type)