Alembic: store a pointer to the object reader in the cache modifiers and
authorKévin Dietrich <kevin.dietrich@mailoo.org>
Sat, 29 Oct 2016 10:23:09 +0000 (12:23 +0200)
committerKévin Dietrich <kevin.dietrich@mailoo.org>
Sat, 29 Oct 2016 10:23:09 +0000 (12:23 +0200)
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.

22 files changed:
source/blender/alembic/ABC_alembic.h
source/blender/alembic/intern/abc_curves.cc
source/blender/alembic/intern/abc_curves.h
source/blender/alembic/intern/abc_mesh.cc
source/blender/alembic/intern/abc_mesh.h
source/blender/alembic/intern/abc_object.cc
source/blender/alembic/intern/abc_object.h
source/blender/alembic/intern/abc_points.cc
source/blender/alembic/intern/abc_points.h
source/blender/alembic/intern/abc_util.cc
source/blender/alembic/intern/abc_util.h
source/blender/alembic/intern/alembic_capi.cc
source/blender/blenkernel/BKE_cachefile.h
source/blender/blenkernel/intern/cachefile.c
source/blender/blenkernel/intern/constraint.c
source/blender/makesdna/DNA_cachefile_types.h
source/blender/makesdna/DNA_constraint_types.h
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesrna/intern/rna_cachefile.c
source/blender/makesrna/intern/rna_constraint.c
source/blender/makesrna/intern/rna_modifier.c
source/blender/modifiers/intern/MOD_meshsequencecache.c

