2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
20 * ***** END GPL LICENSE BLOCK *****
23 #include "abc_object.h"
28 #include "DNA_cachefile_types.h"
29 #include "DNA_constraint_types.h"
30 #include "DNA_modifier_types.h"
31 #include "DNA_object_types.h"
32 #include "DNA_space_types.h" /* for FILE_MAX */
34 #include "BKE_constraint.h"
35 #include "BKE_idprop.h"
36 #include "BKE_library.h"
37 #include "BKE_modifier.h"
38 #include "BKE_object.h"
40 #include "BLI_listbase.h"
42 #include "BLI_string.h"
45 using Alembic::AbcGeom::IObject;
46 using Alembic::AbcGeom::IXform;
47 using Alembic::AbcGeom::IXformSchema;
49 using Alembic::AbcGeom::OCompoundProperty;
50 using Alembic::AbcGeom::ODoubleArrayProperty;
51 using Alembic::AbcGeom::ODoubleProperty;
52 using Alembic::AbcGeom::OFloatArrayProperty;
53 using Alembic::AbcGeom::OFloatProperty;
54 using Alembic::AbcGeom::OInt32ArrayProperty;
55 using Alembic::AbcGeom::OInt32Property;
56 using Alembic::AbcGeom::OStringArrayProperty;
57 using Alembic::AbcGeom::OStringProperty;
59 /* ************************************************************************** */
61 AbcObjectWriter::AbcObjectWriter(Scene *scene,
63 uint32_t time_sampling,
64 ExportSettings &settings,
65 AbcObjectWriter *parent)
67 , m_settings(settings)
69 , m_time_sampling(time_sampling)
72 m_name = get_id_name(m_object) + "Shape";
75 parent->addChild(this);
79 AbcObjectWriter::~AbcObjectWriter()
82 void AbcObjectWriter::addChild(AbcObjectWriter *child)
84 m_children.push_back(child);
87 Imath::Box3d AbcObjectWriter::bounds()
89 BoundBox *bb = BKE_object_boundbox_get(this->m_object);
92 if (this->m_object->type != OB_CAMERA) {
93 ABC_LOG(m_settings.logger) << "Bounding box is null!\n";
96 return Imath::Box3d();
99 /* Convert Z-up to Y-up. This also changes which vector goes into which min/max property. */
100 this->m_bounds.min.x = bb->vec[0][0];
101 this->m_bounds.min.y = bb->vec[0][2];
102 this->m_bounds.min.z = -bb->vec[6][1];
104 this->m_bounds.max.x = bb->vec[6][0];
105 this->m_bounds.max.y = bb->vec[6][2];
106 this->m_bounds.max.z = -bb->vec[0][1];
108 return this->m_bounds;
111 void AbcObjectWriter::write()
114 m_first_frame = false;
117 /* ************************************************************************** */
119 AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings)
125 , m_settings(&settings)
126 , m_min_time(std::numeric_limits<chrono_t>::max())
127 , m_max_time(std::numeric_limits<chrono_t>::min())
129 , parent_reader(NULL)
131 m_name = object.getFullName();
132 std::vector<std::string> parts;
133 split(m_name, '/', parts);
135 if (parts.size() >= 2) {
136 m_object_name = parts[parts.size() - 2];
137 m_data_name = parts[parts.size() - 1];
140 m_object_name = m_data_name = parts[parts.size() - 1];
144 AbcObjectReader::~AbcObjectReader()
147 const IObject &AbcObjectReader::iobject() const
152 Object *AbcObjectReader::object() const
157 void AbcObjectReader::object(Object *ob)
162 static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1, const float weight)
164 float mat0[4][4], mat1[4][4], ret[4][4];
166 /* Cannot use Imath::M44d::getValue() since this returns a pointer to
167 * doubles and interp_m4_m4m4 expects pointers to floats. So need to convert
168 * the matrices manually.
171 for (int i = 0; i < 4; ++i) {
172 for (int j = 0; j < 4; ++j) {
173 mat0[i][j] = static_cast<float>(m0[i][j]);
177 for (int i = 0; i < 4; ++i) {
178 for (int j = 0; j < 4; ++j) {
179 mat1[i][j] = static_cast<float>(m1[i][j]);
183 interp_m4_m4m4(ret, mat0, mat1, weight);
187 for (int i = 0; i < 4; ++i) {
188 for (int j = 0; j < 4; ++j) {
196 Imath::M44d get_matrix(const IXformSchema &schema, const float time)
198 Alembic::AbcGeom::index_t i0, i1;
199 Alembic::AbcGeom::XformSample s0, s1;
201 const float weight = get_weight_and_index(time,
202 schema.getTimeSampling(),
203 schema.getNumSamples(),
207 schema.get(s0, Alembic::AbcGeom::ISampleSelector(i0));
210 schema.get(s1, Alembic::AbcGeom::ISampleSelector(i1));
211 return blend_matrices(s0.getMatrix(), s1.getMatrix(), weight);
214 return s0.getMatrix();
217 DerivedMesh *AbcObjectReader::read_derivedmesh(DerivedMesh *dm,
218 const Alembic::Abc::ISampleSelector &UNUSED(sample_sel),
219 int UNUSED(read_flag),
220 const char **UNUSED(err_str))
225 void AbcObjectReader::setupObjectTransform(const float time)
227 bool is_constant = false;
229 this->read_matrix(m_object->obmat, time, m_settings->scale, is_constant);
230 invert_m4_m4(m_object->imat, m_object->obmat);
232 BKE_object_apply_mat4(m_object, m_object->obmat, false, false);
235 bConstraint *con = BKE_constraint_add_for_object(m_object, NULL, CONSTRAINT_TYPE_TRANSFORM_CACHE);
236 bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(con->data);
237 BLI_strncpy(data->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
239 data->cache_file = m_settings->cache_file;
240 id_us_plus(&data->cache_file->id);
242 data->reader = reinterpret_cast<CacheReader *>(this);
247 Alembic::AbcGeom::IXform AbcObjectReader::xform()
249 /* Check that we have an empty object (locator, bone head/tail...). */
250 if (IXform::matches(m_iobject.getMetaData())) {
251 return IXform(m_iobject, Alembic::AbcGeom::kWrapExisting);
254 /* Check that we have an object with actual data, in which case the
255 * parent Alembic object should contain the transform. */
256 IObject abc_parent = m_iobject.getParent();
258 /* The archive's top object can be recognised by not having a parent. */
259 if (abc_parent.getParent()
260 && IXform::matches(abc_parent.getMetaData())) {
261 return IXform(abc_parent, Alembic::AbcGeom::kWrapExisting);
264 /* Should not happen. */
265 std::cerr << "AbcObjectReader::xform(): "
266 << "unable to find IXform for Alembic object '"
267 << m_iobject.getFullName() << "'\n";
273 void AbcObjectReader::read_matrix(float r_mat[4][4], const float time,
274 const float scale, bool &is_constant)
276 IXform ixform = xform();
281 const IXformSchema & schema(ixform.getSchema());
282 if (!schema.valid()) {
283 std::cerr << "Alembic object " << ixform.getFullName()
284 << " has an invalid schema." << std::endl;
288 bool has_alembic_parent;
289 IObject ixform_parent = ixform.getParent();
290 if (!ixform_parent.getParent()) {
291 /* The archive top object certainly is not a transform itself, so handle
292 * it as "no parent". */
293 has_alembic_parent = false;
296 has_alembic_parent = ixform_parent && schema.getInheritsXforms();
298 if (has_alembic_parent && m_object->parent == NULL) {
299 /* TODO Sybren: This happened in some files. I think I solved it,
300 * but I'll leave this check in here anyway until we've tested it
301 * more thoroughly. Better than crashing on a null parent anyway. */
302 std::cerr << "Alembic object " << m_iobject.getFullName()
303 << " with transform " << ixform.getFullName()
304 << " has an Alembic parent but no parent Blender object."
306 has_alembic_parent = false;
310 const Imath::M44d matrix = get_matrix(schema, time);
311 convert_matrix(matrix, m_object, r_mat);
313 if (has_alembic_parent) {
314 /* In this case, the matrix in Alembic is in local coordinates, so
315 * convert to world matrix. To prevent us from reading and accumulating
316 * all parent matrices in the Alembic file, we assume that the Blender
317 * parent object is already updated for the current timekey, and use its
319 BLI_assert(m_object->parent);
320 mul_m4_m4m4(r_mat, m_object->parent->obmat, r_mat);
323 /* Only apply scaling to root objects, parenting will propagate it. */
324 float scale_mat[4][4];
325 scale_m4_fl(scale_mat, scale);
326 scale_mat[3][3] = scale; /* scale translations too */
327 mul_m4_m4m4(r_mat, r_mat, scale_mat);
330 is_constant = schema.isConstant();
333 void AbcObjectReader::addCacheModifier()
335 ModifierData *md = modifier_new(eModifierType_MeshSequenceCache);
336 BLI_addtail(&m_object->modifiers, md);
338 MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
340 mcmd->cache_file = m_settings->cache_file;
341 id_us_plus(&mcmd->cache_file->id);
343 BLI_strncpy(mcmd->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
345 mcmd->reader = reinterpret_cast<CacheReader *>(this);
349 chrono_t AbcObjectReader::minTime() const
354 chrono_t AbcObjectReader::maxTime() const
359 int AbcObjectReader::refcount() const
364 void AbcObjectReader::incref()
369 void AbcObjectReader::decref()
372 BLI_assert(m_refcount >= 0);