0b2c8cb6b8a19b80a886a1303cd6b43b91aa109c
[blender.git] / source / blender / alembic / intern / abc_object.cc
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
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.
8  *
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.
13  *
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.
17  *
18  * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 #include "abc_object.h"
24
25 #include "abc_util.h"
26
27 extern "C" {
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 */
33
34 #include "BKE_constraint.h"
35 #include "BKE_depsgraph.h"
36 #include "BKE_idprop.h"
37 #include "BKE_library.h"
38 #include "BKE_modifier.h"
39 #include "BKE_object.h"
40
41 #include "BLI_listbase.h"
42 #include "BLI_math.h"
43 #include "BLI_string.h"
44 }
45
46 using Alembic::AbcGeom::IObject;
47 using Alembic::AbcGeom::IXform;
48 using Alembic::AbcGeom::IXformSchema;
49
50 using Alembic::AbcGeom::OCompoundProperty;
51 using Alembic::AbcGeom::ODoubleArrayProperty;
52 using Alembic::AbcGeom::ODoubleProperty;
53 using Alembic::AbcGeom::OFloatArrayProperty;
54 using Alembic::AbcGeom::OFloatProperty;
55 using Alembic::AbcGeom::OInt32ArrayProperty;
56 using Alembic::AbcGeom::OInt32Property;
57 using Alembic::AbcGeom::OStringArrayProperty;
58 using Alembic::AbcGeom::OStringProperty;
59
60 /* ************************************************************************** */
61
62 AbcObjectWriter::AbcObjectWriter(Scene *scene,
63                                  Object *ob,
64                                  uint32_t time_sampling,
65                                  ExportSettings &settings,
66                                  AbcObjectWriter *parent)
67     : m_object(ob)
68     , m_settings(settings)
69     , m_scene(scene)
70     , m_time_sampling(time_sampling)
71     , m_first_frame(true)
72 {
73         m_name = get_id_name(m_object) + "Shape";
74
75         if (parent) {
76                 parent->addChild(this);
77         }
78 }
79
80 AbcObjectWriter::~AbcObjectWriter()
81 {}
82
83 void AbcObjectWriter::addChild(AbcObjectWriter *child)
84 {
85         m_children.push_back(child);
86 }
87
88 Imath::Box3d AbcObjectWriter::bounds()
89 {
90         BoundBox *bb = BKE_object_boundbox_get(this->m_object);
91
92         if (!bb) {
93                 if (this->m_object->type != OB_CAMERA) {
94                         ABC_LOG(m_settings.logger) << "Bounding box is null!\n";
95                 }
96
97                 return Imath::Box3d();
98         }
99
100         /* Convert Z-up to Y-up. This also changes which vector goes into which min/max property. */
101         this->m_bounds.min.x = bb->vec[0][0];
102         this->m_bounds.min.y = bb->vec[0][2];
103         this->m_bounds.min.z = -bb->vec[6][1];
104
105         this->m_bounds.max.x = bb->vec[6][0];
106         this->m_bounds.max.y = bb->vec[6][2];
107         this->m_bounds.max.z = -bb->vec[0][1];
108
109         return this->m_bounds;
110 }
111
112 void AbcObjectWriter::write()
113 {
114         do_write();
115         m_first_frame = false;
116 }
117
118 /* ************************************************************************** */
119
120 AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings)
121     : m_name("")
122     , m_object_name("")
123     , m_data_name("")
124     , m_object(NULL)
125     , m_iobject(object)
126     , m_settings(&settings)
127     , m_min_time(std::numeric_limits<chrono_t>::max())
128     , m_max_time(std::numeric_limits<chrono_t>::min())
129     , m_refcount(0)
130 {
131         m_name = object.getFullName();
132         std::vector<std::string> parts;
133         split(m_name, '/', parts);
134
135         if (parts.size() >= 2) {
136                 m_object_name = parts[parts.size() - 2];
137                 m_data_name = parts[parts.size() - 1];
138         }
139         else {
140                 m_object_name = m_data_name = parts[parts.size() - 1];
141         }
142 }
143
144 AbcObjectReader::~AbcObjectReader()
145 {}
146
147 const IObject &AbcObjectReader::iobject() const
148 {
149         return m_iobject;
150 }
151
152 Object *AbcObjectReader::object() const
153 {
154         return m_object;
155 }
156
157 void AbcObjectReader::object(Object *ob)
158 {
159         m_object = ob;
160 }
161
162 static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1, const float weight)
163 {
164         float mat0[4][4], mat1[4][4], ret[4][4];
165
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.
169          */
170
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]);
174                 }
175         }
176
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]);
180                 }
181         }
182
183         interp_m4_m4m4(ret, mat0, mat1, weight);
184
185         Imath::M44d m;
186
187         for (int i = 0; i < 4; ++i) {
188                 for (int j = 0; j < 4; ++j) {
189                         m[i][j] = ret[i][j];
190                 }
191         }
192
193         return m;
194 }
195
196 Imath::M44d get_matrix(const IXformSchema &schema, const float time)
197 {
198         Alembic::AbcGeom::index_t i0, i1;
199         Alembic::AbcGeom::XformSample s0, s1;
200
201         const float weight = get_weight_and_index(time,
202                                                   schema.getTimeSampling(),
203                                                   schema.getNumSamples(),
204                                                   i0,
205                                                   i1);
206
207         schema.get(s0, Alembic::AbcGeom::ISampleSelector(i0));
208
209         if (i0 != i1) {
210                 schema.get(s1, Alembic::AbcGeom::ISampleSelector(i1));
211                 return blend_matrices(s0.getMatrix(), s1.getMatrix(), weight);
212         }
213
214         return s0.getMatrix();
215 }
216
217 void AbcObjectReader::readObjectMatrix(const float time)
218 {
219         bool is_constant = false;
220
221         this->read_matrix(m_object->obmat, time, m_settings->scale, is_constant);
222         invert_m4_m4(m_object->imat, m_object->obmat);
223
224         BKE_object_apply_mat4(m_object, m_object->obmat, false,  false);
225
226         if (!is_constant) {
227                 bConstraint *con = BKE_constraint_add_for_object(m_object, NULL, CONSTRAINT_TYPE_TRANSFORM_CACHE);
228                 bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(con->data);
229                 BLI_strncpy(data->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
230
231                 data->cache_file = m_settings->cache_file;
232                 id_us_plus(&data->cache_file->id);
233
234                 data->reader = reinterpret_cast<CacheReader *>(this);
235                 this->incref();
236         }
237 }
238
239
240 Alembic::AbcGeom::IXform AbcObjectReader::xform()
241 {
242         /* Check that we have an empty object (locator, bone head/tail...).  */
243         if (IXform::matches(m_iobject.getMetaData())) {
244                 return IXform(m_iobject, Alembic::AbcGeom::kWrapExisting);
245         }
246
247         /* Check that we have an object with actual data, in which case the
248          * parent Alembic object should contain the transform. */
249         IObject abc_parent = m_iobject.getParent();
250
251         /* The archive's top object can be recognised by not having a parent. */
252         if (abc_parent.getParent()
253                 && IXform::matches(abc_parent.getMetaData())) {
254                 return IXform(abc_parent, Alembic::AbcGeom::kWrapExisting);
255         }
256
257         /* Should not happen. */
258         std::cerr << "AbcObjectReader::xform(): "
259                   << "unable to find IXform for Alembic object '"
260                   << m_iobject.getFullName() << "'\n";
261         BLI_assert(false);
262
263         return IXform();
264 }
265
266
267 void AbcObjectReader::read_matrix(float mat[4][4], const float time, const float scale, bool &is_constant)
268 {
269         IXform ixform = xform();
270         if (!ixform) {
271                 return;
272         }
273
274         const IXformSchema & schema(ixform.getSchema());
275         if (!schema.valid()) {
276                 std::cerr << "Alembic object " << ixform.getFullName()
277                           << " has an invalid schema." << std::endl;
278                 return;
279         }
280
281         bool has_alembic_parent;
282         IObject ixform_parent = ixform.getParent();
283         if (!ixform_parent.getParent()) {
284                 /* The archive top object certainly is not a transform itself, so handle
285                  * it as "no parent". */
286                 has_alembic_parent = false;
287         }
288         else {
289                 has_alembic_parent = ixform_parent && schema.getInheritsXforms();
290         }
291
292         const Imath::M44d matrix = get_matrix(schema, time);
293         convert_matrix(matrix, m_object, mat, scale, has_alembic_parent);
294
295         is_constant = schema.isConstant();
296 }
297
298 void AbcObjectReader::addCacheModifier()
299 {
300         ModifierData *md = modifier_new(eModifierType_MeshSequenceCache);
301         BLI_addtail(&m_object->modifiers, md);
302
303         MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
304
305         mcmd->cache_file = m_settings->cache_file;
306         id_us_plus(&mcmd->cache_file->id);
307
308         BLI_strncpy(mcmd->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
309
310         mcmd->reader = reinterpret_cast<CacheReader *>(this);
311         this->incref();
312 }
313
314 chrono_t AbcObjectReader::minTime() const
315 {
316         return m_min_time;
317 }
318
319 chrono_t AbcObjectReader::maxTime() const
320 {
321         return m_max_time;
322 }
323
324 int AbcObjectReader::refcount() const
325 {
326         return m_refcount;
327 }
328
329 void AbcObjectReader::incref()
330 {
331         ++m_refcount;
332 }
333
334 void AbcObjectReader::decref()
335 {
336         --m_refcount;
337 }