Alembic: store a pointer to the object reader in the cache modifiers and
[blender.git] / source / blender / alembic / intern / alembic_capi.cc
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 #include "../ABC_alembic.h"
24
25 #include <Alembic/AbcMaterial/IMaterial.h>
26
27 #include "abc_archive.h"
28 #include "abc_camera.h"
29 #include "abc_curves.h"
30 #include "abc_hair.h"
31 #include "abc_mesh.h"
32 #include "abc_nurbs.h"
33 #include "abc_points.h"
34 #include "abc_transform.h"
35 #include "abc_util.h"
36
37 extern "C" {
38 #include "MEM_guardedalloc.h"
39
40 #include "DNA_cachefile_types.h"
41 #include "DNA_curve_types.h"
42 #include "DNA_modifier_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_scene_types.h"
45
46 #include "BKE_cachefile.h"
47 #include "BKE_cdderivedmesh.h"
48 #include "BKE_context.h"
49 #include "BKE_curve.h"
50 #include "BKE_depsgraph.h"
51 #include "BKE_global.h"
52 #include "BKE_library.h"
53 #include "BKE_main.h"
54 #include "BKE_scene.h"
55
56 /* SpaceType struct has a member called 'new' which obviously conflicts with C++
57  * so temporarily redefining the new keyword to make it compile. */
58 #define new extern_new
59 #include "BKE_screen.h"
60 #undef new
61
62 #include "BLI_fileops.h"
63 #include "BLI_ghash.h"
64 #include "BLI_listbase.h"
65 #include "BLI_math.h"
66 #include "BLI_path_util.h"
67 #include "BLI_string.h"
68
69 #include "WM_api.h"
70 #include "WM_types.h"
71 }
72
73 using Alembic::Abc::Int32ArraySamplePtr;
74 using Alembic::Abc::ObjectHeader;
75
76 using Alembic::AbcGeom::MetaData;
77 using Alembic::AbcGeom::P3fArraySamplePtr;
78 using Alembic::AbcGeom::kWrapExisting;
79
80 using Alembic::AbcGeom::ICamera;
81 using Alembic::AbcGeom::ICurves;
82 using Alembic::AbcGeom::ICurvesSchema;
83 using Alembic::AbcGeom::IFaceSet;
84 using Alembic::AbcGeom::ILight;
85 using Alembic::AbcGeom::INuPatch;
86 using Alembic::AbcGeom::IObject;
87 using Alembic::AbcGeom::IPoints;
88 using Alembic::AbcGeom::IPointsSchema;
89 using Alembic::AbcGeom::IPolyMesh;
90 using Alembic::AbcGeom::IPolyMeshSchema;
91 using Alembic::AbcGeom::ISampleSelector;
92 using Alembic::AbcGeom::ISubD;
93 using Alembic::AbcGeom::IV2fGeomParam;
94 using Alembic::AbcGeom::IXform;
95 using Alembic::AbcGeom::IXformSchema;
96 using Alembic::AbcGeom::N3fArraySamplePtr;
97 using Alembic::AbcGeom::XformSample;
98 using Alembic::AbcGeom::ICompoundProperty;
99 using Alembic::AbcGeom::IN3fArrayProperty;
100 using Alembic::AbcGeom::IN3fGeomParam;
101 using Alembic::AbcGeom::V3fArraySamplePtr;
102
103 using Alembic::AbcMaterial::IMaterial;
104
105 struct AbcArchiveHandle {
106         int unused;
107 };
108
109 ABC_INLINE ArchiveReader *archive_from_handle(AbcArchiveHandle *handle)
110 {
111         return reinterpret_cast<ArchiveReader *>(handle);
112 }
113
114 ABC_INLINE AbcArchiveHandle *handle_from_archive(ArchiveReader *archive)
115 {
116         return reinterpret_cast<AbcArchiveHandle *>(archive);
117 }
118
119 //#define USE_NURBS
120
121 /* NOTE: this function is similar to visit_objects below, need to keep them in
122  * sync. */
123 static void gather_objects_paths(const IObject &object, ListBase *object_paths)
124 {
125         if (!object.valid()) {
126                 return;
127         }
128
129         for (int i = 0; i < object.getNumChildren(); ++i) {
130                 IObject child = object.getChild(i);
131
132                 if (!child.valid()) {
133                         continue;
134                 }
135
136                 bool get_path = false;
137
138                 const MetaData &md = child.getMetaData();
139
140                 if (IXform::matches(md)) {
141                         /* Check whether or not this object is a Maya locator, which is
142                          * similar to empties used as parent object in Blender. */
143                         if (has_property(child.getProperties(), "locator")) {
144                                 get_path = true;
145                         }
146                         else {
147                                 /* Avoid creating an empty object if the child of this transform
148                                  * is not a transform (that is an empty). */
149                                 if (child.getNumChildren() == 1) {
150                                         if (IXform::matches(child.getChild(0).getMetaData())) {
151                                                 get_path = true;
152                                         }
153 #if 0
154                                         else {
155                                                 std::cerr << "Skipping " << child.getFullName() << '\n';
156                                         }
157 #endif
158                                 }
159                                 else {
160                                         get_path = true;
161                                 }
162                         }
163                 }
164                 else if (IPolyMesh::matches(md)) {
165                         get_path = true;
166                 }
167                 else if (ISubD::matches(md)) {
168                         get_path = true;
169                 }
170                 else if (INuPatch::matches(md)) {
171 #ifdef USE_NURBS
172                         get_path = true;
173 #endif
174                 }
175                 else if (ICamera::matches(md)) {
176                         get_path = true;
177                 }
178                 else if (IPoints::matches(md)) {
179                         get_path = true;
180                 }
181                 else if (IMaterial::matches(md)) {
182                         /* Pass for now. */
183                 }
184                 else if (ILight::matches(md)) {
185                         /* Pass for now. */
186                 }
187                 else if (IFaceSet::matches(md)) {
188                         /* Pass, those are handled in the mesh reader. */
189                 }
190                 else if (ICurves::matches(md)) {
191                         get_path = true;
192                 }
193                 else {
194                         assert(false);
195                 }
196
197                 if (get_path) {
198                         AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(
199                                                           MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"));
200
201                         BLI_strncpy(abc_path->path, child.getFullName().c_str(), PATH_MAX);
202
203                         BLI_addtail(object_paths, abc_path);
204                 }
205
206                 gather_objects_paths(child, object_paths);
207         }
208 }
209
210 AbcArchiveHandle *ABC_create_handle(const char *filename, ListBase *object_paths)
211 {
212         ArchiveReader *archive = new ArchiveReader(filename);
213
214         if (!archive->valid()) {
215                 delete archive;
216                 return NULL;
217         }
218
219         if (object_paths) {
220                 gather_objects_paths(archive->getTop(), object_paths);
221         }
222
223         return handle_from_archive(archive);
224 }
225
226 void ABC_free_handle(AbcArchiveHandle *handle)
227 {
228         delete archive_from_handle(handle);
229 }
230
231 int ABC_get_version()
232 {
233         return ALEMBIC_LIBRARY_VERSION;
234 }
235
236 static void find_iobject(const IObject &object, IObject &ret,
237                          const std::string &path)
238 {
239         if (!object.valid()) {
240                 return;
241         }
242
243         std::vector<std::string> tokens;
244         split(path, '/', tokens);
245
246         IObject tmp = object;
247
248         std::vector<std::string>::iterator iter;
249         for (iter = tokens.begin(); iter != tokens.end(); ++iter) {
250                 IObject child = tmp.getChild(*iter);
251                 tmp = child;
252         }
253
254         ret = tmp;
255 }
256
257 struct ExportJobData {
258         Scene *scene;
259         Main *bmain;
260
261         char filename[1024];
262         ExportSettings settings;
263
264         short *stop;
265         short *do_update;
266         float *progress;
267
268         bool was_canceled;
269 };
270
271 static void export_startjob(void *customdata, short *stop, short *do_update, float *progress)
272 {
273         ExportJobData *data = static_cast<ExportJobData *>(customdata);
274
275         data->stop = stop;
276         data->do_update = do_update;
277         data->progress = progress;
278
279         /* XXX annoying hack: needed to prevent data corruption when changing
280          * scene frame in separate threads
281          */
282         G.is_rendering = true;
283         BKE_spacedata_draw_locks(true);
284
285         G.is_break = false;
286
287         try {
288                 Scene *scene = data->scene;
289                 AbcExporter exporter(scene, data->filename, data->settings);
290
291                 const int orig_frame = CFRA;
292
293                 data->was_canceled = false;
294                 exporter(data->bmain, *data->progress, data->was_canceled);
295
296                 if (CFRA != orig_frame) {
297                         CFRA = orig_frame;
298
299                         BKE_scene_update_for_newframe(data->bmain->eval_ctx, data->bmain,
300                                                       scene, scene->lay);
301                 }
302         }
303         catch (const std::exception &e) {
304                 std::cerr << "Abc Export error: " << e.what() << '\n';
305         }
306         catch (...) {
307                 std::cerr << "Abc Export error\n";
308         }
309 }
310
311 static void export_endjob(void *customdata)
312 {
313         ExportJobData *data = static_cast<ExportJobData *>(customdata);
314
315         if (data->was_canceled && BLI_exists(data->filename)) {
316                 BLI_delete(data->filename, false, false);
317         }
318
319         G.is_rendering = false;
320         BKE_spacedata_draw_locks(false);
321 }
322
323 void ABC_export(
324         Scene *scene,
325         bContext *C,
326         const char *filepath,
327         const struct AlembicExportParams *params)
328 {
329         ExportJobData *job = static_cast<ExportJobData *>(MEM_mallocN(sizeof(ExportJobData), "ExportJobData"));
330         job->scene = scene;
331         job->bmain = CTX_data_main(C);
332         BLI_strncpy(job->filename, filepath, 1024);
333
334         job->settings.scene = job->scene;
335         job->settings.frame_start = params->frame_start;
336         job->settings.frame_end = params->frame_end;
337         job->settings.frame_step_xform = params->frame_step_xform;
338         job->settings.frame_step_shape = params->frame_step_shape;
339         job->settings.shutter_open = params->shutter_open;
340         job->settings.shutter_close = params->shutter_close;
341         job->settings.selected_only = params->selected_only;
342         job->settings.export_face_sets = params->face_sets;
343         job->settings.export_normals = params->normals;
344         job->settings.export_uvs = params->uvs;
345         job->settings.export_vcols = params->vcolors;
346         job->settings.apply_subdiv = params->apply_subdiv;
347         job->settings.flatten_hierarchy = params->flatten_hierarchy;
348         job->settings.visible_layers_only = params->visible_layers_only;
349         job->settings.renderable_only = params->renderable_only;
350         job->settings.use_subdiv_schema = params->use_subdiv_schema;
351         job->settings.export_ogawa = (params->compression_type == ABC_ARCHIVE_OGAWA);
352         job->settings.pack_uv = params->packuv;
353         job->settings.global_scale = params->global_scale;
354         job->settings.triangulate = params->triangulate;
355         job->settings.quad_method = params->quad_method;
356         job->settings.ngon_method = params->ngon_method;
357
358         if (job->settings.frame_start > job->settings.frame_end) {
359                 std::swap(job->settings.frame_start, job->settings.frame_end);
360         }
361
362         wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
363                                     CTX_wm_window(C),
364                                     job->scene,
365                                     "Alembic Export",
366                                     WM_JOB_PROGRESS,
367                                     WM_JOB_TYPE_ALEMBIC);
368
369         /* setup job */
370         WM_jobs_customdata_set(wm_job, job, MEM_freeN);
371         WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
372         WM_jobs_callbacks(wm_job, export_startjob, NULL, NULL, export_endjob);
373
374         WM_jobs_start(CTX_wm_manager(C), wm_job);
375 }
376
377 /* ********************** Import file ********************** */
378
379 static void visit_object(const IObject &object,
380                          std::vector<AbcObjectReader *> &readers,
381                          GHash *parent_map,
382                          ImportSettings &settings)
383 {
384         if (!object.valid()) {
385                 return;
386         }
387
388         for (int i = 0; i < object.getNumChildren(); ++i) {
389                 IObject child = object.getChild(i);
390
391                 if (!child.valid()) {
392                         continue;
393                 }
394
395                 AbcObjectReader *reader = NULL;
396
397                 const MetaData &md = child.getMetaData();
398
399                 if (IXform::matches(md)) {
400                         bool create_xform = false;
401
402                         /* Check whether or not this object is a Maya locator, which is
403                          * similar to empties used as parent object in Blender. */
404                         if (has_property(child.getProperties(), "locator")) {
405                                 create_xform = true;
406                         }
407                         else {
408                                 /* Avoid creating an empty object if the child of this transform
409                                  * is not a transform (that is an empty). */
410                                 if (child.getNumChildren() == 1) {
411                                         if (IXform::matches(child.getChild(0).getMetaData())) {
412                                                 create_xform = true;
413                                         }
414 #if 0
415                                         else {
416                                                 std::cerr << "Skipping " << child.getFullName() << '\n';
417                                         }
418 #endif
419                                 }
420                                 else {
421                                         create_xform = true;
422                                 }
423                         }
424
425                         if (create_xform) {
426                                 reader = new AbcEmptyReader(child, settings);
427                         }
428                 }
429                 else if (IPolyMesh::matches(md)) {
430                         reader = new AbcMeshReader(child, settings);
431                 }
432                 else if (ISubD::matches(md)) {
433                         reader = new AbcSubDReader(child, settings);
434                 }
435                 else if (INuPatch::matches(md)) {
436 #ifdef USE_NURBS
437                         /* TODO(kevin): importing cyclic NURBS from other software crashes
438                          * at the moment. This is due to the fact that NURBS in other
439                          * software have duplicated points which causes buffer overflows in
440                          * Blender. Need to figure out exactly how these points are
441                          * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV).
442                          * Until this is fixed, disabling NURBS reading. */
443                         reader = new AbcNurbsReader(child, settings);
444 #endif
445                 }
446                 else if (ICamera::matches(md)) {
447                         reader = new AbcCameraReader(child, settings);
448                 }
449                 else if (IPoints::matches(md)) {
450                         reader = new AbcPointsReader(child, settings);
451                 }
452                 else if (IMaterial::matches(md)) {
453                         /* Pass for now. */
454                 }
455                 else if (ILight::matches(md)) {
456                         /* Pass for now. */
457                 }
458                 else if (IFaceSet::matches(md)) {
459                         /* Pass, those are handled in the mesh reader. */
460                 }
461                 else if (ICurves::matches(md)) {
462                         reader = new AbcCurveReader(child, settings);
463                 }
464                 else {
465                         assert(false);
466                 }
467
468                 if (reader) {
469                         readers.push_back(reader);
470                         reader->incref();
471
472                         AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(
473                                                           MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"));
474
475                         BLI_strncpy(abc_path->path, child.getFullName().c_str(), PATH_MAX);
476
477                         BLI_addtail(&settings.cache_file->object_paths, abc_path);
478
479                         /* Cast to `void *` explicitly to avoid compiler errors because it
480                          * is a `const char *` which the compiler cast to `const void *`
481                          * instead of the expected `void *`. */
482                         BLI_ghash_insert(parent_map, (void *)child.getFullName().c_str(), reader);
483                 }
484
485                 visit_object(child, readers, parent_map, settings);
486         }
487 }
488
489 enum {
490         ABC_NO_ERROR = 0,
491         ABC_ARCHIVE_FAIL,
492 };
493
494 struct ImportJobData {
495         Main *bmain;
496         Scene *scene;
497
498         char filename[1024];
499         ImportSettings settings;
500
501         GHash *parent_map;
502         std::vector<AbcObjectReader *> readers;
503
504         short *stop;
505         short *do_update;
506         float *progress;
507
508         char error_code;
509         bool was_cancelled;
510 };
511
512 ABC_INLINE bool is_mesh_and_strands(const IObject &object)
513 {
514         bool has_mesh = false;
515         bool has_curve = false;
516
517         for (int i = 0; i < object.getNumChildren(); ++i) {
518                 const IObject &child = object.getChild(i);
519
520                 if (!child.valid()) {
521                         continue;
522                 }
523
524                 const MetaData &md = child.getMetaData();
525
526                 if (IPolyMesh::matches(md)) {
527                         has_mesh = true;
528                 }
529                 else if (ISubD::matches(md)) {
530                         has_mesh = true;
531                 }
532                 else if (ICurves::matches(md)) {
533                         has_curve = true;
534                 }
535                 else if (IPoints::matches(md)) {
536                         has_curve = true;
537                 }
538         }
539
540         return has_mesh && has_curve;
541 }
542
543 static void import_startjob(void *user_data, short *stop, short *do_update, float *progress)
544 {
545         ImportJobData *data = static_cast<ImportJobData *>(user_data);
546
547         data->stop = stop;
548         data->do_update = do_update;
549         data->progress = progress;
550
551         ArchiveReader *archive = new ArchiveReader(data->filename);
552
553         if (!archive->valid()) {
554                 delete archive;
555                 data->error_code = ABC_ARCHIVE_FAIL;
556                 return;
557         }
558
559         CacheFile *cache_file = static_cast<CacheFile *>(BKE_cachefile_add(data->bmain, BLI_path_basename(data->filename)));
560
561         /* Decrement the ID ref-count because it is going to be incremented for each
562          * modifier and constraint that it will be attached to, so since currently
563          * it is not used by anyone, its use count will off by one. */
564         id_us_min(&cache_file->id);
565
566         cache_file->is_sequence = data->settings.is_sequence;
567         cache_file->scale = data->settings.scale;
568         cache_file->handle = handle_from_archive(archive);
569         BLI_strncpy(cache_file->filepath, data->filename, 1024);
570
571         data->settings.cache_file = cache_file;
572
573         *data->do_update = true;
574         *data->progress = 0.05f;
575
576         data->parent_map = BLI_ghash_str_new("alembic parent ghash");
577
578         /* Parse Alembic Archive. */
579
580         visit_object(archive->getTop(), data->readers, data->parent_map, data->settings);
581
582         if (G.is_break) {
583                 data->was_cancelled = true;
584                 return;
585         }
586
587         *data->do_update = true;
588         *data->progress = 0.1f;
589
590         /* Create objects and set scene frame range. */
591
592         const float size = static_cast<float>(data->readers.size());
593         size_t i = 0;
594
595         chrono_t min_time = std::numeric_limits<chrono_t>::max();
596         chrono_t max_time = std::numeric_limits<chrono_t>::min();
597
598         std::vector<AbcObjectReader *>::iterator iter;
599         for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
600                 AbcObjectReader *reader = *iter;
601
602                 if (reader->valid()) {
603                         reader->readObjectData(data->bmain, 0.0f);
604                         reader->readObjectMatrix(0.0f);
605
606                         min_time = std::min(min_time, reader->minTime());
607                         max_time = std::max(max_time, reader->maxTime());
608                 }
609
610                 *data->progress = 0.1f + 0.6f * (++i / size);
611                 *data->do_update = true;
612
613                 if (G.is_break) {
614                         data->was_cancelled = true;
615                         return;
616                 }
617         }
618
619         if (data->settings.set_frame_range) {
620                 Scene *scene = data->scene;
621
622                 if (data->settings.is_sequence) {
623                         SFRA = data->settings.offset;
624                         EFRA = SFRA + (data->settings.sequence_len - 1);
625                         CFRA = SFRA;
626                 }
627                 else if (min_time < max_time) {
628                         SFRA = min_time * FPS;
629                         EFRA = max_time * FPS;
630                         CFRA = SFRA;
631                 }
632         }
633
634         /* Setup parentship. */
635
636         i = 0;
637         for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
638                 const AbcObjectReader *reader = *iter;
639                 const AbcObjectReader *parent_reader = NULL;
640                 const IObject &iobject = reader->iobject();
641
642                 IObject parent = iobject.getParent();
643
644                 if (!IXform::matches(iobject.getHeader())) {
645                         /* In the case of an non XForm node, the parent is the transform
646                          * matrix of the data itself, so we get the its grand parent.
647                          */
648
649                         /* Special case with object only containing a mesh and some strands,
650                          * we want both objects to be parented to the same object. */
651                         if (!is_mesh_and_strands(parent)) {
652                                 parent = parent.getParent();
653                         }
654                 }
655
656                 parent_reader = reinterpret_cast<AbcObjectReader *>(
657                                     BLI_ghash_lookup(data->parent_map, parent.getFullName().c_str()));
658
659                 if (parent_reader) {
660                         Object *parent = parent_reader->object();
661
662                         if (parent != NULL && reader->object() != parent) {
663                                 Object *ob = reader->object();
664                                 ob->parent = parent;
665                         }
666                 }
667
668                 *data->progress = 0.7f + 0.3f * (++i / size);
669                 *data->do_update = true;
670
671                 if (G.is_break) {
672                         data->was_cancelled = true;
673                         return;
674                 }
675         }
676 }
677
678 static void import_endjob(void *user_data)
679 {
680         ImportJobData *data = static_cast<ImportJobData *>(user_data);
681
682         std::vector<AbcObjectReader *>::iterator iter;
683
684         /* Delete objects on cancelation. */
685         if (data->was_cancelled) {
686                 for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
687                         Object *ob = (*iter)->object();
688
689                         if (ob->data) {
690                                 BKE_libblock_free_us(data->bmain, ob->data);
691                                 ob->data = NULL;
692                         }
693
694                         BKE_libblock_free_us(data->bmain, ob);
695                 }
696         }
697         else {
698                 /* Add object to scene. */
699                 BKE_scene_base_deselect_all(data->scene);
700
701                 for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
702                         Object *ob = (*iter)->object();
703                         ob->lay = data->scene->lay;
704
705                         BKE_scene_base_add(data->scene, ob);
706
707                         DAG_id_tag_update_ex(data->bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
708                 }
709
710                 DAG_relations_tag_update(data->bmain);
711         }
712
713         for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
714                 AbcObjectReader *reader = *iter;
715                 reader->decref();
716
717                 if (reader->refcount() == 0) {
718                         delete reader;
719                 }
720         }
721
722         if (data->parent_map) {
723                 BLI_ghash_free(data->parent_map, NULL, NULL);
724         }
725
726         switch (data->error_code) {
727                 default:
728                 case ABC_NO_ERROR:
729                         break;
730                 case ABC_ARCHIVE_FAIL:
731                         WM_report(RPT_ERROR, "Could not open Alembic archive for reading! See console for detail.");
732                         break;
733         }
734
735         WM_main_add_notifier(NC_SCENE | ND_FRAME, data->scene);
736 }
737
738 static void import_freejob(void *user_data)
739 {
740         ImportJobData *data = static_cast<ImportJobData *>(user_data);
741         delete data;
742 }
743
744 void ABC_import(bContext *C, const char *filepath, float scale, bool is_sequence, bool set_frame_range, int sequence_len, int offset, bool validate_meshes)
745 {
746         /* Using new here since MEM_* funcs do not call ctor to properly initialize
747          * data. */
748         ImportJobData *job = new ImportJobData();
749         job->bmain = CTX_data_main(C);
750         job->scene = CTX_data_scene(C);
751         BLI_strncpy(job->filename, filepath, 1024);
752
753         job->settings.scale = scale;
754         job->settings.is_sequence = is_sequence;
755         job->settings.set_frame_range = set_frame_range;
756         job->settings.sequence_len = sequence_len;
757         job->settings.offset = offset;
758         job->settings.validate_meshes = validate_meshes;
759         job->parent_map = NULL;
760         job->error_code = ABC_NO_ERROR;
761         job->was_cancelled = false;
762
763         G.is_break = false;
764
765         wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
766                                     CTX_wm_window(C),
767                                     job->scene,
768                                     "Alembic Import",
769                                     WM_JOB_PROGRESS,
770                                     WM_JOB_TYPE_ALEMBIC);
771
772         /* setup job */
773         WM_jobs_customdata_set(wm_job, job, import_freejob);
774         WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
775         WM_jobs_callbacks(wm_job, import_startjob, NULL, NULL, import_endjob);
776
777         WM_jobs_start(CTX_wm_manager(C), wm_job);
778 }
779
780 /* ************************************************************************** */
781
782 void ABC_get_transform(CacheReader *reader, float r_mat[4][4], float time, float scale)
783 {
784         if (!reader) {
785                 return;
786         }
787
788         AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader);
789
790         bool is_constant = false;
791         abc_reader->read_matrix(r_mat, time, scale, is_constant);
792 }
793
794 /* ************************************************************************** */
795
796 DerivedMesh *ABC_read_mesh(CacheReader *reader,
797                            Object *ob,
798                            DerivedMesh *dm,
799                            const float time,
800                            const char **err_str,
801                            int read_flag)
802 {
803         AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader);
804         IObject iobject = abc_reader->iobject();
805
806         if (!iobject.valid()) {
807                 *err_str = "Invalid object: verify object path";
808                 return NULL;
809         }
810
811         const ObjectHeader &header = iobject.getHeader();
812
813         if (IPolyMesh::matches(header)) {
814                 if (ob->type != OB_MESH) {
815                         *err_str = "Object type mismatch: object path points to a mesh!";
816                         return NULL;
817                 }
818
819                 return abc_reader->read_derivedmesh(dm, time, read_flag);
820         }
821         else if (ISubD::matches(header)) {
822                 if (ob->type != OB_MESH) {
823                         *err_str = "Object type mismatch: object path points to a subdivision mesh!";
824                         return NULL;
825                 }
826
827                 return abc_reader->read_derivedmesh(dm, time, read_flag);
828         }
829         else if (IPoints::matches(header)) {
830                 if (ob->type != OB_MESH) {
831                         *err_str = "Object type mismatch: object path points to a point cloud (requires a mesh object)!";
832                         return NULL;
833                 }
834
835                 return abc_reader->read_derivedmesh(dm, time, read_flag);
836         }
837         else if (ICurves::matches(header)) {
838                 if (ob->type != OB_CURVE) {
839                         *err_str = "Object type mismatch: object path points to a curve!";
840                         return NULL;
841                 }
842
843                 return abc_reader->read_derivedmesh(dm, time, read_flag);
844         }
845
846         *err_str = "Unsupported object type: verify object path"; // or poke developer
847         return NULL;
848 }
849
850 /* ************************************************************************** */
851
852 void CacheReader_free(CacheReader *reader)
853 {
854         AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader);
855         abc_reader->decref();
856
857         if (abc_reader->refcount() == 0) {
858                 delete abc_reader;
859         }
860 }
861
862 CacheReader *CacheReader_open_alembic_object(AbcArchiveHandle *handle, CacheReader *reader, Object *object, const char *object_path)
863 {
864         if (object_path[0] == '\0') {
865                 return reader;
866         }
867
868         ArchiveReader *archive = archive_from_handle(handle);
869
870         if (!archive || !archive->valid()) {
871                 return reader;
872         }
873
874         IObject iobject;
875         find_iobject(archive->getTop(), iobject, object_path);
876
877         if (reader) {
878                 CacheReader_free(reader);
879         }
880
881         ImportSettings settings;
882         AbcObjectReader *abc_reader = create_reader(iobject, settings);
883         abc_reader->object(object);
884         abc_reader->incref();
885
886         return reinterpret_cast<CacheReader *>(abc_reader);
887 }