Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKévin Dietrich <kevin.dietrich@mailoo.org>2016-10-29 13:23:09 +0300
committerKévin Dietrich <kevin.dietrich@mailoo.org>2016-10-29 13:23:09 +0300
commit753edafcb77d9aaf07fe869372319b841dd80681 (patch)
tree676445ce05cf2a8a53ced9deedf5bcba37fd9653 /source/blender/alembic
parent0c13792437b3e501c06605876a0396e187c0f7da (diff)
Alembic: store a pointer to the object reader in the cache modifiers and
constraints. This avoids traversing the archive everytime object data is needed and gives an overall consistent ~2x speedup here with files containing between 136 and 500 Alembic objects. Also this somewhat nicely de- duplicates code between data creation (upon import) and data streaming (modifiers and constraints). The only worying part is what happens when a CacheFile is deleted and/or has its path changed. For now, we traverse the whole scene and for each object using the CacheFile we free the pointer and NULL-ify it (see BKE_cachefile_clean), but at some point this should be re-considered and make use of the dependency graph.
Diffstat (limited to 'source/blender/alembic')
-rw-r--r--source/blender/alembic/ABC_alembic.h15
-rw-r--r--source/blender/alembic/intern/abc_curves.cc52
-rw-r--r--source/blender/alembic/intern/abc_curves.h3
-rw-r--r--source/blender/alembic/intern/abc_mesh.cc307
-rw-r--r--source/blender/alembic/intern/abc_mesh.h11
-rw-r--r--source/blender/alembic/intern/abc_object.cc63
-rw-r--r--source/blender/alembic/intern/abc_object.h22
-rw-r--r--source/blender/alembic/intern/abc_points.cc32
-rw-r--r--source/blender/alembic/intern/abc_points.h2
-rw-r--r--source/blender/alembic/intern/abc_util.cc62
-rw-r--r--source/blender/alembic/intern/abc_util.h7
-rw-r--r--source/blender/alembic/intern/alembic_capi.cc340
12 files changed, 468 insertions, 448 deletions
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<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);
+}
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<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;
+}
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<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];
@@ -210,6 +216,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;
+}
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 <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;
+}
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<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);
+}