Blender  V3.3
alembic_capi.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include "../ABC_alembic.h"
8 #include "IO_types.h"
9 
10 #include <Alembic/AbcMaterial/IMaterial.h>
11 
12 #include "abc_axis_conversion.h"
13 #include "abc_reader_archive.h"
14 #include "abc_reader_camera.h"
15 #include "abc_reader_curves.h"
16 #include "abc_reader_mesh.h"
17 #include "abc_reader_nurbs.h"
18 #include "abc_reader_points.h"
19 #include "abc_reader_transform.h"
20 #include "abc_util.h"
21 
22 #include "MEM_guardedalloc.h"
23 
24 #include "DNA_cachefile_types.h"
25 #include "DNA_collection_types.h"
26 #include "DNA_curve_types.h"
27 #include "DNA_modifier_types.h"
28 #include "DNA_object_types.h"
29 #include "DNA_scene_types.h"
30 
31 #include "BKE_cachefile.h"
32 #include "BKE_context.h"
33 #include "BKE_curve.h"
34 #include "BKE_global.h"
35 #include "BKE_layer.h"
36 #include "BKE_lib_id.h"
37 #include "BKE_object.h"
38 #include "BKE_scene.h"
39 #include "BKE_screen.h"
40 
41 #include "DEG_depsgraph.h"
42 #include "DEG_depsgraph_build.h"
43 
44 #include "ED_undo.h"
45 
46 #include "BLI_compiler_compat.h"
47 #include "BLI_fileops.h"
48 #include "BLI_ghash.h"
49 #include "BLI_listbase.h"
50 #include "BLI_math.h"
51 #include "BLI_path_util.h"
52 #include "BLI_string.h"
53 #include "BLI_timeit.hh"
54 
55 #include "WM_api.h"
56 #include "WM_types.h"
57 
58 using Alembic::Abc::IV3fArrayProperty;
59 using Alembic::Abc::ObjectHeader;
60 using Alembic::Abc::PropertyHeader;
61 using Alembic::Abc::V3fArraySamplePtr;
62 using Alembic::AbcGeom::ICamera;
63 using Alembic::AbcGeom::ICurves;
64 using Alembic::AbcGeom::IFaceSet;
65 using Alembic::AbcGeom::ILight;
66 using Alembic::AbcGeom::INuPatch;
67 using Alembic::AbcGeom::IObject;
68 using Alembic::AbcGeom::IPoints;
69 using Alembic::AbcGeom::IPolyMesh;
70 using Alembic::AbcGeom::IPolyMeshSchema;
71 using Alembic::AbcGeom::ISampleSelector;
72 using Alembic::AbcGeom::ISubD;
73 using Alembic::AbcGeom::IXform;
74 using Alembic::AbcGeom::kWrapExisting;
75 using Alembic::AbcGeom::MetaData;
76 using Alembic::AbcMaterial::IMaterial;
77 
78 using namespace blender::io::alembic;
79 
81 {
82  return reinterpret_cast<ArchiveReader *>(handle);
83 }
84 
86 {
87  return reinterpret_cast<CacheArchiveHandle *>(archive);
88 }
89 
90 //#define USE_NURBS
91 
92 /* NOTE: this function is similar to visit_objects below, need to keep them in
93  * sync. */
94 static bool gather_objects_paths(const IObject &object, ListBase *object_paths)
95 {
96  if (!object.valid()) {
97  return false;
98  }
99 
100  size_t children_claiming_this_object = 0;
101  size_t num_children = object.getNumChildren();
102 
103  for (size_t i = 0; i < num_children; i++) {
104  bool child_claims_this_object = gather_objects_paths(object.getChild(i), object_paths);
105  children_claiming_this_object += child_claims_this_object ? 1 : 0;
106  }
107 
108  const MetaData &md = object.getMetaData();
109  bool get_path = false;
110  bool parent_is_part_of_this_object = false;
111 
112  if (!object.getParent()) {
113  /* The root itself is not an object we should import. */
114  }
115  else if (IXform::matches(md)) {
116  if (has_property(object.getProperties(), "locator")) {
117  get_path = true;
118  }
119  else {
120  get_path = children_claiming_this_object == 0;
121  }
122 
123  /* Transforms are never "data" for their parent. */
124  parent_is_part_of_this_object = false;
125  }
126  else {
127  /* These types are "data" for their parent. */
128  get_path = IPolyMesh::matches(md) || ISubD::matches(md) ||
129 #ifdef USE_NURBS
130  INuPatch::matches(md) ||
131 #endif
132  ICamera::matches(md) || IPoints::matches(md) || ICurves::matches(md);
133  parent_is_part_of_this_object = get_path;
134  }
135 
136  if (get_path) {
137  void *abc_path_void = MEM_callocN(sizeof(CacheObjectPath), "CacheObjectPath");
138  CacheObjectPath *abc_path = static_cast<CacheObjectPath *>(abc_path_void);
139 
140  BLI_strncpy(abc_path->path, object.getFullName().c_str(), sizeof(abc_path->path));
141  BLI_addtail(object_paths, abc_path);
142  }
143 
144  return parent_is_part_of_this_object;
145 }
146 
148  const char *filename,
149  const CacheFileLayer *layers,
150  ListBase *object_paths)
151 {
152  std::vector<const char *> filenames;
153  filenames.push_back(filename);
154 
155  while (layers) {
156  if ((layers->flag & CACHEFILE_LAYER_HIDDEN) == 0) {
157  filenames.push_back(layers->filepath);
158  }
159  layers = layers->next;
160  }
161 
162  /* We need to reverse the order as overriding archives should come first. */
163  std::reverse(filenames.begin(), filenames.end());
164 
165  ArchiveReader *archive = ArchiveReader::get(bmain, filenames);
166 
167  if (!archive || !archive->valid()) {
168  delete archive;
169  return nullptr;
170  }
171 
172  if (object_paths) {
173  gather_objects_paths(archive->getTop(), object_paths);
174  }
175 
176  return handle_from_archive(archive);
177 }
178 
180 {
181  delete archive_from_handle(handle);
182 }
183 
185 {
186  return ALEMBIC_LIBRARY_VERSION;
187 }
188 
189 static void find_iobject(const IObject &object, IObject &ret, const std::string &path)
190 {
191  if (!object.valid()) {
192  return;
193  }
194 
195  std::vector<std::string> tokens;
196  split(path, '/', tokens);
197 
198  IObject tmp = object;
199 
200  std::vector<std::string>::iterator iter;
201  for (iter = tokens.begin(); iter != tokens.end(); ++iter) {
202  IObject child = tmp.getChild(*iter);
203  tmp = child;
204  }
205 
206  ret = tmp;
207 }
208 
209 /* ********************** Import file ********************** */
210 
231 static std::pair<bool, AbcObjectReader *> visit_object(
232  const IObject &object,
234  ImportSettings &settings,
235  AbcObjectReader::ptr_vector &r_assign_as_parent)
236 {
237  const std::string &full_name = object.getFullName();
238 
239  if (!object.valid()) {
240  std::cerr << " - " << full_name << ": object is invalid, skipping it and all its children.\n";
241  return std::make_pair(false, static_cast<AbcObjectReader *>(nullptr));
242  }
243 
244  /* The interpretation of data by the children determine the role of this
245  * object. This is especially important for Xform objects, as they can be
246  * either part of a Blender object or a Blender object (Empty) themselves.
247  */
248  size_t children_claiming_this_object = 0;
249  size_t num_children = object.getNumChildren();
250  AbcObjectReader::ptr_vector claiming_child_readers;
251  AbcObjectReader::ptr_vector nonclaiming_child_readers;
252  AbcObjectReader::ptr_vector assign_as_parent;
253  for (size_t i = 0; i < num_children; i++) {
254  const IObject ichild = object.getChild(i);
255 
256  /* TODO: When we only support C++11, use std::tie() instead. */
257  std::pair<bool, AbcObjectReader *> child_result;
258  child_result = visit_object(ichild, readers, settings, assign_as_parent);
259 
260  bool child_claims_this_object = child_result.first;
261  AbcObjectReader *child_reader = child_result.second;
262 
263  if (child_reader == nullptr) {
264  BLI_assert(!child_claims_this_object);
265  }
266  else {
267  if (child_claims_this_object) {
268  claiming_child_readers.push_back(child_reader);
269  }
270  else {
271  nonclaiming_child_readers.push_back(child_reader);
272  }
273  }
274 
275  children_claiming_this_object += child_claims_this_object ? 1 : 0;
276  }
277  BLI_assert(children_claiming_this_object == claiming_child_readers.size());
278  UNUSED_VARS_NDEBUG(children_claiming_this_object);
279 
280  AbcObjectReader *reader = nullptr;
281  const MetaData &md = object.getMetaData();
282  bool parent_is_part_of_this_object = false;
283 
284  if (!object.getParent()) {
285  /* The root itself is not an object we should import. */
286  }
287  else if (IXform::matches(md)) {
288  bool create_empty;
289 
290  /* An xform can either be a Blender Object (if it contains a mesh, for
291  * example), but it can also be an Empty. Its correct translation to
292  * Blender's data model depends on its children. */
293 
294  /* Check whether or not this object is a Maya locator, which is
295  * similar to empties used as parent object in Blender. */
296  if (has_property(object.getProperties(), "locator")) {
297  create_empty = true;
298  }
299  else {
300  create_empty = claiming_child_readers.empty();
301  }
302 
303  if (create_empty) {
304  reader = new AbcEmptyReader(object, settings);
305  }
306  }
307  else if (IPolyMesh::matches(md)) {
308  reader = new AbcMeshReader(object, settings);
309  parent_is_part_of_this_object = true;
310  }
311  else if (ISubD::matches(md)) {
312  reader = new AbcSubDReader(object, settings);
313  parent_is_part_of_this_object = true;
314  }
315  else if (INuPatch::matches(md)) {
316 #ifdef USE_NURBS
317  /* TODO(kevin): importing cyclic NURBS from other software crashes
318  * at the moment. This is due to the fact that NURBS in other
319  * software have duplicated points which causes buffer overflows in
320  * Blender. Need to figure out exactly how these points are
321  * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV).
322  * Until this is fixed, disabling NURBS reading. */
323  reader = new AbcNurbsReader(object, settings);
324  parent_is_part_of_this_object = true;
325 #endif
326  }
327  else if (ICamera::matches(md)) {
328  reader = new AbcCameraReader(object, settings);
329  parent_is_part_of_this_object = true;
330  }
331  else if (IPoints::matches(md)) {
332  reader = new AbcPointsReader(object, settings);
333  parent_is_part_of_this_object = true;
334  }
335  else if (IMaterial::matches(md)) {
336  /* Pass for now. */
337  }
338  else if (ILight::matches(md)) {
339  /* Pass for now. */
340  }
341  else if (IFaceSet::matches(md)) {
342  /* Pass, those are handled in the mesh reader. */
343  }
344  else if (ICurves::matches(md)) {
345  reader = new AbcCurveReader(object, settings);
346  parent_is_part_of_this_object = true;
347  }
348  else {
349  std::cerr << "Alembic object " << full_name << " is of unsupported schema type '"
350  << object.getMetaData().get("schemaObjTitle") << "'" << std::endl;
351  }
352 
353  if (reader) {
354  /* We have created a reader, which should imply that this object is
355  * not claimed as part of any child Alembic object. */
356  BLI_assert(claiming_child_readers.empty());
357 
358  readers.push_back(reader);
359  reader->incref();
360 
361  CacheObjectPath *abc_path = static_cast<CacheObjectPath *>(
362  MEM_callocN(sizeof(CacheObjectPath), "CacheObjectPath"));
363  BLI_strncpy(abc_path->path, full_name.c_str(), sizeof(abc_path->path));
364  BLI_addtail(&settings.cache_file->object_paths, abc_path);
365 
366  /* We can now assign this reader as parent for our children. */
367  if (nonclaiming_child_readers.size() + assign_as_parent.size() > 0) {
368  for (AbcObjectReader *child_reader : nonclaiming_child_readers) {
369  child_reader->parent_reader = reader;
370  }
371  for (AbcObjectReader *child_reader : assign_as_parent) {
372  child_reader->parent_reader = reader;
373  }
374  }
375  }
376  else if (object.getParent()) {
377  if (!claiming_child_readers.empty()) {
378  /* The first claiming child will serve just fine as parent to
379  * our non-claiming children. Since all claiming children share
380  * the same XForm, it doesn't really matter which one we pick. */
381  AbcObjectReader *claiming_child = claiming_child_readers[0];
382  for (AbcObjectReader *child_reader : nonclaiming_child_readers) {
383  child_reader->parent_reader = claiming_child;
384  }
385  for (AbcObjectReader *child_reader : assign_as_parent) {
386  child_reader->parent_reader = claiming_child;
387  }
388  /* Claiming children should have our parent set as their parent. */
389  for (AbcObjectReader *child_reader : claiming_child_readers) {
390  r_assign_as_parent.push_back(child_reader);
391  }
392  }
393  else {
394  /* This object isn't claimed by any child, and didn't produce
395  * a reader. Odd situation, could be the top Alembic object, or
396  * an unsupported Alembic schema. Delegate to our parent. */
397  for (AbcObjectReader *child_reader : claiming_child_readers) {
398  r_assign_as_parent.push_back(child_reader);
399  }
400  for (AbcObjectReader *child_reader : nonclaiming_child_readers) {
401  r_assign_as_parent.push_back(child_reader);
402  }
403  for (AbcObjectReader *child_reader : assign_as_parent) {
404  r_assign_as_parent.push_back(child_reader);
405  }
406  }
407  }
408 
409  return std::make_pair(parent_is_part_of_this_object, reader);
410 }
411 
412 enum {
415 };
416 
423 
424  char filename[1024];
426 
428  std::vector<AbcObjectReader *> readers;
429 
430  short *stop;
431  short *do_update;
432  float *progress;
433 
436  bool import_ok;
439 };
440 
442 {
443  blender::timeit::Nanoseconds duration = blender::timeit::Clock::now() - data->start_time;
444  std::cout << "Alembic import of '" << data->filename << "' took ";
446  std::cout << '\n';
447 }
448 
449 static void import_startjob(void *user_data, short *stop, short *do_update, float *progress)
450 {
451  SCOPE_TIMER("Alembic import, objects reading and creation");
452 
453  ImportJobData *data = static_cast<ImportJobData *>(user_data);
454 
455  data->stop = stop;
456  data->do_update = do_update;
457  data->progress = progress;
458  data->start_time = blender::timeit::Clock::now();
459 
460  WM_set_locked_interface(data->wm, true);
461 
462  ArchiveReader *archive = ArchiveReader::get(data->bmain, {data->filename});
463 
464  if (!archive || !archive->valid()) {
465  data->error_code = ABC_ARCHIVE_FAIL;
466  delete archive;
467  return;
468  }
469 
470  CacheFile *cache_file = static_cast<CacheFile *>(
471  BKE_cachefile_add(data->bmain, BLI_path_basename(data->filename)));
472 
473  /* Decrement the ID ref-count because it is going to be incremented for each
474  * modifier and constraint that it will be attached to, so since currently
475  * it is not used by anyone, its use count will be off by one. */
476  id_us_min(&cache_file->id);
477 
478  cache_file->is_sequence = data->settings.is_sequence;
479  cache_file->scale = data->settings.scale;
480  STRNCPY(cache_file->filepath, data->filename);
481 
482  data->archive = archive;
483  data->settings.cache_file = cache_file;
484 
485  *data->do_update = true;
486  *data->progress = 0.05f;
487 
488  /* Parse Alembic Archive. */
489  AbcObjectReader::ptr_vector assign_as_parent;
490  visit_object(archive->getTop(), data->readers, data->settings, assign_as_parent);
491 
492  /* There shouldn't be any orphans. */
493  BLI_assert(assign_as_parent.empty());
494 
495  if (G.is_break) {
496  data->was_cancelled = true;
497  return;
498  }
499 
500  *data->do_update = true;
501  *data->progress = 0.1f;
502 
503  /* Create objects and set scene frame range. */
504 
505  const float size = static_cast<float>(data->readers.size());
506  size_t i = 0;
507 
508  chrono_t min_time = std::numeric_limits<chrono_t>::max();
509  chrono_t max_time = std::numeric_limits<chrono_t>::min();
510 
511  ISampleSelector sample_sel(0.0);
512  std::vector<AbcObjectReader *>::iterator iter;
513  for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
514  AbcObjectReader *reader = *iter;
515 
516  if (reader->valid()) {
517  reader->readObjectData(data->bmain, sample_sel);
518 
519  min_time = std::min(min_time, reader->minTime());
520  max_time = std::max(max_time, reader->maxTime());
521  }
522  else {
523  std::cerr << "Object " << reader->name() << " in Alembic file " << data->filename
524  << " is invalid.\n";
525  }
526 
527  *data->progress = 0.1f + 0.3f * (++i / size);
528  *data->do_update = true;
529 
530  if (G.is_break) {
531  data->was_cancelled = true;
532  return;
533  }
534  }
535 
536  if (data->settings.set_frame_range) {
537  Scene *scene = data->scene;
538 
539  if (data->settings.is_sequence) {
540  scene->r.sfra = data->settings.sequence_offset;
541  scene->r.efra = scene->r.sfra + (data->settings.sequence_len - 1);
542  scene->r.cfra = scene->r.sfra;
543  }
544  else if (min_time < max_time) {
545  scene->r.sfra = static_cast<int>(round(min_time * FPS));
546  scene->r.efra = static_cast<int>(round(max_time * FPS));
547  scene->r.cfra = scene->r.sfra;
548  }
549  }
550 
551  /* Setup parenthood. */
552  for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
553  const AbcObjectReader *reader = *iter;
554  const AbcObjectReader *parent_reader = reader->parent_reader;
555  Object *ob = reader->object();
556 
557  if (parent_reader == nullptr || !reader->inherits_xform()) {
558  ob->parent = nullptr;
559  }
560  else {
561  ob->parent = parent_reader->object();
562  }
563  }
564 
565  /* Setup transformations and constraints. */
566  i = 0;
567  for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
568  AbcObjectReader *reader = *iter;
569  reader->setupObjectTransform(0.0);
570 
571  *data->progress = 0.7f + 0.3f * (++i / size);
572  *data->do_update = true;
573 
574  if (G.is_break) {
575  data->was_cancelled = true;
576  return;
577  }
578  }
579 }
580 
581 static void import_endjob(void *user_data)
582 {
583  SCOPE_TIMER("Alembic import, cleanup");
584 
585  ImportJobData *data = static_cast<ImportJobData *>(user_data);
586 
587  /* Delete objects on cancellation. */
588  if (data->was_cancelled) {
589  for (AbcObjectReader *reader : data->readers) {
590  Object *ob = reader->object();
591 
592  /* It's possible that cancellation occurred between the creation of
593  * the reader and the creation of the Blender object. */
594  if (ob == nullptr) {
595  continue;
596  }
597 
598  BKE_id_free_us(data->bmain, ob);
599  }
600  }
601  else {
602  Base *base;
603  LayerCollection *lc;
604  ViewLayer *view_layer = data->view_layer;
605 
607 
608  lc = BKE_layer_collection_get_active(view_layer);
609 
610  /* Add all objects to the collection (don't do sync for each object). */
612  for (AbcObjectReader *reader : data->readers) {
613  Object *ob = reader->object();
614  BKE_collection_object_add(data->bmain, lc->collection, ob);
615  }
616  /* Sync the collection, and do view layer operations. */
619  for (AbcObjectReader *reader : data->readers) {
620  Object *ob = reader->object();
621  base = BKE_view_layer_base_find(view_layer, ob);
622  /* TODO: is setting active needed? */
624 
626  DEG_id_tag_update_ex(data->bmain,
627  &ob->id,
630  }
631 
634 
635  if (data->is_background_job) {
636  /* Blender already returned from the import operator, so we need to store our own extra undo
637  * step. */
638  ED_undo_push(data->C, "Alembic Import Finished");
639  }
640  }
641 
642  for (AbcObjectReader *reader : data->readers) {
643  reader->decref();
644 
645  if (reader->refcount() == 0) {
646  delete reader;
647  }
648  }
649 
650  WM_set_locked_interface(data->wm, false);
651 
652  switch (data->error_code) {
653  default:
654  case ABC_NO_ERROR:
655  data->import_ok = !data->was_cancelled;
656  break;
657  case ABC_ARCHIVE_FAIL:
658  WM_report(RPT_ERROR, "Could not open Alembic archive for reading! See console for detail.");
659  break;
660  }
661 
664 }
665 
666 static void import_freejob(void *user_data)
667 {
668  ImportJobData *data = static_cast<ImportJobData *>(user_data);
669  delete data->archive;
670  delete data;
671 }
672 
674  const char *filepath,
675  float scale,
676  bool is_sequence,
677  bool set_frame_range,
678  int sequence_len,
679  int offset,
680  bool validate_meshes,
681  bool always_add_cache_reader,
682  bool as_background_job)
683 {
684  /* Using new here since MEM_* functions do not call constructor to properly initialize data. */
685  ImportJobData *job = new ImportJobData();
686  job->C = C;
687  job->bmain = CTX_data_main(C);
688  job->scene = CTX_data_scene(C);
690  job->wm = CTX_wm_manager(C);
691  job->import_ok = false;
692  BLI_strncpy(job->filename, filepath, 1024);
693 
694  job->settings.scale = scale;
695  job->settings.is_sequence = is_sequence;
696  job->settings.set_frame_range = set_frame_range;
697  job->settings.sequence_len = sequence_len;
699  job->settings.validate_meshes = validate_meshes;
700  job->settings.always_add_cache_reader = always_add_cache_reader;
701  job->error_code = ABC_NO_ERROR;
702  job->was_cancelled = false;
703  job->archive = nullptr;
704  job->is_background_job = as_background_job;
705 
706  G.is_break = false;
707 
708  bool import_ok = false;
709  if (as_background_job) {
710  wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
711  CTX_wm_window(C),
712  job->scene,
713  "Alembic Import",
716 
717  /* setup job */
719  WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
720  WM_jobs_callbacks(wm_job, import_startjob, nullptr, nullptr, import_endjob);
721 
722  WM_jobs_start(CTX_wm_manager(C), wm_job);
723  }
724  else {
725  /* Fake a job context, so that we don't need NULL pointer checks while importing. */
726  short stop = 0, do_update = 0;
727  float progress = 0.0f;
728 
729  import_startjob(job, &stop, &do_update, &progress);
730  import_endjob(job);
731  import_ok = job->import_ok;
732 
733  import_freejob(job);
734  }
735 
736  return import_ok;
737 }
738 
739 /* ************************************************************************** */
740 
741 void ABC_get_transform(CacheReader *reader, float r_mat_world[4][4], double time, float scale)
742 {
743  if (!reader) {
744  return;
745  }
746 
747  AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader);
748 
749  bool is_constant = false;
750 
751  /* Convert from the local matrix we obtain from Alembic to world coordinates
752  * for Blender. This conversion is done here rather than by Blender due to
753  * work around the non-standard interpretation of CONSTRAINT_SPACE_LOCAL in
754  * BKE_constraint_mat_convertspace(). */
755  Object *object = abc_reader->object();
756  if (object->parent == nullptr) {
757  /* No parent, so local space is the same as world space. */
758  abc_reader->read_matrix(r_mat_world, time, scale, is_constant);
759  return;
760  }
761 
762  float mat_parent[4][4];
763  BKE_object_get_parent_matrix(object, object->parent, mat_parent);
764 
765  float mat_local[4][4];
766  abc_reader->read_matrix(mat_local, time, scale, is_constant);
767  mul_m4_m4m4(r_mat_world, mat_parent, object->parentinv);
768  mul_m4_m4m4(r_mat_world, r_mat_world, mat_local);
769 }
770 
771 /* ************************************************************************** */
772 
773 static AbcObjectReader *get_abc_reader(CacheReader *reader, Object *ob, const char **err_str)
774 {
775  AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader);
776  IObject iobject = abc_reader->iobject();
777 
778  if (!iobject.valid()) {
779  *err_str = "Invalid object: verify object path";
780  return nullptr;
781  }
782 
783  const ObjectHeader &header = iobject.getHeader();
784  if (!abc_reader->accepts_object_type(header, ob, err_str)) {
785  /* err_str is set by acceptsObjectType() */
786  return nullptr;
787  }
788 
789  return abc_reader;
790 }
791 
792 static ISampleSelector sample_selector_for_time(chrono_t time)
793 {
794  /* kFloorIndex is used to be compatible with non-interpolating
795  * properties; they use the floor. */
796  return ISampleSelector(time, ISampleSelector::kFloorIndex);
797 }
798 
800  Object *ob,
801  Mesh *existing_mesh,
802  const ABCReadParams *params,
803  const char **err_str)
804 {
805  AbcObjectReader *abc_reader = get_abc_reader(reader, ob, err_str);
806  if (abc_reader == nullptr) {
807  return nullptr;
808  }
809 
810  ISampleSelector sample_sel = sample_selector_for_time(params->time);
811  return abc_reader->read_mesh(existing_mesh,
812  sample_sel,
813  params->read_flags,
814  params->velocity_name,
815  params->velocity_scale,
816  err_str);
817 }
818 
820  Object *ob,
821  const Mesh *existing_mesh,
822  const double time,
823  const char **err_str)
824 {
825  AbcObjectReader *abc_reader = get_abc_reader(reader, ob, err_str);
826  if (abc_reader == nullptr) {
827  return false;
828  }
829 
830  ISampleSelector sample_sel = sample_selector_for_time(time);
831  return abc_reader->topology_changed(existing_mesh, sample_sel);
832 }
833 
834 /* ************************************************************************** */
835 
837 {
838  AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader);
839  abc_reader->decref();
840 
841  if (abc_reader->refcount() == 0) {
842  delete abc_reader;
843  }
844 }
845 
847 {
848  AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader);
849  abc_reader->incref();
850 }
851 
853  CacheReader *reader,
854  Object *object,
855  const char *object_path)
856 {
857  if (object_path[0] == '\0') {
858  return reader;
859  }
860 
861  ArchiveReader *archive = archive_from_handle(handle);
862 
863  if (!archive || !archive->valid()) {
864  return reader;
865  }
866 
867  IObject iobject;
868  find_iobject(archive->getTop(), iobject, object_path);
869 
870  if (reader) {
871  ABC_CacheReader_free(reader);
872  }
873 
874  ImportSettings settings;
875  AbcObjectReader *abc_reader = create_reader(iobject, settings);
876  if (abc_reader == nullptr) {
877  /* This object is not supported */
878  return nullptr;
879  }
880  abc_reader->object(object);
881  abc_reader->incref();
882 
883  return reinterpret_cast<CacheReader *>(abc_reader);
884 }
void * BKE_cachefile_add(struct Main *bmain, const char *name)
Definition: cachefile.c:324
bool BKE_collection_object_add(struct Main *bmain, struct Collection *collection, struct Object *ob)
Definition: collection.c:1125
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:713
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
struct LayerCollection * BKE_layer_collection_get_active(struct ViewLayer *view_layer)
Definition: layer.c:636
void BKE_main_collection_sync(const struct Main *bmain)
void BKE_layer_collection_resync_allow(void)
Definition: layer.c:766
void BKE_view_layer_base_deselect_all(struct ViewLayer *view_layer)
Definition: layer.c:388
struct Base * BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob)
Definition: layer.c:379
void BKE_view_layer_base_select_and_set_active(struct ViewLayer *view_layer, struct Base *selbase)
Definition: layer.c:397
void BKE_layer_collection_resync_forbid(void)
Definition: layer.c:761
void id_us_min(struct ID *id)
Definition: lib_id.c:313
void BKE_id_free_us(struct Main *bmain, void *idv) ATTR_NONNULL()
General operations, lookup, etc. for blender objects.
void BKE_object_get_parent_matrix(struct Object *ob, struct Object *par, float r_parentmat[4][4])
Definition: object.cc:3342
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_INLINE
File and directory operations.
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:259
const char * BLI_path_basename(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1653
#define STRNCPY(dst, src)
Definition: BLI_string.h:483
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
#define UNUSED_VARS_NDEBUG(...)
void DEG_id_tag_update_ex(struct Main *bmain, struct ID *id, int flag)
void DEG_id_tag_update(struct ID *id, int flag)
void DEG_relations_tag_update(struct Main *bmain)
@ ID_RECALC_TRANSFORM
Definition: DNA_ID.h:771
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:834
@ ID_RECALC_ANIMATION
Definition: DNA_ID.h:794
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ ID_RECALC_BASE_FLAGS
Definition: DNA_ID.h:821
@ CACHEFILE_LAYER_HIDDEN
Object groups, one object can be in many groups at once.
Object is a sort of wrapper for general info.
#define FPS
void ED_undo_push(struct bContext *C, const char *str)
Definition: ed_undo.c:100
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:25
@ WM_JOB_PROGRESS
Definition: WM_api.h:1339
@ WM_JOB_TYPE_ALEMBIC
Definition: WM_api.h:1366
#define NC_SCENE
Definition: WM_types.h:328
#define ND_FRAME
Definition: WM_types.h:382
#define SCOPE_TIMER(message)
Definition: abc_util.h:106
bool ABC_import(bContext *C, const char *filepath, float scale, bool is_sequence, bool set_frame_range, int sequence_len, int offset, bool validate_meshes, bool always_add_cache_reader, bool as_background_job)
static void import_freejob(void *user_data)
static void import_startjob(void *user_data, short *stop, short *do_update, float *progress)
static ISampleSelector sample_selector_for_time(chrono_t time)
void ABC_CacheReader_incref(CacheReader *reader)
CacheReader * CacheReader_open_alembic_object(CacheArchiveHandle *handle, CacheReader *reader, Object *object, const char *object_path)
void ABC_get_transform(CacheReader *reader, float r_mat_world[4][4], double time, float scale)
void ABC_free_handle(CacheArchiveHandle *handle)
BLI_INLINE CacheArchiveHandle * handle_from_archive(ArchiveReader *archive)
Definition: alembic_capi.cc:85
static bool gather_objects_paths(const IObject &object, ListBase *object_paths)
Definition: alembic_capi.cc:94
BLI_INLINE ArchiveReader * archive_from_handle(CacheArchiveHandle *handle)
Definition: alembic_capi.cc:80
bool ABC_mesh_topology_changed(CacheReader *reader, Object *ob, const Mesh *existing_mesh, const double time, const char **err_str)
CacheArchiveHandle * ABC_create_handle(struct Main *bmain, const char *filename, const CacheFileLayer *layers, ListBase *object_paths)
@ ABC_ARCHIVE_FAIL
@ ABC_NO_ERROR
int ABC_get_version()
static AbcObjectReader * get_abc_reader(CacheReader *reader, Object *ob, const char **err_str)
Mesh * ABC_read_mesh(CacheReader *reader, Object *ob, Mesh *existing_mesh, const ABCReadParams *params, const char **err_str)
void ABC_CacheReader_free(CacheReader *reader)
static void import_endjob(void *user_data)
static void find_iobject(const IObject &object, IObject &ret, const std::string &path)
static std::pair< bool, AbcObjectReader * > visit_object(const IObject &object, AbcObjectReader::ptr_vector &readers, ImportSettings &settings, AbcObjectReader::ptr_vector &r_assign_as_parent)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
int getParent(int link_num) const
void read_matrix(float r_mat[4][4], chrono_t time, float scale, bool &is_constant)
const Alembic::Abc::IObject & iobject() const
virtual bool topology_changed(const Mesh *existing_mesh, const Alembic::Abc::ISampleSelector &sample_sel)
const std::string & name() const
virtual void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)=0
virtual struct Mesh * read_mesh(struct Mesh *mesh, const Alembic::Abc::ISampleSelector &sample_sel, int read_flag, const char *velocity_name, float velocity_scale, const char **err_str)
virtual bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, const Object *const ob, const char **err_str) const =0
std::vector< AbcObjectReader * > ptr_vector
static ArchiveReader * get(struct Main *bmain, const std::vector< const char * > &filenames)
double time
Scene scene
void * user_data
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
#define G(x, y, z)
bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name)
Definition: abc_util.cc:106
AbcObjectReader * create_reader(const Alembic::AbcGeom::IObject &object, ImportSettings &settings)
Definition: abc_util.cc:151
void split(const std::string &s, const char delim, std::vector< std::string > &tokens)
Definition: abc_util.cc:92
static void report_job_duration(const ExportJobData *data)
Clock::time_point TimePoint
Definition: BLI_timeit.hh:14
void print_duration(Nanoseconds duration)
Definition: timeit.cc:10
std::chrono::nanoseconds Nanoseconds
Definition: BLI_timeit.hh:15
return ret
#define min(a, b)
Definition: sort.c:35
struct CacheFileLayer * next
ListBase object_paths
char filepath[1024]
blender::timeit::TimePoint start_time
wmWindowManager * wm
ViewLayer * view_layer
std::vector< AbcObjectReader * > readers
short * do_update
bool is_background_job
ImportSettings settings
float * progress
char filename[1024]
ArchiveReader * archive
bContext * C
struct Collection * collection
Definition: BKE_main.h:121
float parentinv[4][4]
struct Object * parent
struct RenderData r
Definition: wm_jobs.c:57
float max
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_report(eReportType type, const char *message)
void WM_set_locked_interface(wmWindowManager *wm, bool lock)
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition: wm_jobs.c:437
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
Definition: wm_jobs.c:351
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *))
Definition: wm_jobs.c:323
void WM_jobs_timer(wmJob *wm_job, double timestep, unsigned int note, unsigned int endnote)
Definition: wm_jobs.c:339
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, int flag, int job_type)
Definition: wm_jobs.c:184