12#include <Alembic/AbcGeom/ILight.h>
13#include <Alembic/AbcMaterial/IMaterial.h>
58using Alembic::Abc::IV3fArrayProperty;
59using Alembic::Abc::ObjectHeader;
60using Alembic::Abc::PropertyHeader;
61using Alembic::Abc::V3fArraySamplePtr;
62using Alembic::AbcGeom::ICamera;
63using Alembic::AbcGeom::ICurves;
64using Alembic::AbcGeom::IFaceSet;
65using Alembic::AbcGeom::ILight;
66using Alembic::AbcGeom::INuPatch;
67using Alembic::AbcGeom::IObject;
68using Alembic::AbcGeom::IPoints;
69using Alembic::AbcGeom::IPolyMesh;
70using Alembic::AbcGeom::IPolyMeshSchema;
71using Alembic::AbcGeom::ISampleSelector;
72using Alembic::AbcGeom::ISubD;
73using Alembic::AbcGeom::IXform;
74using Alembic::AbcGeom::kWrapExisting;
75using Alembic::AbcGeom::MetaData;
76using Alembic::AbcMaterial::IMaterial;
95 CacheObjectPath *abc_path = MEM_cnew<CacheObjectPath>(
"CacheObjectPath");
96 STRNCPY(abc_path->
path,
object.getFullName().c_str());
106 if (!
object.valid()) {
110 size_t children_claiming_this_object = 0;
111 size_t num_children =
object.getNumChildren();
113 for (
size_t i = 0; i < num_children; i++) {
115 children_claiming_this_object += child_claims_this_object ? 1 : 0;
118 const MetaData &md =
object.getMetaData();
119 bool get_path =
false;
120 bool parent_is_part_of_this_object =
false;
125 else if (IXform::matches(md)) {
130 get_path = children_claiming_this_object == 0;
134 parent_is_part_of_this_object =
false;
138 get_path = IPolyMesh::matches(md) || ISubD::matches(md) ||
140 INuPatch::matches(md) ||
142 ICamera::matches(md) || IPoints::matches(md) || ICurves::matches(md);
143 parent_is_part_of_this_object = get_path;
150 return parent_is_part_of_this_object;
154 const char *filepath,
158 std::vector<const char *> filepaths;
159 filepaths.push_back(filepath);
163 filepaths.push_back(layers->filepath);
165 layers = layers->next;
169 std::reverse(filepaths.begin(), filepaths.end());
173 if (!archive || !archive->
valid()) {
192 return ALEMBIC_LIBRARY_VERSION;
197 if (!
object.valid()) {
201 std::vector<std::string> tokens;
202 split(path,
'/', tokens);
204 IObject tmp = object;
206 std::vector<std::string>::iterator iter;
207 for (iter = tokens.begin(); iter != tokens.end(); ++iter) {
208 IObject child = tmp.getChild(*iter);
238 const IObject &
object,
243 const std::string &full_name =
object.getFullName();
245 if (!
object.valid()) {
246 std::cerr <<
" - " << full_name <<
": object is invalid, skipping it and all its children.\n";
254 size_t children_claiming_this_object = 0;
255 size_t num_children =
object.getNumChildren();
259 for (
size_t i = 0; i < num_children; i++) {
260 const IObject ichild =
object.getChild(i);
263 std::pair<bool, AbcObjectReader *> child_result;
264 child_result =
visit_object(ichild, readers, settings, assign_as_parent);
266 bool child_claims_this_object = child_result.first;
269 if (child_reader ==
nullptr) {
273 if (child_claims_this_object) {
274 claiming_child_readers.push_back(child_reader);
277 nonclaiming_child_readers.push_back(child_reader);
281 children_claiming_this_object += child_claims_this_object ? 1 : 0;
283 BLI_assert(children_claiming_this_object == claiming_child_readers.size());
287 const MetaData &md =
object.getMetaData();
288 bool parent_is_part_of_this_object =
false;
293 else if (IXform::matches(md)) {
306 create_empty = claiming_child_readers.empty();
313 else if (IPolyMesh::matches(md)) {
315 parent_is_part_of_this_object =
true;
317 else if (ISubD::matches(md)) {
319 parent_is_part_of_this_object =
true;
321 else if (INuPatch::matches(md)) {
330 parent_is_part_of_this_object =
true;
333 else if (ICamera::matches(md)) {
335 parent_is_part_of_this_object =
true;
337 else if (IPoints::matches(md)) {
339 parent_is_part_of_this_object =
true;
341 else if (IMaterial::matches(md)) {
344 else if (ILight::matches(md)) {
347 else if (IFaceSet::matches(md)) {
350 else if (ICurves::matches(md)) {
352 parent_is_part_of_this_object =
true;
355 std::cerr <<
"Alembic object " << full_name <<
" is of unsupported schema type '"
356 <<
object.getMetaData().get(
"schemaObjTitle") <<
"'" << std::endl;
364 readers.push_back(reader);
370 if (nonclaiming_child_readers.size() + assign_as_parent.size() > 0) {
372 child_reader->parent_reader = reader;
380 if (!claiming_child_readers.empty()) {
386 child_reader->parent_reader = claiming_child;
393 r_assign_as_parent.push_back(child_reader);
401 r_assign_as_parent.push_back(child_reader);
404 r_assign_as_parent.push_back(child_reader);
407 r_assign_as_parent.push_back(child_reader);
412 return std::make_pair(parent_is_part_of_this_object, reader);
435 chrono_t
min_time = std::numeric_limits<chrono_t>::max();
437 chrono_t
max_time = std::numeric_limits<chrono_t>::min();
453 std::cout <<
"Alembic import took ";
462 const char *na = a->name().c_str();
463 const char *nb = b->name().c_str();
464 return BLI_strcasecmp(na, nb) < 0;
471 SCOPE_TIMER(
"Alembic import, objects reading and creation");
475 if (!archive || !archive->
valid()) {
489 cache_file->
is_sequence = data->settings.is_sequence;
490 cache_file->
scale = data->settings.scale;
493 data->archives.append(archive);
494 data->settings.cache_file = cache_file;
496 *data->do_update =
true;
497 *data->progress += 0.05f * progress_factor;
501 std::vector<AbcObjectReader *> readers{};
508 data->was_cancelled =
true;
509 data->readers.extend(readers);
513 *data->do_update =
true;
514 *data->progress += 0.05f * progress_factor;
521 data->readers.extend(readers);
523 const float size =
float(readers.size());
525 ISampleSelector sample_sel(0.0);
526 std::vector<AbcObjectReader *>::iterator iter;
527 const float read_object_progress_step = (0.6f /
size) * progress_factor;
528 for (iter = readers.begin(); iter != readers.end(); ++iter) {
531 if (reader->
valid()) {
534 data->min_time = std::min(data->min_time, reader->
minTime());
535 data->max_time = std::max(data->max_time, reader->
maxTime());
538 std::cerr <<
"Object " << reader->
name() <<
" in Alembic file " << filepath
541 *data->progress += read_object_progress_step;
542 *data->do_update =
true;
545 data->was_cancelled =
true;
551 for (iter = readers.begin(); iter != readers.end(); ++iter) {
565 const float setup_object_transform_progress_step = (0.3f /
size) * progress_factor;
566 for (iter = readers.begin(); iter != readers.end(); ++iter) {
570 *data->progress += setup_object_transform_progress_step;
571 *data->do_update =
true;
574 data->was_cancelled =
true;
579 std::cout <<
"Alembic import " << filepath <<
" took ";
586 if (!data->settings.set_frame_range) {
589 Scene *scene = data->scene;
590 if (data->settings.is_sequence) {
591 scene->
r.
sfra = data->settings.sequence_min_frame;
592 scene->r.efra = data->settings.sequence_max_frame;
593 scene->r.cfra = scene->r.sfra;
595 else if (data->min_time < data->max_time) {
596 scene->r.sfra =
int(round(data->min_time *
FPS));
597 scene->r.efra =
int(round(data->max_time *
FPS));
598 scene->r.cfra = scene->r.sfra;
606 data->do_update = &worker_status->
do_update;
607 data->progress = &worker_status->
progress;
608 data->start_time = blender::timeit::Clock::now();
611 float file_progress_factor = 1.0f /
float(data->paths.size());
612 for (
int idx : data->paths.index_range()) {
613 import_file(data, data->paths[idx].c_str(), file_progress_factor);
615 if (
G.is_break || data->was_cancelled) {
616 data->was_cancelled =
true;
620 worker_status->
progress =
float(idx + 1) * file_progress_factor;
632 if (data->was_cancelled) {
634 Object *ob = reader->object();
648 const Scene *scene = data->scene;
649 ViewLayer *view_layer = data->view_layer;
656 Object *ob = reader->object();
662 Object *ob = reader->object();
677 if (data->is_background_job) {
687 if (reader->refcount() == 0) {
694 switch (data->error_code) {
697 data->import_ok = !data->was_cancelled;
700 WM_report(
RPT_ERROR,
"Could not open Alembic archive for reading, see console for detail");
742 bool import_ok =
false;
743 if (as_background_job) {
780 bool is_constant =
false;
787 if (object->parent ==
nullptr) {
789 abc_reader->
read_matrix(r_mat_world, time, scale, is_constant);
793 float mat_parent[4][4];
796 float mat_local[4][4];
797 abc_reader->
read_matrix(mat_local, time, scale, is_constant);
798 mul_m4_m4m4(r_mat_world, mat_parent, object->parentinv);
807 IObject iobject = abc_reader->
iobject();
809 if (!iobject.valid()) {
810 *r_err_str =
RPT_(
"Invalid object: verify object path");
814 const ObjectHeader &header = iobject.getHeader();
827 return ISampleSelector(time, ISampleSelector::kFloorIndex);
834 const char **r_err_str)
837 if (abc_reader ==
nullptr) {
852 const Mesh *existing_mesh,
854 const char **r_err_str)
857 if (abc_reader ==
nullptr) {
880 const char *object_path,
881 const bool is_sequence)
883 if (object_path[0] ==
'\0') {
889 if (!archive || !archive->
valid()) {
903 if (abc_reader ==
nullptr) {
907 abc_reader->
object(
object);
910 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(struct 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
#define STRNCPY(dst, src)
#define UNUSED_VARS_NDEBUG(...)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_id_tag_update_ex(Main *bmain, 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
#define SCOPE_TIMER(message)
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)
BLI_INLINE CacheArchiveHandle * handle_from_archive(ArchiveReader *archive)
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 ArchiveReader * archive_from_handle(CacheArchiveHandle *handle)
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)
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)
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
const std::string & name() const
std::vector< AbcObjectReader * > ptr_vector
Alembic::Abc::IObject getTop()
static ArchiveReader * get(const struct Main *bmain, const std::vector< const char * > &filenames)
local_group_size(16, 16) .push_constant(Type b
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
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)
blender::timeit::TimePoint start_time
blender::Vector< ArchiveReader * > archives
blender::Vector< std::string > paths
blender::Vector< AbcObjectReader * > readers
struct Collection * collection
bool always_add_cache_reader
void WM_report(eReportType type, const char *message)
void WM_main_add_notifier(uint type, void *reference)
void WM_set_locked_interface(wmWindowManager *wm, bool lock)
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))