merge from master
[blender.git] / source / blender / collada / AnimationExporter.cpp
index 24e5ecb8d1030a14cefb806586511ab1bf097072..a1497a0ab44e8da0861883d0d56e44a69e3ceebc 100644 (file)
@@ -34,7 +34,7 @@ void forEachObjectInExportSet(Scene *sce, Functor &f, LinkNode *export_set)
        }
 }
 
-bool AnimationExporter::exportAnimations(const struct EvaluationContext *eval_ctx, Scene *sce)
+bool AnimationExporter::exportAnimations(EvaluationContext *eval_ctx, Scene *sce)
 {
        bool has_animations = hasAnimations(sce);
        if (has_animations) {
@@ -50,7 +50,16 @@ bool AnimationExporter::exportAnimations(const struct EvaluationContext *eval_ct
        return has_animations;
 }
 
-
+bool AnimationExporter::is_flat_line(std::vector<float> &values, int channel_count)
+{
+       for (int i = 0; i < values.size(); i += channel_count) {
+               for (int j = 0; j < channel_count; j++) {
+                       if (!bc_in_range(values[j], values[i+j], 0.000001))
+                               return false;
+               }
+       }
+       return true;
+}
 /*
  *  This function creates a complete LINEAR Collada <Animation> Entry with all needed 
  *  <source>, <sampler>, and <channel> entries.
@@ -84,9 +93,11 @@ void AnimationExporter::create_sampled_animation(int channel_count,
        std::string axis_name,
        bool is_rot)
 {
-
        char anim_id[200];
 
+       if (is_flat_line(values, channel_count))
+               return;
+
        BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char *)translate_id(ob_name).c_str(), label.c_str(), axis_name.c_str());
 
        openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
@@ -98,8 +109,10 @@ void AnimationExporter::create_sampled_animation(int channel_count,
        std::string output_id;
        if (channel_count == 1)
                output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, &values[0], values.size(), is_rot, anim_id, axis_name.c_str());
-       else if(channel_count = 3)
+       else if (channel_count == 3)
                output_id = create_xyz_source(&values[0], times.size(), anim_id);
+       else if (channel_count == 16)
+               output_id = create_4x4_source(times, values, anim_id);
 
        std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
        COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
@@ -136,26 +149,38 @@ void AnimationExporter::create_sampled_animation(int channel_count,
 void AnimationExporter::export_keyframed_animation_set(Object *ob)
 {
        FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
+       if (!fcu) {
+               return; /* object has no animation */
+       }
 
-       char *transformName;
-       while (fcu) {
-               //for armature animations as objects
-               if (ob->type == OB_ARMATURE)
-                       transformName = fcu->rna_path;
-               else
-                       transformName = extract_transform_name(fcu->rna_path);
+       if (this->export_settings->export_transformation_type == BC_TRANSFORMATION_TYPE_MATRIX) {
 
-               if (
-                       STREQ(transformName, "location") ||
-                       STREQ(transformName, "scale") ||
-                       (STREQ(transformName, "rotation_euler") && ob->rotmode == ROT_MODE_EUL) ||
-                       STREQ(transformName, "rotation_quaternion"))
-               {
-                       create_keyframed_animation(ob, fcu, transformName, false);
-               }
-               fcu = fcu->next;
+               std::vector<float> ctimes;
+               std::vector<float[4][4]> values;
+               find_keyframes(ob, ctimes);
+               if (ctimes.size() > 0)
+                       export_sampled_matrix_animation(ob, ctimes);
        }
+       else {
+               char *transformName;
+               while (fcu) {
+                       //for armature animations as objects
+                       if (ob->type == OB_ARMATURE)
+                               transformName = fcu->rna_path;
+                       else
+                               transformName = extract_transform_name(fcu->rna_path);
 
+                       if (
+                               STREQ(transformName, "location") ||
+                               STREQ(transformName, "scale") ||
+                               (STREQ(transformName, "rotation_euler") && ob->rotmode == ROT_MODE_EUL) ||
+                               STREQ(transformName, "rotation_quaternion"))
+                       {
+                               create_keyframed_animation(ob, fcu, transformName, false);
+                       }
+                       fcu = fcu->next;
+               }
+       }
 }
 
 /*
@@ -171,20 +196,53 @@ void AnimationExporter::export_keyframed_animation_set(Object *ob)
  * Also keyframed animation exports tend to break when negative scales are involved.
  */
 void AnimationExporter::export_sampled_animation_set(Object *ob)
+{
+       std::vector<float>ctimes;
+       find_sampleframes(ob, ctimes);
+       if (ctimes.size() > 0) {
+               if (this->export_settings->export_transformation_type == BC_TRANSFORMATION_TYPE_MATRIX)
+                       export_sampled_matrix_animation(ob, ctimes);
+               else
+                       export_sampled_transrotloc_animation(ob, ctimes);
+       }
+}
+
+void AnimationExporter::export_sampled_matrix_animation(Object *ob, std::vector<float> &ctimes)
+{
+       UnitConverter converter;
+
+       std::vector<float> values;
+
+       for (std::vector<float>::iterator ctime = ctimes.begin(); ctime != ctimes.end(); ++ctime) {
+               float fmat[4][4];
+               float outmat[4][4];
+
+               bc_update_scene(eval_ctx, scene, *ctime);
+               BKE_object_matrix_local_get(ob, fmat);
+               converter.mat4_to_dae(outmat, fmat);
+
+               if (this->export_settings->limit_precision)
+                       bc_sanitize_mat(outmat, 6);
+
+               for (int i = 0; i < 4; i++)
+                       for (int j = 0; j < 4; j++)
+                               values.push_back(outmat[j][i]);
+       }
+
+       std::string ob_name = id_name(ob);
+
+       create_sampled_animation(16, ctimes, values, ob_name, "transform", "", false);
+}
+
+void AnimationExporter::export_sampled_transrotloc_animation(Object *ob, std::vector<float> &ctimes)
 {
        static int LOC   = 0;
        static int EULX  = 1;
        static int EULY  = 2;
        static int EULZ  = 3;
        static int SCALE = 4;
-       static int TIME  = 5;
 
-       if (this->export_settings->sampling_rate < 1)
-               return; // to avoid infinite loop
-
-       std::vector<float> baked_curves[6];
-       std::vector<float> &ctimes = baked_curves[TIME];
-       find_sampleframes(ob, ctimes);
+       std::vector<float> baked_curves[5];
 
        for (std::vector<float>::iterator ctime = ctimes.begin(); ctime != ctimes.end(); ++ctime ) {
                float fmat[4][4];
@@ -193,7 +251,7 @@ void AnimationExporter::export_sampled_animation_set(Object *ob)
                float fsize[3];
                float feul[3];
 
-               evaluate_anim_with_constraints(ob, *ctime); // set object transforms to the frame
+               bc_update_scene(eval_ctx, scene, *ctime);
 
                BKE_object_matrix_local_get(ob, fmat);
                mat4_decompose(floc, fquat, fsize, fmat);
@@ -215,16 +273,16 @@ void AnimationExporter::export_sampled_animation_set(Object *ob)
 
        std::string ob_name = id_name(ob);
 
-       create_sampled_animation(3, baked_curves[TIME], baked_curves[SCALE], ob_name, "scale",   "", false);
-       create_sampled_animation(3, baked_curves[TIME], baked_curves[LOC],  ob_name, "location", "", false);
+       create_sampled_animation(3, ctimes, baked_curves[SCALE], ob_name, "scale",   "", false);
+       create_sampled_animation(3, ctimes, baked_curves[LOC],  ob_name, "location", "", false);
 
        /* Not sure how to export rotation as a 3channel animation, 
         * so separate into 3 single animations for now:
         */
 
-       create_sampled_animation(1, baked_curves[TIME], baked_curves[EULX], ob_name, "rotation", "X", true);
-       create_sampled_animation(1, baked_curves[TIME], baked_curves[EULY], ob_name, "rotation", "Y", true);
-       create_sampled_animation(1, baked_curves[TIME], baked_curves[EULZ], ob_name, "rotation", "Z", true);
+       create_sampled_animation(1, ctimes, baked_curves[EULX], ob_name, "rotation", "X", true);
+       create_sampled_animation(1, ctimes, baked_curves[EULY], ob_name, "rotation", "Y", true);
+       create_sampled_animation(1, ctimes, baked_curves[EULZ], ob_name, "rotation", "Z", true);
 
        fprintf(stdout, "Animation Export: Baked %zd frames for %s (sampling rate: %d)\n",
                baked_curves[0].size(),
@@ -243,19 +301,19 @@ void AnimationExporter::operator()(Object *ob)
        if (ob->adt && ob->adt->action) {
 
                if (ob->type == OB_ARMATURE) {
+                       /* Export skeletal animation (if any)*/
                        bArmature *arm = (bArmature *)ob->data;
                        for (Bone *bone = (Bone *)arm->bonebase.first; bone; bone = bone->next)
                                write_bone_animation_matrix(ob, bone);
                }
+
+               /* Armatures can have object animation and skeletal animation*/
+               if (this->export_settings->sampling_rate < 1) {
+                       export_keyframed_animation_set(ob);
+               }
                else {
-                       if (this->export_settings->sampling_rate == -1) {
-                               export_keyframed_animation_set(ob);
-                       }
-                       else {
-                               export_sampled_animation_set(ob);
-                       }
+                       export_sampled_animation_set(ob);
                }
-
        }
 
        export_object_constraint_animation(ob);
@@ -1187,9 +1245,51 @@ std::string AnimationExporter::create_source_from_vector(COLLADASW::InputSemanti
        return source_id;
 }
 
+std::string AnimationExporter::create_4x4_source(std::vector<float> &ctimes, std::vector<float> &values , const std::string &anim_id)
+{
+       COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
+       std::string source_id = anim_id + get_semantic_suffix(semantic);
+
+       COLLADASW::Float4x4Source source(mSW);
+       source.setId(source_id);
+       source.setArrayId(source_id + ARRAY_ID_SUFFIX);
+       source.setAccessorCount(ctimes.size());
+       source.setAccessorStride(16);
+
+       COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
+       add_source_parameters(param, semantic, false, NULL, true);
+
+       source.prepareToAppendValues();
+
+       bPoseChannel *parchan = NULL;
+       bPoseChannel *pchan = NULL;
+
+
+       std::vector<float>::iterator it;
+
+       for (it = values.begin(); it != values.end(); it+=16) {
+               float mat[4][4];
+
+               bc_copy_m4_farray(mat, &*it);
+
+               UnitConverter converter;
+               double outmat[4][4];
+               converter.mat4_to_dae_double(outmat, mat);
+
+               if (this->export_settings->limit_precision)
+                       bc_sanitize_mat(outmat, 6);
+
+               source.appendValues(outmat);
+       }
+
+       source.finish();
+       return source_id;
+}
 
 std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Object *ob, Bone *bone, const std::string &anim_id)
 {
+       bool is_bone_animation = ob->type == OB_ARMATURE && bone;
+
        COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
        std::string source_id = anim_id + get_semantic_suffix(semantic);
 
@@ -1207,7 +1307,7 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj
        bPoseChannel *parchan = NULL;
        bPoseChannel *pchan = NULL;
 
-       if (ob->type == OB_ARMATURE && bone) {
+       if (is_bone_animation) {
                bPose *pose = ob->pose;
                pchan = BKE_pose_channel_find_name(pose, bone->name);
                if (!pchan)
@@ -1224,12 +1324,10 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj
                float mat[4][4], ipar[4][4];
                float frame = *it;
 
-               float ctime = BKE_scene_frame_get_from_ctime(scene, *it);
-               CFRA = BKE_scene_frame_get_from_ctime(scene, *it);
-               //BKE_scene_graph_update_for_newframe(G.main->eval_ctx, depsgraph, G.main,scene);
-               BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL);
-                               
-               if (bone) {
+               float ctime = BKE_scene_frame_get_from_ctime(scene, frame);
+               bc_update_scene(eval_ctx, scene, ctime);
+               if (is_bone_animation) {
+
                        if (pchan->flag & POSE_CHAIN) {
                                enable_fcurves(ob->adt->action, NULL);
                                BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL);
@@ -1269,9 +1367,6 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj
 
                }
                else {
-                       BKE_scene_frame_set(scene, ctime);
-                       Main *bmain = bc_get_main();
-                       BKE_animsys_evaluate_all_animation(bmain, scene, ctime);
                        copy_m4_m4(mat, ob->obmat);
                }