12#include <Alembic/AbcGeom/ILight.h>
13#include <Alembic/AbcGeom/INuPatch.h>
14#include <Alembic/AbcMaterial/IMaterial.h>
60using Alembic::Abc::IV3fArrayProperty;
61using Alembic::Abc::ObjectHeader;
62using Alembic::Abc::PropertyHeader;
63using Alembic::Abc::V3fArraySamplePtr;
64using Alembic::AbcGeom::ICamera;
65using Alembic::AbcGeom::ICurves;
66using Alembic::AbcGeom::IFaceSet;
67using Alembic::AbcGeom::ILight;
68using Alembic::AbcGeom::INuPatch;
69using Alembic::AbcGeom::IObject;
70using Alembic::AbcGeom::IPoints;
71using Alembic::AbcGeom::IPolyMesh;
72using Alembic::AbcGeom::IPolyMeshSchema;
73using Alembic::AbcGeom::ISampleSelector;
74using Alembic::AbcGeom::ISubD;
75using Alembic::AbcGeom::IXform;
76using Alembic::AbcGeom::kWrapExisting;
77using Alembic::AbcGeom::MetaData;
78using Alembic::AbcMaterial::IMaterial;
113 STRNCPY(abc_path->
path,
object.getFullName().c_str());
123 if (!
object.valid()) {
127 size_t children_claiming_this_object = 0;
128 size_t num_children =
object.getNumChildren();
130 for (
size_t i = 0;
i < num_children;
i++) {
132 children_claiming_this_object += child_claims_this_object ? 1 : 0;
135 const MetaData &md =
object.getMetaData();
136 bool get_path =
false;
137 bool parent_is_part_of_this_object =
false;
142 else if (IXform::matches(md)) {
147 get_path = children_claiming_this_object == 0;
151 parent_is_part_of_this_object =
false;
155 get_path = IPolyMesh::matches(md) || ISubD::matches(md) ||
157 INuPatch::matches(md) ||
159 ICamera::matches(md) || IPoints::matches(md) || ICurves::matches(md);
160 parent_is_part_of_this_object = get_path;
167 return parent_is_part_of_this_object;
171 const char *filepath,
175 std::vector<const char *> filepaths;
176 filepaths.push_back(filepath);
180 filepaths.push_back(layers->
filepath);
182 layers = layers->
next;
186 std::reverse(filepaths.begin(), filepaths.end());
190 if (!archive || !archive->
valid()) {
213 return ALEMBIC_LIBRARY_VERSION;
218 if (!
object.valid()) {
222 std::vector<std::string> tokens;
223 split(path,
'/', tokens);
225 IObject tmp = object;
227 std::vector<std::string>::iterator iter;
228 for (iter = tokens.begin(); iter != tokens.end(); ++iter) {
229 IObject child = tmp.getChild(*iter);
259 const IObject &
object,
264 const std::string &full_name =
object.getFullName();
266 if (!
object.valid()) {
267 std::cerr <<
" - " << full_name <<
": object is invalid, skipping it and all its children.\n";
275 size_t children_claiming_this_object = 0;
276 size_t num_children =
object.getNumChildren();
280 for (
size_t i = 0;
i < num_children;
i++) {
281 const IObject ichild =
object.getChild(
i);
284 std::pair<bool, AbcObjectReader *> child_result;
285 child_result =
visit_object(ichild, readers, settings, assign_as_parent);
287 bool child_claims_this_object = child_result.first;
290 if (child_reader ==
nullptr) {
294 if (child_claims_this_object) {
295 claiming_child_readers.push_back(child_reader);
298 nonclaiming_child_readers.push_back(child_reader);
302 children_claiming_this_object += child_claims_this_object ? 1 : 0;
304 BLI_assert(children_claiming_this_object == claiming_child_readers.size());
308 const MetaData &md =
object.getMetaData();
309 bool parent_is_part_of_this_object =
false;
314 else if (IXform::matches(md)) {
327 create_empty = claiming_child_readers.empty();
334 else if (IPolyMesh::matches(md)) {
336 parent_is_part_of_this_object =
true;
338 else if (ISubD::matches(md)) {
340 parent_is_part_of_this_object =
true;
342 else if (INuPatch::matches(md)) {
351 parent_is_part_of_this_object =
true;
354 else if (ICamera::matches(md)) {
356 parent_is_part_of_this_object =
true;
358 else if (IPoints::matches(md)) {
360 parent_is_part_of_this_object =
true;
362 else if (IMaterial::matches(md)) {
365 else if (ILight::matches(md)) {
368 else if (IFaceSet::matches(md)) {
371 else if (ICurves::matches(md)) {
373 parent_is_part_of_this_object =
true;
376 std::cerr <<
"Alembic object " << full_name <<
" is of unsupported schema type '"
377 <<
object.getMetaData().get(
"schemaObjTitle") <<
"'" << std::endl;
385 readers.push_back(reader);
391 if (nonclaiming_child_readers.size() + assign_as_parent.size() > 0) {
393 child_reader->parent_reader = reader;
396 child_reader->parent_reader = reader;
401 if (!claiming_child_readers.empty()) {
407 child_reader->parent_reader = claiming_child;
410 child_reader->parent_reader = claiming_child;
414 r_assign_as_parent.push_back(child_reader);
422 r_assign_as_parent.push_back(child_reader);
425 r_assign_as_parent.push_back(child_reader);
428 r_assign_as_parent.push_back(child_reader);
433 return std::make_pair(parent_is_part_of_this_object, reader);
456 chrono_t
min_time = std::numeric_limits<chrono_t>::max();
458 chrono_t
max_time = std::numeric_limits<chrono_t>::min();
474 std::cout <<
"Alembic import took ";
483 const char *na = a->name().c_str();
484 const char *nb = b->name().c_str();
485 return BLI_strcasecmp(na, nb) < 0;
495 if (!archive || !archive->
valid()) {
510 cache_file->
scale =
data->settings.scale;
513 data->archives.append(archive);
514 data->settings.cache_file = cache_file;
517 *
data->do_update =
true;
518 *
data->progress += 0.05f * progress_factor;
522 std::vector<AbcObjectReader *> readers{};
529 data->was_cancelled =
true;
530 data->readers.extend(readers);
534 *
data->do_update =
true;
535 *
data->progress += 0.05f * progress_factor;
542 data->readers.extend(readers);
544 const float size =
float(readers.size());
546 ISampleSelector sample_sel(0.0);
547 std::vector<AbcObjectReader *>::iterator iter;
548 const float read_object_progress_step = (0.6f /
size) * progress_factor;
549 for (iter = readers.begin(); iter != readers.end(); ++iter) {
552 if (reader->
valid()) {
559 std::cerr <<
"Object " << reader->
name() <<
" in Alembic file " << filepath
562 *
data->progress += read_object_progress_step;
563 *
data->do_update =
true;
566 data->was_cancelled =
true;
572 for (iter = readers.begin(); iter != readers.end(); ++iter) {
586 const float setup_object_transform_progress_step = (0.3f /
size) * progress_factor;
587 for (iter = readers.begin(); iter != readers.end(); ++iter) {
591 *
data->progress += setup_object_transform_progress_step;
592 *
data->do_update =
true;
595 data->was_cancelled =
true;
600 std::cout <<
"Alembic import " << filepath <<
" took ";
607 if (!
data->settings.set_frame_range) {
611 if (
data->settings.is_sequence) {
612 scene->
r.
sfra =
data->settings.sequence_min_frame;
613 scene->
r.
efra =
data->settings.sequence_max_frame;
616 else if (
data->min_time <
data->max_time) {
617 scene->
r.
sfra = int(
round(
data->min_time * scene->frames_per_second()));
618 scene->
r.
efra = int(
round(
data->max_time * scene->frames_per_second()));
629 data->start_time = blender::timeit::Clock::now();
632 float file_progress_factor = 1.0f /
float(
data->paths.size());
633 for (
int idx :
data->paths.index_range()) {
636 if (
G.is_break ||
data->was_cancelled) {
637 data->was_cancelled =
true;
641 worker_status->
progress =
float(idx + 1) * file_progress_factor;
651 if (
data->was_cancelled) {
696 if (
data->is_background_job) {
713 switch (
data->error_code) {
716 data->import_ok = !
data->was_cancelled;
720 "Could not open Alembic archive for reading, see console for detail");
762 bool import_ok =
false;
763 if (as_background_job) {
767 "Importing Alembic...",
800 bool is_constant =
false;
807 if (object->
parent ==
nullptr) {
809 abc_reader->
read_matrix(r_mat_world, time, scale, is_constant);
813 float mat_parent[4][4];
816 float mat_local[4][4];
817 abc_reader->
read_matrix(mat_local, time, scale, is_constant);
827 IObject iobject = abc_reader->
iobject();
829 if (!iobject.valid()) {
830 *r_err_str =
RPT_(
"Invalid object: verify object path");
834 const ObjectHeader &header = iobject.getHeader();
847 return ISampleSelector(time, ISampleSelector::kFloorIndex);
854 const char **r_err_str)
857 if (abc_reader ==
nullptr) {
872 const Mesh *existing_mesh,
874 const char **r_err_str)
877 if (abc_reader ==
nullptr) {
900 const char *object_path,
901 const bool is_sequence)
903 if (object_path[0] ==
'\0') {
913 if (!archive || !archive->
valid()) {
929 if (abc_reader ==
nullptr) {
933 abc_reader->
object(
object);
936 return reinterpret_cast<CacheReader *
>(abc_reader);
void * BKE_cachefile_add(Main *bmain, const char *name)
bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
LayerCollection * BKE_layer_collection_get_active(ViewLayer *view_layer)
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
void BKE_view_layer_base_deselect_all(const Scene *scene, ViewLayer *view_layer)
Base * BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
void BKE_view_layer_base_select_and_set_active(ViewLayer *view_layer, Base *selbase)
void BKE_id_free_us(Main *bmain, void *idv) ATTR_NONNULL()
General operations, lookup, etc. for blender objects.
void BKE_object_get_parent_matrix(const Object *ob, Object *par, float r_parentmat[4][4])
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void void void const char * BLI_path_basename(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
char * STRNCPY(char(&dst)[N], const char *src)
#define UNUSED_VARS_NDEBUG(...)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
Object groups, one object can be in many groups at once.
Object is a sort of wrapper for general info.
void ED_undo_push(bContext *C, const char *str)
Read Guarded memory(de)allocation.
@ WM_JOB_TYPE_ALEMBIC_IMPORT
static void import_freejob(void *user_data)
static std::pair< bool, AbcObjectReader * > visit_object(const IObject &object, AbcObjectReader::ptr_vector &readers, ImportSettings &settings, AbcObjectReader::ptr_vector &r_assign_as_parent)
static ISampleSelector sample_selector_for_time(chrono_t time)
void ABC_read_geometry(CacheReader *reader, Object *ob, blender::bke::GeometrySet &geometry_set, const ABCReadParams *params, const char **r_err_str)
static void import_file(ImportJobData *data, const char *filepath, float progress_factor)
void ABC_get_transform(CacheReader *reader, float r_mat_world[4][4], double time, float scale)
void ABC_free_handle(CacheArchiveHandle *handle)
CacheReader * CacheReader_open_alembic_object(CacheArchiveHandle *handle, CacheReader *reader, Object *object, const char *object_path, const bool is_sequence)
static bool gather_objects_paths(const IObject &object, ListBase *object_paths)
static AbcObjectReader * get_abc_reader(CacheReader *reader, Object *ob, const char **r_err_str)
BLI_INLINE CacheArchiveHandle * handle_from_archive(AlembicArchiveData *archive)
static void sort_readers(blender::MutableSpan< AbcObjectReader * > readers)
bool ABC_mesh_topology_changed(CacheReader *reader, Object *ob, const Mesh *existing_mesh, const double time, const char **r_err_str)
static void import_startjob(void *user_data, wmJobWorkerStatus *worker_status)
bool ABC_import(bContext *C, const AlembicImportParams *params, bool as_background_job)
BLI_INLINE AlembicArchiveData * archive_from_handle(CacheArchiveHandle *handle)
CacheArchiveHandle * ABC_create_handle(const Main *bmain, const char *filepath, const CacheFileLayer *layers, ListBase *object_paths)
void ABC_CacheReader_free(CacheReader *reader)
static void import_endjob(void *user_data)
static void add_object_path(ListBase *object_paths, const IObject &object)
static void find_iobject(const IObject &object, IObject &ret, const std::string &path)
static void set_frame_range(ImportJobData *data)
BMesh const char void * data
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
int getParent(int link_num) const
constexpr T * end() const
constexpr T * begin() const
AbcObjectReader * parent_reader
void read_matrix(float r_mat[4][4], chrono_t time, float scale, bool &is_constant)
const Alembic::Abc::IObject & iobject() const
virtual bool valid() const =0
virtual bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, const Object *const ob, const char **r_err_str) const =0
virtual bool topology_changed(const Mesh *existing_mesh, const Alembic::Abc::ISampleSelector &sample_sel)
void setupObjectTransform(chrono_t time)
virtual void read_geometry(bke::GeometrySet &geometry_set, const Alembic::Abc::ISampleSelector &sample_sel, int read_flag, const char *velocity_name, float velocity_scale, const char **r_err_str)
bool inherits_xform() const
virtual void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)=0
std::vector< AbcObjectReader * > ptr_vector
const std::string & name() const
Alembic::Abc::IObject getTop()
bool is_blender_archive_version_prior_44()
static ArchiveReader * get(const struct Main *bmain, const std::vector< const char * > &filenames)
DEG_id_tag_update_ex(cb_data->bmain, cb_data->owner_id, ID_RECALC_TAG_FOR_UNDO|ID_RECALC_SYNC_TO_EVAL)
void * MEM_callocN(size_t len, const char *str)
bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name)
AbcObjectReader * create_reader(const Alembic::AbcGeom::IObject &object, ImportSettings &settings)
void split(const std::string &s, const char delim, std::vector< std::string > &tokens)
static void report_job_duration(const ExportJobData *data)
std::chrono::nanoseconds Nanoseconds
Clock::time_point TimePoint
void print_duration(Nanoseconds duration)
void parallel_sort(RandomAccessIterator begin, RandomAccessIterator end)
ImportSettings * settings
AlembicArchiveData(const AlembicArchiveData &)=delete
AlembicArchiveData()=default
AlembicArchiveData & operator==(const AlembicArchiveData &)=delete
ArchiveReader * archive_reader
struct CacheFileLayer * next
blender::timeit::TimePoint start_time
blender::Vector< ArchiveReader * > archives
blender::Vector< std::string > paths
blender::Vector< AbcObjectReader * > readers
struct Collection * collection
bool blender_archive_version_prior_44
bool always_add_cache_reader
void WM_locked_interface_set(wmWindowManager *wm, bool lock)
void WM_global_report(eReportType type, const char *message)
void WM_main_add_notifier(uint type, void *reference)
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, const eWM_JobFlag flag, const eWM_JobType job_type)
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))