index e62713f57f5faddcd31fe1d28334b18168fd846d..e92d5f2d9f714f4116d23444bf7fe224d39e1589 100644 (file)
@@ -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
index 2b54741a5c5c5dd8a07e29c366f88cd80d3b6b7f..7e5ea3b1853467650e10f319d42cb0243c51000f 100644 (file)
@@ -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<Curve *>(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<Nurb *>(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);
+}
index ee47f1931eaf9553914f3faad784598ac483566a..979ee8af639413c68f7a427f958eba4a5d175308 100644 (file)
@@ -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__ */
index bb5d5ce3566993023674c3ca303dffcc5d81f48d..5b282e3c5bb59ebf4620d0e93614f0a8e46a12b2 100644 (file)
@@ -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<std::string, Material *> &mat_map)
 {
        Material *material = static_cast<Material *>(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<Mesh *>(user_data);
-       CustomDataType cd_data_type = static_cast<CustomDataType>(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<DerivedMesh *>(user_data);
+       CustomDataType cd_data_type = static_cast<CustomDataType>(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;
+}
index 41abe78f75fdec41d0807a5942b2f5105e7f91e8..66e6585a3d339080506b3e2192605ec4b82124bc 100644 (file)
@@ -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__ */
index 32468fdadedb8d62f7eed70fa8fe5fa4235800eb..314b2568bed33eceafed2ca530d42d98fa16ed6b 100644 (file)
@@ -126,6 +126,7 @@ AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings
     , m_settings(&settings)
     , m_min_time(std::numeric_limits<chrono_t>::max())
     , m_max_time(std::numeric_limits<chrono_t>::min())
+    , m_refcount(0)
 {
        m_name = object.getFullName();
        std::vector<std::string> 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<bTransformCacheConstraint *>(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<CacheReader *>(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<bTransformCacheConstraint *>(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<CacheReader *>(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;
+}
index a35faa37565b5369ccbae5bcc8acb6765c0eb26a..7ff927b4d33f58274102cc2a549db39984c7177c 100644 (file)
@@ -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);
index 03014547416de913dc796dc487eb093e0ba51e28..c16da621c779795eba1e0a91acaf22979f74a59c 100644 (file)
@@ -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;
+}
index 51f3103bd8bfe0accf96ae64591fc9b4650c7b26..54873eed34615c213641a7245c46571f77e5fac6 100644 (file)
@@ -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,
index 60c66bca1c8063b65eb29406911ccd5c4ee0c9e0..f87d18605d4a228874decf4526cdb61cee503bf8 100644 (file)
 
 #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 <Alembic/AbcMaterial/IMaterial.h>
+
 #include <algorithm>
 
 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;
+}
index 9e9f0c397bafc09708274031b8efe5d4fa728c36..2f423a9f8c589032712717828dfe616581481c7a 100644 (file)
 #  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
index c6988351db89ac7e8a70b418cb09fe9f419fd643..e690a25550539625a78b89ebc854507d1bf1916d 100644 (file)
@@ -467,6 +467,7 @@ static void visit_object(const IObject &object,
 
                if (reader) {
                        readers.push_back(reader);
+                       reader->incref();
 
                        AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(
                                                          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<DerivedMesh *>(user_data);
-       CustomDataType cd_data_type = static_cast<CustomDataType>(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<AbcObjectReader *>(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<Curve *>(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<Nurb *>(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<AbcObjectReader *>(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<AbcObjectReader *>(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<CacheReader *>(abc_reader);
+}
index a55cb51766cf35c9e6ea62b9eda497c13ef870a8..7e1c069df9a9ac4d5eb9700c81d7479575a2c9c8 100644 (file)
@@ -63,6 +63,8 @@ bool BKE_cachefile_filepath_get(
 
 float BKE_cachefile_time_offset(struct CacheFile *cache_file, const float time, const float fps);
 
+void BKE_cachefile_clean(struct Scene *scene, struct CacheFile *cache_file);
+
 #ifdef __cplusplus
 }
 #endif
index e62e652b4a698ca0c299e6258d09cc89598ab373..2a2699f3a141118adbb6824e112691552fe4b14d 100644 (file)
@@ -29,6 +29,8 @@
 
 #include "DNA_anim_types.h"
 #include "DNA_cachefile_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h"
 #include "DNA_scene_types.h"
 
 #include "BLI_fileops.h"
@@ -43,6 +45,7 @@
 #include "BKE_global.h"
 #include "BKE_library.h"
 #include "BKE_main.h"
+#include "BKE_modifier.h"
 #include "BKE_scene.h"
 
 #ifdef WITH_ALEMBIC
@@ -196,3 +199,37 @@ float BKE_cachefile_time_offset(CacheFile *cache_file, const float time, const f
        const float frame = (cache_file->override_frame ? cache_file->frame : time);
        return cache_file->is_sequence ? frame : frame / fps;
 }
+
+/* TODO(kevin): replace this with some depsgraph mechanism, or something similar. */
+void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file)
+{
+       for (Base *base = scene->base.first; base; base = base->next) {
+               Object *ob = base->object;
+
+               ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
+
+               if (md) {
+                       MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+
+                       if (cache_file == mcmd->cache_file) {
+                               CacheReader_free(mcmd->reader);
+                               mcmd->reader = NULL;
+                               mcmd->object_path[0] = '\0';
+                       }
+               }
+
+               for (bConstraint *con = ob->constraints.first; con; con = con->next) {
+                       if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) {
+                               continue;
+                       }
+
+                       bTransformCacheConstraint *data = con->data;
+
+                       if (cache_file == data->cache_file) {
+                               CacheReader_free(data->reader);
+                               data->reader = NULL;
+                               data->object_path[0] = '\0';
+                       }
+               }
+       }
+}
index c4afa58b7d371cf704ad689ebe33089c2ef529fa..c7750707cc4fe1345bcd57473a328cb45abf4a1c 100644 (file)
@@ -4364,8 +4364,14 @@ static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBa
 
        BKE_cachefile_ensure_handle(G.main, cache_file);
 
-       ABC_get_transform(cache_file->handle, cob->ob, data->object_path,
-                         cob->matrix, time, cache_file->scale);
+       if (!data->reader) {
+               data->reader = CacheReader_open_alembic_object(cache_file->handle,
+                                                              data->reader,
+                                                              cob->ob,
+                                                              data->object_path);
+       }
+
+       ABC_get_transform(data->reader, cob->matrix, time, cache_file->scale);
 #else
        UNUSED_VARS(con, cob);
 #endif
@@ -4393,6 +4399,10 @@ static void transformcache_free(bConstraint *con)
        if (data->cache_file) {
                id_us_min(&data->cache_file->id);
        }
+
+       if (data->reader) {
+               CacheReader_free(data->reader);
+       }
 }
 
 static void transformcache_new_data(void *cdata)
index dd47d63fc1963ddcad4c9a483289268f5afd6651..46b1adf27256f1127c361a5d92f41bb85e4620c9 100644 (file)
 extern "C" {
 #endif
 
-
 /* CacheFile::flag */
 enum {
        CACHEFILE_DS_EXPAND = (1 << 0),
+       CACHEFILE_DIRTY     = (1 << 1),
 };
 
 /* CacheFile::draw_flag */
index fc4e7de73f51039505fa60384490a1e8857fb968..ca774864e95bce6e486ab441aeae48eeb6f0b88d 100644 (file)
@@ -461,6 +461,7 @@ typedef struct bObjectSolverConstraint {
 /* Transform matrix cache constraint */
 typedef struct bTransformCacheConstraint {
        struct CacheFile *cache_file;
+       struct CacheReader *reader;
        char object_path[1024];  /* FILE_MAX */
 } bTransformCacheConstraint;
 
index 1398e9de76f0c504defbf2c32b7d04d0d917b523..f95533a88f9fca8f2cc2451e44d60bddd70b816f 100644 (file)
@@ -1555,6 +1555,7 @@ typedef struct MeshSeqCacheModifierData {
        ModifierData modifier;
 
        struct CacheFile *cache_file;
+       struct CacheReader *reader;
        char object_path[1024];  /* 1024 = FILE_MAX */
 
        char read_flag;
index 7249ebd5feb3c76fe3b12298e69a6eedd64352b1..09fdeb15b10921d61d765dbd473a6ca0e5aef249 100644 (file)
@@ -37,6 +37,8 @@
 #include "BKE_cachefile.h"
 #include "BKE_depsgraph.h"
 
+#include "BLI_string.h"
+
 #include "DEG_depsgraph.h"
 
 #include "WM_api.h"
@@ -60,6 +62,12 @@ static void rna_CacheFile_update_handle(Main *bmain, Scene *scene, PointerRNA *p
 {
        CacheFile *cache_file = ptr->data;
 
+       if ((cache_file->flag & CACHEFILE_DIRTY) != 0) {
+               BKE_cachefile_clean(scene, cache_file);
+               BLI_freelistN(&cache_file->object_paths);
+               cache_file->flag &= ~CACHEFILE_DIRTY;
+       }
+
        BKE_cachefile_reload(bmain, cache_file);
 
        rna_CacheFile_update(bmain, scene, ptr);
@@ -71,6 +79,20 @@ static void rna_CacheFile_object_paths_begin(CollectionPropertyIterator *iter, P
        rna_iterator_listbase_begin(iter, &cache_file->object_paths, NULL);
 }
 
+static void rna_CacheFile_filename_set(PointerRNA *ptr, const char *value)
+{
+       CacheFile *cache_file = ptr->data;
+
+       if (STREQ(cache_file->filepath, value)) {
+               return;
+       }
+
+       /* Different file is opened, close all readers. */
+       cache_file->flag |= CACHEFILE_DIRTY;
+
+       BLI_strncpy(cache_file->filepath, value, sizeof(cache_file->filepath));
+}
+
 #else
 
 /* cachefile.object_paths */
@@ -103,6 +125,7 @@ static void rna_def_cachefile(BlenderRNA *brna)
        RNA_def_struct_ui_icon(srna, ICON_FILE);
 
        PropertyRNA *prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
+       RNA_def_property_string_funcs(prop, NULL, NULL, "rna_CacheFile_filename_set");
        RNA_def_property_ui_text(prop, "File Path", "Path to external displacements file");
        RNA_def_property_update(prop, 0, "rna_CacheFile_update_handle");
 
index db3f76f3cfccc85e8e83496c07cc5071d164b456..ad037af943d503aa0dfa91711958962611d98991 100644 (file)
@@ -148,12 +148,17 @@ static EnumPropertyItem space_object_items[] = {
        {0, NULL, 0, NULL, NULL}
 };
 
+#include "DNA_cachefile_types.h"
+
 #include "BKE_animsys.h"
 #include "BKE_action.h"
 #include "BKE_constraint.h"
 #include "BKE_context.h"
 #include "BKE_depsgraph.h"
 
+#ifdef WITH_ALEMBIC
+#  include "ABC_alembic.h"
+#endif
 
 static StructRNA *rna_ConstraintType_refine(struct PointerRNA *ptr)
 {
@@ -471,6 +476,20 @@ static void rna_Constraint_objectSolver_camera_set(PointerRNA *ptr, PointerRNA v
        }
 }
 
+static void rna_Constraint_transformCache_object_path_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+       bConstraint *con = (bConstraint *)ptr->data;
+       bTransformCacheConstraint *data = (bTransformCacheConstraint *)con->data;
+       Object *ob = (Object *)ptr->id.data;
+
+       data->reader = CacheReader_open_alembic_object(data->cache_file->handle,
+                                                      data->reader,
+                                                      ob,
+                                                      data->object_path);
+
+       rna_Constraint_update(bmain, scene, ptr);
+}
+
 #else
 
 static EnumPropertyItem constraint_distance_items[] = {
@@ -2593,7 +2612,7 @@ static void rna_def_constraint_transform_cache(BlenderRNA *brna)
 
        prop = RNA_def_property(srna, "object_path", PROP_STRING, PROP_NONE);
        RNA_def_property_ui_text(prop, "Object Path", "Path to the object in the Alembic archive used to lookup the transform matrix");
-       RNA_def_property_update(prop, 0, "rna_Constraint_update");
+       RNA_def_property_update(prop, 0, "rna_Constraint_transformCache_object_path_update");
 }
 
 /* base struct for constraints */
index 39f6298ca61826c765c97dbfc0c335a91041348d..b30c156a88ccb0b5bde2124afdc68e6d544a4db1 100644 (file)
@@ -1131,6 +1131,19 @@ static int rna_CorrectiveSmoothModifier_is_bind_get(PointerRNA *ptr)
        return (csmd->bind_coords != NULL);
 }
 
+static void rna_MeshSequenceCache_object_path_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+       MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)ptr->data;
+       Object *ob = (Object *)ptr->id.data;
+
+       mcmd->reader = CacheReader_open_alembic_object(mcmd->cache_file->handle,
+                                                      mcmd->reader,
+                                                      ob,
+                                                      mcmd->object_path);
+
+       rna_Modifier_update(bmain, scene, ptr);
+}
+
 #else
 
 static PropertyRNA *rna_def_property_subdivision_common(StructRNA *srna, const char type[])
@@ -4257,7 +4270,7 @@ static void rna_def_modifier_meshseqcache(BlenderRNA *brna)
 
        prop = RNA_def_property(srna, "object_path", PROP_STRING, PROP_NONE);
        RNA_def_property_ui_text(prop, "Object Path", "Path to the object in the Alembic archive used to lookup geometric data");
-       RNA_def_property_update(prop, 0, "rna_Modifier_update");
+       RNA_def_property_update(prop, 0, "rna_MeshSequenceCache_object_path_update");
 
        static EnumPropertyItem read_flag_items[] = {
                {MOD_MESHSEQ_READ_VERT,  "VERT", 0, "Vertex", ""},
index 355ac9563dd40f75e23c3cac9ae74fd89ea733d0..cf137784e65061bf3db17443459d7631cfe8675e 100644 (file)
@@ -65,6 +65,7 @@ static void copyData(ModifierData *md, ModifierData *target)
 
        if (tmcmd->cache_file) {
                id_us_plus(&tmcmd->cache_file->id);
+               tmcmd->reader = NULL;
        }
 }
 
@@ -75,6 +76,10 @@ static void freeData(ModifierData *md)
        if (mcmd->cache_file) {
                id_us_min(&mcmd->cache_file->id);
        }
+
+       if (mcmd->reader) {
+               CacheReader_free(mcmd->reader);
+       }
 }
 
 static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
@@ -102,10 +107,16 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
 
        BKE_cachefile_ensure_handle(G.main, cache_file);
 
-       DerivedMesh *result = ABC_read_mesh(cache_file->handle,
+       if (!mcmd->reader) {
+               mcmd->reader = CacheReader_open_alembic_object(cache_file->handle,
+                                                              mcmd->reader,
+                                                              ob,
+                                                              mcmd->object_path);
+       }
+
+       DerivedMesh *result = ABC_read_mesh(mcmd->reader,
                                            ob,
                                            dm,
-                                           mcmd->object_path,
                                            time,
                                            &err_str,
                                            mcmd->read_flag);