From ead79e535d403f3cff00352a9ef0a750afbab30d Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Sun, 29 Nov 2009 14:38:50 +0000 Subject: COLLADA branch: bone animation import works! Here's the doc describing how it works: http://wiki.blender.org/index.php/User:Kazanbas/Collada_Animation_Import Here's a video showing it at work: http://vimeo.com/7877617 --- source/blender/collada/DocumentExporter.cpp | 2 +- source/blender/collada/DocumentImporter.cpp | 1046 +++++++++++++++++++++++---- source/blender/collada/collada_internal.h | 11 +- 3 files changed, 899 insertions(+), 160 deletions(-) (limited to 'source/blender/collada') diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp index fac7b2c882a..c3550dfd408 100644 --- a/source/blender/collada/DocumentExporter.cpp +++ b/source/blender/collada/DocumentExporter.cpp @@ -673,7 +673,7 @@ protected: copy_m4_m4(local, mat); } - TransformBase::decompose(local, loc, rot, size); + TransformBase::decompose(local, loc, rot, NULL, size); /* // this code used to create a single representing object rotation diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index 83f0debb60d..381632523fa 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -1,3 +1,7 @@ +// TODO: +// * name imported objects +// * import object rotation as euler + #include "COLLADAFWRoot.h" #include "COLLADAFWIWriter.h" #include "COLLADAFWStableHeaders.h" @@ -51,6 +55,7 @@ extern "C" #include "BLI_util.h" #include "BKE_displist.h" #include "BLI_math.h" +#include "BKE_scene.h" } #include "BKE_armature.h" #include "BKE_mesh.h" @@ -91,6 +96,7 @@ extern "C" #include // #define COLLADA_DEBUG +#define ARMATURE_TEST char *CustomData_get_layer_name(const struct CustomData *data, int type, int n); @@ -132,8 +138,10 @@ const char *geomTypeToStr(COLLADAFW::Geometry::GeometryType type) return "SPLINE"; case COLLADAFW::Geometry::GEO_TYPE_CONVEX_MESH: return "CONVEX_MESH"; + case COLLADAFW::Geometry::GEO_TYPE_UNKNOWN: + default: + return "UNKNOWN"; } - return "UNKNOWN"; } // works for COLLADAFW::Node, COLLADAFW::Geometry @@ -196,41 +204,16 @@ public: switch(type) { case COLLADAFW::Transformation::TRANSLATE: - { - COLLADAFW::Translate *tra = (COLLADAFW::Translate*)tm; - COLLADABU::Math::Vector3& t = tra->getTranslation(); - - unit_m4(cur); - cur[3][0] = (float)t[0]; - cur[3][1] = (float)t[1]; - cur[3][2] = (float)t[2]; - } + dae_translate_to_mat4(tm, cur); break; case COLLADAFW::Transformation::ROTATE: - { - COLLADAFW::Rotate *ro = (COLLADAFW::Rotate*)tm; - COLLADABU::Math::Vector3& raxis = ro->getRotationAxis(); - float angle = (float)(ro->getRotationAngle() * M_PI / 180.0f); - float axis[] = {raxis[0], raxis[1], raxis[2]}; - float quat[4]; - float rot_copy[3][3]; - float mat[3][3]; - axis_angle_to_quat(quat, axis, angle); - - quat_to_mat4( cur,quat); - } + dae_rotate_to_mat4(tm, cur); break; case COLLADAFW::Transformation::SCALE: - { - COLLADABU::Math::Vector3& s = ((COLLADAFW::Scale*)tm)->getScale(); - float size[3] = {(float)s[0], (float)s[1], (float)s[2]}; - size_to_mat4( cur,size); - } + dae_scale_to_mat4(tm, cur); break; case COLLADAFW::Transformation::MATRIX: - { - unit_converter->mat4_from_dae(cur, ((COLLADAFW::Matrix*)tm)->getMatrix()); - } + dae_matrix_to_mat4(tm, cur); break; case COLLADAFW::Transformation::LOOKAT: case COLLADAFW::Transformation::SKEW: @@ -251,6 +234,42 @@ public: } } } + + void dae_rotate_to_mat4(COLLADAFW::Transformation *tm, float m[][4]) + { + COLLADAFW::Rotate *ro = (COLLADAFW::Rotate*)tm; + COLLADABU::Math::Vector3& axis = ro->getRotationAxis(); + float angle = (float)(ro->getRotationAngle() * M_PI / 180.0f); + float ax[] = {axis[0], axis[1], axis[2]}; + // float quat[4]; + // axis_angle_to_quat(quat, axis, angle); + // quat_to_mat4(m, quat); + axis_angle_to_mat4(m, ax, angle); + } + + void dae_translate_to_mat4(COLLADAFW::Transformation *tm, float m[][4]) + { + COLLADAFW::Translate *tra = (COLLADAFW::Translate*)tm; + COLLADABU::Math::Vector3& t = tra->getTranslation(); + + unit_m4(m); + + m[3][0] = (float)t[0]; + m[3][1] = (float)t[1]; + m[3][2] = (float)t[2]; + } + + void dae_scale_to_mat4(COLLADAFW::Transformation *tm, float m[][4]) + { + COLLADABU::Math::Vector3& s = ((COLLADAFW::Scale*)tm)->getScale(); + float size[3] = {(float)s[0], (float)s[1], (float)s[2]}; + size_to_mat4(m, size); + } + + void dae_matrix_to_mat4(COLLADAFW::Transformation *tm, float m[][4]) + { + unit_converter->dae_matrix_to_mat4(m, ((COLLADAFW::Matrix*)tm)->getMatrix()); + } }; // only for ArmatureImporter to "see" MeshImporter::get_object_by_geom_uid @@ -264,7 +283,7 @@ public: class AnimationImporterBase { public: - virtual void change_eul_to_quat(Object *ob, bAction *act) = 0; + // virtual void change_eul_to_quat(Object *ob, bAction *act) = 0; }; class ArmatureImporter : private TransformReader @@ -390,7 +409,7 @@ private: for (int i = 0; i < weight.getValuesCount(); i++) weights.push_back(get_float_value(weight, i)); - unit_converter->mat4_from_dae(bind_shape_matrix, skin->getBindShapeMatrix()); + unit_converter->dae_matrix_to_mat4(bind_shape_matrix, skin->getBindShapeMatrix()); } void free() @@ -407,7 +426,7 @@ private: void add_joint(const COLLADABU::Math::Matrix4& matrix) { JointData jd; - unit_converter->mat4_from_dae(jd.inv_bind_mat, matrix); + unit_converter->dae_matrix_to_mat4(jd.inv_bind_mat, matrix); joint_data.push_back(jd); } @@ -481,7 +500,7 @@ private: void link_armature(bContext *C, Object *ob, std::map& joint_by_uid, TransformReader *tm) { - tm->decompose(bind_shape_matrix, ob->loc, ob->rot, ob->size); + tm->decompose(bind_shape_matrix, ob->loc, ob->rot, NULL, ob->size); ob->parent = ob_arm; ob->partype = PARSKEL; @@ -708,6 +727,7 @@ private: } } +#if 0 void set_euler_rotmode() { // just set rotmode = ROT_MODE_EUL on pose channel for each joint @@ -738,6 +758,7 @@ private: } } } +#endif Object *get_empty_for_leaves() { @@ -820,7 +841,7 @@ private: set_leaf_bone_shapes(ob_arm); - set_euler_rotmode(); + // set_euler_rotmode(); } @@ -992,6 +1013,7 @@ public: BLI_snprintf(joint_path, count, "pose.bones[\"%s\"]", get_joint_name(node)); } +#if 0 void fix_animation() { /* Change Euler rotation to Quaternion for bone animation */ @@ -1002,6 +1024,23 @@ public: anim_importer->change_eul_to_quat(ob, ob->adt->action); } } +#endif + + // gives a world-space mat + bool get_joint_bind_mat(float m[][4], COLLADAFW::Node *joint) + { + std::map::iterator it; + bool found = false; + for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) { + SkinInfo& skin = it->second; + if ((found = skin.get_joint_inv_bind_matrix(m, joint))) { + invert_m4(m); + break; + } + } + + return found; + } }; class MeshImporter : public MeshImporterBase @@ -1080,6 +1119,9 @@ private: } break; + case COLLADAFW::MeshVertexData::DATA_TYPE_UNKNOWN: + default: + fprintf(stderr, "MeshImporter.getUV(): unknown data type\n"); } } }; @@ -1320,7 +1362,7 @@ private: int count_new_tris(COLLADAFW::Mesh *mesh, Mesh *me) { COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives(); - int i, j, k; + int i, j; int tottri = 0; for (i = 0; i < prim_arr.getCount(); i++) { @@ -1730,11 +1772,14 @@ private: ArmatureImporter *armature_importer; Scene *scene; - std::map > uid_fcurve_map; + std::map > curve_map; std::map uid_animated_map; - std::map > fcurves_actionGroup_map; + // std::map > fcurves_actionGroup_map; + std::map animlist_map; + std::vector unused_curves; + std::map joint_objects; - FCurve *create_fcurve(int array_index, char *rna_path) + FCurve *create_fcurve(int array_index, const char *rna_path) { FCurve *fcu = (FCurve*)MEM_callocN(sizeof(FCurve), "FCurve"); @@ -1757,6 +1802,105 @@ private: calchandles_fcurve(fcu); } + // create one or several fcurves depending on the number of parameters being animated + void animation_to_fcurves(COLLADAFW::AnimationCurve *curve) + { + COLLADAFW::FloatOrDoubleArray& input = curve->getInputValues(); + COLLADAFW::FloatOrDoubleArray& output = curve->getOutputValues(); + // COLLADAFW::FloatOrDoubleArray& intan = curve->getInTangentValues(); + // COLLADAFW::FloatOrDoubleArray& outtan = curve->getOutTangentValues(); + float fps = (float)FPS; + size_t dim = curve->getOutDimension(); + int i; + + std::vector& fcurves = curve_map[curve->getUniqueId()]; + + if (dim == 1) { + FCurve *fcu = (FCurve*)MEM_callocN(sizeof(FCurve), "FCurve"); + + fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED); + // fcu->rna_path = BLI_strdupn(path, strlen(path)); + fcu->array_index = 0; + //fcu->totvert = curve->getKeyCount(); + + // create beztriple for each key + for (i = 0; i < curve->getKeyCount(); i++) { + BezTriple bez; + memset(&bez, 0, sizeof(BezTriple)); + + // intangent + // bez.vec[0][0] = get_float_value(intan, i + i) * fps; + // bez.vec[0][1] = get_float_value(intan, i + i + 1); + + // input, output + bez.vec[1][0] = get_float_value(input, i) * fps; + bez.vec[1][1] = get_float_value(output, i); + + // outtangent + // bez.vec[2][0] = get_float_value(outtan, i + i) * fps; + // bez.vec[2][1] = get_float_value(outtan, i + i + 1); + + bez.ipo = U.ipo_new; /* use default interpolation mode here... */ + bez.f1 = bez.f2 = bez.f3 = SELECT; + bez.h1 = bez.h2 = HD_AUTO; + insert_bezt_fcurve(fcu, &bez, 0); + } + + calchandles_fcurve(fcu); + + fcurves.push_back(fcu); + } + else if(dim == 3) { + for (i = 0; i < dim; i++ ) { + FCurve *fcu = (FCurve*)MEM_callocN(sizeof(FCurve), "FCurve"); + + fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED); + // fcu->rna_path = BLI_strdupn(path, strlen(path)); + fcu->array_index = 0; + //fcu->totvert = curve->getKeyCount(); + + // create beztriple for each key + for (int j = 0; j < curve->getKeyCount(); j++) { + BezTriple bez; + memset(&bez, 0, sizeof(BezTriple)); + + // intangent + // bez.vec[0][0] = get_float_value(intan, j * 6 + i + i) * fps; + // bez.vec[0][1] = get_float_value(intan, j * 6 + i + i + 1); + + // input, output + bez.vec[1][0] = get_float_value(input, j) * fps; + bez.vec[1][1] = get_float_value(output, j * 3 + i); + + // outtangent + // bez.vec[2][0] = get_float_value(outtan, j * 6 + i + i) * fps; + // bez.vec[2][1] = get_float_value(outtan, j * 6 + i + i + 1); + + bez.ipo = U.ipo_new; /* use default interpolation mode here... */ + bez.f1 = bez.f2 = bez.f3 = SELECT; + bez.h1 = bez.h2 = HD_AUTO; + insert_bezt_fcurve(fcu, &bez, 0); + } + + calchandles_fcurve(fcu); + + fcurves.push_back(fcu); + } + } + + for (std::vector::iterator it = fcurves.begin(); it != fcurves.end(); it++) + unused_curves.push_back(*it); + } + + void fcurve_deg_to_rad(FCurve *cu) + { + for (int i = 0; i < cu->totvert; i++) { + // TODO convert handles too + cu->bezt[i].vec[1][1] *= M_PI / 180.0f; + } + } + +#if 0 void make_fcurves_from_animation(COLLADAFW::AnimationCurve *curve, COLLADAFW::FloatOrDoubleArray& input, COLLADAFW::FloatOrDoubleArray& output, @@ -1765,7 +1909,7 @@ private: { int i; // char *path = "location"; - std::vector& fcurves = uid_fcurve_map[curve->getUniqueId()]; + std::vector& fcurves = curve_map[curve->getUniqueId()]; if (dim == 1) { // create fcurve @@ -1834,49 +1978,36 @@ private: } } } +#endif void add_fcurves_to_object(Object *ob, std::vector& curves, char *rna_path, int array_index, Animation *animated) { - ID *id = &ob->id; bAction *act; - bActionGroup *grp = NULL; - if (!ob->adt || !ob->adt->action) act = verify_adt_action(id, 1); - else act = verify_adt_action(id, 0); - - if (!ob->adt || !ob->adt->action) { - fprintf(stderr, "Cannot create anim data or action for this object. \n"); - return; - } + if (!ob->adt || !ob->adt->action) act = verify_adt_action((ID*)&ob->id, 1); + else act = ob->adt->action; - FCurve *fcu; std::vector::iterator it; - int i = 0; + int i; +#if 0 char *p = strstr(rna_path, "rotation_euler"); bool is_rotation = p && *(p + strlen("rotation_euler")) == '\0'; + + // convert degrees to radians for rotation + if (is_rotation) + fcurve_deg_to_rad(fcu); +#endif - for (it = curves.begin(); it != curves.end(); it++) { - fcu = *it; + for (it = curves.begin(), i = 0; it != curves.end(); it++, i++) { + FCurve *fcu = *it; fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path)); if (array_index == -1) fcu->array_index = i; else fcu->array_index = array_index; - - // convert degrees to radians for rotation - if (is_rotation) { - for(int j = 0; j < fcu->totvert; j++) { - float rot_intan = fcu->bezt[j].vec[0][1]; - float rot_output = fcu->bezt[j].vec[1][1]; - float rot_outtan = fcu->bezt[j].vec[2][1]; - fcu->bezt[j].vec[0][1] = rot_intan * M_PI / 180.0f; - fcu->bezt[j].vec[1][1] = rot_output * M_PI / 180.0f; - fcu->bezt[j].vec[2][1] = rot_outtan * M_PI / 180.0f; - } - } - + if (ob->type == OB_ARMATURE) { - bAction *act = ob->adt->action; + bActionGroup *grp = NULL; const char *bone_name = get_joint_name(animated->node); if (bone_name) { @@ -1889,7 +2020,7 @@ private: grp = (bActionGroup*)MEM_callocN(sizeof(bActionGroup), "bActionGroup"); grp->flag = AGRP_SELECTED; - BLI_snprintf(grp->name, sizeof(grp->name), bone_name); + BLI_strncpy(grp->name, bone_name, sizeof(grp->name)); BLI_addtail(&act->groups, grp); BLI_uniquename(&act->groups, grp, "Group", '.', offsetof(bActionGroup, name), 64); @@ -1899,15 +2030,18 @@ private: action_groups_add_channel(act, grp, fcu); } +#if 0 if (is_rotation) { fcurves_actionGroup_map[grp].push_back(fcu); } +#endif } else { BLI_addtail(&act->curves, fcu); } - i++; + // curve is used, so remove it from unused_curves + unused_curves.erase(std::remove(unused_curves.begin(), unused_curves.end(), fcu), unused_curves.end()); } } public: @@ -1915,13 +2049,20 @@ public: AnimationImporter(UnitConverter *conv, ArmatureImporter *arm, Scene *scene) : TransformReader(conv), armature_importer(arm), scene(scene) { } - bool write_animation( const COLLADAFW::Animation* anim ) + ~AnimationImporter() { - float fps = (float)FPS; + // free unused FCurves + for (std::vector::iterator it = unused_curves.begin(); it != unused_curves.end(); it++) + free_fcurve(*it); + + if (unused_curves.size()) + fprintf(stderr, "removed %u unused curves\n", unused_curves.size()); + } + bool write_animation(const COLLADAFW::Animation* anim) + { if (anim->getAnimationType() == COLLADAFW::Animation::ANIMATION_CURVE) { COLLADAFW::AnimationCurve *curve = (COLLADAFW::AnimationCurve*)anim; - size_t dim = curve->getOutDimension(); // XXX Don't know if it's necessary // Should we check outPhysicalDimension? @@ -1930,11 +2071,6 @@ public: return true; } - COLLADAFW::FloatOrDoubleArray& input = curve->getInputValues(); - COLLADAFW::FloatOrDoubleArray& output = curve->getOutputValues(); - COLLADAFW::FloatOrDoubleArray& intan = curve->getInTangentValues(); - COLLADAFW::FloatOrDoubleArray& outtan = curve->getOutTangentValues(); - // a curve can have mixed interpolation type, // in this case curve->getInterpolationTypes returns a list of interpolation types per key COLLADAFW::AnimationCurve::InterpolationType interp = curve->getInterpolationType(); @@ -1942,17 +2078,11 @@ public: if (interp != COLLADAFW::AnimationCurve::INTERPOLATION_MIXED) { switch (interp) { case COLLADAFW::AnimationCurve::INTERPOLATION_LINEAR: - // support this - make_fcurves_from_animation(curve, input, output, intan, outtan, dim, fps); - break; case COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER: - // and this - make_fcurves_from_animation(curve, input, output, intan, outtan, dim, fps); + animation_to_fcurves(curve); break; - case COLLADAFW::AnimationCurve::INTERPOLATION_CARDINAL: - case COLLADAFW::AnimationCurve::INTERPOLATION_HERMITE: - case COLLADAFW::AnimationCurve::INTERPOLATION_BSPLINE: - case COLLADAFW::AnimationCurve::INTERPOLATION_STEP: + default: + // TODO there're also CARDINAL, HERMITE, BSPLINE and STEP types fprintf(stderr, "CARDINAL, HERMITE, BSPLINE and STEP anim interpolation types not supported yet.\n"); break; } @@ -1970,19 +2100,22 @@ public: } // called on post-process stage after writeVisualScenes - bool write_animation_list( const COLLADAFW::AnimationList* animationList ) + bool write_animation_list(const COLLADAFW::AnimationList* animlist) { - const COLLADAFW::UniqueId& anim_list_id = animationList->getUniqueId(); + const COLLADAFW::UniqueId& animlist_id = animlist->getUniqueId(); + + animlist_map[animlist_id] = animlist; - // possible in case we cannot interpret some transform - if (uid_animated_map.find(anim_list_id) == uid_animated_map.end()) { +#if 0 + // should not happen + if (uid_animated_map.find(animlist_id) == uid_animated_map.end()) { return true; } // for bones rna_path is like: pose.bones["bone-name"].rotation // what does this AnimationList animate? - Animation& animated = uid_animated_map[anim_list_id]; + Animation& animated = uid_animated_map[animlist_id]; Object *ob = animated.ob; char rna_path[100]; @@ -2003,26 +2136,28 @@ public: is_joint = true; } - const COLLADAFW::AnimationList::AnimationBindings& bindings = animationList->getAnimationBindings(); + const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings(); switch (animated.tm->getTransformationType()) { case COLLADAFW::Transformation::TRANSLATE: + case COLLADAFW::Transformation::SCALE: { + bool loc = animated.tm->getTransformationType() == COLLADAFW::Transformation::TRANSLATE; if (is_joint) - BLI_snprintf(rna_path, sizeof(rna_path), "%s.location", joint_path); + BLI_snprintf(rna_path, sizeof(rna_path), "%s.%s", joint_path, loc ? "location" : "scale"); else - BLI_strncpy(rna_path, "location", sizeof(rna_path)); + BLI_strncpy(rna_path, loc ? "location" : "scale", sizeof(rna_path)); for (int i = 0; i < bindings.getCount(); i++) { const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[i]; COLLADAFW::UniqueId anim_uid = binding.animation; - if (uid_fcurve_map.find(anim_uid) == uid_fcurve_map.end()) { + if (curve_map.find(anim_uid) == curve_map.end()) { fprintf(stderr, "Cannot find FCurve by animation UID.\n"); continue; } - std::vector& fcurves = uid_fcurve_map[anim_uid]; + std::vector& fcurves = curve_map[anim_uid]; switch (binding.animationClass) { case COLLADAFW::AnimationList::POSITION_X: @@ -2038,8 +2173,8 @@ public: add_fcurves_to_object(ob, fcurves, rna_path, -1, &animated); break; default: - fprintf(stderr, "AnimationClass %d is not supported for TRANSLATE transformation.\n", - binding.animationClass); + fprintf(stderr, "AnimationClass %d is not supported for %s.\n", + binding.animationClass, loc ? "TRANSLATE" : "SCALE"); } } } @@ -2058,12 +2193,12 @@ public: const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[i]; COLLADAFW::UniqueId anim_uid = binding.animation; - if (uid_fcurve_map.find(anim_uid) == uid_fcurve_map.end()) { + if (curve_map.find(anim_uid) == curve_map.end()) { fprintf(stderr, "Cannot find FCurve by animation UID.\n"); continue; } - std::vector& fcurves = uid_fcurve_map[anim_uid]; + std::vector& fcurves = curve_map[anim_uid]; switch (binding.animationClass) { case COLLADAFW::AnimationList::ANGLE: @@ -2086,51 +2221,13 @@ public: } } break; - case COLLADAFW::Transformation::SCALE: - { - if (is_joint) - BLI_snprintf(rna_path, sizeof(rna_path), "%s.scale", joint_path); - else - BLI_strncpy(rna_path, "scale", sizeof(rna_path)); - - // same as for TRANSLATE - for (int i = 0; i < bindings.getCount(); i++) { - const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[i]; - COLLADAFW::UniqueId anim_uid = binding.animation; - - if (uid_fcurve_map.find(anim_uid) == uid_fcurve_map.end()) { - fprintf(stderr, "Cannot find FCurve by animation UID.\n"); - continue; - } - - std::vector& fcurves = uid_fcurve_map[anim_uid]; - - switch (binding.animationClass) { - case COLLADAFW::AnimationList::POSITION_X: - add_fcurves_to_object(ob, fcurves, rna_path, 0, &animated); - break; - case COLLADAFW::AnimationList::POSITION_Y: - add_fcurves_to_object(ob, fcurves, rna_path, 1, &animated); - break; - case COLLADAFW::AnimationList::POSITION_Z: - add_fcurves_to_object(ob, fcurves, rna_path, 2, &animated); - break; - case COLLADAFW::AnimationList::POSITION_XYZ: - add_fcurves_to_object(ob, fcurves, rna_path, -1, &animated); - break; - default: - fprintf(stderr, "AnimationClass %d is not supported for SCALE transformation.\n", - binding.animationClass); - } - } - } - break; case COLLADAFW::Transformation::MATRIX: case COLLADAFW::Transformation::SKEW: case COLLADAFW::Transformation::LOOKAT: fprintf(stderr, "Animation of MATRIX, SKEW and LOOKAT transformations is not supported yet.\n"); break; } +#endif return true; } @@ -2140,9 +2237,10 @@ public: float mat[4][4]; TransformReader::get_node_mat(mat, node, &uid_animated_map, ob); if (ob) - TransformReader::decompose(mat, ob->loc, ob->rot, ob->size); + TransformReader::decompose(mat, ob->loc, ob->rot, NULL, ob->size); } +#if 0 virtual void change_eul_to_quat(Object *ob, bAction *act) { bActionGroup *grp; @@ -2166,7 +2264,7 @@ public: char rna_path[100]; BLI_snprintf(joint_path, sizeof(joint_path), "pose.bones[\"%s\"]", grp->name); - BLI_snprintf(rna_path, sizeof(rna_path), "%s.rotation_euler", joint_path); + BLI_snprintf(rna_path, sizeof(rna_path), "%s.rotation_quaternion", joint_path); FCurve *quatcu[4] = { create_fcurve(0, rna_path), @@ -2175,6 +2273,12 @@ public: create_fcurve(3, rna_path) }; + bPoseChannel *chan = get_pose_channel(ob->pose, grp->name); + + float m4[4][4], irest[3][3]; + invert_m4_m4(m4, chan->bone->arm_mat); + copy_m3_m4(irest, m4); + for (i = 0; i < 3; i++) { FCurve *cu = eulcu[i]; @@ -2190,9 +2294,17 @@ public: eulcu[2] ? evaluate_fcurve(eulcu[2], frame) : 0.0f }; - float quat[4]; + // make eul relative to bone rest pose + float rot[3][3], rel[3][3], quat[4]; + + /*eul_to_mat3(rot, eul); + + mul_m3_m3m3(rel, irest, rot); - eul_to_quat( quat,eul); + mat3_to_quat(quat, rel); + */ + + eul_to_quat(quat, eul); for (int k = 0; k < 4; k++) create_bezt(quatcu[k], frame, quat[k]); @@ -2208,7 +2320,7 @@ public: free_fcurve(eulcu[i]); } - get_pose_channel(ob->pose, grp->name)->rotmode = ROT_MODE_QUAT; + chan->rotmode = ROT_MODE_QUAT; for (i = 0; i < 4; i++) action_groups_add_channel(act, grp, quatcu[i]); @@ -2218,7 +2330,581 @@ public: for (pchan = (bPoseChannel*)ob->pose->chanbase.first; pchan; pchan = pchan->next) { pchan->rotmode = ROT_MODE_QUAT; } - } + } +#endif + + // prerequisites: + // animlist_map - map animlist id -> animlist + // curve_map - map anim id -> curve(s) +#ifdef ARMATURE_TEST + Object *translate_animation(COLLADAFW::Node *node, + std::map& object_map, + std::map& root_map, + COLLADAFW::Transformation::TransformationType tm_type, + Object *par_job = NULL) +#else + void translate_animation(COLLADAFW::Node *node, + std::map& object_map, + std::map& root_map, + COLLADAFW::Transformation::TransformationType tm_type) +#endif + { + bool is_rotation = tm_type == COLLADAFW::Transformation::ROTATE; + bool is_joint = node->getType() == COLLADAFW::Node::JOINT; + COLLADAFW::Node *root = root_map.find(node->getUniqueId()) == root_map.end() ? node : root_map[node->getUniqueId()]; + Object *ob = is_joint ? armature_importer->get_armature_for_joint(node) : object_map[node->getUniqueId()]; + const char *bone_name = is_joint ? get_joint_name(node) : NULL; + + if (!ob) { + fprintf(stderr, "cannot find Object for Node with id=\"%s\"\n", node->getOriginalId().c_str()); +#ifdef ARMATURE_TEST + return NULL; +#else + return; +#endif + } + + // frames at which to sample + std::vector frames; + + // for each , , etc. there is a separate Transformation + const COLLADAFW::TransformationPointerArray& tms = node->getTransformations(); + + std::vector old_curves; + + int i; + + // find frames at which to sample plus convert all keys to radians + for (i = 0; i < tms.getCount(); i++) { + COLLADAFW::Transformation *tm = tms[i]; + COLLADAFW::Transformation::TransformationType type = tm->getTransformationType(); + + if (type == tm_type) { + const COLLADAFW::UniqueId& listid = tm->getAnimationList(); + + if (animlist_map.find(listid) != animlist_map.end()) { + const COLLADAFW::AnimationList *animlist = animlist_map[listid]; + const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings(); + + if (bindings.getCount()) { + for (int j = 0; j < bindings.getCount(); j++) { + std::vector& curves = curve_map[bindings[j].animation]; + bool xyz = ((type == COLLADAFW::Transformation::TRANSLATE || type == COLLADAFW::Transformation::SCALE) && bindings[j].animationClass == COLLADAFW::AnimationList::POSITION_XYZ); + + if ((!xyz && curves.size() == 1) || (xyz && curves.size() == 3)) { + std::vector::iterator iter; + + for (iter = curves.begin(); iter != curves.end(); iter++) { + FCurve *fcu = *iter; + + if (is_rotation) + fcurve_deg_to_rad(fcu); + + for (int k = 0; k < fcu->totvert; k++) { + float fra = fcu->bezt[k].vec[1][0]; + if (std::find(frames.begin(), frames.end(), fra) == frames.end()) + frames.push_back(fra); + } + } + } + else { + fprintf(stderr, "expected 1 or 3 curves, got %u\n", curves.size()); + } + + for (std::vector::iterator it = curves.begin(); it != curves.end(); it++) + old_curves.push_back(*it); + } + } + } + } + } + + sort(frames.begin(), frames.end()); + + float irest_dae[4][4]; + float rest[4][4], irest[4][4]; + + if (is_joint) { + if (is_joint) + get_joint_rest_mat(irest_dae, root, node); + else + evaluate_transform_at_frame(irest_dae, node, 0.0f); + invert_m4(irest_dae); + + Bone *bone = get_named_bone((bArmature*)ob->data, bone_name); + if (!bone) { + fprintf(stderr, "cannot find bone \"%s\"", bone_name); +#ifdef ARMATURE_TEST + return NULL; +#else + return; +#endif + } + + unit_m4(rest); + copy_m4_m4(rest, bone->arm_mat); + invert_m4_m4(irest, rest); + } + + char rna_path[200]; + +#ifdef ARMATURE_TEST + Object *job = get_joint_object(root, node, par_job); + FCurve *job_curves[4]; +#endif + + if (frames.size() == 0) { +#ifdef ARMATURE_TEST + return job; +#else + return; +#endif + } + + const char *tm_str = NULL; + switch (tm_type) { + case COLLADAFW::Transformation::ROTATE: + tm_str = "rotation_quaternion"; + break; + case COLLADAFW::Transformation::SCALE: + tm_str = "scale"; + break; + case COLLADAFW::Transformation::TRANSLATE: + tm_str = "location"; + break; + default: +#ifdef ARMATURE_TEST + return job; +#else + return; +#endif + } + + if (is_joint) { + char joint_path[200]; + armature_importer->get_rna_path_for_joint(node, joint_path, sizeof(joint_path)); + BLI_snprintf(rna_path, sizeof(rna_path), "%s.%s", joint_path, tm_str); + } + else { + strcpy(rna_path, tm_str); + } + + // new curves + FCurve *newcu[4]; + int totcu = is_rotation ? 4 : 3; + + for (i = 0; i < totcu; i++) { + newcu[i] = create_fcurve(i, rna_path); +#ifdef ARMATURE_TEST + job_curves[i] = create_fcurve(i, tm_str); +#endif + } + + std::vector::iterator it; + + // sample values at each frame + for (it = frames.begin(); it != frames.end(); it++) { + float fra = *it; + + float mat[4][4]; + + unit_m4(mat); + + // calc object-space mat + evaluate_transform_at_frame(mat, node, fra); + + // for joints, we need a special matrix + if (is_joint) { + // special matrix: iR * M * iR_dae * R + // where R, iR are bone rest and inverse rest mats in world space (Blender bones), + // iR_dae is joint inverse rest matrix (DAE) and M is an evaluated joint world-space matrix (DAE) + float temp[4][4], par[4][4]; + + // calc M + calc_joint_parent_mat_rest(par, NULL, root, node); + mul_m4_m4m4(temp, mat, par); + + // evaluate_joint_world_transform_at_frame(temp, NULL, , node, fra); + + // calc special matrix + mul_serie_m4(mat, irest, temp, irest_dae, rest, NULL, NULL, NULL, NULL); + } + + float val[4]; + + switch (tm_type) { + case COLLADAFW::Transformation::ROTATE: + mat4_to_quat(val, mat); + break; + case COLLADAFW::Transformation::SCALE: + mat4_to_size(val, mat); + break; + case COLLADAFW::Transformation::TRANSLATE: + copy_v3_v3(val, mat[3]); + break; + default: + break; + } + + // add 4 or 3 keys + for (i = 0; i < totcu; i++) { + add_bezt(newcu[i], fra, val[i]); + } + +#ifdef ARMATURE_TEST + if (is_joint) { + evaluate_transform_at_frame(mat, node, fra); + + switch (tm_type) { + case COLLADAFW::Transformation::ROTATE: + mat4_to_quat(val, mat); + break; + case COLLADAFW::Transformation::SCALE: + mat4_to_size(val, mat); + break; + case COLLADAFW::Transformation::TRANSLATE: + copy_v3_v3(val, mat[3]); + break; + default: + break; + } + + for (i = 0; i < totcu; i++) + add_bezt(job_curves[i], fra, val[i]); + } +#endif + } + + verify_adt_action((ID*)&ob->id, 1); + + ListBase *curves = &ob->adt->action->curves; + // no longer needed +#if 0 + // remove old curves + for (std::vector::iterator it = old_curves.begin(); it != old_curves.end(); it++) { + if (is_joint) + action_groups_remove_channel(ob->adt->action, *it); + else + BLI_remlink(curves, *it); + + // std::remove(unused_curves.begin(), unused_curves.end(), *it); + // free_fcurve(*it); + } +#endif + + // add curves + for (i = 0; i < totcu; i++) { + if (is_joint) + add_bone_fcurve(ob, node, newcu[i]); + else + BLI_addtail(curves, newcu[i]); + +#ifdef ARMATURE_TEST + if (is_joint) + BLI_addtail(&job->adt->action->curves, job_curves[i]); +#endif + } + + if (is_rotation) { + if (is_joint) { + bPoseChannel *chan = get_pose_channel(ob->pose, bone_name); + chan->rotmode = ROT_MODE_QUAT; + } + else { + ob->rotmode = ROT_MODE_QUAT; + } + } + +#ifdef ARMATURE_TEST + return job; +#endif + } + + // internal, better make it private + // warning: evaluates only rotation + // prerequisites: animlist_map, curve_map + void evaluate_transform_at_frame(float mat[4][4], COLLADAFW::Node *node, float fra) + { + const COLLADAFW::TransformationPointerArray& tms = node->getTransformations(); + + unit_m4(mat); + + for (int i = 0; i < tms.getCount(); i++) { + COLLADAFW::Transformation *tm = tms[i]; + COLLADAFW::Transformation::TransformationType type = tm->getTransformationType(); + float m[4][4]; + + unit_m4(m); + + if (!evaluate_animation(tm, m, fra)) { + switch (type) { + case COLLADAFW::Transformation::ROTATE: + dae_rotate_to_mat4(tm, m); + break; + case COLLADAFW::Transformation::TRANSLATE: + dae_translate_to_mat4(tm, m); + break; + case COLLADAFW::Transformation::SCALE: + dae_scale_to_mat4(tm, m); + break; + case COLLADAFW::Transformation::MATRIX: + dae_matrix_to_mat4(tm, m); + break; + default: + fprintf(stderr, "unsupported transformation type %d\n", type); + } + } + + float temp[4][4]; + copy_m4_m4(temp, mat); + + mul_m4_m4m4(mat, m, temp); + } + } + + bool evaluate_animation(COLLADAFW::Transformation *tm, float mat[4][4], float fra) + { + const COLLADAFW::UniqueId& listid = tm->getAnimationList(); + + if (animlist_map.find(listid) != animlist_map.end()) { + const COLLADAFW::AnimationList *animlist = animlist_map[listid]; + const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings(); + + if (bindings.getCount()) { + for (int j = 0; j < bindings.getCount(); j++) { + std::vector& curves = curve_map[bindings[j].animation]; + COLLADAFW::AnimationList::AnimationClass animclass = bindings[j].animationClass; + COLLADAFW::Transformation::TransformationType type = tm->getTransformationType(); + bool xyz = ((type == COLLADAFW::Transformation::TRANSLATE || type == COLLADAFW::Transformation::SCALE) && bindings[j].animationClass == COLLADAFW::AnimationList::POSITION_XYZ); + + if (type == COLLADAFW::Transformation::ROTATE) { + if (curves.size() != 1) { + fprintf(stderr, "expected 1 curve, got %u\n", curves.size()); + } + else { + if (animclass == COLLADAFW::AnimationList::ANGLE) { + COLLADABU::Math::Vector3& axis = ((COLLADAFW::Rotate*)tm)->getRotationAxis(); + float ax[3] = {axis[0], axis[1], axis[2]}; + float angle = evaluate_fcurve(curves[0], fra); + axis_angle_to_mat4(mat, ax, angle); + + return true; + } + else { + // TODO support other animclasses + fprintf(stderr, " animclass %d is not supported yet\n", bindings[j].animationClass); + } + } + } + else if (type == COLLADAFW::Transformation::SCALE || type == COLLADAFW::Transformation::TRANSLATE) { + if ((!xyz && curves.size() == 1) || (xyz && curves.size() == 3)) { + bool animated = true; + bool scale = (type == COLLADAFW::Transformation::SCALE); + + float vec[3] = {0.0f, 0.0f, 0.0f}; + if (scale) + vec[0] = vec[1] = vec[2] = 1.0f; + + switch (animclass) { + case COLLADAFW::AnimationList::POSITION_X: + vec[0] = evaluate_fcurve(curves[0], fra); + break; + case COLLADAFW::AnimationList::POSITION_Y: + vec[1] = evaluate_fcurve(curves[0], fra); + break; + case COLLADAFW::AnimationList::POSITION_Z: + vec[2] = evaluate_fcurve(curves[0], fra); + break; + case COLLADAFW::AnimationList::POSITION_XYZ: + vec[0] = evaluate_fcurve(curves[0], fra); + vec[1] = evaluate_fcurve(curves[1], fra); + vec[2] = evaluate_fcurve(curves[2], fra); + break; + default: + fprintf(stderr, "<%s> animclass %d is not supported yet\n", scale ? "scale" : "translate", animclass); + animated = false; + break; + } + + if (animated) { + if (scale) + size_to_mat4(mat, vec); + else + copy_v3_v3(mat[3], vec); + } + + return animated; + } + else { + fprintf(stderr, "expected 1 or 3 curves, got %u, animclass is %d\n", curves.size(), animclass); + } + } + else { + // not very useful for user + fprintf(stderr, "animation of transformation %d is not supported yet\n", type); + } + } + } + } + + return false; + } + + // gives a world-space mat of joint at rest position + void get_joint_rest_mat(float mat[4][4], COLLADAFW::Node *root, COLLADAFW::Node *node) + { + // if bind mat is not available, + // use "current" node transform, i.e. all those tms listed inside + if (!armature_importer->get_joint_bind_mat(mat, node)) { + float par[4][4], m[4][4]; + + calc_joint_parent_mat_rest(par, NULL, root, node); + get_node_mat(m, node, NULL, NULL); + mul_m4_m4m4(mat, m, par); + } + } + + // gives a world-space mat, end's mat not included + bool calc_joint_parent_mat_rest(float mat[4][4], float par[4][4], COLLADAFW::Node *node, COLLADAFW::Node *end) + { + float m[4][4]; + + if (node == end) { + par ? copy_m4_m4(mat, par) : unit_m4(mat); + return true; + } + + // use bind matrix if available or calc "current" world mat + if (!armature_importer->get_joint_bind_mat(m, node)) { + float temp[4][4]; + get_node_mat(temp, node, NULL, NULL); + mul_m4_m4m4(m, temp, par); + } + + COLLADAFW::NodePointerArray& children = node->getChildNodes(); + for (int i = 0; i < children.getCount(); i++) { + if (calc_joint_parent_mat_rest(mat, m, children[i], end)) + return true; + } + + return false; + } + +#ifdef ARMATURE_TEST + Object *get_joint_object(COLLADAFW::Node *root, COLLADAFW::Node *node, Object *par_job) + { + if (joint_objects.find(node->getUniqueId()) == joint_objects.end()) { + Object *job = add_object(scene, OB_EMPTY); + + rename_id((ID*)&job->id, (char*)get_joint_name(node)); + + job->lay = object_in_scene(job, scene)->lay = 2; + + mul_v3_fl(job->size, 0.5f); + job->recalc |= OB_RECALC_OB; + + verify_adt_action((ID*)&job->id, 1); + + job->rotmode = ROT_MODE_QUAT; + + float mat[4][4]; + get_joint_rest_mat(mat, root, node); + + if (par_job) { + float temp[4][4], ipar[4][4]; + invert_m4_m4(ipar, par_job->obmat); + copy_m4_m4(temp, mat); + mul_m4_m4m4(mat, temp, ipar); + } + + TransformBase::decompose(mat, job->loc, NULL, job->quat, job->size); + + if (par_job) { + job->parent = par_job; + + par_job->recalc |= OB_RECALC_OB; + job->parsubstr[0] = 0; + } + + where_is_object(scene, job); + + // after parenting and layer change + DAG_scene_sort(scene); + + joint_objects[node->getUniqueId()] = job; + } + + return joint_objects[node->getUniqueId()]; + } +#endif + +#if 0 + // recursively evaluates joint tree until end is found, mat then is world-space matrix of end + // mat must be identity on enter, node must be root + bool evaluate_joint_world_transform_at_frame(float mat[4][4], float par[4][4], COLLADAFW::Node *node, COLLADAFW::Node *end, float fra) + { + float m[4][4]; + if (par) { + float temp[4][4]; + evaluate_transform_at_frame(temp, node, node == end ? fra : 0.0f); + mul_m4_m4m4(m, temp, par); + } + else { + evaluate_transform_at_frame(m, node, node == end ? fra : 0.0f); + } + + if (node == end) { + copy_m4_m4(mat, m); + return true; + } + else { + COLLADAFW::NodePointerArray& children = node->getChildNodes(); + for (int i = 0; i < children.getCount(); i++) { + if (evaluate_joint_world_transform_at_frame(mat, m, children[i], end, fra)) + return true; + } + } + + return false; + } +#endif + + void add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurve *fcu) + { + const char *bone_name = get_joint_name(node); + bAction *act = ob->adt->action; + + /* try to find group */ + bActionGroup *grp = action_groups_find_named(act, bone_name); + + /* no matching groups, so add one */ + if (grp == NULL) { + /* Add a new group, and make it active */ + grp = (bActionGroup*)MEM_callocN(sizeof(bActionGroup), "bActionGroup"); + + grp->flag = AGRP_SELECTED; + BLI_strncpy(grp->name, bone_name, sizeof(grp->name)); + + BLI_addtail(&act->groups, grp); + BLI_uniquename(&act->groups, grp, "Group", '.', offsetof(bActionGroup, name), 64); + } + + /* add F-Curve to group */ + action_groups_add_channel(act, grp, fcu); + } + + void add_bezt(FCurve *fcu, float fra, float value) + { + BezTriple bez; + memset(&bez, 0, sizeof(BezTriple)); + bez.vec[1][0] = fra; + bez.vec[1][1] = value; + bez.ipo = U.ipo_new; /* use default interpolation mode here... */ + bez.f1 = bez.f2 = bez.f3 = SELECT; + bez.h1 = bez.h2 = HD_AUTO; + insert_bezt_fcurve(fcu, &bez, 0); + calchandles_fcurve(fcu); + } }; /* @@ -2248,6 +2934,11 @@ private: std::map uid_camera_map; std::map uid_lamp_map; std::map material_texture_mapping_map; + std::map object_map; + std::vector vscenes; + + std::map root_map; // find root joint by child joint uid, for bone tree evaluation during resampling + // animation // std::map > uid_fcurve_map; // Nodes don't share AnimationLists (Arystan) @@ -2256,7 +2947,7 @@ private: public: /** Constructor. */ - Writer(bContext *C, const char *filename) : mContext(C), mFilename(filename), + Writer(bContext *C, const char *filename) : mFilename(filename), mContext(C), armature_importer(&unit_converter, &mesh_importer, &anim_importer, CTX_data_scene(C)), mesh_importer(&armature_importer, CTX_data_scene(C)), anim_importer(&unit_converter, &armature_importer, CTX_data_scene(C)) {} @@ -2298,8 +2989,51 @@ public: /** This method is called after the last write* method. No other methods will be called after this.*/ virtual void finish() { +#if 0 armature_importer.fix_animation(); +#endif + + for (std::vector::iterator it = vscenes.begin(); it != vscenes.end(); it++) { + const COLLADAFW::NodePointerArray& roots = (*it)->getRootNodes(); + + for (int i = 0; i < roots.getCount(); i++) + translate_anim_recursive(roots[i]); + } + + } + + +#ifdef ARMATURE_TEST + void translate_anim_recursive(COLLADAFW::Node *node, COLLADAFW::Node *par = NULL, Object *parob = NULL) + { + if (par && par->getType() == COLLADAFW::Node::JOINT) { + // par is root if there's no corresp. key in root_map + if (root_map.find(par->getUniqueId()) == root_map.end()) + root_map[node->getUniqueId()] = par; + else + root_map[node->getUniqueId()] = root_map[par->getUniqueId()]; + } + + COLLADAFW::Transformation::TransformationType types[] = { + COLLADAFW::Transformation::ROTATE, + COLLADAFW::Transformation::SCALE, + COLLADAFW::Transformation::TRANSLATE + }; + + int i; + Object *ob; + + for (i = 0; i < 3; i++) + ob = anim_importer.translate_animation(node, object_map, root_map, types[i]); + + COLLADAFW::NodePointerArray &children = node->getChildNodes(); + for (int i = 0; i < children.getCount(); i++) { + translate_anim_recursive(children[i], node, ob); + } } +#else + +#endif /** When this method is called, the writer must write the global document asset. @return The writer should return true, if writing succeeded, false otherwise.*/ @@ -2399,11 +3133,11 @@ public: // check if object is not NULL if (!ob) return; + + object_map[node->getUniqueId()] = ob; // if par was given make this object child of the previous if (par && ob) { - Object workob; - ob->parent = par; // doing what 'set parent' operator does @@ -2427,7 +3161,7 @@ public: @return The writer should return true, if writing succeeded, false otherwise.*/ virtual bool writeVisualScene ( const COLLADAFW::VisualScene* visualScene ) { - // This method is guaranteed to be called _after_ writeGeometry, writeMaterial, etc. + // this method called on post process after writeGeometry, writeMaterial, etc. // for each in : // create an Object @@ -2437,15 +3171,15 @@ public: // writeGeometry because does not reference , // we link Objects with Meshes here + vscenes.push_back(visualScene); + // TODO: create a new scene except the selected - use current blender // scene for it Scene *sce = CTX_data_scene(mContext); + const COLLADAFW::NodePointerArray& roots = visualScene->getRootNodes(); - for (int i = 0; i < visualScene->getRootNodes().getCount(); i++) { - COLLADAFW::Node *node = visualScene->getRootNodes()[i]; - const COLLADAFW::Node::NodeType& type = node->getType(); - - write_node(node, NULL, sce, NULL); + for (int i = 0; i < roots.getCount(); i++) { + write_node(roots[i], NULL, sce, NULL); } armature_importer.make_armatures(mContext); @@ -2497,7 +3231,7 @@ public: ma->mtex[i] = add_mtex(); ma->mtex[i]->texco = TEXCO_UV; - ma->mtex[i]->tex = add_texture("texture"); + ma->mtex[i]->tex = add_texture("Texture"); ma->mtex[i]->tex->type = TEX_IMAGE; ma->mtex[i]->tex->imaflag &= ~TEX_USEALPHA; ma->mtex[i]->tex->ima = uid_image_map[ima_uid]; @@ -2802,12 +3536,14 @@ public: // this function is called only for animations that pass COLLADAFW::validate virtual bool writeAnimation( const COLLADAFW::Animation* anim ) { + // return true; return anim_importer.write_animation(anim); } // called on post-process stage after writeVisualScenes virtual bool writeAnimationList( const COLLADAFW::AnimationList* animationList ) { + // return true; return anim_importer.write_animation_list(animationList); } diff --git a/source/blender/collada/collada_internal.h b/source/blender/collada/collada_internal.h index 32c3e7af874..278cd37ac66 100644 --- a/source/blender/collada/collada_internal.h +++ b/source/blender/collada/collada_internal.h @@ -26,7 +26,7 @@ public: // TODO need also for angle conversion, time conversion... - void mat4_from_dae(float out[][4], const COLLADABU::Math::Matrix4& in) + void dae_matrix_to_mat4(float out[][4], const COLLADABU::Math::Matrix4& in) { // in DAE, matrices use columns vectors, (see comments in COLLADABUMathMatrix4.h) // so here, to make a blender matrix, we swap columns and rows @@ -58,10 +58,13 @@ public: class TransformBase { public: - void decompose(float mat[][4], float *loc, float *rot, float *size) + void decompose(float mat[][4], float *loc, float eul[3], float quat[4], float *size) { - mat4_to_size( size,mat); - mat4_to_eul( rot,mat); + mat4_to_size(size, mat); + if (eul) + mat4_to_eul(eul, mat); + if (quat) + mat4_to_quat(quat, mat); copy_v3_v3(loc, mat[3]); } }; -- cgit v1.2.3 From 11059178927fcb12fc39079c4b11c00660abc8c7 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Fri, 11 Dec 2009 13:06:18 +0000 Subject: COLLADA branch: small code clean-ups in bone anim export. Correct bone anim export is to be done yet. --- source/blender/collada/DocumentExporter.cpp | 110 ++++++++++++++-------------- 1 file changed, 57 insertions(+), 53 deletions(-) (limited to 'source/blender/collada') diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp index c3550dfd408..6a11fd51e4a 100644 --- a/source/blender/collada/DocumentExporter.cpp +++ b/source/blender/collada/DocumentExporter.cpp @@ -1720,8 +1720,6 @@ public: class AnimationExporter: COLLADASW::LibraryAnimations { Scene *scene; - std::map > fcurves_actionGroup_map; - std::map > rotfcurves_actionGroup_map; public: AnimationExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryAnimations(sw) {} @@ -1875,20 +1873,13 @@ public: // return std::string(rna_path) + axis_name; // return std::string(rna_path) + "." + axis_name; - std::string new_rna_path; - - if (strstr(rna_path, "rotation")) { - new_rna_path = "rotation"; - return new_rna_path + axis_name; - } - else if (strstr(rna_path, "location")) { - new_rna_path = strstr(rna_path, "location"); - return new_rna_path + "." + axis_name; - } - else if (strstr(rna_path, "scale")) { - new_rna_path = strstr(rna_path, "scale"); - return new_rna_path + "." + axis_name; - } + char *name = extract_transform_name(rna_path); + + if (strstr(name, "rotation")) + return std::string("rotation") + axis_name; + else if (!strcmp(name, "location") || !strcmp(name, "scale")) + return std::string(name) + "." + axis_name; + return NULL; } @@ -2012,17 +2003,15 @@ public: calchandles_fcurve(fcu); } - void change_quat_to_eul(Object *ob, bActionGroup *grp, char *grpname) + void change_quat_to_eul(Object *ob, std::vector rcurves, char *grpname) { - std::vector &rot_fcurves = rotfcurves_actionGroup_map[grp]; - FCurve *quatcu[4] = {NULL, NULL, NULL, NULL}; int i; - for (i = 0; i < rot_fcurves.size(); i++) - quatcu[rot_fcurves[i]->array_index] = rot_fcurves[i]; + for (i = 0; i < rcurves.size(); i++) + quatcu[rcurves[i]->array_index] = rcurves[i]; - char *rna_path = rot_fcurves[0]->rna_path; + char *rna_path = rcurves[0]->rna_path; FCurve *eulcu[3] = { create_fcurve(0, rna_path), @@ -2040,7 +2029,7 @@ public: float frame = cu->bezt[j].vec[1][0]; float quat[4] = { - quatcu[0] ? evaluate_fcurve(quatcu[0], frame) : 0.0f, + quatcu[0] ? evaluate_fcurve(quatcu[0], frame) : 1.0f, quatcu[1] ? evaluate_fcurve(quatcu[1], frame) : 0.0f, quatcu[2] ? evaluate_fcurve(quatcu[2], frame) : 0.0f, quatcu[3] ? evaluate_fcurve(quatcu[3], frame) : 0.0f @@ -2061,6 +2050,12 @@ public: } } + char *extract_transform_name(char *rna_path) + { + char *dot = strrchr(rna_path, '.'); + return dot ? (dot + 1) : rna_path; + } + // called for each exported object void operator() (Object *ob) { @@ -2069,12 +2064,22 @@ public: FCurve *fcu = (FCurve*)ob->adt->action->curves.first; if (ob->type == OB_ARMATURE) { + std::map< bActionGroup*, std::vector > lcurve_map, quatcurve_map, eulcurve_map; while (fcu) { - - if (strstr(fcu->rna_path, ".rotation")) - rotfcurves_actionGroup_map[fcu->grp].push_back(fcu); - else fcurves_actionGroup_map[fcu->grp].push_back(fcu); + // rna path should start with "pose.bones" + if (strstr(fcu->rna_path, "pose.bones") == fcu->rna_path) { + char *name = extract_transform_name(fcu->rna_path); + + if (!strcmp(name, "rotation_quaternion")) + quatcurve_map[fcu->grp].push_back(fcu); + else if (!strcmp(name, "rotation_euler")) + eulcurve_map[fcu->grp].push_back(fcu); + else if (!strcmp(name, "scale") || !strcmp(name, "location")) + lcurve_map[fcu->grp].push_back(fcu); + else + fprintf(stderr, "warning: not writing fcurve for %s\n", name); + } fcu = fcu->next; } @@ -2086,40 +2091,39 @@ public: if (!grp) continue; - // write animation for location & scaling - if (fcurves_actionGroup_map.find(grp) == fcurves_actionGroup_map.end()) continue; - - std::vector &fcurves = fcurves_actionGroup_map[grp]; - for (i = 0; i < fcurves.size(); i++) - add_bone_animation(fcurves[i], id_name(ob), std::string(grpname)); - - // ... for rotation - if (rotfcurves_actionGroup_map.find(grp) == rotfcurves_actionGroup_map.end()) - continue; + // write animation for location and scale + if (lcurve_map.find(grp) != lcurve_map.end()) { + std::vector &lcurves = lcurve_map[grp]; + + for (i = 0; i < lcurves.size(); i++) + add_bone_animation(lcurves[i], id_name(ob), std::string(grpname)); + } - // if rotation mode is euler - no need to convert it + // rotation + // FIXME, this only supports XYZ order now, need to support others too if (pchan->rotmode == ROT_MODE_EUL) { - - std::vector &rotfcurves = rotfcurves_actionGroup_map[grp]; - - for (i = 0; i < rotfcurves.size(); i++) - add_bone_animation(rotfcurves[i], id_name(ob), std::string(grpname)); - } + if (eulcurve_map.find(grp) != eulcurve_map.end()) { + std::vector &eulcu = eulcurve_map[grp]; - // convert rotation to euler & write animation - else change_quat_to_eul(ob, grp, grpname); + // write euler values "as is" + for (i = 0; i < eulcu.size(); i++) + add_bone_animation(eulcu[i], id_name(ob), std::string(grpname)); + } + } + else if (pchan->rotmode == ROT_MODE_QUAT) { + // convert rotation to euler and write animation + if (quatcurve_map.find(grp) != quatcurve_map.end()) + change_quat_to_eul(ob, quatcurve_map[grp], grpname); + } } } else { while (fcu) { - - if (!strcmp(fcu->rna_path, "location") || - !strcmp(fcu->rna_path, "scale") || - !strcmp(fcu->rna_path, "rotation_euler")) { - + // TODO "rotation_quaternion" is also possible for objects (although euler is default) + if ((!strcmp(fcu->rna_path, "location") || !strcmp(fcu->rna_path, "scale")) || + (!strcmp(fcu->rna_path, "rotation_euler") && ob->rotmode == ROT_MODE_EUL)) add_animation(fcu, id_name(ob)); - } - + fcu = fcu->next; } } -- cgit v1.2.3 From 4654afb34c040e54d44308ad338ed5ba14aec176 Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Fri, 11 Dec 2009 13:54:56 +0000 Subject: COLLADA branch: patch from Jan Diederich for bump-map export via tag. --- source/blender/collada/DocumentExporter.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'source/blender/collada') diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp index 6a11fd51e4a..e2a3cca4f33 100644 --- a/source/blender/collada/DocumentExporter.cpp +++ b/source/blender/collada/DocumentExporter.cpp @@ -1538,9 +1538,23 @@ public: if (t->mapto & MAP_REF) { ep.setReflective(createTexture(ima, uvname, sampler)); } + // alpha if (t->mapto & MAP_ALPHA) { ep.setTransparent(createTexture(ima, uvname, sampler)); } + // extension: + // Normal map --> Must be stored with tag as different technique, + // since COLLADA doesn't support normal maps, even in current COLLADA 1.5. + if (t->mapto & MAP_NORM) { + COLLADASW::Texture texture(key); + texture.setTexcoord(uvname); + texture.setSampler(*sampler); + // technique FCOLLADA, with the tag, is most likely the best understood, + // most widespread de-facto standard. + texture.setProfileName("FCOLLADA"); + texture.setChildElementName("bump"); + ep.setExtraTechniqueColorOrTexture(COLLADASW::ColorOrTexture(texture)); + } } // performs the actual writing ep.addProfileElements(); -- cgit v1.2.3 From 18eb6d98274126c7c26b85be8cba7a49b3699bab Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Thu, 31 Dec 2009 14:31:42 +0000 Subject: COLLADA branch: fixed a small bug in bone anim import code. --- source/blender/collada/DocumentImporter.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'source/blender/collada') diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index 9ebcc8b191f..3e64f29247b 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -624,6 +624,9 @@ private: if (parent && totchild == 1) { copy_v3_v3(parent->tail, bone->head); + // not setting BONE_CONNECTED because this would lock child bone location with respect to parent + // bone->flag |= BONE_CONNECTED; + // XXX increase this to prevent "very" small bones? const float epsilon = 0.000001f; @@ -2430,7 +2433,7 @@ public: Bone *bone = get_named_bone((bArmature*)ob->data, bone_name); if (!bone) { - fprintf(stderr, "cannot find bone \"%s\"", bone_name); + fprintf(stderr, "cannot find bone \"%s\"\n", bone_name); #ifdef ARMATURE_TEST return NULL; #else @@ -2773,9 +2776,14 @@ public: // use bind matrix if available or calc "current" world mat if (!armature_importer->get_joint_bind_mat(m, node)) { - float temp[4][4]; - get_node_mat(temp, node, NULL, NULL); - mul_m4_m4m4(m, temp, par); + if (par) { + float temp[4][4]; + get_node_mat(temp, node, NULL, NULL); + mul_m4_m4m4(m, temp, par); + } + else { + get_node_mat(m, node, NULL, NULL); + } } COLLADAFW::NodePointerArray& children = node->getChildNodes(); -- cgit v1.2.3 From 06d548bd6fdb9d3e4fc99ecf3b26617648e6b73c Mon Sep 17 00:00:00 2001 From: Arystanbek Dyussenov Date: Tue, 5 Jan 2010 16:07:10 +0000 Subject: COLLADA branch: bone anim export works. Export-import roundtrip is possible. Importer now takes mesh bind position into account. TODO: read/write object-level anim on armatures and fix memleaks. --- source/blender/collada/DocumentExporter.cpp | 668 ++++++++++++++++++---------- source/blender/collada/DocumentImporter.cpp | 23 +- 2 files changed, 440 insertions(+), 251 deletions(-) (limited to 'source/blender/collada') diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp index e2a3cca4f33..38f96a786e5 100644 --- a/source/blender/collada/DocumentExporter.cpp +++ b/source/blender/collada/DocumentExporter.cpp @@ -21,6 +21,7 @@ extern "C" { #include "BKE_DerivedMesh.h" #include "BKE_fcurve.h" +#include "BKE_animsys.h" #include "BLI_util.h" #include "BLI_fileops.h" #include "ED_keyframing.h" @@ -36,6 +37,7 @@ extern "C" #include "BKE_armature.h" #include "BKE_image.h" #include "BKE_utildefines.h" +#include "BKE_object.h" #include "BLI_math.h" #include "BLI_string.h" @@ -198,6 +200,12 @@ static std::string get_camera_id(Object *ob) return translate_id(id_name(ob)) + "-camera"; } +std::string get_joint_id(Bone *bone, Object *ob_arm) +{ + return translate_id(id_name(ob_arm) + "_" + bone->name); +} + + /* Utilities to avoid code duplication. Definition can take some time to understand, but they should be useful. @@ -851,11 +859,6 @@ private: return ob_arm; } - std::string get_joint_id(Bone *bone, Object *ob_arm) - { - return translate_id(id_name(ob_arm) + "_" + bone->name); - } - std::string get_joint_sid(Bone *bone) { char name[100]; @@ -1734,7 +1737,9 @@ public: class AnimationExporter: COLLADASW::LibraryAnimations { Scene *scene; + public: + AnimationExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryAnimations(sw) {} void exportAnimations(Scene *sce) @@ -1748,17 +1753,278 @@ public: closeLibrary(); } - // create for each transform axis + // called for each exported object + void operator() (Object *ob) + { + if (!ob->adt || !ob->adt->action) return; + + FCurve *fcu = (FCurve*)ob->adt->action->curves.first; + + if (ob->type == OB_ARMATURE) { + if (!ob->data) return; + + bArmature *arm = (bArmature*)ob->data; + for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next) + write_bone_animation(ob, bone); + } + else { + while (fcu) { + // TODO "rotation_quaternion" is also possible for objects (although euler is default) + if ((!strcmp(fcu->rna_path, "location") || !strcmp(fcu->rna_path, "scale")) || + (!strcmp(fcu->rna_path, "rotation_euler") && ob->rotmode == ROT_MODE_EUL)) + dae_animation(fcu, id_name(ob)); + + fcu = fcu->next; + } + } + } + +protected: + + void dae_animation(FCurve *fcu, std::string ob_name) + { + const char *axis_names[] = {"X", "Y", "Z"}; + const char *axis_name = NULL; + char anim_id[200]; + char anim_name[200]; + + if (fcu->array_index < 3) + axis_name = axis_names[fcu->array_index]; + + BLI_snprintf(anim_id, sizeof(anim_id), "%s.%s.%s", (char*)translate_id(ob_name).c_str(), + fcu->rna_path, axis_names[fcu->array_index]); + BLI_snprintf(anim_name, sizeof(anim_name), "%s.%s.%s", + (char*)ob_name.c_str(), fcu->rna_path, axis_names[fcu->array_index]); + + // check rna_path is one of: rotation, scale, location + + openAnimation(anim_id, anim_name); + + // create input source + std::string input_id = create_source_from_fcurve(Sampler::INPUT, fcu, anim_id, axis_name); + + // create output source + std::string output_id = create_source_from_fcurve(Sampler::OUTPUT, fcu, anim_id, axis_name); + + // create interpolations source + std::string interpolation_id = create_interpolation_source(fcu->totvert, anim_id, axis_name); + + std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX; + COLLADASW::LibraryAnimations::Sampler sampler(sampler_id); + std::string empty; + sampler.addInput(Sampler::INPUT, COLLADABU::URI(empty, input_id)); + sampler.addInput(Sampler::OUTPUT, COLLADABU::URI(empty, output_id)); + + // this input is required + sampler.addInput(Sampler::INTERPOLATION, COLLADABU::URI(empty, interpolation_id)); + + addSampler(sampler); + + std::string target = translate_id(ob_name) + + "/" + get_transform_sid(fcu->rna_path, -1, axis_name); + addChannel(COLLADABU::URI(empty, sampler_id), target); + + closeAnimation(); + } + + void write_bone_animation(Object *ob_arm, Bone *bone) + { + if (!ob_arm->adt) + return; + + for (int i = 0; i < 3; i++) + sample_and_write_bone_animation(ob_arm, bone, i); + + for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next) + write_bone_animation(ob_arm, child); + } + + void sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type) + { + bArmature *arm = (bArmature*)ob_arm->data; + int flag = arm->flag; + std::vector fra; + char prefix[256]; + + BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone->name); + + bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name); + if (!pchan) + return; + + switch (transform_type) { + case 0: + find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode); + break; + case 1: + find_frames(ob_arm, fra, prefix, "scale"); + break; + case 2: + find_frames(ob_arm, fra, prefix, "location"); + break; + default: + return; + } + + // exit rest position + if (flag & ARM_RESTPOS) { + arm->flag &= ~ARM_RESTPOS; + where_is_pose(scene, ob_arm); + } + + if (fra.size()) { + float *v = (float*)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames"); + sample_animation(v, fra, transform_type, bone, ob_arm); + + if (transform_type == 0) { + // write x, y, z curves separately if it is rotation + float *c = (float*)MEM_callocN(sizeof(float) * fra.size(), "temp. anim frames"); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < fra.size(); j++) + c[j] = v[j * 3 + i]; + + dae_bone_animation(fra, c, transform_type, i, id_name(ob_arm), bone->name); + } + MEM_freeN(c); + } + else { + // write xyz at once if it is location or scale + dae_bone_animation(fra, v, transform_type, -1, id_name(ob_arm), bone->name); + } + + MEM_freeN(v); + } + + // restore restpos + if (flag & ARM_RESTPOS) + arm->flag = flag; + where_is_pose(scene, ob_arm); + } + + void sample_animation(float *v, std::vector &frames, int type, Bone *bone, Object *ob_arm) + { + bPoseChannel *pchan, *parchan = NULL; + bPose *pose = ob_arm->pose; + + pchan = get_pose_channel(pose, bone->name); + + if (!pchan) + return; + + parchan = pchan->parent; + + enable_fcurves(ob_arm->adt->action, bone->name); + + std::vector::iterator it; + for (it = frames.begin(); it != frames.end(); it++) { + float mat[4][4], ipar[4][4]; + + float ctime = bsystem_time(scene, ob_arm, *it, 0.0f); + + BKE_animsys_evaluate_animdata(&ob_arm->id, ob_arm->adt, *it, ADT_RECALC_ANIM); + where_is_pose_bone(scene, ob_arm, pchan, ctime); + + // compute bone local mat + if (bone->parent) { + invert_m4_m4(ipar, parchan->pose_mat); + mul_m4_m4m4(mat, pchan->pose_mat, ipar); + } + else + copy_m4_m4(mat, pchan->pose_mat); + + switch (type) { + case 0: + mat4_to_eul(v, mat); + break; + case 1: + mat4_to_size(v, mat); + break; + case 2: + copy_v3_v3(v, mat[3]); + break; + } + + v += 3; + } + + enable_fcurves(ob_arm->adt->action, NULL); + } + + // dae_bone_animation -> add_bone_animation + // (blend this into dae_bone_animation) + void dae_bone_animation(std::vector &fra, float *v, int tm_type, int axis, std::string ob_name, std::string bone_name) + { + const char *axis_names[] = {"X", "Y", "Z"}; + const char *axis_name = NULL; + char anim_id[200]; + char anim_name[200]; + bool is_rot = tm_type == 0; + + if (!fra.size()) + return; - float convert_time(float frame) { + char rna_path[200]; + BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].%s", bone_name.c_str(), + tm_type == 0 ? "rotation_quaternion" : (tm_type == 1 ? "scale" : "location")); + + if (axis > -1) + axis_name = axis_names[axis]; + + std::string transform_sid = get_transform_sid(NULL, tm_type, axis_name); + + BLI_snprintf(anim_id, sizeof(anim_id), "%s.%s.%s", (char*)translate_id(ob_name).c_str(), + (char*)translate_id(bone_name).c_str(), (char*)transform_sid.c_str()); + BLI_snprintf(anim_name, sizeof(anim_name), "%s.%s.%s", + (char*)ob_name.c_str(), (char*)bone_name.c_str(), (char*)transform_sid.c_str()); + + // TODO check rna_path is one of: rotation, scale, location + + openAnimation(anim_id, anim_name); + + // create input source + std::string input_id = create_source_from_vector(Sampler::INPUT, fra, is_rot, anim_id, axis_name); + + // create output source + std::string output_id; + if (axis == -1) + output_id = create_xyz_source(v, fra.size(), anim_id); + else + output_id = create_source_from_array(Sampler::OUTPUT, v, fra.size(), is_rot, anim_id, axis_name); + + // create interpolations source + std::string interpolation_id = create_interpolation_source(fra.size(), anim_id, axis_name); + + std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX; + COLLADASW::LibraryAnimations::Sampler sampler(sampler_id); + std::string empty; + sampler.addInput(Sampler::INPUT, COLLADABU::URI(empty, input_id)); + sampler.addInput(Sampler::OUTPUT, COLLADABU::URI(empty, output_id)); + + // TODO create in/out tangents source + + // this input is required + sampler.addInput(Sampler::INTERPOLATION, COLLADABU::URI(empty, interpolation_id)); + + addSampler(sampler); + + std::string target = translate_id(ob_name + "_" + bone_name) + "/" + transform_sid; + addChannel(COLLADABU::URI(empty, sampler_id), target); + + closeAnimation(); + } + + float convert_time(float frame) + { return FRA2TIME(frame); } - float convert_angle(float angle) { + float convert_angle(float angle) + { return COLLADABU::Math::Utils::radToDegF(angle); } - std::string get_semantic_suffix(Sampler::Semantic semantic) { + std::string get_semantic_suffix(Sampler::Semantic semantic) + { switch(semantic) { case Sampler::INPUT: return INPUT_SOURCE_ID_SUFFIX; @@ -1775,17 +2041,25 @@ public: } void add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param, - Sampler::Semantic semantic, bool rotation, const char *axis) { + Sampler::Semantic semantic, bool is_rot, const char *axis) + { switch(semantic) { case Sampler::INPUT: param.push_back("TIME"); break; case Sampler::OUTPUT: - if (rotation) { + if (is_rot) { param.push_back("ANGLE"); } else { - param.push_back(axis); + if (axis) { + param.push_back(axis); + } + else { + param.push_back("X"); + param.push_back("Y"); + param.push_back("Z"); + } } break; case Sampler::IN_TANGENT: @@ -1820,7 +2094,7 @@ public: } } - std::string create_source(Sampler::Semantic semantic, FCurve *fcu, std::string& anim_id, const char *axis_name) + std::string create_source_from_fcurve(Sampler::Semantic semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name) { std::string source_id = anim_id + get_semantic_suffix(semantic); @@ -1854,26 +2128,28 @@ public: return source_id; } - std::string create_interpolation_source(FCurve *fcu, std::string& anim_id, const char *axis_name) + std::string create_source_from_array(Sampler::Semantic semantic, float *v, int tot, bool is_rot, const std::string& anim_id, const char *axis_name) { - std::string source_id = anim_id + get_semantic_suffix(Sampler::INTERPOLATION); - - //bool is_rotation = !strcmp(fcu->rna_path, "rotation"); + std::string source_id = anim_id + get_semantic_suffix(semantic); - COLLADASW::NameSource source(mSW); + COLLADASW::FloatSourceF source(mSW); source.setId(source_id); source.setArrayId(source_id + ARRAY_ID_SUFFIX); - source.setAccessorCount(fcu->totvert); + source.setAccessorCount(tot); source.setAccessorStride(1); COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); - param.push_back("INTERPOLATION"); + add_source_parameters(param, semantic, is_rot, axis_name); source.prepareToAppendValues(); - for (int i = 0; i < fcu->totvert; i++) { - // XXX - source.appendValues(LINEAR_NAME); + for (int i = 0; i < tot; i++) { + float val = v[i]; + if (semantic == Sampler::INPUT) + val = convert_time(val); + else if (is_rot) + val = convert_angle(val); + source.appendValues(val); } source.finish(); @@ -1881,187 +2157,105 @@ public: return source_id; } - std::string get_transform_sid(char *rna_path, const char *axis_name) + std::string create_source_from_vector(Sampler::Semantic semantic, std::vector &fra, bool is_rot, const std::string& anim_id, const char *axis_name) { - // if (!strcmp(rna_path, "rotation")) -// return std::string(rna_path) + axis_name; - -// return std::string(rna_path) + "." + axis_name; - char *name = extract_transform_name(rna_path); - - if (strstr(name, "rotation")) - return std::string("rotation") + axis_name; - else if (!strcmp(name, "location") || !strcmp(name, "scale")) - return std::string(name) + "." + axis_name; - - return NULL; - } + std::string source_id = anim_id + get_semantic_suffix(semantic); - void add_animation(FCurve *fcu, std::string ob_name) - { - const char *axis_names[] = {"X", "Y", "Z"}; - const char *axis_name = NULL; - char c_anim_id[100]; // careful! - char c_anim_name[100]; // careful! + COLLADASW::FloatSourceF source(mSW); + source.setId(source_id); + source.setArrayId(source_id + ARRAY_ID_SUFFIX); + source.setAccessorCount(fra.size()); + source.setAccessorStride(1); - if (fcu->array_index < 3) - axis_name = axis_names[fcu->array_index]; - - BLI_snprintf(c_anim_id, sizeof(c_anim_id), "%s.%s.%s", (char*)translate_id(ob_name).c_str(), - fcu->rna_path, axis_names[fcu->array_index]); - std::string anim_id(c_anim_id); - BLI_snprintf(c_anim_name, sizeof(c_anim_name), "%s.%s.%s", - (char*)ob_name.c_str(), fcu->rna_path, axis_names[fcu->array_index]); - std::string anim_name = c_anim_name; - - // check rna_path is one of: rotation, scale, location - - openAnimation(anim_id, anim_name); - - // create input source - std::string input_id = create_source(Sampler::INPUT, fcu, anim_id, axis_name); - - // create output source - std::string output_id = create_source(Sampler::OUTPUT, fcu, anim_id, axis_name); - - // create interpolations source - std::string interpolation_id = create_interpolation_source(fcu, anim_id, axis_name); - - std::string sampler_id = anim_id + SAMPLER_ID_SUFFIX; - COLLADASW::LibraryAnimations::Sampler sampler(sampler_id); - std::string empty; - sampler.addInput(Sampler::INPUT, COLLADABU::URI(empty, input_id)); - sampler.addInput(Sampler::OUTPUT, COLLADABU::URI(empty, output_id)); + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); + add_source_parameters(param, semantic, is_rot, axis_name); - // this input is required - sampler.addInput(Sampler::INTERPOLATION, COLLADABU::URI(empty, interpolation_id)); + source.prepareToAppendValues(); - addSampler(sampler); + std::vector::iterator it; + for (it = fra.begin(); it != fra.end(); it++) { + float val = *it; + if (semantic == Sampler::INPUT) + val = convert_time(val); + else if (is_rot) + val = convert_angle(val); + source.appendValues(val); + } - std::string target = translate_id(ob_name) - + "/" + get_transform_sid(fcu->rna_path, axis_name); - addChannel(COLLADABU::URI(empty, sampler_id), target); + source.finish(); - closeAnimation(); + return source_id; } - - void add_bone_animation(FCurve *fcu, std::string ob_name, std::string bone_name) + + // only used for sources with OUTPUT semantic + std::string create_xyz_source(float *v, int tot, const std::string& anim_id) { - const char *axis_names[] = {"X", "Y", "Z"}; - const char *axis_name = NULL; - char c_anim_id[100]; // careful! - char c_anim_name[100]; // careful! + Sampler::Semantic semantic = Sampler::OUTPUT; + std::string source_id = anim_id + get_semantic_suffix(semantic); - if (fcu->array_index < 3) - axis_name = axis_names[fcu->array_index]; - - std::string transform_sid = get_transform_sid(fcu->rna_path, axis_name); + COLLADASW::FloatSourceF source(mSW); + source.setId(source_id); + source.setArrayId(source_id + ARRAY_ID_SUFFIX); + source.setAccessorCount(tot); + source.setAccessorStride(3); - BLI_snprintf(c_anim_id, sizeof(c_anim_id), "%s.%s.%s", (char*)translate_id(ob_name).c_str(), - (char*)translate_id(bone_name).c_str(), (char*)transform_sid.c_str()); - std::string anim_id(c_anim_id); - BLI_snprintf(c_anim_name, sizeof(c_anim_name), "%s.%s.%s", - (char*)ob_name.c_str(), (char*)bone_name.c_str(), (char*)transform_sid.c_str()); - std::string anim_name(c_anim_name); + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); + add_source_parameters(param, semantic, false, NULL); - // check rna_path is one of: rotation, scale, location + source.prepareToAppendValues(); - openAnimation(anim_id, anim_name); + for (int i = 0; i < tot; i++) { + source.appendValues(*v, *(v + 1), *(v + 2)); + v += 3; + } - // create input source - std::string input_id = create_source(Sampler::INPUT, fcu, anim_id, axis_name); + source.finish(); - // create output source - std::string output_id = create_source(Sampler::OUTPUT, fcu, anim_id, axis_name); + return source_id; + } - // create interpolations source - std::string interpolation_id = create_interpolation_source(fcu, anim_id, axis_name); + std::string create_interpolation_source(int tot, const std::string& anim_id, const char *axis_name) + { + std::string source_id = anim_id + get_semantic_suffix(Sampler::INTERPOLATION); - std::string sampler_id = anim_id + SAMPLER_ID_SUFFIX; - COLLADASW::LibraryAnimations::Sampler sampler(sampler_id); - std::string empty; - sampler.addInput(Sampler::INPUT, COLLADABU::URI(empty, input_id)); - sampler.addInput(Sampler::OUTPUT, COLLADABU::URI(empty, output_id)); + COLLADASW::NameSource source(mSW); + source.setId(source_id); + source.setArrayId(source_id + ARRAY_ID_SUFFIX); + source.setAccessorCount(tot); + source.setAccessorStride(1); + + COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList(); + param.push_back("INTERPOLATION"); - // this input is required - sampler.addInput(Sampler::INTERPOLATION, COLLADABU::URI(empty, interpolation_id)); + source.prepareToAppendValues(); - addSampler(sampler); + for (int i = 0; i < tot; i++) { + source.appendValues(LINEAR_NAME); + } - std::string target = translate_id(ob_name + "_" + bone_name) + "/" + transform_sid; - addChannel(COLLADABU::URI(empty, sampler_id), target); + source.finish(); - closeAnimation(); - } - - FCurve *create_fcurve(int array_index, char *rna_path) - { - FCurve *fcu = (FCurve*)MEM_callocN(sizeof(FCurve), "FCurve"); - - fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED); - fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path)); - fcu->array_index = array_index; - return fcu; - } - - void create_bezt(FCurve *fcu, float frame, float output) - { - BezTriple bez; - memset(&bez, 0, sizeof(BezTriple)); - bez.vec[1][0] = frame; - bez.vec[1][1] = output; - bez.ipo = U.ipo_new; /* use default interpolation mode here... */ - bez.f1 = bez.f2 = bez.f3 = SELECT; - bez.h1 = bez.h2 = HD_AUTO; - insert_bezt_fcurve(fcu, &bez, 0); - calchandles_fcurve(fcu); + return source_id; } - - void change_quat_to_eul(Object *ob, std::vector rcurves, char *grpname) + + std::string get_transform_sid(char *rna_path, int tm_type, const char *axis_name) { - FCurve *quatcu[4] = {NULL, NULL, NULL, NULL}; - int i; - - for (i = 0; i < rcurves.size(); i++) - quatcu[rcurves[i]->array_index] = rcurves[i]; - - char *rna_path = rcurves[0]->rna_path; - - FCurve *eulcu[3] = { - create_fcurve(0, rna_path), - create_fcurve(1, rna_path), - create_fcurve(2, rna_path) - }; - - for (i = 0; i < 4; i++) { - - FCurve *cu = quatcu[i]; - - if (!cu) continue; - - for (int j = 0; j < cu->totvert; j++) { - float frame = cu->bezt[j].vec[1][0]; - - float quat[4] = { - quatcu[0] ? evaluate_fcurve(quatcu[0], frame) : 1.0f, - quatcu[1] ? evaluate_fcurve(quatcu[1], frame) : 0.0f, - quatcu[2] ? evaluate_fcurve(quatcu[2], frame) : 0.0f, - quatcu[3] ? evaluate_fcurve(quatcu[3], frame) : 0.0f - }; - - float eul[3]; - - quat_to_eul( eul,quat); - - for (int k = 0; k < 3; k++) - create_bezt(eulcu[k], frame, eul[k]); - } + if (rna_path) { + char *name = extract_transform_name(rna_path); + + if (strstr(name, "rotation")) + return std::string("rotation") + axis_name; + else if (!strcmp(name, "location") || !strcmp(name, "scale")) + return std::string(name); } - - for (i = 0; i < 3; i++) { - add_bone_animation(eulcu[i], id_name(ob), std::string(grpname)); - free_fcurve(eulcu[i]); + else { + if (tm_type == 0) + return std::string("rotation") + axis_name; + else + return tm_type == 1 ? "scale" : "location"; } + + return NULL; } char *extract_transform_name(char *rna_path) @@ -2070,75 +2264,54 @@ public: return dot ? (dot + 1) : rna_path; } - // called for each exported object - void operator() (Object *ob) + void find_frames(Object *ob, std::vector &fra, const char *prefix, const char *tm_name) { - if (!ob->adt || !ob->adt->action) return; - - FCurve *fcu = (FCurve*)ob->adt->action->curves.first; - - if (ob->type == OB_ARMATURE) { - std::map< bActionGroup*, std::vector > lcurve_map, quatcurve_map, eulcurve_map; - - while (fcu) { - // rna path should start with "pose.bones" - if (strstr(fcu->rna_path, "pose.bones") == fcu->rna_path) { - char *name = extract_transform_name(fcu->rna_path); - - if (!strcmp(name, "rotation_quaternion")) - quatcurve_map[fcu->grp].push_back(fcu); - else if (!strcmp(name, "rotation_euler")) - eulcurve_map[fcu->grp].push_back(fcu); - else if (!strcmp(name, "scale") || !strcmp(name, "location")) - lcurve_map[fcu->grp].push_back(fcu); - else - fprintf(stderr, "warning: not writing fcurve for %s\n", name); - } - - fcu = fcu->next; - } - - for (bPoseChannel *pchan = (bPoseChannel*)ob->pose->chanbase.first; pchan; pchan = pchan->next) { - int i; - char *grpname = pchan->name; - bActionGroup *grp = action_groups_find_named(ob->adt->action, grpname); - - if (!grp) continue; - - // write animation for location and scale - if (lcurve_map.find(grp) != lcurve_map.end()) { - std::vector &lcurves = lcurve_map[grp]; - - for (i = 0; i < lcurves.size(); i++) - add_bone_animation(lcurves[i], id_name(ob), std::string(grpname)); - } - - // rotation - // FIXME, this only supports XYZ order now, need to support others too - if (pchan->rotmode == ROT_MODE_EUL) { - if (eulcurve_map.find(grp) != eulcurve_map.end()) { - std::vector &eulcu = eulcurve_map[grp]; - - // write euler values "as is" - for (i = 0; i < eulcu.size(); i++) - add_bone_animation(eulcu[i], id_name(ob), std::string(grpname)); - } - } - else if (pchan->rotmode == ROT_MODE_QUAT) { - // convert rotation to euler and write animation - if (quatcurve_map.find(grp) != quatcurve_map.end()) - change_quat_to_eul(ob, quatcurve_map[grp], grpname); + FCurve *fcu= (FCurve*)ob->adt->action->curves.first; + + for (; fcu; fcu = fcu->next) { + if (prefix && strncmp(prefix, fcu->rna_path, strlen(prefix))) + continue; + + char *name = extract_transform_name(fcu->rna_path); + if (!strcmp(name, tm_name)) { + for (int i = 0; i < fcu->totvert; i++) { + float f = fcu->bezt[i].vec[1][0]; + if (std::find(fra.begin(), fra.end(), f) == fra.end()) + fra.push_back(f); } } } - else { - while (fcu) { - // TODO "rotation_quaternion" is also possible for objects (although euler is default) - if ((!strcmp(fcu->rna_path, "location") || !strcmp(fcu->rna_path, "scale")) || - (!strcmp(fcu->rna_path, "rotation_euler") && ob->rotmode == ROT_MODE_EUL)) - add_animation(fcu, id_name(ob)); + } - fcu = fcu->next; + void find_rotation_frames(Object *ob, std::vector &fra, const char *prefix, int rotmode) + { + if (rotmode > 0) + find_frames(ob, fra, prefix, "rotation_euler"); + else if (rotmode == ROT_MODE_QUAT) + find_frames(ob, fra, prefix, "rotation_quaternion"); + else if (rotmode == ROT_MODE_AXISANGLE) + ; + } + + // enable fcurves driving a specific bone, disable all the rest + // if bone_name = NULL enable all fcurves + void enable_fcurves(bAction *act, char *bone_name) + { + FCurve *fcu; + char prefix[200]; + + if (bone_name) + BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name); + + for (fcu = (FCurve*)act->curves.first; fcu; fcu = fcu->next) { + if (bone_name) { + if (!strncmp(fcu->rna_path, prefix, strlen(prefix))) + fcu->flag &= ~FCURVE_DISABLED; + else + fcu->flag |= FCURVE_DISABLED; + } + else { + fcu->flag &= ~FCURVE_DISABLED; } } } @@ -2210,3 +2383,12 @@ void DocumentExporter::exportCurrentScene(Scene *sce, const char* filename) void DocumentExporter::exportScenes(const char* filename) { } + +/* + +NOTES: + +* AnimationExporter::sample_animation enables all curves on armature, this is undesirable for a user + + */ + diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index 3e64f29247b..6fa9656391b 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -43,6 +43,8 @@ extern "C" #include "ED_armature.h" #include "ED_mesh.h" // ED_vgroup_vert_add, ... #include "ED_anim_api.h" +#include "ED_object.h" + #include "WM_types.h" #include "WM_api.h" @@ -82,6 +84,7 @@ extern "C" #include "DNA_mesh_types.h" #include "DNA_material_types.h" #include "DNA_scene_types.h" +#include "DNA_modifier_types.h" #include "MEM_guardedalloc.h" @@ -497,20 +500,24 @@ private: void link_armature(bContext *C, Object *ob, std::map& joint_by_uid, TransformReader *tm) { + Object workob; + Scene *scene = CTX_data_scene(C); + + ModifierData *md = ED_object_modifier_add(NULL, scene, ob, NULL, eModifierType_Armature); + ((ArmatureModifierData *)md)->object = ob_arm; + tm->decompose(bind_shape_matrix, ob->loc, ob->rot, NULL, ob->size); ob->parent = ob_arm; - ob->partype = PARSKEL; + ob->partype = PAROBJECT; + + what_does_parent(scene, ob, &workob); + invert_m4_m4(ob->parentinv, workob.obmat); + ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA; ((bArmature*)ob_arm->data)->deformflag = ARM_DEF_VGROUP; - // we need armature matrix here... where do we get it from I wonder... - // root node/joint? or node with ? - float parmat[4][4]; - unit_m4(parmat); - invert_m4_m4(ob->parentinv, parmat); - // create all vertex groups std::vector::iterator it; int joint_index; @@ -551,7 +558,7 @@ private: } } - DAG_scene_sort(CTX_data_scene(C)); + DAG_scene_sort(scene); DAG_ids_flush_update(0); WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); } -- cgit v1.2.3