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(); + DerivedMesh *dm = CDDM_from_mesh(mesh); + DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL); - utils::mesh_add_verts(mesh, positions->size()); - utils::mesh_add_mpolygons(mesh, face_counts->size()); - utils::mesh_add_mloops(mesh, face_indices->size()); + if (ndm != dm) { + dm->release(dm); + } - m_mesh_data = create_config(mesh); - - bool has_smooth_normals = false; - read_mesh_sample(m_settings, m_schema, sample_sel, m_mesh_data, has_smooth_normals); - - 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; + DerivedMesh *dm = CDDM_from_mesh(mesh); + DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL); + + if (ndm != dm) { + dm->release(dm); + } + + 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); - - 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); - - read_subd_sample(m_settings, m_schema, sample_sel, m_mesh_data); - 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); + convert_matrix(matrix, m_object, mat, 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); - - 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); + AbcObjectReader *abc_reader = reinterpret_cast(reader); - 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); + bool is_constant = false; + abc_reader->read_matrix(r_mat, time, scale, is_constant); } -/* ***************************************** */ +/* ************************************************************************** */ -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); - } - - return dm; -} - -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); +} diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h index a55cb51766c..7e1c069df9a 100644 --- a/source/blender/blenkernel/BKE_cachefile.h +++ b/source/blender/blenkernel/BKE_cachefile.h @@ -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 diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index e62e652b4a6..2a2699f3a14 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -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'; + } + } + } +} diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index c4afa58b7d3..c7750707cc4 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -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) diff --git a/source/blender/makesdna/DNA_cachefile_types.h b/source/blender/makesdna/DNA_cachefile_types.h index dd47d63fc19..46b1adf2725 100644 --- a/source/blender/makesdna/DNA_cachefile_types.h +++ b/source/blender/makesdna/DNA_cachefile_types.h @@ -36,10 +36,10 @@ extern "C" { #endif - /* CacheFile::flag */ enum { CACHEFILE_DS_EXPAND = (1 << 0), + CACHEFILE_DIRTY = (1 << 1), }; /* CacheFile::draw_flag */ diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index fc4e7de73f5..ca774864e95 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -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; diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 1398e9de76f..f95533a88f9 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -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; diff --git a/source/blender/makesrna/intern/rna_cachefile.c b/source/blender/makesrna/intern/rna_cachefile.c index 7249ebd5feb..09fdeb15b10 100644 --- a/source/blender/makesrna/intern/rna_cachefile.c +++ b/source/blender/makesrna/intern/rna_cachefile.c @@ -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"); diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index db3f76f3cfc..ad037af943d 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -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 */ diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 39f6298ca61..b30c156a88c 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -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", ""}, diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index 355ac9563dd..cf137784e65 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -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);