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.
This commit is contained in:
parent
0c13792437
commit
753edafcb7
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
#endif /* __ABC_CURVES_H__ */
|
||||
|
|
|
@ -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();
|
||||
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<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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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);
|
||||
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<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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(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<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);
|
||||
}
|
||||
|
||||
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<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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -36,10 +36,10 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* CacheFile::flag */
|
||||
enum {
|
||||
CACHEFILE_DS_EXPAND = (1 << 0),
|
||||
CACHEFILE_DIRTY = (1 << 1),
|
||||
};
|
||||
|
||||
/* CacheFile::draw_flag */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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", ""},
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue