Blender  V2.59
AnimationImporter.cpp
Go to the documentation of this file.
00001 /*
00002  * $Id: AnimationImporter.cpp 37664 2011-06-20 12:43:10Z jesterking $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory.
00021  *
00022  * ***** END GPL LICENSE BLOCK *****
00023  */
00024 
00029 #include <stddef.h>
00030 
00031 /* COLLADABU_ASSERT, may be able to remove later */
00032 #include "COLLADABUPlatform.h"
00033 
00034 #include "DNA_armature_types.h"
00035 
00036 #include "ED_keyframing.h"
00037 
00038 #include "BLI_listbase.h"
00039 #include "BLI_math.h"
00040 #include "BLI_path_util.h"
00041 #include "BLI_string.h"
00042 
00043 #include "BKE_action.h"
00044 #include "BKE_armature.h"
00045 #include "BKE_fcurve.h"
00046 #include "BKE_object.h"
00047 
00048 #include "MEM_guardedalloc.h"
00049 
00050 #include "collada_utils.h"
00051 #include "AnimationImporter.h"
00052 #include "ArmatureImporter.h"
00053 
00054 #include <algorithm>
00055 #include <cstddef>
00056 
00057 // first try node name, if not available (since is optional), fall back to original id
00058 template<class T>
00059 static const char *bc_get_joint_name(T *node)
00060 {
00061         const std::string& id = node->getName();
00062         return id.size() ? id.c_str() : node->getOriginalId().c_str();
00063 }
00064 
00065 FCurve *AnimationImporter::create_fcurve(int array_index, const char *rna_path)
00066 {
00067         FCurve *fcu = (FCurve*)MEM_callocN(sizeof(FCurve), "FCurve");
00068         
00069         fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
00070         fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
00071         fcu->array_index = array_index;
00072         return fcu;
00073 }
00074         
00075 void AnimationImporter::create_bezt(FCurve *fcu, float frame, float output)
00076 {
00077         BezTriple bez;
00078         memset(&bez, 0, sizeof(BezTriple));
00079         bez.vec[1][0] = frame;
00080         bez.vec[1][1] = output;
00081         bez.ipo = U.ipo_new; /* use default interpolation mode here... */
00082         bez.f1 = bez.f2 = bez.f3 = SELECT;
00083         bez.h1 = bez.h2 = HD_AUTO;
00084         insert_bezt_fcurve(fcu, &bez, 0);
00085         calchandles_fcurve(fcu);
00086 }
00087 
00088 // create one or several fcurves depending on the number of parameters being animated
00089 void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve)
00090 {
00091         COLLADAFW::FloatOrDoubleArray& input = curve->getInputValues();
00092         COLLADAFW::FloatOrDoubleArray& output = curve->getOutputValues();
00093         // COLLADAFW::FloatOrDoubleArray& intan = curve->getInTangentValues();
00094         // COLLADAFW::FloatOrDoubleArray& outtan = curve->getOutTangentValues();
00095         float fps = (float)FPS;
00096         size_t dim = curve->getOutDimension();
00097         unsigned int i;
00098 
00099         std::vector<FCurve*>& fcurves = curve_map[curve->getUniqueId()];
00100 
00101         switch (dim) {
00102         case 1: // X, Y, Z or angle
00103         case 3: // XYZ
00104         case 16: // matrix
00105                 {
00106                         for (i = 0; i < dim; i++ ) {
00107                                 FCurve *fcu = (FCurve*)MEM_callocN(sizeof(FCurve), "FCurve");
00108                         
00109                                 fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
00110                                 // fcu->rna_path = BLI_strdupn(path, strlen(path));
00111                                 fcu->array_index = 0;
00112                                 //fcu->totvert = curve->getKeyCount();
00113                         
00114                                 // create beztriple for each key
00115                                 for (unsigned int j = 0; j < curve->getKeyCount(); j++) {
00116                                         BezTriple bez;
00117                                         memset(&bez, 0, sizeof(BezTriple));
00118 
00119                                         // intangent
00120                                         // bez.vec[0][0] = get_float_value(intan, j * 6 + i + i) * fps;
00121                                         // bez.vec[0][1] = get_float_value(intan, j * 6 + i + i + 1);
00122 
00123                                         // input, output
00124                                         bez.vec[1][0] = bc_get_float_value(input, j) * fps; 
00125                                         bez.vec[1][1] = bc_get_float_value(output, j * dim + i);
00126 
00127                                         // outtangent
00128                                         // bez.vec[2][0] = get_float_value(outtan, j * 6 + i + i) * fps;
00129                                         // bez.vec[2][1] = get_float_value(outtan, j * 6 + i + i + 1);
00130 
00131                                         bez.ipo = U.ipo_new; /* use default interpolation mode here... */
00132                                         bez.f1 = bez.f2 = bez.f3 = SELECT;
00133                                         bez.h1 = bez.h2 = HD_AUTO;
00134                                         insert_bezt_fcurve(fcu, &bez, 0);
00135                                 }
00136 
00137                                 calchandles_fcurve(fcu);
00138 
00139                                 fcurves.push_back(fcu);
00140                         }
00141                 }
00142                 break;
00143         default:
00144                 fprintf(stderr, "Output dimension of %d is not yet supported (animation id = %s)\n", (int)dim, curve->getOriginalId().c_str());
00145         }
00146 
00147         for (std::vector<FCurve*>::iterator it = fcurves.begin(); it != fcurves.end(); it++)
00148                 unused_curves.push_back(*it);
00149 }
00150 
00151 void AnimationImporter::fcurve_deg_to_rad(FCurve *cu)
00152 {
00153         for (unsigned int i = 0; i < cu->totvert; i++) {
00154                 // TODO convert handles too
00155                 cu->bezt[i].vec[1][1] *= M_PI / 180.0f;
00156         }
00157 }
00158 
00159 void AnimationImporter::add_fcurves_to_object(Object *ob, std::vector<FCurve*>& curves, char *rna_path, int array_index, Animation *animated)
00160 {
00161         bAction *act;
00162         
00163         if (!ob->adt || !ob->adt->action) act = verify_adt_action((ID*)&ob->id, 1);
00164         else act = ob->adt->action;
00165         
00166         std::vector<FCurve*>::iterator it;
00167         int i;
00168 
00169 #if 0
00170         char *p = strstr(rna_path, "rotation_euler");
00171         bool is_rotation = p && *(p + strlen("rotation_euler")) == '\0';
00172 
00173         // convert degrees to radians for rotation
00174         if (is_rotation)
00175                 fcurve_deg_to_rad(fcu);
00176 #endif
00177         
00178         for (it = curves.begin(), i = 0; it != curves.end(); it++, i++) {
00179                 FCurve *fcu = *it;
00180                 fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
00181                 
00182                 if (array_index == -1) fcu->array_index = i;
00183                 else fcu->array_index = array_index;
00184         
00185                 if (ob->type == OB_ARMATURE) {
00186                         bActionGroup *grp = NULL;
00187                         const char *bone_name = bc_get_joint_name(animated->node);
00188                         
00189                         if (bone_name) {
00190                                 /* try to find group */
00191                                 grp = action_groups_find_named(act, bone_name);
00192                                 
00193                                 /* no matching groups, so add one */
00194                                 if (grp == NULL) {
00195                                         /* Add a new group, and make it active */
00196                                         grp = (bActionGroup*)MEM_callocN(sizeof(bActionGroup), "bActionGroup");
00197                                         
00198                                         grp->flag = AGRP_SELECTED;
00199                                         BLI_strncpy(grp->name, bone_name, sizeof(grp->name));
00200                                         
00201                                         BLI_addtail(&act->groups, grp);
00202                                         BLI_uniquename(&act->groups, grp, "Group", '.', offsetof(bActionGroup, name), 64);
00203                                 }
00204                                 
00205                                 /* add F-Curve to group */
00206                                 action_groups_add_channel(act, grp, fcu);
00207                                 
00208                         }
00209 #if 0
00210                         if (is_rotation) {
00211                                 fcurves_actionGroup_map[grp].push_back(fcu);
00212                         }
00213 #endif
00214                 }
00215                 else {
00216                         BLI_addtail(&act->curves, fcu);
00217                 }
00218 
00219                 // curve is used, so remove it from unused_curves
00220                 unused_curves.erase(std::remove(unused_curves.begin(), unused_curves.end(), fcu), unused_curves.end());
00221         }
00222 }
00223 
00224 AnimationImporter::AnimationImporter(UnitConverter *conv, ArmatureImporter *arm, Scene *scene) :
00225                 TransformReader(conv), armature_importer(arm), scene(scene) { }
00226 
00227 AnimationImporter::~AnimationImporter()
00228 {
00229         // free unused FCurves
00230         for (std::vector<FCurve*>::iterator it = unused_curves.begin(); it != unused_curves.end(); it++)
00231                 free_fcurve(*it);
00232 
00233         if (unused_curves.size())
00234                 fprintf(stderr, "removed %d unused curves\n", (int)unused_curves.size());
00235 }
00236 
00237 bool AnimationImporter::write_animation(const COLLADAFW::Animation* anim) 
00238 {
00239         if (anim->getAnimationType() == COLLADAFW::Animation::ANIMATION_CURVE) {
00240                 COLLADAFW::AnimationCurve *curve = (COLLADAFW::AnimationCurve*)anim;
00241                 
00242                 // XXX Don't know if it's necessary
00243                 // Should we check outPhysicalDimension?
00244                 if (curve->getInPhysicalDimension() != COLLADAFW::PHYSICAL_DIMENSION_TIME) {
00245                         fprintf(stderr, "Inputs physical dimension is not time. \n");
00246                         return true;
00247                 }
00248 
00249                 // a curve can have mixed interpolation type,
00250                 // in this case curve->getInterpolationTypes returns a list of interpolation types per key
00251                 COLLADAFW::AnimationCurve::InterpolationType interp = curve->getInterpolationType();
00252 
00253                 if (interp != COLLADAFW::AnimationCurve::INTERPOLATION_MIXED) {
00254                         switch (interp) {
00255                         case COLLADAFW::AnimationCurve::INTERPOLATION_LINEAR:
00256                         case COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER:
00257                                 animation_to_fcurves(curve);
00258                                 break;
00259                         default:
00260                                 // TODO there're also CARDINAL, HERMITE, BSPLINE and STEP types
00261                                 fprintf(stderr, "CARDINAL, HERMITE, BSPLINE and STEP anim interpolation types not supported yet.\n");
00262                                 break;
00263                         }
00264                 }
00265                 else {
00266                         // not supported yet
00267                         fprintf(stderr, "MIXED anim interpolation type is not supported yet.\n");
00268                 }
00269         }
00270         else {
00271                 fprintf(stderr, "FORMULA animation type is not supported yet.\n");
00272         }
00273         
00274         return true;
00275 }
00276         
00277 // called on post-process stage after writeVisualScenes
00278 bool AnimationImporter::write_animation_list(const COLLADAFW::AnimationList* animlist) 
00279 {
00280         const COLLADAFW::UniqueId& animlist_id = animlist->getUniqueId();
00281 
00282         animlist_map[animlist_id] = animlist;
00283 
00284 #if 0
00285         // should not happen
00286         if (uid_animated_map.find(animlist_id) == uid_animated_map.end()) {
00287                 return true;
00288         }
00289 
00290         // for bones rna_path is like: pose.bones["bone-name"].rotation
00291         
00292         // what does this AnimationList animate?
00293         Animation& animated = uid_animated_map[animlist_id];
00294         Object *ob = animated.ob;
00295 
00296         char rna_path[100];
00297         char joint_path[100];
00298         bool is_joint = false;
00299 
00300         // if ob is NULL, it should be a JOINT
00301         if (!ob) {
00302                 ob = armature_importer->get_armature_for_joint(animated.node);
00303 
00304                 if (!ob) {
00305                         fprintf(stderr, "Cannot find armature for node %s\n", get_joint_name(animated.node));
00306                         return true;
00307                 }
00308 
00309                 armature_importer->get_rna_path_for_joint(animated.node, joint_path, sizeof(joint_path));
00310 
00311                 is_joint = true;
00312         }
00313         
00314         const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings();
00315 
00316         switch (animated.tm->getTransformationType()) {
00317         case COLLADAFW::Transformation::TRANSLATE:
00318         case COLLADAFW::Transformation::SCALE:
00319                 {
00320                         bool loc = animated.tm->getTransformationType() == COLLADAFW::Transformation::TRANSLATE;
00321                         if (is_joint)
00322                                 BLI_snprintf(rna_path, sizeof(rna_path), "%s.%s", joint_path, loc ? "location" : "scale");
00323                         else
00324                                 BLI_strncpy(rna_path, loc ? "location" : "scale", sizeof(rna_path));
00325 
00326                         for (int i = 0; i < bindings.getCount(); i++) {
00327                                 const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[i];
00328                                 COLLADAFW::UniqueId anim_uid = binding.animation;
00329 
00330                                 if (curve_map.find(anim_uid) == curve_map.end()) {
00331                                         fprintf(stderr, "Cannot find FCurve by animation UID.\n");
00332                                         continue;
00333                                 }
00334 
00335                                 std::vector<FCurve*>& fcurves = curve_map[anim_uid];
00336                                 
00337                                 switch (binding.animationClass) {
00338                                 case COLLADAFW::AnimationList::POSITION_X:
00339                                         add_fcurves_to_object(ob, fcurves, rna_path, 0, &animated);
00340                                         break;
00341                                 case COLLADAFW::AnimationList::POSITION_Y:
00342                                         add_fcurves_to_object(ob, fcurves, rna_path, 1, &animated);
00343                                         break;
00344                                 case COLLADAFW::AnimationList::POSITION_Z:
00345                                         add_fcurves_to_object(ob, fcurves, rna_path, 2, &animated);
00346                                         break;
00347                                 case COLLADAFW::AnimationList::POSITION_XYZ:
00348                                         add_fcurves_to_object(ob, fcurves, rna_path, -1, &animated);
00349                                         break;
00350                                 default:
00351                                         fprintf(stderr, "AnimationClass %d is not supported for %s.\n",
00352                                                         binding.animationClass, loc ? "TRANSLATE" : "SCALE");
00353                                 }
00354                         }
00355                 }
00356                 break;
00357         case COLLADAFW::Transformation::ROTATE:
00358                 {
00359                         if (is_joint)
00360                                 BLI_snprintf(rna_path, sizeof(rna_path), "%s.rotation_euler", joint_path);
00361                         else
00362                                 BLI_strncpy(rna_path, "rotation_euler", sizeof(rna_path));
00363 
00364                         COLLADAFW::Rotate* rot = (COLLADAFW::Rotate*)animated.tm;
00365                         COLLADABU::Math::Vector3& axis = rot->getRotationAxis();
00366                         
00367                         for (int i = 0; i < bindings.getCount(); i++) {
00368                                 const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[i];
00369                                 COLLADAFW::UniqueId anim_uid = binding.animation;
00370 
00371                                 if (curve_map.find(anim_uid) == curve_map.end()) {
00372                                         fprintf(stderr, "Cannot find FCurve by animation UID.\n");
00373                                         continue;
00374                                 }
00375 
00376                                 std::vector<FCurve*>& fcurves = curve_map[anim_uid];
00377 
00378                                 switch (binding.animationClass) {
00379                                 case COLLADAFW::AnimationList::ANGLE:
00380                                         if (COLLADABU::Math::Vector3::UNIT_X == axis) {
00381                                                 add_fcurves_to_object(ob, fcurves, rna_path, 0, &animated);
00382                                         }
00383                                         else if (COLLADABU::Math::Vector3::UNIT_Y == axis) {
00384                                                 add_fcurves_to_object(ob, fcurves, rna_path, 1, &animated);
00385                                         }
00386                                         else if (COLLADABU::Math::Vector3::UNIT_Z == axis) {
00387                                                 add_fcurves_to_object(ob, fcurves, rna_path, 2, &animated);
00388                                         }
00389                                         break;
00390                                 case COLLADAFW::AnimationList::AXISANGLE:
00391                                         // TODO convert axis-angle to quat? or XYZ?
00392                                 default:
00393                                         fprintf(stderr, "AnimationClass %d is not supported for ROTATE transformation.\n",
00394                                                         binding.animationClass);
00395                                 }
00396                         }
00397                 }
00398                 break;
00399         case COLLADAFW::Transformation::MATRIX:
00400         case COLLADAFW::Transformation::SKEW:
00401         case COLLADAFW::Transformation::LOOKAT:
00402                 fprintf(stderr, "Animation of MATRIX, SKEW and LOOKAT transformations is not supported yet.\n");
00403                 break;
00404         }
00405 #endif
00406         
00407         return true;
00408 }
00409 
00410 // \todo refactor read_node_transform to not automatically apply anything,
00411 // but rather return the transform matrix, so caller can do with it what is
00412 // necessary. Same for \ref get_node_mat
00413 void AnimationImporter::read_node_transform(COLLADAFW::Node *node, Object *ob)
00414 {
00415         float mat[4][4];
00416         TransformReader::get_node_mat(mat, node, &uid_animated_map, ob);
00417         if (ob) {
00418                 copy_m4_m4(ob->obmat, mat);
00419                 object_apply_mat4(ob, ob->obmat, 0, 0);
00420         }
00421 }
00422 
00423 #if 0
00424 virtual void AnimationImporter::change_eul_to_quat(Object *ob, bAction *act)
00425 {
00426         bActionGroup *grp;
00427         int i;
00428         
00429         for (grp = (bActionGroup*)act->groups.first; grp; grp = grp->next) {
00430 
00431                 FCurve *eulcu[3] = {NULL, NULL, NULL};
00432                 
00433                 if (fcurves_actionGroup_map.find(grp) == fcurves_actionGroup_map.end())
00434                         continue;
00435 
00436                 std::vector<FCurve*> &rot_fcurves = fcurves_actionGroup_map[grp];
00437                 
00438                 if (rot_fcurves.size() > 3) continue;
00439 
00440                 for (i = 0; i < rot_fcurves.size(); i++)
00441                         eulcu[rot_fcurves[i]->array_index] = rot_fcurves[i];
00442 
00443                 char joint_path[100];
00444                 char rna_path[100];
00445 
00446                 BLI_snprintf(joint_path, sizeof(joint_path), "pose.bones[\"%s\"]", grp->name);
00447                 BLI_snprintf(rna_path, sizeof(rna_path), "%s.rotation_quaternion", joint_path);
00448 
00449                 FCurve *quatcu[4] = {
00450                         create_fcurve(0, rna_path),
00451                         create_fcurve(1, rna_path),
00452                         create_fcurve(2, rna_path),
00453                         create_fcurve(3, rna_path)
00454                 };
00455 
00456                 bPoseChannel *chan = get_pose_channel(ob->pose, grp->name);
00457 
00458                 float m4[4][4], irest[3][3];
00459                 invert_m4_m4(m4, chan->bone->arm_mat);
00460                 copy_m3_m4(irest, m4);
00461 
00462                 for (i = 0; i < 3; i++) {
00463 
00464                         FCurve *cu = eulcu[i];
00465 
00466                         if (!cu) continue;
00467 
00468                         for (int j = 0; j < cu->totvert; j++) {
00469                                 float frame = cu->bezt[j].vec[1][0];
00470 
00471                                 float eul[3] = {
00472                                         eulcu[0] ? evaluate_fcurve(eulcu[0], frame) : 0.0f,
00473                                         eulcu[1] ? evaluate_fcurve(eulcu[1], frame) : 0.0f,
00474                                         eulcu[2] ? evaluate_fcurve(eulcu[2], frame) : 0.0f
00475                                 };
00476 
00477                                 // make eul relative to bone rest pose
00478                                 float rot[3][3], rel[3][3], quat[4];
00479 
00480                                 /*eul_to_mat3(rot, eul);
00481 
00482                                 mul_m3_m3m3(rel, irest, rot);
00483 
00484                                 mat3_to_quat(quat, rel);
00485                                 */
00486 
00487                                 eul_to_quat(quat, eul);
00488 
00489                                 for (int k = 0; k < 4; k++)
00490                                         create_bezt(quatcu[k], frame, quat[k]);
00491                         }
00492                 }
00493 
00494                 // now replace old Euler curves
00495 
00496                 for (i = 0; i < 3; i++) {
00497                         if (!eulcu[i]) continue;
00498 
00499                         action_groups_remove_channel(act, eulcu[i]);
00500                         free_fcurve(eulcu[i]);
00501                 }
00502 
00503                 chan->rotmode = ROT_MODE_QUAT;
00504 
00505                 for (i = 0; i < 4; i++)
00506                         action_groups_add_channel(act, grp, quatcu[i]);
00507         }
00508 
00509         bPoseChannel *pchan;
00510         for (pchan = (bPoseChannel*)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
00511                 pchan->rotmode = ROT_MODE_QUAT;
00512         }
00513 }
00514 #endif
00515 
00516 // prerequisites:
00517 // animlist_map - map animlist id -> animlist
00518 // curve_map - map anim id -> curve(s)
00519 Object *AnimationImporter::translate_animation(COLLADAFW::Node *node,
00520                                                         std::map<COLLADAFW::UniqueId, Object*>& object_map,
00521                                                         std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map,
00522                                                         COLLADAFW::Transformation::TransformationType tm_type,
00523                                                         Object *par_job)
00524 {
00525         bool is_rotation = tm_type == COLLADAFW::Transformation::ROTATE;
00526         bool is_matrix = tm_type == COLLADAFW::Transformation::MATRIX;
00527         bool is_joint = node->getType() == COLLADAFW::Node::JOINT;
00528 
00529         COLLADAFW::Node *root = root_map.find(node->getUniqueId()) == root_map.end() ? node : root_map[node->getUniqueId()];
00530         Object *ob = is_joint ? armature_importer->get_armature_for_joint(node) : object_map[node->getUniqueId()];
00531         const char *bone_name = is_joint ? bc_get_joint_name(node) : NULL;
00532 
00533         if (!ob) {
00534                 fprintf(stderr, "cannot find Object for Node with id=\"%s\"\n", node->getOriginalId().c_str());
00535                 return NULL;
00536         }
00537 
00538         // frames at which to sample
00539         std::vector<float> frames;
00540 
00541         // for each <rotate>, <translate>, etc. there is a separate Transformation
00542         const COLLADAFW::TransformationPointerArray& tms = node->getTransformations();
00543 
00544         unsigned int i;
00545 
00546         // find frames at which to sample plus convert all rotation keys to radians
00547         for (i = 0; i < tms.getCount(); i++) {
00548                 COLLADAFW::Transformation *tm = tms[i];
00549                 COLLADAFW::Transformation::TransformationType type = tm->getTransformationType();
00550 
00551                 if (type == tm_type) {
00552                         const COLLADAFW::UniqueId& listid = tm->getAnimationList();
00553 
00554                         if (animlist_map.find(listid) != animlist_map.end()) {
00555                                 const COLLADAFW::AnimationList *animlist = animlist_map[listid];
00556                                 const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings();
00557 
00558                                 if (bindings.getCount()) {
00559                                         for (unsigned int j = 0; j < bindings.getCount(); j++) {
00560                                                 std::vector<FCurve*>& curves = curve_map[bindings[j].animation];
00561                                                 bool xyz = ((type == COLLADAFW::Transformation::TRANSLATE || type == COLLADAFW::Transformation::SCALE) && bindings[j].animationClass == COLLADAFW::AnimationList::POSITION_XYZ);
00562 
00563                                                 if ((!xyz && curves.size() == 1) || (xyz && curves.size() == 3) || is_matrix) {
00564                                                         std::vector<FCurve*>::iterator iter;
00565 
00566                                                         for (iter = curves.begin(); iter != curves.end(); iter++) {
00567                                                                 FCurve *fcu = *iter;
00568 
00569                                                                 if (is_rotation)
00570                                                                         fcurve_deg_to_rad(fcu);
00571 
00572                                                                 for (unsigned int k = 0; k < fcu->totvert; k++) {
00573                                                                         float fra = fcu->bezt[k].vec[1][0];
00574                                                                         if (std::find(frames.begin(), frames.end(), fra) == frames.end())
00575                                                                                 frames.push_back(fra);
00576                                                                 }
00577                                                         }
00578                                                 }
00579                                                 else {
00580                                                         fprintf(stderr, "expected %d curves, got %d\n", xyz ? 3 : 1, (int)curves.size());
00581                                                 }
00582                                         }
00583                                 }
00584                         }
00585                 }
00586         }
00587 
00588         float irest_dae[4][4];
00589         float rest[4][4], irest[4][4];
00590 
00591         if (is_joint) {
00592                 get_joint_rest_mat(irest_dae, root, node);
00593                 invert_m4(irest_dae);
00594 
00595                 Bone *bone = get_named_bone((bArmature*)ob->data, bone_name);
00596                 if (!bone) {
00597                         fprintf(stderr, "cannot find bone \"%s\"\n", bone_name);
00598                         return NULL;
00599                 }
00600 
00601                 unit_m4(rest);
00602                 copy_m4_m4(rest, bone->arm_mat);
00603                 invert_m4_m4(irest, rest);
00604         }
00605 
00606         Object *job = NULL;
00607 
00608 #ifdef ARMATURE_TEST
00609         FCurve *job_curves[10];
00610         job = get_joint_object(root, node, par_job);
00611 #endif
00612 
00613         if (frames.size() == 0)
00614                 return job;
00615 
00616         std::sort(frames.begin(), frames.end());
00617 
00618         const char *tm_str = NULL;
00619         switch (tm_type) {
00620         case COLLADAFW::Transformation::ROTATE:
00621                 tm_str = "rotation_quaternion";
00622                 break;
00623         case COLLADAFW::Transformation::SCALE:
00624                 tm_str = "scale";
00625                 break;
00626         case COLLADAFW::Transformation::TRANSLATE:
00627                 tm_str = "location";
00628                 break;
00629         case COLLADAFW::Transformation::MATRIX:
00630                 break;
00631         default:
00632                 return job;
00633         }
00634 
00635         char rna_path[200];
00636         char joint_path[200];
00637 
00638         if (is_joint)
00639                 armature_importer->get_rna_path_for_joint(node, joint_path, sizeof(joint_path));
00640 
00641         // new curves
00642         FCurve *newcu[10]; // if tm_type is matrix, then create 10 curves: 4 rot, 3 loc, 3 scale
00643         unsigned int totcu = is_matrix ? 10 : (is_rotation ? 4 : 3);
00644 
00645         for (i = 0; i < totcu; i++) {
00646 
00647                 int axis = i;
00648 
00649                 if (is_matrix) {
00650                         if (i < 4) {
00651                                 tm_str = "rotation_quaternion";
00652                                 axis = i;
00653                         }
00654                         else if (i < 7) {
00655                                 tm_str = "location";
00656                                 axis = i - 4;
00657                         }
00658                         else {
00659                                 tm_str = "scale";
00660                                 axis = i - 7;
00661                         }
00662                 }
00663 
00664                 if (is_joint)
00665                         BLI_snprintf(rna_path, sizeof(rna_path), "%s.%s", joint_path, tm_str);
00666                 else
00667                         strcpy(rna_path, tm_str);
00668 
00669                 newcu[i] = create_fcurve(axis, rna_path);
00670 
00671 #ifdef ARMATURE_TEST
00672                 if (is_joint)
00673                         job_curves[i] = create_fcurve(axis, tm_str);
00674 #endif
00675         }
00676 
00677         std::vector<float>::iterator it;
00678 
00679         // sample values at each frame
00680         for (it = frames.begin(); it != frames.end(); it++) {
00681                 float fra = *it;
00682 
00683                 float mat[4][4];
00684                 float matfra[4][4];
00685 
00686                 unit_m4(matfra);
00687 
00688                 // calc object-space mat
00689                 evaluate_transform_at_frame(matfra, node, fra);
00690 
00691                 // for joints, we need a special matrix
00692                 if (is_joint) {
00693                         // special matrix: iR * M * iR_dae * R
00694                         // where R, iR are bone rest and inverse rest mats in world space (Blender bones),
00695                         // iR_dae is joint inverse rest matrix (DAE) and M is an evaluated joint world-space matrix (DAE)
00696                         float temp[4][4], par[4][4];
00697 
00698                         // calc M
00699                         calc_joint_parent_mat_rest(par, NULL, root, node);
00700                         mul_m4_m4m4(temp, matfra, par);
00701 
00702                         // evaluate_joint_world_transform_at_frame(temp, NULL, , node, fra);
00703 
00704                         // calc special matrix
00705                         mul_serie_m4(mat, irest, temp, irest_dae, rest, NULL, NULL, NULL, NULL);
00706                 }
00707                 else {
00708                         copy_m4_m4(mat, matfra);
00709                 }
00710 
00711                 float val[4], rot[4], loc[3], scale[3];
00712 
00713                 switch (tm_type) {
00714                 case COLLADAFW::Transformation::ROTATE:
00715                         mat4_to_quat(val, mat);
00716                         break;
00717                 case COLLADAFW::Transformation::SCALE:
00718                         mat4_to_size(val, mat);
00719                         break;
00720                 case COLLADAFW::Transformation::TRANSLATE:
00721                         copy_v3_v3(val, mat[3]);
00722                         break;
00723                 case COLLADAFW::Transformation::MATRIX:
00724                         mat4_to_quat(rot, mat);
00725                         copy_v3_v3(loc, mat[3]);
00726                         mat4_to_size(scale, mat);
00727                         break;
00728                 default:
00729                         break;
00730                 }
00731 
00732                 // add keys
00733                 for (i = 0; i < totcu; i++) {
00734                         if (is_matrix) {
00735                                 if (i < 4)
00736                                         add_bezt(newcu[i], fra, rot[i]);
00737                                 else if (i < 7)
00738                                         add_bezt(newcu[i], fra, loc[i - 4]);
00739                                 else
00740                                         add_bezt(newcu[i], fra, scale[i - 7]);
00741                         }
00742                         else {
00743                                 add_bezt(newcu[i], fra, val[i]);
00744                         }
00745                 }
00746 
00747 #ifdef ARMATURE_TEST
00748                 if (is_joint) {
00749                         switch (tm_type) {
00750                         case COLLADAFW::Transformation::ROTATE:
00751                                 mat4_to_quat(val, matfra);
00752                                 break;
00753                         case COLLADAFW::Transformation::SCALE:
00754                                 mat4_to_size(val, matfra);
00755                                 break;
00756                         case COLLADAFW::Transformation::TRANSLATE:
00757                                 copy_v3_v3(val, matfra[3]);
00758                                 break;
00759                         case MATRIX:
00760                                 mat4_to_quat(rot, matfra);
00761                                 copy_v3_v3(loc, matfra[3]);
00762                                 mat4_to_size(scale, matfra);
00763                                 break;
00764                         default:
00765                                 break;
00766                         }
00767 
00768                         for (i = 0; i < totcu; i++) {
00769                                 if (is_matrix) {
00770                                         if (i < 4)
00771                                                 add_bezt(job_curves[i], fra, rot[i]);
00772                                         else if (i < 7)
00773                                                 add_bezt(job_curves[i], fra, loc[i - 4]);
00774                                         else
00775                                                 add_bezt(job_curves[i], fra, scale[i - 7]);
00776                                 }
00777                                 else {
00778                                         add_bezt(job_curves[i], fra, val[i]);
00779                                 }
00780                         }
00781                 }
00782 #endif
00783         }
00784 
00785         verify_adt_action((ID*)&ob->id, 1);
00786 
00787         ListBase *curves = &ob->adt->action->curves;
00788 
00789         // add curves
00790         for (i = 0; i < totcu; i++) {
00791                 if (is_joint)
00792                         add_bone_fcurve(ob, node, newcu[i]);
00793                 else
00794                         BLI_addtail(curves, newcu[i]);
00795 
00796 #ifdef ARMATURE_TEST
00797                 if (is_joint)
00798                         BLI_addtail(&job->adt->action->curves, job_curves[i]);
00799 #endif
00800         }
00801 
00802         if (is_rotation || is_matrix) {
00803                 if (is_joint) {
00804                         bPoseChannel *chan = get_pose_channel(ob->pose, bone_name);
00805                         chan->rotmode = ROT_MODE_QUAT;
00806                 }
00807                 else {
00808                         ob->rotmode = ROT_MODE_QUAT;
00809                 }
00810         }
00811 
00812         return job;
00813 }
00814 
00815 // internal, better make it private
00816 // warning: evaluates only rotation
00817 // prerequisites: animlist_map, curve_map
00818 void AnimationImporter::evaluate_transform_at_frame(float mat[4][4], COLLADAFW::Node *node, float fra)
00819 {
00820         const COLLADAFW::TransformationPointerArray& tms = node->getTransformations();
00821 
00822         unit_m4(mat);
00823 
00824         for (unsigned int i = 0; i < tms.getCount(); i++) {
00825                 COLLADAFW::Transformation *tm = tms[i];
00826                 COLLADAFW::Transformation::TransformationType type = tm->getTransformationType();
00827                 float m[4][4];
00828 
00829                 unit_m4(m);
00830 
00831                 std::string nodename = node->getName().size() ? node->getName() : node->getOriginalId();
00832                 if (!evaluate_animation(tm, m, fra, nodename.c_str())) {
00833                         switch (type) {
00834                         case COLLADAFW::Transformation::ROTATE:
00835                                 dae_rotate_to_mat4(tm, m);
00836                                 break;
00837                         case COLLADAFW::Transformation::TRANSLATE:
00838                                 dae_translate_to_mat4(tm, m);
00839                                 break;
00840                         case COLLADAFW::Transformation::SCALE:
00841                                 dae_scale_to_mat4(tm, m);
00842                                 break;
00843                         case COLLADAFW::Transformation::MATRIX:
00844                                 dae_matrix_to_mat4(tm, m);
00845                                 break;
00846                         default:
00847                                 fprintf(stderr, "unsupported transformation type %d\n", type);
00848                         }
00849                 }
00850 
00851                 float temp[4][4];
00852                 copy_m4_m4(temp, mat);
00853 
00854                 mul_m4_m4m4(mat, m, temp);
00855         }
00856 }
00857 
00858 // return true to indicate that mat contains a sane value
00859 bool AnimationImporter::evaluate_animation(COLLADAFW::Transformation *tm, float mat[4][4], float fra, const char *node_id)
00860 {
00861         const COLLADAFW::UniqueId& listid = tm->getAnimationList();
00862         COLLADAFW::Transformation::TransformationType type = tm->getTransformationType();
00863 
00864         if (type != COLLADAFW::Transformation::ROTATE &&
00865             type != COLLADAFW::Transformation::SCALE &&
00866             type != COLLADAFW::Transformation::TRANSLATE &&
00867             type != COLLADAFW::Transformation::MATRIX) {
00868                 fprintf(stderr, "animation of transformation %d is not supported yet\n", type);
00869                 return false;
00870         }
00871 
00872         if (animlist_map.find(listid) == animlist_map.end())
00873                 return false;
00874 
00875         const COLLADAFW::AnimationList *animlist = animlist_map[listid];
00876         const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings();
00877 
00878         if (bindings.getCount()) {
00879                 float vec[3];
00880 
00881                 bool is_scale = (type == COLLADAFW::Transformation::SCALE);
00882                 bool is_translate = (type == COLLADAFW::Transformation::TRANSLATE);
00883 
00884                 if (type == COLLADAFW::Transformation::SCALE)
00885                         dae_scale_to_v3(tm, vec);
00886                 else if (type == COLLADAFW::Transformation::TRANSLATE)
00887                         dae_translate_to_v3(tm, vec);
00888 
00889                 for (unsigned int j = 0; j < bindings.getCount(); j++) {
00890                         const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[j];
00891                         std::vector<FCurve*>& curves = curve_map[binding.animation];
00892                         COLLADAFW::AnimationList::AnimationClass animclass = binding.animationClass;
00893                         char path[100];
00894 
00895                         switch (type) {
00896                         case COLLADAFW::Transformation::ROTATE:
00897                                 BLI_snprintf(path, sizeof(path), "%s.rotate (binding %u)", node_id, j);
00898                                 break;
00899                         case COLLADAFW::Transformation::SCALE:
00900                                 BLI_snprintf(path, sizeof(path), "%s.scale (binding %u)", node_id, j);
00901                                 break;
00902                         case COLLADAFW::Transformation::TRANSLATE:
00903                                 BLI_snprintf(path, sizeof(path), "%s.translate (binding %u)", node_id, j);
00904                                 break;
00905                         case COLLADAFW::Transformation::MATRIX:
00906                                 BLI_snprintf(path, sizeof(path), "%s.matrix (binding %u)", node_id, j);
00907                                 break;
00908                         default:
00909                                 break;
00910                         }
00911 
00912                         if (animclass == COLLADAFW::AnimationList::UNKNOWN_CLASS) {
00913                                 fprintf(stderr, "%s: UNKNOWN animation class\n", path);
00914                                 continue;
00915                         }
00916 
00917                         if (type == COLLADAFW::Transformation::ROTATE) {
00918                                 if (curves.size() != 1) {
00919                                         fprintf(stderr, "expected 1 curve, got %d\n", (int)curves.size());
00920                                         return false;
00921                                 }
00922 
00923                                 // TODO support other animclasses
00924                                 if (animclass != COLLADAFW::AnimationList::ANGLE) {
00925                                         fprintf(stderr, "%s: animation class %d is not supported yet\n", path, animclass);
00926                                         return false;
00927                                 }
00928 
00929                                 COLLADABU::Math::Vector3& axis = ((COLLADAFW::Rotate*)tm)->getRotationAxis();
00930                                 float ax[3] = {axis[0], axis[1], axis[2]};
00931                                 float angle = evaluate_fcurve(curves[0], fra);
00932                                 axis_angle_to_mat4(mat, ax, angle);
00933 
00934                                 return true;
00935                         }
00936                         else if (is_scale || is_translate) {
00937                                 bool is_xyz = animclass == COLLADAFW::AnimationList::POSITION_XYZ;
00938 
00939                                 if ((!is_xyz && curves.size() != 1) || (is_xyz && curves.size() != 3)) {
00940                                         if (is_xyz)
00941                                                 fprintf(stderr, "%s: expected 3 curves, got %d\n", path, (int)curves.size());
00942                                         else
00943                                                 fprintf(stderr, "%s: expected 1 curve, got %d\n", path, (int)curves.size());
00944                                         return false;
00945                                 }
00946                                 
00947                                 switch (animclass) {
00948                                 case COLLADAFW::AnimationList::POSITION_X:
00949                                         vec[0] = evaluate_fcurve(curves[0], fra);
00950                                         break;
00951                                 case COLLADAFW::AnimationList::POSITION_Y:
00952                                         vec[1] = evaluate_fcurve(curves[0], fra);
00953                                         break;
00954                                 case COLLADAFW::AnimationList::POSITION_Z:
00955                                         vec[2] = evaluate_fcurve(curves[0], fra);
00956                                         break;
00957                                 case COLLADAFW::AnimationList::POSITION_XYZ:
00958                                         vec[0] = evaluate_fcurve(curves[0], fra);
00959                                         vec[1] = evaluate_fcurve(curves[1], fra);
00960                                         vec[2] = evaluate_fcurve(curves[2], fra);
00961                                         break;
00962                                 default:
00963                                         fprintf(stderr, "%s: animation class %d is not supported yet\n", path, animclass);
00964                                         break;
00965                                 }
00966                         }
00967                         else if (type == COLLADAFW::Transformation::MATRIX) {
00968                                 // for now, of matrix animation, support only the case when all values are packed into one animation
00969                                 if (curves.size() != 16) {
00970                                         fprintf(stderr, "%s: expected 16 curves, got %d\n", path, (int)curves.size());
00971                                         return false;
00972                                 }
00973 
00974                                 COLLADABU::Math::Matrix4 matrix;
00975                                 int i = 0, j = 0;
00976 
00977                                 for (std::vector<FCurve*>::iterator it = curves.begin(); it != curves.end(); it++) {
00978                                         matrix.setElement(i, j, evaluate_fcurve(*it, fra));
00979                                         j++;
00980                                         if (j == 4) {
00981                                                 i++;
00982                                                 j = 0;
00983                                         }
00984                                 }
00985 
00986                                 COLLADAFW::Matrix tm(matrix);
00987                                 dae_matrix_to_mat4(&tm, mat);
00988 
00989                                 return true;
00990                         }
00991                 }
00992 
00993                 if (is_scale)
00994                         size_to_mat4(mat, vec);
00995                 else
00996                         copy_v3_v3(mat[3], vec);
00997 
00998                 return is_scale || is_translate;
00999         }
01000 
01001         return false;
01002 }
01003 
01004 // gives a world-space mat of joint at rest position
01005 void AnimationImporter::get_joint_rest_mat(float mat[4][4], COLLADAFW::Node *root, COLLADAFW::Node *node)
01006 {
01007         // if bind mat is not available,
01008         // use "current" node transform, i.e. all those tms listed inside <node>
01009         if (!armature_importer->get_joint_bind_mat(mat, node)) {
01010                 float par[4][4], m[4][4];
01011 
01012                 calc_joint_parent_mat_rest(par, NULL, root, node);
01013                 get_node_mat(m, node, NULL, NULL);
01014                 mul_m4_m4m4(mat, m, par);
01015         }
01016 }
01017 
01018 // gives a world-space mat, end's mat not included
01019 bool AnimationImporter::calc_joint_parent_mat_rest(float mat[4][4], float par[4][4], COLLADAFW::Node *node, COLLADAFW::Node *end)
01020 {
01021         float m[4][4];
01022 
01023         if (node == end) {
01024                 par ? copy_m4_m4(mat, par) : unit_m4(mat);
01025                 return true;
01026         }
01027 
01028         // use bind matrix if available or calc "current" world mat
01029         if (!armature_importer->get_joint_bind_mat(m, node)) {
01030                 if (par) {
01031                         float temp[4][4];
01032                         get_node_mat(temp, node, NULL, NULL);
01033                         mul_m4_m4m4(m, temp, par);
01034                 }
01035                 else {
01036                         get_node_mat(m, node, NULL, NULL);
01037                 }
01038         }
01039 
01040         COLLADAFW::NodePointerArray& children = node->getChildNodes();
01041         for (unsigned int i = 0; i < children.getCount(); i++) {
01042                 if (calc_joint_parent_mat_rest(mat, m, children[i], end))
01043                         return true;
01044         }
01045 
01046         return false;
01047 }
01048 
01049 #ifdef ARMATURE_TEST
01050 Object *AnimationImporter::get_joint_object(COLLADAFW::Node *root, COLLADAFW::Node *node, Object *par_job)
01051 {
01052         if (joint_objects.find(node->getUniqueId()) == joint_objects.end()) {
01053                 Object *job = add_object(scene, OB_EMPTY);
01054 
01055                 rename_id((ID*)&job->id, (char*)get_joint_name(node));
01056 
01057                 job->lay = object_in_scene(job, scene)->lay = 2;
01058 
01059                 mul_v3_fl(job->size, 0.5f);
01060                 job->recalc |= OB_RECALC_OB;
01061 
01062                 verify_adt_action((ID*)&job->id, 1);
01063 
01064                 job->rotmode = ROT_MODE_QUAT;
01065 
01066                 float mat[4][4];
01067                 get_joint_rest_mat(mat, root, node);
01068 
01069                 if (par_job) {
01070                         float temp[4][4], ipar[4][4];
01071                         invert_m4_m4(ipar, par_job->obmat);
01072                         copy_m4_m4(temp, mat);
01073                         mul_m4_m4m4(mat, temp, ipar);
01074                 }
01075 
01076                 TransformBase::decompose(mat, job->loc, NULL, job->quat, job->size);
01077 
01078                 if (par_job) {
01079                         job->parent = par_job;
01080 
01081                         par_job->recalc |= OB_RECALC_OB;
01082                         job->parsubstr[0] = 0;
01083                 }
01084 
01085                 where_is_object(scene, job);
01086 
01087                 // after parenting and layer change
01088                 DAG_scene_sort(CTX_data_main(C), scene);
01089 
01090                 joint_objects[node->getUniqueId()] = job;
01091         }
01092 
01093         return joint_objects[node->getUniqueId()];
01094 }
01095 #endif
01096 
01097 #if 0
01098 // recursively evaluates joint tree until end is found, mat then is world-space matrix of end
01099 // mat must be identity on enter, node must be root
01100 bool AnimationImporter::evaluate_joint_world_transform_at_frame(float mat[4][4], float par[4][4], COLLADAFW::Node *node, COLLADAFW::Node *end, float fra)
01101 {
01102         float m[4][4];
01103         if (par) {
01104                 float temp[4][4];
01105                 evaluate_transform_at_frame(temp, node, node == end ? fra : 0.0f);
01106                 mul_m4_m4m4(m, temp, par);
01107         }
01108         else {
01109                 evaluate_transform_at_frame(m, node, node == end ? fra : 0.0f);
01110         }
01111 
01112         if (node == end) {
01113                 copy_m4_m4(mat, m);
01114                 return true;
01115         }
01116         else {
01117                 COLLADAFW::NodePointerArray& children = node->getChildNodes();
01118                 for (int i = 0; i < children.getCount(); i++) {
01119                         if (evaluate_joint_world_transform_at_frame(mat, m, children[i], end, fra))
01120                                 return true;
01121                 }
01122         }
01123 
01124         return false;
01125 }
01126 #endif
01127 
01128 void AnimationImporter::add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurve *fcu)
01129 {
01130         const char *bone_name = bc_get_joint_name(node);
01131         bAction *act = ob->adt->action;
01132                         
01133         /* try to find group */
01134         bActionGroup *grp = action_groups_find_named(act, bone_name);
01135 
01136         /* no matching groups, so add one */
01137         if (grp == NULL) {
01138                 /* Add a new group, and make it active */
01139                 grp = (bActionGroup*)MEM_callocN(sizeof(bActionGroup), "bActionGroup");
01140                                         
01141                 grp->flag = AGRP_SELECTED;
01142                 BLI_strncpy(grp->name, bone_name, sizeof(grp->name));
01143                                         
01144                 BLI_addtail(&act->groups, grp);
01145                 BLI_uniquename(&act->groups, grp, "Group", '.', offsetof(bActionGroup, name), 64);
01146         }
01147                                 
01148         /* add F-Curve to group */
01149         action_groups_add_channel(act, grp, fcu);
01150 }
01151 
01152 void AnimationImporter::add_bezt(FCurve *fcu, float fra, float value)
01153 {
01154         BezTriple bez;
01155         memset(&bez, 0, sizeof(BezTriple));
01156         bez.vec[1][0] = fra;
01157         bez.vec[1][1] = value;
01158         bez.ipo = U.ipo_new; /* use default interpolation mode here... */
01159         bez.f1 = bez.f2 = bez.f3 = SELECT;
01160         bez.h1 = bez.h2 = HD_AUTO;
01161         insert_bezt_fcurve(fcu, &bez, 0);
01162         calchandles_fcurve(fcu);
01163 }