1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 /** \file
18  * \ingroup balembic
19  */
20 
21 #include "abc_reader_object.h"
22 #include "abc_axis_conversion.h"
23 #include "abc_util.h"
24 
25 #include "DNA_cachefile_types.h"
26 #include "DNA_constraint_types.h"
27 #include "DNA_modifier_types.h"
28 #include "DNA_space_types.h" /* for FILE_MAX */
29 
30 #include "BKE_constraint.h"
31 #include "BKE_lib_id.h"
32 #include "BKE_modifier.h"
33 #include "BKE_object.h"
34 
35 #include "BLI_listbase.h"
36 #include "BLI_math_geom.h"
37 #include "BLI_string.h"
38 #include "BLI_utildefines.h"
39 
40 using Alembic::AbcGeom::IObject;
41 using Alembic::AbcGeom::IXform;
42 using Alembic::AbcGeom::IXformSchema;
43 
44 namespace blender::io::alembic {
45 
AbcObjectReader(const IObject & object,ImportSettings & settings)46 AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings)
47     : m_object(NULL),
48       m_iobject(object),
49       m_settings(&settings),
50       m_min_time(std::numeric_limits<chrono_t>::max()),
51       m_max_time(std::numeric_limits<chrono_t>::min()),
52       m_refcount(0),
53       parent_reader(NULL)
54 {
55   m_name = object.getFullName();
56   std::vector<std::string> parts;
57   split(m_name, '/', parts);
58 
59   if (parts.size() >= 2) {
60     m_object_name = parts[parts.size() - 2];
61     m_data_name = parts[parts.size() - 1];
62   }
63   else {
64     m_object_name = m_data_name = parts[parts.size() - 1];
65   }
66 
67   determine_inherits_xform();
68 }
69 
70 /* Determine whether we can inherit our parent's XForm */
determine_inherits_xform()71 void AbcObjectReader::determine_inherits_xform()
72 {
73   m_inherits_xform = false;
74 
75   IXform ixform = xform();
76   if (!ixform) {
77     return;
78   }
79 
80   const IXformSchema &schema(ixform.getSchema());
81   if (!schema.valid()) {
82     std::cerr << "Alembic object " << ixform.getFullName() << " has an invalid schema."
83               << std::endl;
84     return;
85   }
86 
87   m_inherits_xform = schema.getInheritsXforms();
88 
89   IObject ixform_parent = ixform.getParent();
90   if (!ixform_parent.getParent()) {
91     /* The archive top object certainly is not a transform itself, so handle
92      * it as "no parent". */
93     m_inherits_xform = false;
94   }
95   else {
96     m_inherits_xform = ixform_parent && m_inherits_xform;
97   }
98 }
99 
~AbcObjectReader()100 AbcObjectReader::~AbcObjectReader()
101 {
102 }
103 
iobject() const104 const IObject &AbcObjectReader::iobject() const
105 {
106   return m_iobject;
107 }
108 
object() const109 Object *AbcObjectReader::object() const
110 {
111   return m_object;
112 }
113 
object(Object * ob)114 void AbcObjectReader::object(Object *ob)
115 {
116   m_object = ob;
117 }
118 
blend_matrices(const Imath::M44d & m0,const Imath::M44d & m1,const float weight)119 static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1, const float weight)
120 {
121   float mat0[4][4], mat1[4][4], ret[4][4];
122 
123   /* Cannot use Imath::M44d::getValue() since this returns a pointer to
124    * doubles and interp_m4_m4m4 expects pointers to floats. So need to convert
125    * the matrices manually.
126    */
127 
128   for (int i = 0; i < 4; i++) {
129     for (int j = 0; j < 4; j++) {
130       mat0[i][j] = static_cast<float>(m0[i][j]);
131     }
132   }
133 
134   for (int i = 0; i < 4; i++) {
135     for (int j = 0; j < 4; j++) {
136       mat1[i][j] = static_cast<float>(m1[i][j]);
137     }
138   }
139 
140   interp_m4_m4m4(ret, mat0, mat1, weight);
141 
142   Imath::M44d m;
143 
144   for (int i = 0; i < 4; i++) {
145     for (int j = 0; j < 4; j++) {
146       m[i][j] = ret[i][j];
147     }
148   }
149 
150   return m;
151 }
152 
get_matrix(const IXformSchema & schema,const float time)153 Imath::M44d get_matrix(const IXformSchema &schema, const float time)
154 {
155   Alembic::AbcGeom::index_t i0, i1;
156   Alembic::AbcGeom::XformSample s0, s1;
157 
158   const float weight = get_weight_and_index(
159       time, schema.getTimeSampling(), schema.getNumSamples(), i0, i1);
160 
161   schema.get(s0, Alembic::AbcGeom::ISampleSelector(i0));
162 
163   if (i0 != i1) {
164     schema.get(s1, Alembic::AbcGeom::ISampleSelector(i1));
165     return blend_matrices(s0.getMatrix(), s1.getMatrix(), weight);
166   }
167 
168   return s0.getMatrix();
169 }
170 
read_mesh(struct Mesh * existing_mesh,const Alembic::Abc::ISampleSelector & UNUSED (sample_sel),int UNUSED (read_flag),const char ** UNUSED (err_str))171 struct Mesh *AbcObjectReader::read_mesh(struct Mesh *existing_mesh,
172                                         const Alembic::Abc::ISampleSelector &UNUSED(sample_sel),
173                                         int UNUSED(read_flag),
174                                         const char **UNUSED(err_str))
175 {
176   return existing_mesh;
177 }
178 
topology_changed(Mesh *,const Alembic::Abc::ISampleSelector &)179 bool AbcObjectReader::topology_changed(Mesh * /*existing_mesh*/,
180                                        const Alembic::Abc::ISampleSelector & /*sample_sel*/)
181 {
182   /* The default implementation of read_mesh() just returns the original mesh, so never changes the
183    * topology. */
184   return false;
185 }
186 
setupObjectTransform(const float time)187 void AbcObjectReader::setupObjectTransform(const float time)
188 {
189   bool is_constant = false;
190   float transform_from_alembic[4][4];
191 
192   /* If the parent is a camera, apply the inverse rotation to make up for the from-Maya rotation.
193    * This assumes that the parent object also was imported from Alembic. */
194   if (m_object->parent != nullptr && m_object->parent->type == OB_CAMERA) {
195     axis_angle_to_mat4_single(m_object->parentinv, 'X', -M_PI_2);
196   }
197 
198   this->read_matrix(transform_from_alembic, time, m_settings->scale, is_constant);
199 
200   /* Apply the matrix to the object. */
201   BKE_object_apply_mat4(m_object, transform_from_alembic, true, false);
202   BKE_object_to_mat4(m_object, m_object->obmat);
203 
204   if (!is_constant) {
205     bConstraint *con = BKE_constraint_add_for_object(
206         m_object, NULL, CONSTRAINT_TYPE_TRANSFORM_CACHE);
207     bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(con->data);
208     BLI_strncpy(data->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
209 
210     data->cache_file = m_settings->cache_file;
211     id_us_plus(&data->cache_file->id);
212   }
213 }
214 
xform()215 Alembic::AbcGeom::IXform AbcObjectReader::xform()
216 {
217   /* Check that we have an empty object (locator, bone head/tail...).  */
218   if (IXform::matches(m_iobject.getMetaData())) {
219     try {
220       return IXform(m_iobject, Alembic::AbcGeom::kWrapExisting);
221     }
222     catch (Alembic::Util::Exception &ex) {
223       printf("Alembic: error reading object transform for '%s': %s\n",
224              m_iobject.getFullName().c_str(),
225              ex.what());
226       return IXform();
227     }
228   }
229 
230   /* Check that we have an object with actual data, in which case the
231    * parent Alembic object should contain the transform. */
232   IObject abc_parent = m_iobject.getParent();
233 
234   /* The archive's top object can be recognized by not having a parent. */
235   if (abc_parent.getParent() && IXform::matches(abc_parent.getMetaData())) {
236     try {
237       return IXform(abc_parent, Alembic::AbcGeom::kWrapExisting);
238     }
239     catch (Alembic::Util::Exception &ex) {
240       printf("Alembic: error reading object transform for '%s': %s\n",
241              abc_parent.getFullName().c_str(),
242              ex.what());
243       return IXform();
244     }
245   }
246 
247   /* This can happen in certain cases. For example, MeshLab exports
248    * point clouds without parent XForm. */
249   return IXform();
250 }
251 
read_matrix(float r_mat[4][4],const float time,const float scale,bool & is_constant)252 void AbcObjectReader::read_matrix(float r_mat[4][4] /* local matrix */,
253                                   const float time,
254                                   const float scale,
255                                   bool &is_constant)
256 {
257   IXform ixform = xform();
258   if (!ixform) {
259     unit_m4(r_mat);
260     is_constant = true;
261     return;
262   }
263 
264   const IXformSchema &schema(ixform.getSchema());
265   if (!schema.valid()) {
266     std::cerr << "Alembic object " << ixform.getFullName() << " has an invalid schema."
267               << std::endl;
268     return;
269   }
270 
271   const Imath::M44d matrix = get_matrix(schema, time);
272   convert_matrix_datatype(matrix, r_mat);
273   copy_m44_axis_swap(r_mat, r_mat, ABC_ZUP_FROM_YUP);
274 
275   /* Convert from Maya to Blender camera orientation. Children of this camera
276    * will have the opposite transform as their Parent Inverse matrix.
277    * See AbcObjectReader::setupObjectTransform(). */
278   if (m_object->type == OB_CAMERA) {
279     float camera_rotation[4][4];
280     axis_angle_to_mat4_single(camera_rotation, 'X', M_PI_2);
281     mul_m4_m4m4(r_mat, r_mat, camera_rotation);
282   }
283 
284   if (!m_inherits_xform) {
285     /* Only apply scaling to root objects, parenting will propagate it. */
286     float scale_mat[4][4];
287     scale_m4_fl(scale_mat, scale);
288     mul_m4_m4m4(r_mat, scale_mat, r_mat);
289   }
290 
291   is_constant = schema.isConstant();
292 }
293 
addCacheModifier()294 void AbcObjectReader::addCacheModifier()
295 {
296   ModifierData *md = BKE_modifier_new(eModifierType_MeshSequenceCache);
297   BLI_addtail(&m_object->modifiers, md);
298 
299   MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
300 
301   mcmd->cache_file = m_settings->cache_file;
302   id_us_plus(&mcmd->cache_file->id);
303 
304   BLI_strncpy(mcmd->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
305 }
306 
minTime() const307 chrono_t AbcObjectReader::minTime() const
308 {
309   return m_min_time;
310 }
311 
maxTime() const312 chrono_t AbcObjectReader::maxTime() const
313 {
314   return m_max_time;
315 }
316 
refcount() const317 int AbcObjectReader::refcount() const
318 {
319   return m_refcount;
320 }
321 
incref()322 void AbcObjectReader::incref()
323 {
324   m_refcount++;
325 }
326 
decref()327 void AbcObjectReader::decref()
328 {
329   m_refcount--;
330   BLI_assert(m_refcount >= 0);
331 }
332 
333 }  // namespace blender::io::alembic
334