From 753edafcb77d9aaf07fe869372319b841dd80681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Sat, 29 Oct 2016 12:23:09 +0200 Subject: Alembic: store a pointer to the object reader in the cache modifiers and constraints. This avoids traversing the archive everytime object data is needed and gives an overall consistent ~2x speedup here with files containing between 136 and 500 Alembic objects. Also this somewhat nicely de- duplicates code between data creation (upon import) and data streaming (modifiers and constraints). The only worying part is what happens when a CacheFile is deleted and/or has its path changed. For now, we traverse the whole scene and for each object using the CacheFile we free the pointer and NULL-ify it (see BKE_cachefile_clean), but at some point this should be re-considered and make use of the dependency graph. --- source/blender/alembic/ABC_alembic.h | 15 +- source/blender/alembic/intern/abc_curves.cc | 52 ++++ source/blender/alembic/intern/abc_curves.h | 3 +- source/blender/alembic/intern/abc_mesh.cc | 307 +++++++++++++---------- source/blender/alembic/intern/abc_mesh.h | 11 +- source/blender/alembic/intern/abc_object.cc | 63 +++-- source/blender/alembic/intern/abc_object.h | 22 +- source/blender/alembic/intern/abc_points.cc | 32 ++- source/blender/alembic/intern/abc_points.h | 2 + source/blender/alembic/intern/abc_util.cc | 62 +++++ source/blender/alembic/intern/abc_util.h | 7 + source/blender/alembic/intern/alembic_capi.cc | 340 +++++--------------------- 12 files changed, 468 insertions(+), 448 deletions(-) (limited to 'source/blender/alembic') diff --git a/source/blender/alembic/ABC_alembic.h b/source/blender/alembic/ABC_alembic.h index e62713f57f5..e92d5f2d9f7 100644 --- a/source/blender/alembic/ABC_alembic.h +++ b/source/blender/alembic/ABC_alembic.h @@ -28,6 +28,7 @@ extern "C" { #endif struct bContext; +struct CacheReader; struct DerivedMesh; struct ListBase; struct Object; @@ -92,21 +93,25 @@ AbcArchiveHandle *ABC_create_handle(const char *filename, struct ListBase *objec void ABC_free_handle(AbcArchiveHandle *handle); -void ABC_get_transform(AbcArchiveHandle *handle, - struct Object *ob, - const char *object_path, +void ABC_get_transform(struct CacheReader *reader, float r_mat[4][4], float time, float scale); -struct DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle, +struct DerivedMesh *ABC_read_mesh(struct CacheReader *reader, struct Object *ob, struct DerivedMesh *dm, - const char *object_path, const float time, const char **err_str, int flags); +void CacheReader_free(struct CacheReader *reader); + +struct CacheReader *CacheReader_open_alembic_object(struct AbcArchiveHandle *handle, + struct CacheReader *reader, + struct Object *object, + const char *object_path); + #ifdef __cplusplus } #endif diff --git a/source/blender/alembic/intern/abc_curves.cc b/source/blender/alembic/intern/abc_curves.cc index 2b54741a5c5..7e5ea3b1853 100644 --- a/source/blender/alembic/intern/abc_curves.cc +++ b/source/blender/alembic/intern/abc_curves.cc @@ -37,6 +37,7 @@ extern "C" { #include "BLI_listbase.h" +#include "BKE_cdderivedmesh.h" #include "BKE_curve.h" #include "BKE_object.h" @@ -353,3 +354,54 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time) BLI_addtail(BKE_curve_nurbs_get(cu), nu); } } + +/* NOTE: Alembic only stores data about control points, but the DerivedMesh + * passed from the cache modifier contains the displist, which has more data + * than the control points, so to avoid corrupting the displist we modify the + * object directly and create a new DerivedMesh from that. Also we might need to + * create new or delete existing NURBS in the curve. + */ +DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh */*dm*/, const float time, int /*read_flag*/) +{ + ISampleSelector sample_sel(time); + const ICurvesSchema::Sample sample = m_curves_schema.getValue(sample_sel); + + const P3fArraySamplePtr &positions = sample.getPositions(); + const Int32ArraySamplePtr num_vertices = sample.getCurvesNumVertices(); + + int vertex_idx = 0; + int curve_idx = 0; + Curve *curve = static_cast(m_object->data); + + const int curve_count = BLI_listbase_count(&curve->nurb); + + if (curve_count != num_vertices->size()) { + BKE_nurbList_free(&curve->nurb); + read_curve_sample(curve, m_curves_schema, time); + } + else { + Nurb *nurbs = static_cast(curve->nurb.first); + for (; nurbs; nurbs = nurbs->next, ++curve_idx) { + const int totpoint = (*num_vertices)[curve_idx]; + + if (nurbs->bp) { + BPoint *point = nurbs->bp; + + for (int i = 0; i < totpoint; ++i, ++point, ++vertex_idx) { + const Imath::V3f &pos = (*positions)[vertex_idx]; + copy_yup_zup(point->vec, pos.getValue()); + } + } + else if (nurbs->bezt) { + BezTriple *bezier = nurbs->bezt; + + for (int i = 0; i < totpoint; ++i, ++bezier, ++vertex_idx) { + const Imath::V3f &pos = (*positions)[vertex_idx]; + copy_yup_zup(bezier->vec[1], pos.getValue()); + } + } + } + } + + return CDDM_from_curve(m_object); +} diff --git a/source/blender/alembic/intern/abc_curves.h b/source/blender/alembic/intern/abc_curves.h index ee47f1931ea..979ee8af639 100644 --- a/source/blender/alembic/intern/abc_curves.h +++ b/source/blender/alembic/intern/abc_curves.h @@ -56,10 +56,11 @@ public: bool valid() const; void readObjectData(Main *bmain, float time); + DerivedMesh *read_derivedmesh(DerivedMesh *, const float time, int); }; /* ************************************************************************** */ void read_curve_sample(Curve *cu, const Alembic::AbcGeom::ICurvesSchema &schema, const float time); -#endif /* __ABC_CURVES_H__ */ \ No newline at end of file +#endif /* __ABC_CURVES_H__ */ diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc index bb5d5ce3566..5b282e3c5bb 100644 --- a/source/blender/alembic/intern/abc_mesh.cc +++ b/source/blender/alembic/intern/abc_mesh.cc @@ -646,75 +646,6 @@ void AbcMeshWriter::getGeoGroups( /* Some helpers for mesh generation */ namespace utils { -void mesh_add_verts(Mesh *mesh, size_t len) -{ - if (len == 0) { - return; - } - - const int totvert = mesh->totvert + len; - CustomData vdata; - CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert); - CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert); - - if (!CustomData_has_layer(&vdata, CD_MVERT)) { - CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert); - } - - CustomData_free(&mesh->vdata, mesh->totvert); - mesh->vdata = vdata; - BKE_mesh_update_customdata_pointers(mesh, false); - - mesh->totvert = totvert; -} - -static void mesh_add_mloops(Mesh *mesh, size_t len) -{ - if (len == 0) { - return; - } - - /* new face count */ - const int totloops = mesh->totloop + len; - - CustomData ldata; - CustomData_copy(&mesh->ldata, &ldata, CD_MASK_MESH, CD_DEFAULT, totloops); - CustomData_copy_data(&mesh->ldata, &ldata, 0, 0, mesh->totloop); - - if (!CustomData_has_layer(&ldata, CD_MLOOP)) { - CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, NULL, totloops); - } - - CustomData_free(&mesh->ldata, mesh->totloop); - mesh->ldata = ldata; - BKE_mesh_update_customdata_pointers(mesh, false); - - mesh->totloop = totloops; -} - -static void mesh_add_mpolygons(Mesh *mesh, size_t len) -{ - if (len == 0) { - return; - } - - const int totpolys = mesh->totpoly + len; - - CustomData pdata; - CustomData_copy(&mesh->pdata, &pdata, CD_MASK_MESH, CD_DEFAULT, totpolys); - CustomData_copy_data(&mesh->pdata, &pdata, 0, 0, mesh->totpoly); - - if (!CustomData_has_layer(&pdata, CD_MPOLY)) { - CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, NULL, totpolys); - } - - CustomData_free(&mesh->pdata, mesh->totpoly); - mesh->pdata = pdata; - BKE_mesh_update_customdata_pointers(mesh, false); - - mesh->totpoly = totpolys; -} - static void build_mat_map(const Main *bmain, std::map &mat_map) { Material *material = static_cast(bmain->mat.first); @@ -786,45 +717,6 @@ struct AbcMeshData { UInt32ArraySamplePtr uvs_indices; }; -static void *add_customdata_cb(void *user_data, const char *name, int data_type) -{ - Mesh *mesh = static_cast(user_data); - CustomDataType cd_data_type = static_cast(data_type); - void *cd_ptr = NULL; - - int index = -1; - if (cd_data_type == CD_MLOOPUV) { - index = ED_mesh_uv_texture_add(mesh, name, true); - cd_ptr = CustomData_get_layer(&mesh->ldata, cd_data_type); - } - else if (cd_data_type == CD_MLOOPCOL) { - index = ED_mesh_color_add(mesh, name, true); - cd_ptr = CustomData_get_layer(&mesh->ldata, cd_data_type); - } - - if (index == -1) { - return NULL; - } - - return cd_ptr; -} - -CDStreamConfig create_config(Mesh *mesh) -{ - CDStreamConfig config; - - config.mvert = mesh->mvert; - config.mpoly = mesh->mpoly; - config.mloop = mesh->mloop; - config.totpoly = mesh->totpoly; - config.totloop = mesh->totloop; - config.user_data = mesh; - config.loopdata = &mesh->ldata; - config.add_customdata_cb = add_customdata_cb; - - return config; -} - static void read_mverts_interp(MVert *mverts, const P3fArraySamplePtr &positions, const P3fArraySamplePtr &ceil_positions, const float weight) { float tmp[3]; @@ -1002,23 +894,15 @@ void AbcMeshReader::readObjectData(Main *bmain, float time) m_object->data = mesh; const ISampleSelector sample_sel(time); - const IPolyMeshSchema::Sample sample = m_schema.getValue(sample_sel); - - const P3fArraySamplePtr &positions = sample.getPositions(); - const Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); - const Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); - - utils::mesh_add_verts(mesh, positions->size()); - utils::mesh_add_mpolygons(mesh, face_counts->size()); - utils::mesh_add_mloops(mesh, face_indices->size()); - m_mesh_data = create_config(mesh); + DerivedMesh *dm = CDDM_from_mesh(mesh); + DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL); - bool has_smooth_normals = false; - read_mesh_sample(m_settings, m_schema, sample_sel, m_mesh_data, has_smooth_normals); + if (ndm != dm) { + dm->release(dm); + } - BKE_mesh_calc_normals(mesh); - BKE_mesh_calc_edges(mesh, false, false); + DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true); if (m_settings->validate_meshes) { BKE_mesh_validate(mesh, false, false); @@ -1031,6 +915,120 @@ void AbcMeshReader::readObjectData(Main *bmain, float time) } } +static bool check_smooth_poly_flag(DerivedMesh *dm) +{ + MPoly *mpolys = dm->getPolyArray(dm); + + for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) { + MPoly &poly = mpolys[i]; + + if ((poly.flag & ME_SMOOTH) != 0) { + return true; + } + } + + return false; +} + +static void set_smooth_poly_flag(DerivedMesh *dm) +{ + MPoly *mpolys = dm->getPolyArray(dm); + + for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) { + MPoly &poly = mpolys[i]; + poly.flag |= ME_SMOOTH; + } +} + +static void *add_customdata_cb(void *user_data, const char *name, int data_type) +{ + DerivedMesh *dm = static_cast(user_data); + CustomDataType cd_data_type = static_cast(data_type); + void *cd_ptr = NULL; + + if (ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) { + cd_ptr = CustomData_get_layer_named(dm->getLoopDataLayout(dm), cd_data_type, name); + + if (cd_ptr == NULL) { + cd_ptr = CustomData_add_layer_named(dm->getLoopDataLayout(dm), + cd_data_type, + CD_DEFAULT, + NULL, + dm->getNumLoops(dm), + name); + } + } + + return cd_ptr; +} + +CDStreamConfig get_config(DerivedMesh *dm) +{ + CDStreamConfig config; + + config.user_data = dm; + config.mvert = dm->getVertArray(dm); + config.mloop = dm->getLoopArray(dm); + config.mpoly = dm->getPolyArray(dm); + config.totloop = dm->getNumLoops(dm); + config.totpoly = dm->getNumPolys(dm); + config.loopdata = dm->getLoopDataLayout(dm); + config.add_customdata_cb = add_customdata_cb; + + return config; +} + +DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag) +{ + ISampleSelector sample_sel(time); + const IPolyMeshSchema::Sample sample = m_schema.getValue(sample_sel); + + const P3fArraySamplePtr &positions = sample.getPositions(); + const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); + const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); + + DerivedMesh *new_dm = NULL; + + /* Only read point data when streaming meshes, unless we need to create new ones. */ + ImportSettings settings; + settings.read_flag |= read_flag; + + if (dm->getNumVerts(dm) != positions->size()) { + new_dm = CDDM_from_template(dm, + positions->size(), + 0, + 0, + face_indices->size(), + face_counts->size()); + + settings.read_flag |= MOD_MESHSEQ_READ_ALL; + } + + CDStreamConfig config = get_config(new_dm ? new_dm : dm); + config.time = time; + + bool do_normals = false; + read_mesh_sample(&settings, m_schema, sample_sel, config, do_normals); + + if (new_dm) { + /* Check if we had ME_SMOOTH flag set to restore it. */ + if (!do_normals && check_smooth_poly_flag(dm)) { + set_smooth_poly_flag(new_dm); + } + + CDDM_calc_normals(new_dm); + CDDM_calc_edges(new_dm); + + return new_dm; + } + + if (do_normals) { + CDDM_calc_normals(dm); + } + + return dm; +} + void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start, const ISampleSelector &sample_sel) { @@ -1178,21 +1176,17 @@ void AbcSubDReader::readObjectData(Main *bmain, float time) m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str()); m_object->data = mesh; - const ISampleSelector sample_sel(time); - const ISubDSchema::Sample sample = m_schema.getValue(sample_sel); - - const P3fArraySamplePtr &positions = sample.getPositions(); - const Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); - const Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); - - utils::mesh_add_verts(mesh, positions->size()); - utils::mesh_add_mpolygons(mesh, face_counts->size()); - utils::mesh_add_mloops(mesh, face_indices->size()); + DerivedMesh *dm = CDDM_from_mesh(mesh); + DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL); - m_mesh_data = create_config(mesh); + if (ndm != dm) { + dm->release(dm); + } - read_subd_sample(m_settings, m_schema, sample_sel, m_mesh_data); + DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true); + const ISampleSelector sample_sel(time); + const ISubDSchema::Sample sample = m_schema.getValue(sample_sel); Int32ArraySamplePtr indices = sample.getCreaseIndices(); Alembic::Abc::FloatArraySamplePtr sharpnesses = sample.getCreaseSharpnesses(); @@ -1262,3 +1256,48 @@ void read_subd_sample(ImportSettings *settings, /* TODO: face sets */ } + +DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag) +{ + ISampleSelector sample_sel(time); + const ISubDSchema::Sample sample = m_schema.getValue(sample_sel); + + const P3fArraySamplePtr &positions = sample.getPositions(); + const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); + const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); + + DerivedMesh *new_dm = NULL; + + ImportSettings settings; + settings.read_flag |= read_flag; + + if (dm->getNumVerts(dm) != positions->size()) { + new_dm = CDDM_from_template(dm, + positions->size(), + 0, + 0, + face_indices->size(), + face_counts->size()); + + settings.read_flag |= MOD_MESHSEQ_READ_ALL; + } + + /* Only read point data when streaming meshes, unless we need to create new ones. */ + CDStreamConfig config = get_config(new_dm ? new_dm : dm); + config.time = time; + read_subd_sample(&settings, m_schema, sample_sel, config); + + if (new_dm) { + /* Check if we had ME_SMOOTH flag set to restore it. */ + if (check_smooth_poly_flag(dm)) { + set_smooth_poly_flag(new_dm); + } + + CDDM_calc_normals(new_dm); + CDDM_calc_edges(new_dm); + + return new_dm; + } + + return dm; +} diff --git a/source/blender/alembic/intern/abc_mesh.h b/source/blender/alembic/intern/abc_mesh.h index 41abe78f75f..66e6585a3d3 100644 --- a/source/blender/alembic/intern/abc_mesh.h +++ b/source/blender/alembic/intern/abc_mesh.h @@ -102,6 +102,8 @@ public: void readObjectData(Main *bmain, float time); + DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag); + private: void readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start, const Alembic::AbcGeom::ISampleSelector &sample_sel); @@ -126,6 +128,7 @@ public: bool valid() const; void readObjectData(Main *bmain, float time); + DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag); }; void read_subd_sample(ImportSettings *settings, @@ -135,16 +138,10 @@ void read_subd_sample(ImportSettings *settings, /* ************************************************************************** */ -namespace utils { - -void mesh_add_verts(struct Mesh *mesh, size_t len); - -} - void read_mverts(MVert *mverts, const Alembic::AbcGeom::P3fArraySamplePtr &positions, const Alembic::AbcGeom::N3fArraySamplePtr &normals); -CDStreamConfig create_config(Mesh *mesh); +CDStreamConfig get_config(DerivedMesh *dm); #endif /* __ABC_MESH_H__ */ diff --git a/source/blender/alembic/intern/abc_object.cc b/source/blender/alembic/intern/abc_object.cc index 32468fdaded..314b2568bed 100644 --- a/source/blender/alembic/intern/abc_object.cc +++ b/source/blender/alembic/intern/abc_object.cc @@ -126,6 +126,7 @@ AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings , m_settings(&settings) , m_min_time(std::numeric_limits::max()) , m_max_time(std::numeric_limits::min()) + , m_refcount(0) { m_name = object.getFullName(); std::vector parts; @@ -153,6 +154,11 @@ Object *AbcObjectReader::object() const return m_object; } +void AbcObjectReader::object(Object *ob) +{ + m_object = ob; +} + static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1, const float weight) { float mat0[4][4], mat1[4][4], ret[4][4]; @@ -209,6 +215,28 @@ Imath::M44d get_matrix(const IXformSchema &schema, const float time) } void AbcObjectReader::readObjectMatrix(const float time) +{ + bool is_constant = false; + + this->read_matrix(m_object->obmat, time, m_settings->scale, is_constant); + invert_m4_m4(m_object->imat, m_object->obmat); + + BKE_object_apply_mat4(m_object, m_object->obmat, false, false); + + if (!is_constant) { + bConstraint *con = BKE_constraint_add_for_object(m_object, NULL, CONSTRAINT_TYPE_TRANSFORM_CACHE); + bTransformCacheConstraint *data = static_cast(con->data); + BLI_strncpy(data->object_path, m_iobject.getFullName().c_str(), FILE_MAX); + + data->cache_file = m_settings->cache_file; + id_us_plus(&data->cache_file->id); + + data->reader = reinterpret_cast(this); + this->incref(); + } +} + +void AbcObjectReader::read_matrix(float mat[4][4], const float time, const float scale, bool &is_constant) { IXform ixform; bool has_alembic_parent = false; @@ -250,23 +278,12 @@ void AbcObjectReader::readObjectMatrix(const float time) } const Imath::M44d matrix = get_matrix(schema, time); - convert_matrix(matrix, m_object, m_object->obmat, m_settings->scale, has_alembic_parent); - - invert_m4_m4(m_object->imat, m_object->obmat); - - BKE_object_apply_mat4(m_object, m_object->obmat, false, false); - - if (!schema.isConstant()) { - bConstraint *con = BKE_constraint_add_for_object(m_object, NULL, CONSTRAINT_TYPE_TRANSFORM_CACHE); - bTransformCacheConstraint *data = static_cast(con->data); - BLI_strncpy(data->object_path, m_iobject.getFullName().c_str(), FILE_MAX); + convert_matrix(matrix, m_object, mat, scale, has_alembic_parent); - data->cache_file = m_settings->cache_file; - id_us_plus(&data->cache_file->id); - } + is_constant = schema.isConstant(); } -void AbcObjectReader::addCacheModifier() const +void AbcObjectReader::addCacheModifier() { ModifierData *md = modifier_new(eModifierType_MeshSequenceCache); BLI_addtail(&m_object->modifiers, md); @@ -277,6 +294,9 @@ void AbcObjectReader::addCacheModifier() const id_us_plus(&mcmd->cache_file->id); BLI_strncpy(mcmd->object_path, m_iobject.getFullName().c_str(), FILE_MAX); + + mcmd->reader = reinterpret_cast(this); + this->incref(); } chrono_t AbcObjectReader::minTime() const @@ -288,3 +308,18 @@ chrono_t AbcObjectReader::maxTime() const { return m_max_time; } + +int AbcObjectReader::refcount() const +{ + return m_refcount; +} + +void AbcObjectReader::incref() +{ + ++m_refcount; +} + +void AbcObjectReader::decref() +{ + --m_refcount; +} diff --git a/source/blender/alembic/intern/abc_object.h b/source/blender/alembic/intern/abc_object.h index a35faa37565..7ff927b4d33 100644 --- a/source/blender/alembic/intern/abc_object.h +++ b/source/blender/alembic/intern/abc_object.h @@ -130,6 +130,8 @@ static bool has_animations(Schema &schema, ImportSettings *settings) /* ************************************************************************** */ +struct DerivedMesh; + using Alembic::AbcCoreAbstract::chrono_t; class AbcObjectReader { @@ -145,6 +147,10 @@ protected: chrono_t m_min_time; chrono_t m_max_time; + /* Use reference counting since the same reader may be used by multiple + * modifiers and/or constraints. */ + int m_refcount; + public: explicit AbcObjectReader(const Alembic::Abc::IObject &object, ImportSettings &settings); @@ -153,17 +159,31 @@ public: const Alembic::Abc::IObject &iobject() const; Object *object() const; + void object(Object *ob); virtual bool valid() const = 0; virtual void readObjectData(Main *bmain, float time) = 0; + virtual DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag) + { + (void)time; + (void)read_flag; + return dm; + } + void readObjectMatrix(const float time); - void addCacheModifier() const; + void addCacheModifier(); chrono_t minTime() const; chrono_t maxTime() const; + + int refcount() const; + void incref(); + void decref(); + + void read_matrix(float mat[4][4], const float time, const float scale, bool &is_constant); }; Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, const float time); diff --git a/source/blender/alembic/intern/abc_points.cc b/source/blender/alembic/intern/abc_points.cc index 03014547416..c16da621c77 100644 --- a/source/blender/alembic/intern/abc_points.cc +++ b/source/blender/alembic/intern/abc_points.cc @@ -32,6 +32,7 @@ extern "C" { #include "DNA_mesh_types.h" #include "DNA_object_types.h" +#include "BKE_cdderivedmesh.h" #include "BKE_lattice.h" #include "BKE_mesh.h" #include "BKE_object.h" @@ -154,14 +155,14 @@ void AbcPointsReader::readObjectData(Main *bmain, float time) { Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str()); - const ISampleSelector sample_sel(time); - m_sample = m_schema.getValue(sample_sel); + DerivedMesh *dm = CDDM_from_mesh(mesh); + DerivedMesh *ndm = this->read_derivedmesh(dm, time, 0); - const P3fArraySamplePtr &positions = m_sample.getPositions(); - utils::mesh_add_verts(mesh, positions->size()); + if (ndm != dm) { + dm->release(dm); + } - CDStreamConfig config = create_config(mesh); - read_points_sample(m_schema, sample_sel, config, time); + DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true); if (m_settings->validate_meshes) { BKE_mesh_validate(mesh, false, false); @@ -197,3 +198,22 @@ void read_points_sample(const IPointsSchema &schema, read_mverts(config.mvert, positions, vnormals); } + +DerivedMesh *AbcPointsReader::read_derivedmesh(DerivedMesh *dm, const float time, int /*read_flag*/) +{ + ISampleSelector sample_sel(time); + const IPointsSchema::Sample sample = m_schema.getValue(sample_sel); + + const P3fArraySamplePtr &positions = sample.getPositions(); + + DerivedMesh *new_dm = NULL; + + if (dm->getNumVerts(dm) != positions->size()) { + new_dm = CDDM_new(positions->size(), 0, 0, 0, 0); + } + + CDStreamConfig config = get_config(new_dm ? new_dm : dm); + read_points_sample(m_schema, sample_sel, config, time); + + return new_dm ? new_dm : dm; +} diff --git a/source/blender/alembic/intern/abc_points.h b/source/blender/alembic/intern/abc_points.h index 51f3103bd8b..54873eed346 100644 --- a/source/blender/alembic/intern/abc_points.h +++ b/source/blender/alembic/intern/abc_points.h @@ -60,6 +60,8 @@ public: bool valid() const; void readObjectData(Main *bmain, float time); + + DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag); }; void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema, diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc index 60c66bca1c8..f87d18605d4 100644 --- a/source/blender/alembic/intern/abc_util.cc +++ b/source/blender/alembic/intern/abc_util.cc @@ -22,6 +22,15 @@ #include "abc_util.h" +#include "abc_camera.h" +#include "abc_curves.h" +#include "abc_mesh.h" +#include "abc_nurbs.h" +#include "abc_points.h" +#include "abc_transform.h" + +#include + #include extern "C" { @@ -462,3 +471,56 @@ float get_weight_and_index(float time, return bias; } + +//#define USE_NURBS + +AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSettings &settings) +{ + AbcObjectReader *reader = NULL; + + const Alembic::AbcGeom::MetaData &md = object.getMetaData(); + + if (Alembic::AbcGeom::IXform::matches(md)) { + reader = new AbcEmptyReader(object, settings); + } + else if (Alembic::AbcGeom::IPolyMesh::matches(md)) { + reader = new AbcMeshReader(object, settings); + } + else if (Alembic::AbcGeom::ISubD::matches(md)) { + reader = new AbcSubDReader(object, settings); + } + else if (Alembic::AbcGeom::INuPatch::matches(md)) { +#ifdef USE_NURBS + /* TODO(kevin): importing cyclic NURBS from other software crashes + * at the moment. This is due to the fact that NURBS in other + * software have duplicated points which causes buffer overflows in + * Blender. Need to figure out exactly how these points are + * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV). + * Until this is fixed, disabling NURBS reading. */ + reader = new AbcNurbsReader(child, settings); +#endif + } + else if (Alembic::AbcGeom::ICamera::matches(md)) { + reader = new AbcCameraReader(object, settings); + } + else if (Alembic::AbcGeom::IPoints::matches(md)) { + reader = new AbcPointsReader(object, settings); + } + else if (Alembic::AbcMaterial::IMaterial::matches(md)) { + /* Pass for now. */ + } + else if (Alembic::AbcGeom::ILight::matches(md)) { + /* Pass for now. */ + } + else if (Alembic::AbcGeom::IFaceSet::matches(md)) { + /* Pass, those are handled in the mesh reader. */ + } + else if (Alembic::AbcGeom::ICurves::matches(md)) { + reader = new AbcCurveReader(object, settings); + } + else { + assert(false); + } + + return reader; +} diff --git a/source/blender/alembic/intern/abc_util.h b/source/blender/alembic/intern/abc_util.h index 9e9f0c397ba..2f423a9f8c5 100644 --- a/source/blender/alembic/intern/abc_util.h +++ b/source/blender/alembic/intern/abc_util.h @@ -32,8 +32,13 @@ # define ABC_INLINE static inline #endif +struct CacheReader { + int unused; +}; + using Alembic::Abc::chrono_t; +class AbcObjectReader; class ImportSettings; struct ID; @@ -100,6 +105,8 @@ float get_weight_and_index(float time, Alembic::AbcGeom::index_t &i0, Alembic::AbcGeom::index_t &i1); +AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSettings &settings); + /* ************************** */ /* TODO(kevin): for now keeping these transformations hardcoded to make sure diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc index c6988351db8..e690a255505 100644 --- a/source/blender/alembic/intern/alembic_capi.cc +++ b/source/blender/alembic/intern/alembic_capi.cc @@ -467,6 +467,7 @@ static void visit_object(const IObject &object, if (reader) { readers.push_back(reader); + reader->incref(); AlembicObjectPath *abc_path = static_cast( MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath")); @@ -710,7 +711,12 @@ static void import_endjob(void *user_data) } for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { - delete *iter; + AbcObjectReader *reader = *iter; + reader->decref(); + + if (reader->refcount() == 0) { + delete reader; + } } if (data->parent_map) { @@ -771,296 +777,31 @@ void ABC_import(bContext *C, const char *filepath, float scale, bool is_sequence WM_jobs_start(CTX_wm_manager(C), wm_job); } -/* ******************************* */ +/* ************************************************************************** */ -void ABC_get_transform(AbcArchiveHandle *handle, Object *ob, const char *object_path, float r_mat[4][4], float time, float scale) +void ABC_get_transform(CacheReader *reader, float r_mat[4][4], float time, float scale) { - ArchiveReader *archive = archive_from_handle(handle); - - if (!archive || !archive->valid()) { + if (!reader) { return; } - IObject tmp; - find_iobject(archive->getTop(), tmp, object_path); - - IXform ixform; - - if (IXform::matches(tmp.getHeader())) { - ixform = IXform(tmp, kWrapExisting); - } - else { - ixform = IXform(tmp.getParent(), kWrapExisting); - } - - IXformSchema schema = ixform.getSchema(); - - if (!schema.valid()) { - return; - } - - const Imath::M44d matrix = get_matrix(schema, time); - convert_matrix(matrix, ob, r_mat, scale); -} - -/* ***************************************** */ - -static bool check_smooth_poly_flag(DerivedMesh *dm) -{ - MPoly *mpolys = dm->getPolyArray(dm); - - for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) { - MPoly &poly = mpolys[i]; - - if ((poly.flag & ME_SMOOTH) != 0) { - return true; - } - } - - return false; -} - -static void set_smooth_poly_flag(DerivedMesh *dm) -{ - MPoly *mpolys = dm->getPolyArray(dm); - - for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) { - MPoly &poly = mpolys[i]; - poly.flag |= ME_SMOOTH; - } -} - -static void *add_customdata_cb(void *user_data, const char *name, int data_type) -{ - DerivedMesh *dm = static_cast(user_data); - CustomDataType cd_data_type = static_cast(data_type); - void *cd_ptr = NULL; - - if (ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) { - cd_ptr = CustomData_get_layer_named(dm->getLoopDataLayout(dm), cd_data_type, name); - - if (cd_ptr == NULL) { - cd_ptr = CustomData_add_layer_named(dm->getLoopDataLayout(dm), - cd_data_type, - CD_DEFAULT, - NULL, - dm->getNumLoops(dm), - name); - } - } - - return cd_ptr; -} - -ABC_INLINE CDStreamConfig get_config(DerivedMesh *dm) -{ - CDStreamConfig config; - - config.user_data = dm; - config.mvert = dm->getVertArray(dm); - config.mloop = dm->getLoopArray(dm); - config.mpoly = dm->getPolyArray(dm); - config.totloop = dm->getNumLoops(dm); - config.totpoly = dm->getNumPolys(dm); - config.loopdata = dm->getLoopDataLayout(dm); - config.add_customdata_cb = add_customdata_cb; - - return config; -} - -static DerivedMesh *read_mesh_sample(DerivedMesh *dm, const IObject &iobject, const float time, int read_flag) -{ - IPolyMesh mesh(iobject, kWrapExisting); - IPolyMeshSchema schema = mesh.getSchema(); - ISampleSelector sample_sel(time); - const IPolyMeshSchema::Sample sample = schema.getValue(sample_sel); - - const P3fArraySamplePtr &positions = sample.getPositions(); - const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); - const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); - - DerivedMesh *new_dm = NULL; - - /* Only read point data when streaming meshes, unless we need to create new ones. */ - ImportSettings settings; - settings.read_flag |= read_flag; - - if (dm->getNumVerts(dm) != positions->size()) { - new_dm = CDDM_from_template(dm, - positions->size(), - 0, - 0, - face_indices->size(), - face_counts->size()); - - settings.read_flag |= MOD_MESHSEQ_READ_ALL; - } - - CDStreamConfig config = get_config(new_dm ? new_dm : dm); - config.time = time; - - bool do_normals = false; - read_mesh_sample(&settings, schema, sample_sel, config, do_normals); - - if (new_dm) { - /* Check if we had ME_SMOOTH flag set to restore it. */ - if (!do_normals && check_smooth_poly_flag(dm)) { - set_smooth_poly_flag(new_dm); - } - - CDDM_calc_normals(new_dm); - CDDM_calc_edges(new_dm); - - return new_dm; - } - - if (do_normals) { - CDDM_calc_normals(dm); - } + AbcObjectReader *abc_reader = reinterpret_cast(reader); - return dm; + bool is_constant = false; + abc_reader->read_matrix(r_mat, time, scale, is_constant); } -using Alembic::AbcGeom::ISubDSchema; - -static DerivedMesh *read_subd_sample(DerivedMesh *dm, const IObject &iobject, const float time, int read_flag) -{ - ISubD mesh(iobject, kWrapExisting); - ISubDSchema schema = mesh.getSchema(); - ISampleSelector sample_sel(time); - const ISubDSchema::Sample sample = schema.getValue(sample_sel); - - const P3fArraySamplePtr &positions = sample.getPositions(); - const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); - const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); - - DerivedMesh *new_dm = NULL; - - ImportSettings settings; - settings.read_flag |= read_flag; - - if (dm->getNumVerts(dm) != positions->size()) { - new_dm = CDDM_from_template(dm, - positions->size(), - 0, - 0, - face_indices->size(), - face_counts->size()); - - settings.read_flag |= MOD_MESHSEQ_READ_ALL; - } - - /* Only read point data when streaming meshes, unless we need to create new ones. */ - CDStreamConfig config = get_config(new_dm ? new_dm : dm); - config.time = time; - read_subd_sample(&settings, schema, sample_sel, config); +/* ************************************************************************** */ - if (new_dm) { - /* Check if we had ME_SMOOTH flag set to restore it. */ - if (check_smooth_poly_flag(dm)) { - set_smooth_poly_flag(new_dm); - } - - CDDM_calc_normals(new_dm); - CDDM_calc_edges(new_dm); - - return new_dm; - } - - return dm; -} - -static DerivedMesh *read_points_sample(DerivedMesh *dm, const IObject &iobject, const float time) -{ - IPoints points(iobject, kWrapExisting); - IPointsSchema schema = points.getSchema(); - ISampleSelector sample_sel(time); - const IPointsSchema::Sample sample = schema.getValue(sample_sel); - - const P3fArraySamplePtr &positions = sample.getPositions(); - - DerivedMesh *new_dm = NULL; - - if (dm->getNumVerts(dm) != positions->size()) { - new_dm = CDDM_new(positions->size(), 0, 0, 0, 0); - } - - CDStreamConfig config = get_config(new_dm ? new_dm : dm); - read_points_sample(schema, sample_sel, config, time); - - return new_dm ? new_dm : dm; -} - -/* NOTE: Alembic only stores data about control points, but the DerivedMesh - * passed from the cache modifier contains the displist, which has more data - * than the control points, so to avoid corrupting the displist we modify the - * object directly and create a new DerivedMesh from that. Also we might need to - * create new or delete existing NURBS in the curve. - */ -static DerivedMesh *read_curves_sample(Object *ob, const IObject &iobject, const float time) -{ - ICurves points(iobject, kWrapExisting); - ICurvesSchema schema = points.getSchema(); - ISampleSelector sample_sel(time); - const ICurvesSchema::Sample sample = schema.getValue(sample_sel); - - const P3fArraySamplePtr &positions = sample.getPositions(); - const Int32ArraySamplePtr num_vertices = sample.getCurvesNumVertices(); - - int vertex_idx = 0; - int curve_idx = 0; - Curve *curve = static_cast(ob->data); - - const int curve_count = BLI_listbase_count(&curve->nurb); - - if (curve_count != num_vertices->size()) { - BKE_nurbList_free(&curve->nurb); - read_curve_sample(curve, schema, time); - } - else { - Nurb *nurbs = static_cast(curve->nurb.first); - for (; nurbs; nurbs = nurbs->next, ++curve_idx) { - const int totpoint = (*num_vertices)[curve_idx]; - - if (nurbs->bp) { - BPoint *point = nurbs->bp; - - for (int i = 0; i < totpoint; ++i, ++point, ++vertex_idx) { - const Imath::V3f &pos = (*positions)[vertex_idx]; - copy_yup_zup(point->vec, pos.getValue()); - } - } - else if (nurbs->bezt) { - BezTriple *bezier = nurbs->bezt; - - for (int i = 0; i < totpoint; ++i, ++bezier, ++vertex_idx) { - const Imath::V3f &pos = (*positions)[vertex_idx]; - copy_yup_zup(bezier->vec[1], pos.getValue()); - } - } - } - } - - return CDDM_from_curve(ob); -} - -DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle, +DerivedMesh *ABC_read_mesh(CacheReader *reader, Object *ob, DerivedMesh *dm, - const char *object_path, const float time, const char **err_str, int read_flag) { - ArchiveReader *archive = archive_from_handle(handle); - - if (!archive || !archive->valid()) { - *err_str = "Invalid archive!"; - return NULL; - } - - IObject iobject; - find_iobject(archive->getTop(), iobject, object_path); + AbcObjectReader *abc_reader = reinterpret_cast(reader); + IObject iobject = abc_reader->iobject(); if (!iobject.valid()) { *err_str = "Invalid object: verify object path"; @@ -1075,7 +816,7 @@ DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle, return NULL; } - return read_mesh_sample(dm, iobject, time, read_flag); + return abc_reader->read_derivedmesh(dm, time, read_flag); } else if (ISubD::matches(header)) { if (ob->type != OB_MESH) { @@ -1083,7 +824,7 @@ DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle, return NULL; } - return read_subd_sample(dm, iobject, time, read_flag); + return abc_reader->read_derivedmesh(dm, time, read_flag); } else if (IPoints::matches(header)) { if (ob->type != OB_MESH) { @@ -1091,7 +832,7 @@ DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle, return NULL; } - return read_points_sample(dm, iobject, time); + return abc_reader->read_derivedmesh(dm, time, read_flag); } else if (ICurves::matches(header)) { if (ob->type != OB_CURVE) { @@ -1099,9 +840,48 @@ DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle, return NULL; } - return read_curves_sample(ob, iobject, time); + return abc_reader->read_derivedmesh(dm, time, read_flag); } *err_str = "Unsupported object type: verify object path"; // or poke developer return NULL; } + +/* ************************************************************************** */ + +void CacheReader_free(CacheReader *reader) +{ + AbcObjectReader *abc_reader = reinterpret_cast(reader); + abc_reader->decref(); + + if (abc_reader->refcount() == 0) { + delete abc_reader; + } +} + +CacheReader *CacheReader_open_alembic_object(AbcArchiveHandle *handle, CacheReader *reader, Object *object, const char *object_path) +{ + if (object_path[0] == '\0') { + return reader; + } + + ArchiveReader *archive = archive_from_handle(handle); + + if (!archive || !archive->valid()) { + return reader; + } + + IObject iobject; + find_iobject(archive->getTop(), iobject, object_path); + + if (reader) { + CacheReader_free(reader); + } + + ImportSettings settings; + AbcObjectReader *abc_reader = create_reader(iobject, settings); + abc_reader->object(object); + abc_reader->incref(); + + return reinterpret_cast(abc_reader); +} -- cgit v1.2.3