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