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 *****
25 #include "abc_camera.h"
26 #include "abc_curves.h"
28 #include "abc_nurbs.h"
29 #include "abc_points.h"
30 #include "abc_transform.h"
32 #include <Alembic/AbcMaterial/IMaterial.h>
37 #include "DNA_object_types.h"
44 std::string get_id_name(const Object * const ob)
50 return get_id_name(&ob->id);
53 std::string get_id_name(const ID * const id)
55 std::string name(id->name + 2);
56 std::replace(name.begin(), name.end(), ' ', '_');
57 std::replace(name.begin(), name.end(), '.', '_');
58 std::replace(name.begin(), name.end(), ':', '_');
63 std::string get_object_dag_path_name(const Object * const ob, Object *dupli_parent)
65 std::string name = get_id_name(ob);
67 Object *p = ob->parent;
70 name = get_id_name(p) + "/" + name;
74 if (dupli_parent && (ob != dupli_parent)) {
75 name = get_id_name(dupli_parent) + "/" + name;
81 bool object_selected(Object *ob)
83 return ob->flag & SELECT;
86 bool parent_selected(Object *ob)
88 if (object_selected(ob)) {
92 bool do_export = false;
94 Object *parent = ob->parent;
96 while (parent != NULL) {
97 if (object_selected(parent)) {
102 parent = parent->parent;
108 Imath::M44d convert_matrix(float mat[4][4])
112 for (int i = 0; i < 4; ++i) {
113 for (int j = 0; j < 4; ++j) {
121 void split(const std::string &s, const char delim, std::vector<std::string> &tokens)
125 std::stringstream ss(s);
128 while (std::getline(ss, item, delim)) {
130 tokens.push_back(item);
135 /* Create a rotation matrix for each axis from euler angles.
136 * Euler angles are swaped to change coordinate system. */
137 static void create_rotation_matrix(
138 float rot_x_mat[3][3], float rot_y_mat[3][3],
139 float rot_z_mat[3][3], const float euler[3], const bool to_yup)
141 const float rx = euler[0];
142 const float ry = (to_yup) ? euler[2] : -euler[2];
143 const float rz = (to_yup) ? -euler[1] : euler[1];
149 rot_x_mat[1][1] = cos(rx);
150 rot_x_mat[2][1] = -sin(rx);
151 rot_x_mat[1][2] = sin(rx);
152 rot_x_mat[2][2] = cos(rx);
154 rot_y_mat[2][2] = cos(ry);
155 rot_y_mat[0][2] = -sin(ry);
156 rot_y_mat[2][0] = sin(ry);
157 rot_y_mat[0][0] = cos(ry);
159 rot_z_mat[0][0] = cos(rz);
160 rot_z_mat[1][0] = -sin(rz);
161 rot_z_mat[0][1] = sin(rz);
162 rot_z_mat[1][1] = cos(rz);
165 /* Convert matrix from Z=up to Y=up or vice versa. Use yup_mat = zup_mat for in-place conversion. */
166 void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode)
168 float dst_rot[3][3], src_rot[3][3], dst_scale_mat[4][4];
169 float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3];
170 float src_trans[3], dst_scale[3], src_scale[3], euler[3];
178 unit_m4(dst_scale_mat);
180 /* We assume there is no sheer component and no homogeneous scaling component. */
181 BLI_assert(fabs(src_mat[0][3]) < 2 * FLT_EPSILON);
182 BLI_assert(fabs(src_mat[1][3]) < 2 * FLT_EPSILON);
183 BLI_assert(fabs(src_mat[2][3]) < 2 * FLT_EPSILON);
184 BLI_assert(fabs(src_mat[3][3] - 1.0f) < 2 * FLT_EPSILON);
186 /* Extract translation, rotation, and scale form matrix. */
187 mat4_to_loc_rot_size(src_trans, src_rot, src_scale, src_mat);
189 /* Get euler angles from rotation matrix. */
190 mat3_to_eulO(euler, ROT_MODE_XYZ, src_rot);
192 /* Create X, Y, Z rotation matrices from euler angles. */
193 create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler,
194 mode == ABC_YUP_FROM_ZUP);
196 /* Concatenate rotation matrices. */
197 mul_m3_m3m3(dst_rot, dst_rot, rot_y_mat);
198 mul_m3_m3m3(dst_rot, dst_rot, rot_z_mat);
199 mul_m3_m3m3(dst_rot, dst_rot, rot_x_mat);
201 mat3_to_eulO(euler, ROT_MODE_XYZ, dst_rot);
203 /* Start construction of dst_mat from rotation matrix */
205 copy_m4_m3(dst_mat, dst_rot);
207 /* Apply translation */
209 case ABC_ZUP_FROM_YUP:
210 copy_zup_from_yup(dst_mat[3], src_trans);
212 case ABC_YUP_FROM_ZUP:
213 copy_yup_from_zup(dst_mat[3], src_trans);
219 /* Apply scale matrix. Swaps y and z, but does not
220 * negate like translation does. */
221 dst_scale[0] = src_scale[0];
222 dst_scale[1] = src_scale[2];
223 dst_scale[2] = src_scale[1];
225 size_to_mat4(dst_scale_mat, dst_scale);
226 mul_m4_m4m4(dst_mat, dst_mat, dst_scale_mat);
229 void convert_matrix(const Imath::M44d &xform, Object *ob, float r_mat[4][4])
231 for (int i = 0; i < 4; ++i) {
232 for (int j = 0; j < 4; ++j) {
233 r_mat[i][j] = static_cast<float>(xform[i][j]);
237 if (ob->type == OB_CAMERA) {
238 float cam_to_yup[4][4];
239 axis_angle_to_mat4_single(cam_to_yup, 'X', M_PI_2);
240 mul_m4_m4m4(r_mat, r_mat, cam_to_yup);
243 copy_m44_axis_swap(r_mat, r_mat, ABC_ZUP_FROM_YUP);
246 /* Recompute transform matrix of object in new coordinate system
247 * (from Z-Up to Y-Up). */
248 void create_transform_matrix(Object *obj, float r_yup_mat[4][4])
252 /* get local matrix. */
253 /* TODO Sybren: when we're exporting as "flat", i.e. non-hierarchial,
254 * we should export the world matrix even when the object has a parent
257 /* Note that this produces another matrix than the local matrix, due to
258 * constraints and modifiers as well as the obj->parentinv matrix. */
259 invert_m4_m4(obj->parent->imat, obj->parent->obmat);
260 mul_m4_m4m4(zup_mat, obj->parent->imat, obj->obmat);
261 copy_m44_axis_swap(r_yup_mat, zup_mat, ABC_YUP_FROM_ZUP);
264 copy_m44_axis_swap(r_yup_mat, obj->obmat, ABC_YUP_FROM_ZUP);
268 bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name)
274 return prop.getPropertyHeader(name) != NULL;
277 typedef std::pair<Alembic::AbcCoreAbstract::index_t, float> index_time_pair_t;
279 float get_weight_and_index(float time,
280 const Alembic::AbcCoreAbstract::TimeSamplingPtr &time_sampling,
282 Alembic::AbcGeom::index_t &i0,
283 Alembic::AbcGeom::index_t &i1)
285 samples_number = std::max(samples_number, 1);
287 index_time_pair_t t0 = time_sampling->getFloorIndex(time, samples_number);
290 if (samples_number == 1 || (fabs(time - t0.second) < 0.0001f)) {
294 index_time_pair_t t1 = time_sampling->getCeilIndex(time, samples_number);
301 const float bias = (time - t0.second) / (t1.second - t0.second);
303 if (fabs(1.0f - bias) < 0.0001f) {
313 AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSettings &settings)
315 AbcObjectReader *reader = NULL;
317 const Alembic::AbcGeom::MetaData &md = object.getMetaData();
319 if (Alembic::AbcGeom::IXform::matches(md)) {
320 reader = new AbcEmptyReader(object, settings);
322 else if (Alembic::AbcGeom::IPolyMesh::matches(md)) {
323 reader = new AbcMeshReader(object, settings);
325 else if (Alembic::AbcGeom::ISubD::matches(md)) {
326 reader = new AbcSubDReader(object, settings);
328 else if (Alembic::AbcGeom::INuPatch::matches(md)) {
330 /* TODO(kevin): importing cyclic NURBS from other software crashes
331 * at the moment. This is due to the fact that NURBS in other
332 * software have duplicated points which causes buffer overflows in
333 * Blender. Need to figure out exactly how these points are
334 * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV).
335 * Until this is fixed, disabling NURBS reading. */
336 reader = new AbcNurbsReader(child, settings);
339 else if (Alembic::AbcGeom::ICamera::matches(md)) {
340 reader = new AbcCameraReader(object, settings);
342 else if (Alembic::AbcGeom::IPoints::matches(md)) {
343 reader = new AbcPointsReader(object, settings);
345 else if (Alembic::AbcMaterial::IMaterial::matches(md)) {
348 else if (Alembic::AbcGeom::ILight::matches(md)) {
351 else if (Alembic::AbcGeom::IFaceSet::matches(md)) {
352 /* Pass, those are handled in the mesh reader. */
354 else if (Alembic::AbcGeom::ICurves::matches(md)) {
355 reader = new AbcCurveReader(object, settings);
358 std::cerr << "Alembic: unknown how to handle objects of schema "
359 << md.get("schemaObjTitle")
360 << ", skipping object "
361 << object.getFullName() << std::endl;
367 /* ********************** */
369 ScopeTimer::ScopeTimer(const char *message)
371 , m_start(PIL_check_seconds_timer())
374 ScopeTimer::~ScopeTimer()
376 fprintf(stderr, "%s: %fs\n", m_message, PIL_check_seconds_timer() - m_start);
379 /* ********************** */
381 bool SimpleLogger::empty()
383 return ((size_t)m_stream.tellp()) == 0ul;
386 std::string SimpleLogger::str() const
388 return m_stream.str();
391 void SimpleLogger::clear()
397 std::ostringstream &SimpleLogger::stream()
402 std::ostream &operator<<(std::ostream &os, const SimpleLogger &logger)