COLLADA branch: bone animation import works!
authorArystanbek Dyussenov <arystan.d@gmail.com>
Sun, 29 Nov 2009 14:38:50 +0000 (14:38 +0000)
committerArystanbek Dyussenov <arystan.d@gmail.com>
Sun, 29 Nov 2009 14:38:50 +0000 (14:38 +0000)
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/blenkernel/BKE_texture.h
source/blender/blenkernel/intern/texture.c
source/blender/blenlib/BLI_util.h
source/blender/blenlib/intern/util.c
source/blender/collada/DocumentExporter.cpp
source/blender/collada/DocumentImporter.cpp
source/blender/collada/collada_internal.h

index b9dc5916e69ea2fa5c6bc4052b2131eeada7bda7..95ada45f5d817c44c33147c4e3584f3df5c62a0e 100644 (file)
@@ -62,7 +62,7 @@ int do_colorband(struct ColorBand *coba, float in, float out[4]);
 void colorband_table_RGBA(struct ColorBand *coba, float **array, int *size);
 
 void default_tex(struct Tex *tex);
-struct Tex *add_texture(char *name);
+struct Tex *add_texture(const char *name);
 void default_mtex(struct MTex *mtex);
 struct MTex *add_mtex(void);
 struct Tex *copy_texture(struct Tex *tex);
index 0171c58f2c687754111258d3b0b18b5c0b3525a6..818e6195049c92b37e9d1898e2b7d4278a225fed 100644 (file)
@@ -518,7 +518,7 @@ void default_tex(Tex *tex)
 
 /* ------------------------------------------------------------------------- */
 
-Tex *add_texture(char *name)
+Tex *add_texture(const char *name)
 {
        Tex *tex;
 
index 7642b71eea08a242448cf5c42193c3aac082a038..ca483903d46b776ecd73900056eb49b9d7009ae9 100644 (file)
@@ -61,7 +61,7 @@ void BLI_split_dirfile_basic(const char *string, char *dir, char *file);
 void BLI_join_dirfile(char *string, const char *dir, const char *file);
 void BLI_getlastdir(const char* dir, char *last, int maxlen);
 int BLI_testextensie(const char *str, const char *ext);
-void BLI_uniquename(struct ListBase *list, void *vlink, char defname[], char delim, short name_offs, short len);
+void BLI_uniquename(struct ListBase *list, void *vlink, const char defname[], char delim, short name_offs, short len);
 void BLI_newname(char * name, int add);
 int BLI_stringdec(char *string, char *kop, char *start, unsigned short *numlen);
 void BLI_stringenc(char *string, char *kop, char *start, unsigned short numlen, int pic);
index 39afced92bc2b20342c2bfa0d4d5d045936dd7e0..5ff4dfe4e963208c738ab2f3845a0d29a23a8c72 100644 (file)
@@ -223,7 +223,7 @@ void BLI_newname(char *name, int add)
  *     defname: the name that should be used by default if none is specified already
  *     delim: the character which acts as a delimeter between parts of the name
  */
-void BLI_uniquename(ListBase *list, void *vlink, char defname[], char delim, short name_offs, short len)
+void BLI_uniquename(ListBase *list, void *vlink, const char defname[], char delim, short name_offs, short len)
 {
        Link *link;
        char tempname[128];
index fac7b2c882a6071022dffa4471d0eaeb112afa34..c3550dfd408730d9f5a715059db5e66dc647264b 100644 (file)
@@ -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 <rotate> representing object rotation
index 83f0debb60dcc91f624ae5ed30fc91ed3b8a9423..381632523fa3d0e3b955d5d4022b0d3a4fc09c46 100644 (file)
@@ -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 <float.h>
 
 // #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<COLLADAFW::UniqueId, COLLADAFW::Node*>& 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<COLLADAFW::UniqueId, SkinInfo>::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<COLLADAFW::UniqueId, std::vector<FCurve*> > uid_fcurve_map;
+       std::map<COLLADAFW::UniqueId, std::vector<FCurve*> > curve_map;
        std::map<COLLADAFW::UniqueId, TransformReader::Animation> uid_animated_map;
-       std::map<bActionGroup*, std::vector<FCurve*> > fcurves_actionGroup_map;
+       // std::map<bActionGroup*, std::vector<FCurve*> > fcurves_actionGroup_map;
+       std::map<COLLADAFW::UniqueId, const COLLADAFW::AnimationList*> animlist_map;
+       std::vector<FCurve*> unused_curves;
+       std::map<COLLADAFW::UniqueId, Object*> 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<FCurve*>& 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<FCurve*>::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<FCurve*>& fcurves = uid_fcurve_map[curve->getUniqueId()];
+               std::vector<FCurve*>& 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<FCurve*>& 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<FCurve*>::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<FCurve*>::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<FCurve*>& fcurves = uid_fcurve_map[anim_uid];
+                                       std::vector<FCurve*>& 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<FCurve*>& fcurves = uid_fcurve_map[anim_uid];
+                                       std::vector<FCurve*>& 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<FCurve*>& 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<COLLADAFW::UniqueId, Object*>& object_map,
+                                                               std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map,
+                                                               COLLADAFW::Transformation::TransformationType tm_type,
+                                                               Object *par_job = NULL)
+#else
+       void translate_animation(COLLADAFW::Node *node,
+                                                        std::map<COLLADAFW::UniqueId, Object*>& object_map,
+                                                        std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& 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<float> frames;
+
+               // for each <rotate>, <translate>, etc. there is a separate Transformation
+               const COLLADAFW::TransformationPointerArray& tms = node->getTransformations();
+
+               std::vector<FCurve*> 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<FCurve*>& 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<FCurve*>::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<FCurve*>::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<float>::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<FCurve*>::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<FCurve*>& 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, "<rotate> 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 <node>
+               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<COLLADAFW::UniqueId, Camera*> uid_camera_map;
        std::map<COLLADAFW::UniqueId, Lamp*> uid_lamp_map;
        std::map<Material*, TexIndexTextureArrayMap> material_texture_mapping_map;
+       std::map<COLLADAFW::UniqueId, Object*> object_map;
+       std::vector<const COLLADAFW::VisualScene*> vscenes;
+
+       std::map<COLLADAFW::UniqueId, COLLADAFW::Node*> root_map; // find root joint by child joint uid, for bone tree evaluation during resampling
+
        // animation
        // std::map<COLLADAFW::UniqueId, std::vector<FCurve*> > 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<const COLLADAFW::VisualScene*>::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 <node> in <visual_scene>:
                // create an Object
@@ -2437,15 +3171,15 @@ public:
                // writeGeometry because <geometry> does not reference <node>,
                // we link Objects with Meshes here
 
+               vscenes.push_back(visualScene);
+
                // TODO: create a new scene except the selected <visual_scene> - 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);
        }
        
index 32c3e7af8740508b949d4c9078c0ffdd9fe56064..278cd37ac66b18b98233adea98cbb70f3bb2549e 100644 (file)
@@ -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]);
        }
 };