Partial rewrite of the Collada Module for Blender 2.8
authorGaia Clary <gaia.clary@machinimatrix.org>
Fri, 23 Nov 2018 14:57:45 +0000 (15:57 +0100)
committerGaia Clary <gaia.clary@machinimatrix.org>
Fri, 23 Nov 2018 16:08:14 +0000 (17:08 +0100)
Most important changes are in the Animation exporter and Animation Importer.
There is still some cleaning up to be done. But the Exporter/Importer basically
work within Blender 2.8

Some details:

User Interface:
The interface has been reorganized to look more like the FBX interface.

New options in user interface:

* keep_keyframes:
  When sampling the distance between 2 keyframes is defined by
  the sampling rate. Furthermore the keyframes defined in the
  FCurves are not exported. However when this option is enabled
  then also the defined keyframes will be added to the exported fcurves

* keep_smooth_curves:
  When sampling we do not use FCurves. So we also have no Curve handles
  for smooth exporting. However when this option is enabled, Blender
  does its best to recreate the handles for export. This is a very
  experimental feature and it is know to break when:

  - the exported animated objects have parent inverse matrices
    different from the unit matrix
  - The exported objects have negative scaling

  There may be many other situations when this feature breaks.
  This needs to be further tested. It may be removed later or replaced
  by something less wonky.

BlenderContext:
is a new class that contains the bridge to Blender. It contains
pointers to the current export/import context plus derived values
of Depsgraph, Scene, Main

Reporting:
I reorganized the output on the Blender Console to become more
informative and more readable

Preservation of Item names:
name attributes are now encoded with XML entities. This makes
sure that i can export/import names exactly defined in the tool.
This affects material names, bone names and object names.

Hierarchy export:
* Object and Bone Hierarchies are now exported correctly
  by taking the Blender parent/child hierarchy into account
* Export also not selected intermediate objects

  Problem:
  When we export an Object Hierarchy, then we must export
  all elements of the hierarchy to maintain the transforms. This
  is especially important when exporting animated objects, because the
  animation curves are exported as relative curves based on the
  parent-child hierarchy. If an intermediate animated object is missing
  then the exported animation breaks.

  Solution:
  If the "Selected" Optioon is enabled, then take care
  to also export all objects which are not selected and hidden,
  but which are parents of selected objects.

Node Based Material Importer (wip):
Added basic support for Materials with diffuse color and
diffuse textures. More properties (opacity, emission) need
changes in the used shader.
Note: Materials are all constructed by using the principled BSDF shader.

Animation Exporter:
* Massive optimization of the Animation Bake tool (Animation Sampler).
  Instead of sampling each fcurve separately, i now sample all
  exported fcurves simultaneously. So i avoid many (many!)
  scene updates during animation export.
* Add support for Continuous Acceleration (Fcurve handles)
  This allows us to create smoother FCurves during importing Collada
  Animation curves. Possibly this should become an option ionstead of
  a fixed import feature.
* Add support for sampling curves (to bake animations)
* The animation sampler now can be used for any animation curve.
  Before the sampler only looked at curves which are supported by
  Standard Collada 1.4. However the Collada exporter currently
  ignores all animation curves which are not covered by the 1.4.1
  Collada Standards. There is still some room for improvements
  here (work in progres)

  Known issues:

    * Some exports do currently not work reliably, among those
      are the camera animations, material animations and light animations
      those animations will be added back next (work in progres)

    * Exporting animation curves with keyframes (and tangents)
      sometimes results in odd curves (when parent inverse matrix is involved)
      This needs to be checked in more depth (probably it can not be solved).

    * Export of "all animations in scene" is disabled because the
      Collada Importer can not handle this reliably at the
      moment (work in progres).

* Support for Animation Clip export
  Added one extra level to the exported animations
  such that now all scene animations are enclosed:

  <Animation name="id_name(ob)_Action">
    <Animation>...</Animation>
    ...
  </Animation>

Animation Importer:
* Import of animations for objects with multiple materials
  When importing multiple materials for one object,
  the imported material animation curves have all been
  assigned to the first material in the object.

Error handling (wip):
The Importer was a bit confused as it sometimes ignored fatal
parsing errors and continued to import. I did my best to
unconfuse it, but i believe that this needs to be tested more.

Refactoring:

update : move generation of effect id names into own function
update : adjust importer/exporter for no longer supported HEMI lights
cleanup: Removed no lopnger existing attribute from the exporter presets
cleanup: Removed not needed Context attribute from DocumentExporter
fix    : Avoid duplicate deletion of temporary items
cleanup: fixed indentation and white space issues
update : Make BCAnimation class more self contained
cleanup: Renamed classes, updated comments for better reading
cleanup: Moved static class functions to collada_utils
cleanup: Moved typedefs to more intuitive locations
cleanup: indentation and class method declarations
cleanup: Removed no longer needed methods
update : Moved Classes into separate files
cleanup: Added comments
cleanup: take care of name conventions
...    : many more small changes, not helpful to list them all

51 files changed:
release/scripts/presets/operator/wm.collada_export/sl_plus_open_sim_rigged.py
source/blender/collada/AnimationClipExporter.cpp [new file with mode: 0644]
source/blender/collada/AnimationClipExporter.h [new file with mode: 0644]
source/blender/collada/AnimationCurveCache.cpp [new file with mode: 0644]
source/blender/collada/AnimationCurveCache.h [new file with mode: 0644]
source/blender/collada/AnimationExporter.cpp
source/blender/collada/AnimationExporter.h
source/blender/collada/AnimationImporter.cpp
source/blender/collada/AnimationImporter.h
source/blender/collada/ArmatureExporter.cpp
source/blender/collada/ArmatureExporter.h
source/blender/collada/BCAnimationCurve.cpp [new file with mode: 0644]
source/blender/collada/BCAnimationCurve.h [new file with mode: 0644]
source/blender/collada/BCAnimationSampler.cpp [new file with mode: 0644]
source/blender/collada/BCAnimationSampler.h [new file with mode: 0644]
source/blender/collada/BCSampleData.cpp [new file with mode: 0644]
source/blender/collada/BCSampleData.h [new file with mode: 0644]
source/blender/collada/BlenderContext.cpp [new file with mode: 0644]
source/blender/collada/BlenderContext.h [new file with mode: 0644]
source/blender/collada/CMakeLists.txt
source/blender/collada/ControllerExporter.cpp
source/blender/collada/ControllerExporter.h
source/blender/collada/DocumentExporter.cpp
source/blender/collada/DocumentExporter.h
source/blender/collada/DocumentImporter.cpp
source/blender/collada/DocumentImporter.h
source/blender/collada/EffectExporter.cpp
source/blender/collada/EffectExporter.h
source/blender/collada/ErrorHandler.cpp
source/blender/collada/ExportSettings.h
source/blender/collada/GeometryExporter.cpp
source/blender/collada/GeometryExporter.h
source/blender/collada/ImageExporter.cpp
source/blender/collada/ImageExporter.h
source/blender/collada/LightExporter.cpp
source/blender/collada/MaterialExporter.cpp
source/blender/collada/MaterialExporter.h
source/blender/collada/Materials.cpp [new file with mode: 0644]
source/blender/collada/Materials.h [new file with mode: 0644]
source/blender/collada/MeshImporter.cpp
source/blender/collada/SceneExporter.cpp
source/blender/collada/SceneExporter.h
source/blender/collada/SkinInfo.cpp
source/blender/collada/TransformReader.cpp
source/blender/collada/collada.cpp
source/blender/collada/collada.h
source/blender/collada/collada_internal.cpp
source/blender/collada/collada_internal.h
source/blender/collada/collada_utils.cpp
source/blender/collada/collada_utils.h
source/blender/editors/io/io_collada.c

index 7825a4d0f328689106fd6e04909a6ef7d874fb33..311d71c455714721920e52160172de135d2958a3 100644 (file)
@@ -10,7 +10,6 @@ op.include_armatures = True
 op.include_shapekeys = False
 op.deform_bones_only = True
 op.active_uv_only = True
-op.include_uv_textures = True
 op.use_texture_copies = True
 op.triangulate = True
 op.use_object_instantiation = False
diff --git a/source/blender/collada/AnimationClipExporter.cpp b/source/blender/collada/AnimationClipExporter.cpp
new file mode 100644 (file)
index 0000000..a2c4b38
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed.
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+#include "GeometryExporter.h"
+#include "AnimationClipExporter.h"
+#include "MaterialExporter.h"
+
+void AnimationClipExporter::exportAnimationClips(Scene *sce)
+{
+       openLibrary();
+       std::map<std::string, COLLADASW::ColladaAnimationClip *> clips;
+
+       std::vector<std::vector<std::string>>::iterator anim_meta_entry;
+       for (anim_meta_entry = anim_meta.begin(); anim_meta_entry != anim_meta.end(); ++anim_meta_entry) {
+               std::vector<std::string> entry = *anim_meta_entry;
+               std::string action_id = entry[0];
+               std::string action_name = entry[1];
+
+               std::map<std::string, COLLADASW::ColladaAnimationClip *>::iterator it = clips.find(action_name);
+               if (it == clips.end())
+               {
+                       COLLADASW::ColladaAnimationClip *clip = new COLLADASW::ColladaAnimationClip(action_name);
+                       clips[action_name] = clip;
+               }
+               COLLADASW::ColladaAnimationClip *clip = clips[action_name];
+               clip->setInstancedAnimation(action_id);
+       }
+
+       std::map<std::string, COLLADASW::ColladaAnimationClip *>::iterator clips_it;
+       for (clips_it = clips.begin(); clips_it != clips.end(); clips_it++) {
+               COLLADASW::ColladaAnimationClip *clip = (COLLADASW::ColladaAnimationClip *)clips_it->second;
+               addAnimationClip(*clip);
+       }
+
+       closeLibrary();
+}
diff --git a/source/blender/collada/AnimationClipExporter.h b/source/blender/collada/AnimationClipExporter.h
new file mode 100644 (file)
index 0000000..d76a3fa
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "COLLADASWLibraryAnimationClips.h"
+
+
+class AnimationClipExporter:COLLADASW::LibraryAnimationClips {
+private:
+       Depsgraph *depsgraph;
+       Scene *scene;
+       COLLADASW::StreamWriter *sw;
+       const ExportSettings *export_settings;
+       std::vector<std::vector<std::string>> anim_meta;
+
+public:
+
+       AnimationClipExporter(Depsgraph *depsgraph , COLLADASW::StreamWriter *sw, const ExportSettings *export_settings, std::vector<std::vector<std::string>> anim_meta) :
+               depsgraph(depsgraph),
+               COLLADASW::LibraryAnimationClips(sw),
+               export_settings(export_settings),
+               anim_meta(anim_meta)
+       {
+               this->sw = sw;
+       }
+
+       void exportAnimationClips(Scene *sce);
+};
diff --git a/source/blender/collada/AnimationCurveCache.cpp b/source/blender/collada/AnimationCurveCache.cpp
new file mode 100644 (file)
index 0000000..3ad921b
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed.
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+#include "AnimationCurveCache.h"
+
+extern "C" {
+#include "BKE_action.h"
+#include "BLI_listbase.h"
+}
+
+AnimationCurveCache::AnimationCurveCache(bContext *C):
+       mContext(C)
+{
+}
+
+AnimationCurveCache::~AnimationCurveCache()
+{
+       clear_cache();
+}
+
+void AnimationCurveCache::clear_cache()
+{
+
+}
+
+void AnimationCurveCache::clear_cache(Object *ob)
+{
+
+}
+
+void AnimationCurveCache::create_curves(Object *ob)
+{
+
+}
+
+void AnimationCurveCache::addObject(Object *ob)
+{
+       cached_objects.push_back(ob);
+}
+
+bool AnimationCurveCache::bone_matrix_local_get(Object *ob, Bone *bone, float(&mat)[4][4], bool for_opensim)
+{
+
+       /* Ok, lets be super cautious and check if the bone exists */
+       bPose *pose = ob->pose;
+       bPoseChannel *pchan = BKE_pose_channel_find_name(pose, bone->name);
+       if (!pchan) {
+               return false;
+       }
+
+       bAction *action = bc_getSceneObjectAction(ob);
+       bPoseChannel *parchan = pchan->parent;
+       enable_fcurves(action, bone->name);
+       float ipar[4][4];
+
+       if (bone->parent) {
+               invert_m4_m4(ipar, parchan->pose_mat);
+               mul_m4_m4m4(mat, ipar, pchan->pose_mat);
+       }
+       else
+               copy_m4_m4(mat, pchan->pose_mat);
+
+       /* OPEN_SIM_COMPATIBILITY
+       * AFAIK animation to second life is via BVH, but no
+       * reason to not have the collada-animation be correct
+       */
+       if (for_opensim) {
+               float temp[4][4];
+               copy_m4_m4(temp, bone->arm_mat);
+               temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
+               invert_m4(temp);
+
+               mul_m4_m4m4(mat, mat, temp);
+
+               if (bone->parent) {
+                       copy_m4_m4(temp, bone->parent->arm_mat);
+                       temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
+
+                       mul_m4_m4m4(mat, temp, mat);
+               }
+       }
+
+       return true;
+}
+
+void AnimationCurveCache::sampleMain(Scene *scene, BC_export_transformation_type atm_type, bool for_opensim)
+{
+       std::map<int, std::vector<SamplePoint>>::iterator frame;
+       for (frame = sample_frames.begin(); frame != sample_frames.end(); frame++) {
+               int frame_index = frame->first;
+               std::vector<SamplePoint> sample_points = frame->second;
+
+               bc_update_scene(mContext, scene, frame_index);
+
+               for (int spi = 0; spi < sample_points.size(); spi++) {
+                       SamplePoint &point = sample_points[spi];
+                       Object *ob = point.get_object();
+                       float mat[4][4];
+
+                       if (ob->type == OB_ARMATURE) {
+                               /* For Armatures we need to check if this maybe is a pose sample point*/
+                               Bone *bone = point.get_bone();
+                               if (bone) {
+                                       if (bone_matrix_local_get(ob, bone, mat, for_opensim)) {
+                                               point.set_matrix(mat);
+                                       }
+                                       continue;
+                               }
+                       }
+
+                       /* When this SamplePoint is not for a Bone, 
+                        * then we just store the Object local matrix here
+                        */
+
+                       BKE_object_matrix_local_get(ob, mat);
+                       point.set_matrix(mat);
+
+               }
+       }
+}
+
+/*
+* enable fcurves driving a specific bone, disable all the rest
+* if bone_name = NULL enable all fcurves
+*/
+void AnimationCurveCache::enable_fcurves(bAction *act, char *bone_name)
+{
+       FCurve *fcu;
+       char prefix[200];
+
+       if (bone_name)
+               BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name);
+
+       for (fcu = (FCurve *)act->curves.first; fcu; fcu = fcu->next) {
+               if (bone_name) {
+                       if (STREQLEN(fcu->rna_path, prefix, strlen(prefix)))
+                               fcu->flag &= ~FCURVE_DISABLED;
+                       else
+                               fcu->flag |= FCURVE_DISABLED;
+               }
+               else {
+                       fcu->flag &= ~FCURVE_DISABLED;
+               }
+       }
+}
+/*
+* Sample the scene at frames where object fcurves
+* have defined keys.
+*/
+void AnimationCurveCache::sampleScene(Scene *scene, BC_export_transformation_type atm_type, bool for_opensim, bool keyframe_at_end)
+{
+       create_sample_frames_from_keyframes();
+       sampleMain(scene, atm_type, for_opensim);
+}
+
+void AnimationCurveCache::sampleScene(Scene *scene, BC_export_transformation_type atm_type, int sampling_rate, bool for_opensim, bool keyframe_at_end)
+{
+       create_sample_frames_generated(scene->r.sfra, scene->r.efra, sampling_rate, keyframe_at_end);
+       sampleMain(scene, atm_type, for_opensim);
+}
+
+std::vector<FCurve *> *AnimationCurveCache::getSampledCurves(Object *ob)
+{
+       std::map<Object *, std::vector<FCurve *>>::iterator fcurves;
+       fcurves = cached_curves.find(ob);
+       return (fcurves == cached_curves.end()) ? NULL : &fcurves->second;
+}
+
+std::vector<SamplePoint> &AnimationCurveCache::getFrameInfos(int frame_index)
+{
+       std::map<int, std::vector<SamplePoint>>::iterator frames = sample_frames.find(frame_index);
+       if (frames == sample_frames.end()) {
+               std::vector<SamplePoint> sample_points;
+               sample_frames[frame_index] = sample_points;
+       }
+       return sample_frames[frame_index];
+}
+
+
+void AnimationCurveCache::add_sample_point(SamplePoint &point)
+{
+       int frame_index = point.get_frame();
+       std::vector<SamplePoint> &frame_infos = getFrameInfos(frame_index);
+       frame_infos.push_back(point);
+}
+
+/*
+* loop over all cached objects
+*     loop over all fcurves
+*         record all keyframes
+* 
+* The vector sample_frames finally contains a list of vectors
+* where each vector contains a list of SamplePoints which
+* need to be processed when evaluating the animation.
+*/
+void AnimationCurveCache::create_sample_frames_from_keyframes()
+{
+       sample_frames.clear();
+       for (int i = 0; i < cached_objects.size(); i++) {
+               Object *ob = cached_objects[i];
+               bAction *action = bc_getSceneObjectAction(ob);
+               FCurve *fcu = (FCurve *)action->curves.first;
+
+               for (; fcu; fcu = fcu->next) {
+                       for (unsigned int i = 0; i < fcu->totvert; i++) {
+                               float f = fcu->bezt[i].vec[1][0];
+                               int frame_index = int(f);
+                               SamplePoint sample_point(frame_index, ob, fcu, i);
+                               add_sample_point(sample_point);
+                       }
+               }
+       }
+}
+
+/*
+* loop over all cached objects
+*     loop over active action using a stesize of sampling_rate
+*         record all frames
+*
+* The vector sample_frames finally contains a list of vectors
+* where each vector contains a list of SamplePoints which
+* need to be processed when evaluating the animation.
+* Note: The FCurves of the objects will not be used here.
+*/
+void AnimationCurveCache::create_sample_frames_generated(float sfra, float efra, int sampling_rate, int keyframe_at_end)
+{
+       sample_frames.clear();
+
+       for (int i = 0; i < cached_objects.size(); i++) {
+
+               Object *ob = cached_objects[i];
+               float f = sfra;
+
+               do {            
+                       int frame_index = int(f);
+                       SamplePoint sample_point(frame_index, ob);
+                       add_sample_point(sample_point);
+
+                       /* Depending on the Object type add more sample points here
+                       */
+
+                       if (ob && ob->type == OB_ARMATURE) {
+                               LISTBASE_FOREACH(bPoseChannel *, pchan, &ob->pose->chanbase) {
+                                       SamplePoint point(frame_index, ob, pchan->bone);
+                                       add_sample_point(sample_point);
+                               }
+                       }
+
+                       if (f == efra)
+                               break;
+                       f += sampling_rate;
+                       if (f > efra)
+                               if (keyframe_at_end)
+                                       f = efra; // make sure the last frame is always exported
+                               else
+                                       break;
+               } while (true);
+       }
+}
+
+Matrix::Matrix()
+{
+       unit_m4(matrix);
+}
+
+Matrix::Matrix(float (&mat)[4][4])
+{
+       set_matrix(mat);
+}
+
+void Matrix::set_matrix(float(&mat)[4][4])
+{
+       copy_m4_m4(matrix, mat);
+}
+
+void Matrix::set_matrix(Matrix &mat)
+{
+       copy_m4_m4(matrix, mat.matrix);
+}
+
+void Matrix::get_matrix(float(&mat)[4][4])
+{
+       copy_m4_m4(mat, matrix);
+}
+
+SamplePoint::SamplePoint(int frame, Object *ob)
+{
+       this->frame = frame;
+       this->fcu = NULL;
+       this->ob = ob;
+       this->pose_bone = NULL;
+       this->index = -1;
+}
+
+SamplePoint::SamplePoint(int frame, Object *ob, FCurve *fcu, int index)
+{
+       this->frame = frame;
+       this->fcu = fcu;
+       this->ob = ob;
+       this->pose_bone = NULL;
+       this->index = index;
+       this->path = std::string(fcu->rna_path);
+
+       /* Further elaborate on what this Fcurve is doing by checking
+        * its rna_path
+     */
+
+       if (ob && ob->type == OB_ARMATURE) {
+               char *boneName = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
+               bPose *pose = ob->pose;
+               if (boneName) {
+                       bPoseChannel *pchan = BKE_pose_channel_find_name(pose, boneName);
+                       this->pose_bone = pchan->bone;
+               }
+       }
+}
+
+
+SamplePoint::SamplePoint(int frame, Object *ob, Bone *bone)
+{
+       this->frame = frame;
+       this->fcu = NULL;
+       this->ob = ob;
+       this->pose_bone = bone;
+       this->index = -1;
+       this->path = "pose.bones[\"" + id_name(bone) + "\"].matrix";
+}
+
+Matrix &SamplePoint::get_matrix()
+{
+       return matrix;
+}
+
+void SamplePoint::set_matrix(Matrix &mat)
+{
+       this->matrix.set_matrix(mat);
+}
+
+void SamplePoint::set_matrix(float(&mat)[4][4])
+{
+
+}
+
+Object *SamplePoint::get_object()
+{
+       return this->ob;
+}
+
+Bone *SamplePoint::get_bone()
+{
+       return this->pose_bone;
+}
+
+FCurve *SamplePoint::get_fcurve()
+{
+       return this->fcu;
+}
+
+int SamplePoint::get_frame()
+{
+       return this->frame;
+}
+
+int SamplePoint::get_fcurve_index()
+{
+       return this->index;
+}
+
+std::string &SamplePoint::get_path()
+{
+       return path;
+}
\ No newline at end of file
diff --git a/source/blender/collada/AnimationCurveCache.h b/source/blender/collada/AnimationCurveCache.h
new file mode 100644 (file)
index 0000000..4a4cc77
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed.
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+#ifndef __ANIMATION_CURVE_CACHE_H__
+#define __ANIMATION_CURVE_CACHE_H__
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <vector>
+#include <map>
+#include <algorithm>    // std::find
+
+#include "exportSettings.h"
+#include "collada_utils.h"
+
+extern "C"
+{
+#include "DNA_object_types.h"
+#include "DNA_anim_types.h"
+}
+
+class Matrix {
+private:
+       float matrix[4][4];
+public:
+       Matrix();
+       Matrix(float (&mat)[4][4]);
+       void set_matrix(float (&mat)[4][4]);
+       void set_matrix(Matrix &mat);
+       void get_matrix(float (&mat)[4][4]);
+};
+
+class SamplePoint {
+
+private:
+
+       Object * ob;
+       Bone *pose_bone;
+       FCurve *fcu;
+       int frame; /* frame in timeline (not sure if we actually should store a float here) */
+       int index; /* Keyframe index in fcurve (makes sense only when fcu is also set) */
+       std::string path; /* Do not mixup with rna_path. It is used for different purposes! */
+
+       Matrix matrix; /* Local matrix, by default unit matrix, will be set when sampling */
+
+public:
+
+       SamplePoint(int frame, Object *ob);
+       SamplePoint(int frame, Object *ob, FCurve *fcu, int index);
+       SamplePoint(int frame, Object *ob, Bone *bone);
+
+       Object *get_object();
+       Bone *get_bone();
+       FCurve *get_fcurve();
+       int get_frame();
+       int get_fcurve_index();
+       Matrix &get_matrix();
+       std::string &get_path();
+
+       void set_matrix(Matrix &matrix);
+       void set_matrix(float(&mat)[4][4]);
+};
+
+
+class AnimationCurveCache {
+private:
+       void clear_cache(); // remove all sampled FCurves
+       void clear_cache(Object *ob); //remove sampled FCurves for single object
+       void create_curves(Object *ob);
+
+       std::vector<Object *> cached_objects; // list of objects for caching
+       std::map<Object *, std::vector<FCurve *>> cached_curves; //map of cached FCurves
+       std::map<int, std::vector<SamplePoint>> sample_frames; // list of frames where objects need to be sampled
+
+       std::vector<SamplePoint> &getFrameInfos(int frame_index);
+       void add_sample_point(SamplePoint &point);
+       void enable_fcurves(bAction *act, char *bone_name);
+       bool bone_matrix_local_get(Object *ob, Bone *bone, float (&mat)[4][4], bool for_opensim);
+
+       bContext *mContext;
+
+public:
+
+       AnimationCurveCache(bContext *C);
+       ~AnimationCurveCache();
+
+       void addObject(Object *obj);
+       
+       void sampleMain(Scene *scene, 
+               BC_export_transformation_type atm_type, 
+               bool for_opensim);
+       
+       void sampleScene(Scene *scene, 
+               BC_export_transformation_type atm_type, 
+               bool for_opensim,
+               bool keyframe_at_end = true); // use keys from FCurves, use timeline boundaries
+
+       void sampleScene(Scene *scene, 
+               BC_export_transformation_type atm_type,
+               int sampling_rate, bool for_opensim,
+               bool keyframe_at_end = true ); // generate keyframes for frames use timeline boundaries
+
+       std::vector<FCurve *> *getSampledCurves(Object *ob);
+
+       void create_sample_frames_from_keyframes();
+       void create_sample_frames_generated(float sfra, float efra, int sampling_rate, int keyframe_at_end);
+};
+
+
+#endif
index 4113e871e74b97bcacb2189781a2ba2f62610baa..4491b7412a6024f68702d025fdabbad6a04cbb68 100644 (file)
 
 #include "GeometryExporter.h"
 #include "AnimationExporter.h"
+#include "AnimationClipExporter.h"
+#include "BCAnimationSampler.h"
 #include "MaterialExporter.h"
+#include "collada_utils.h"
 
-template<class Functor>
-void forEachObjectInExportSet(Scene *sce, Functor &f, LinkNode *export_set)
-{
-       LinkNode *node;
-       for (node = export_set; node; node = node->next) {
-               Object *ob = (Object *)node->link;
-               f(ob);
-       }
-}
+std::string EMPTY_STRING;
 
-bool AnimationExporter::exportAnimations(Main *bmain, Scene *sce)
+std::string AnimationExporter::get_axis_name(std::string channel, int id)
 {
-       bool has_animations = hasAnimations(sce);
-       m_bmain = bmain;
-       if (has_animations) {
-               this->scene = sce;
-
-               openLibrary();
+       static std::map<std::string, std::vector<std::string>> BC_COLLADA_AXIS_FROM_TYPE = {
+               { "color"         ,{ "R", "G", "B" } },
+               { "specular_color",{ "R", "G", "B" } },
+               { "diffuse_color",{ "R", "G", "B" } },
+               { "alpha",{ "R", "G", "B" } },
+               { "scale",{ "X", "Y", "Z" } },
+               { "location",{ "X", "Y", "Z" } },
+               { "rotation_euler",{ "X", "Y", "Z" } }
+       };
 
-               forEachObjectInExportSet(sce, *this, this->export_settings->export_set);
+       std::map<std::string, std::vector<std::string>>::const_iterator it;
+       it = BC_COLLADA_AXIS_FROM_TYPE.find(channel);
+       if (it == BC_COLLADA_AXIS_FROM_TYPE.end())
+               return "";
 
-               closeLibrary();
-       }
-       return has_animations;
+       const std::vector<std::string> &subchannel = it->second;
+       if (id >= subchannel.size())
+               return "";
+       return subchannel[id];
 }
 
-bool AnimationExporter::is_flat_line(std::vector<float> &values, int channel_count)
+bool AnimationExporter::open_animation_container(bool has_container, Object *ob)
 {
-       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;
-               }
+       if (!has_container) {
+               char anim_id[200];
+               sprintf(anim_id, "action_container-%s", translate_id(id_name(ob)).c_str());
+               openAnimation(anim_id, encode_xml(id_name(ob)));
        }
        return true;
 }
-/*
- * This function creates a complete LINEAR Collada <Animation> Entry with all needed
- * <source>, <sampler>, and <channel> entries.
- * This is is used for creating sampled Transformation Animations for either:
- *
- * 1-axis animation:
- *   times contains the time points in seconds from within the timeline
- *   values contains the data (list of single floats)
- *   channel_count = 1
- *   axis_name = ['X' | 'Y' | 'Z']
- *   is_rot indicates if the animation is a rotation
- *
- * 3-axis animation:
- *   times contains the time points in seconds from within the timeline
- *   values contains the data (list of floats where each 3 entries are one vector)
- *   channel_count = 3
- *   axis_name = "" (actually not used)
- *   is_rot = false (see xxx below)
- *
- * xxx:
- *   I tried to create a 3 axis rotation animation
- *   like for translation or scale. But i could not
- *   figure out how to setup the channel for this case.
- *   So for now rotations are exported as 3 separate 1-axis collada animations
- *   See export_sampled_animation() further down.
- */
-void AnimationExporter::create_sampled_animation(int channel_count,
-       std::vector<float> &times,
-       std::vector<float> &values,
-       std::string ob_name,
-       std::string label,
-       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);
-
-       /* create input source */
-       std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, times, false, anim_id, "");
-
-       /* create output source */
-       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)
-               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);
-       std::string empty;
-       sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
-       sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
-
-       /* TODO create in/out tangents source (LINEAR) */
-       std::string interpolation_id = fake_interpolation_source(times.size(), anim_id, "");
-
-       /* Create Sampler */
-       sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
-       addSampler(sampler);
-
-       /* Create channel */
-       std::string target = translate_id(ob_name) + "/" + label + axis_name + ((is_rot) ? ".ANGLE" : "");
-       addChannel(COLLADABU::URI(empty, sampler_id), target);
-
-       closeAnimation();
-
-}
 
-/*
- * Export all animation FCurves of an Object.
- *
- * Note: This uses the keyframes as sample points,
- * and exports "baked keyframes" while keeping the tangent information
- * of the FCurves intact. This works for simple cases, but breaks
- * especially when negative scales are involved in the animation.
- *
- * If it is necessary to conserve the Animation precisely then
- * use export_sampled_animation_set() instead.
- */
-void AnimationExporter::export_keyframed_animation_set(Object *ob)
+void AnimationExporter::openAnimationWithClip(std::string action_id, std::string action_name)
 {
-       FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
-       if (!fcu) {
-               return; /* object has no animation */
-       }
-
-       if (this->export_settings->export_transformation_type == BC_TRANSFORMATION_TYPE_MATRIX) {
+       std::vector<std::string> anim_meta_entry;
+       anim_meta_entry.push_back(translate_id(action_id));
+       anim_meta_entry.push_back(action_name);
+       anim_meta.push_back(anim_meta_entry);
 
-               std::vector<float> ctimes;
-               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;
-               }
-       }
+       openAnimation(translate_id(action_id), action_name);
 }
 
-/*
- * Export the sampled animation of an Object.
- *
- * Note: This steps over all animation frames (step size is given in export_settings.sample_size)
- * and then evaluates the transformation,
- * and exports "baked samples" This works always, however currently the interpolation type is set
- * to LINEAR for now. (maybe later this can be changed to BEZIER)
- *
- * Note: If it is necessary to keep the FCurves intact, then use export_keyframed_animation_set() instead.
- * However be aware that exporting keyframed animation may modify the animation slightly.
- * Also keyframed animation exports tend to break when negative scales are involved.
- */
-void AnimationExporter::export_sampled_animation_set(Object *ob)
+void AnimationExporter::close_animation_container(bool has_container)
 {
-       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);
-       }
+       if (has_container)
+               closeAnimation();
 }
 
-void AnimationExporter::export_sampled_matrix_animation(Object *ob, std::vector<float> &ctimes)
+bool AnimationExporter::exportAnimations()
 {
-       UnitConverter converter;
+       Scene *sce = blender_context.get_scene();
 
-       std::vector<float> values;
+       LinkNode &export_set = *this->export_settings->export_set;
+       bool has_anim_data = bc_has_animations(sce, export_set);
+       int animation_count = 0;
+       if (has_anim_data) {
 
-       for (std::vector<float>::iterator ctime = ctimes.begin(); ctime != ctimes.end(); ++ctime) {
-               float fmat[4][4];
+               BCObjectSet animated_subset;
+               BCAnimationSampler::get_animated_from_export_set(animated_subset, export_set);
+               animation_count = animated_subset.size();
+               BCAnimationSampler animation_sampler(blender_context, animated_subset);
 
-               bc_update_scene(m_bmain, depsgraph, scene, *ctime);
-               BKE_object_matrix_local_get(ob, fmat);
-               if (this->export_settings->limit_precision)
-                       bc_sanitize_mat(fmat, 6);
-
-               for (int i = 0; i < 4; i++)
-                       for (int j = 0; j < 4; j++)
-                               values.push_back(fmat[i][j]);
-       }
+               try {
+                       animation_sampler.sample_scene(
+                               export_settings->sampling_rate,
+                               /*keyframe_at_end = */ true,
+                               export_settings->open_sim,
+                               export_settings->keep_keyframes,
+                               export_settings->export_animation_type
+                       );
 
-       std::string ob_name = id_name(ob);
+                       openLibrary();
 
-       create_sampled_animation(16, ctimes, values, ob_name, "transform", "", false);
-}
+                       BCObjectSet::iterator it;
+                       for (it = animated_subset.begin(); it != animated_subset.end(); ++it) {
+                               Object *ob = *it;
+                               exportAnimation(ob, animation_sampler);
+                       }
+               }
+               catch (std::invalid_argument &iae)
+               {
+                       fprintf(stderr, "Animation export interrupted");
+                       fprintf(stderr, "Exception was: %s", iae.what());
+               }
 
-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;
-
-       std::vector<float> baked_curves[5];
-
-       for (std::vector<float>::iterator ctime = ctimes.begin(); ctime != ctimes.end(); ++ctime ) {
-               float fmat[4][4];
-               float floc[3];
-               float fquat[4];
-               float fsize[3];
-               float feul[3];
-
-               bc_update_scene(m_bmain, depsgraph, scene, *ctime);
-               BKE_object_matrix_local_get(ob, fmat);
-               mat4_decompose(floc, fquat, fsize, fmat);
-               quat_to_eul(feul, fquat);
-
-               baked_curves[LOC].push_back(floc[0]);
-               baked_curves[LOC].push_back(floc[1]);
-               baked_curves[LOC].push_back(floc[2]);
-
-               baked_curves[EULX].push_back(feul[0]);
-               baked_curves[EULY].push_back(feul[1]);
-               baked_curves[EULZ].push_back(feul[2]);
-
-               baked_curves[SCALE].push_back(fsize[0]);
-               baked_curves[SCALE].push_back(fsize[1]);
-               baked_curves[SCALE].push_back(fsize[2]);
+               closeLibrary();
 
+#if 0
+               /* TODO: If all actions shall be exported, we need to call the
+                * AnimationClipExporter which will figure out which actions
+                * need to be exported for which objects
+                */ 
+               if (this->export_settings->include_all_actions) {
+                       AnimationClipExporter ace(eval_ctx, sw, export_settings, anim_meta);
+                       ace.exportAnimationClips(sce);
+               }
+#endif
        }
-
-       std::string ob_name = id_name(ob);
-
-       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, 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 %d frames for %s (sampling rate: %d)\n",
-               (int)baked_curves[0].size(),
-               ob->id.name,
-               this->export_settings->sampling_rate);
+       return animation_count;
 }
 
 /* called for each exported object */
-void AnimationExporter::operator()(Object *ob)
+void AnimationExporter::exportAnimation(Object *ob, BCAnimationSampler &sampler)
 {
-       char *transformName;
+       bool container_is_open = false;
 
-       /* bool isMatAnim = false; */ /* UNUSED */
+       //Transform animations (trans, rot, scale)
+       container_is_open = open_animation_container(container_is_open, ob);
 
-       //Export transform animations
-       if (ob->adt && ob->adt->action) {
+       /* Now take care of the Object Animations
+        * Note: For Armatures the skeletal animation has already been exported (see above)
+        * However Armatures also can have Object animation.
+        */
+       bool export_as_matrix = this->export_settings->export_transformation_type == BC_TRANSFORMATION_TYPE_MATRIX;
+       if (export_as_matrix) {
+               export_matrix_animation(ob, sampler); // export all transform_curves as one single matrix animation
+       }
 
-               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);
-               }
+       export_curve_animation_set(ob, sampler, export_as_matrix);
 
-               /* Armatures can have object animation and skeletal animation*/
-               if (this->export_settings->sampling_rate < 1) {
-                       export_keyframed_animation_set(ob);
-               }
-               else {
-                       export_sampled_animation_set(ob);
-               }
-       }
+       if (ob->type == OB_ARMATURE) {
 
-       export_object_constraint_animation(ob);
+#ifdef WITH_MORPH_ANIMATION
+               /* TODO: This needs to be handled by extra profiles, postponed for now */
+               export_morph_animation(ob);
+#endif
 
-       //This needs to be handled by extra profiles, so postponed for now
-       //export_morph_animation(ob);
+               /* Export skeletal animation (if any) */
+               bArmature *arm = (bArmature *)ob->data;
+               for (Bone *root_bone = (Bone *)arm->bonebase.first; root_bone; root_bone = root_bone->next)
+                       export_bone_animations_recursive(ob, root_bone, sampler);
+       }
 
-       //Export Lamp parameter animations
-       if ( (ob->type == OB_LAMP) && ((Lamp *)ob->data)->adt && ((Lamp *)ob->data)->adt->action) {
-               FCurve *fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first);
-               while (fcu) {
-                       transformName = extract_transform_name(fcu->rna_path);
+       close_animation_container(container_is_open);
+}
 
-                       if ((STREQ(transformName, "color")) || (STREQ(transformName, "spot_size")) ||
-                           (STREQ(transformName, "spot_blend")) || (STREQ(transformName, "distance")))
-                       {
-                               create_keyframed_animation(ob, fcu, transformName, true);
-                       }
-                       fcu = fcu->next;
+/*
+ * Export all animation FCurves of an Object.
+ *
+ * Note: This uses the keyframes as sample points,
+ * and exports "baked keyframes" while keeping the tangent information
+ * of the FCurves intact. This works for simple cases, but breaks
+ * especially when negative scales are involved in the animation.
+ * And when parent inverse matrices are involved (when exporting
+ * object hierarchies)
+ *
+ */
+void AnimationExporter::export_curve_animation_set(Object *ob, BCAnimationSampler &sampler, bool export_as_matrix)
+{
+       BCAnimationCurveMap *curves = sampler.get_curves(ob);
+
+       BCAnimationCurveMap::iterator it;
+       for (it = curves->begin(); it != curves->end(); ++it) {
+               BCAnimationCurve &curve = *it->second;
+               if (curve.get_channel_target() == "rotation_quaternion") {
+                       /*
+                          Can not export Quaternion animation in Collada as far as i know)
+                          Maybe automatically convert to euler rotation?
+                          Discard for now.
+                       */
+                       continue;
+               }
+
+               if (export_as_matrix && curve.is_transform_curve()) {
+                       /* All Transform curves will be exported within a single matrix animation,
+                        * see export_matrix_animation()
+                        * No need to export the curves here again.
+                        */
+                       continue;
                }
-       }
 
-       //Export Camera parameter animations
-       if ( (ob->type == OB_CAMERA) && ((Camera *)ob->data)->adt && ((Camera *)ob->data)->adt->action) {
-               FCurve *fcu = (FCurve *)(((Camera *)ob->data)->adt->action->curves.first);
-               while (fcu) {
-                       transformName = extract_transform_name(fcu->rna_path);
-
-                       if ((STREQ(transformName, "lens")) ||
-                           (STREQ(transformName, "ortho_scale")) ||
-                           (STREQ(transformName, "clip_end")) ||
-                               (STREQ(transformName, "clip_start")))
-                       {
-                               create_keyframed_animation(ob, fcu, transformName, true);
-                       }
-                       fcu = fcu->next;
+               if (!curve.is_animated()) {
+                       continue;
                }
-       }
 
-       //Export Material parameter animations.
-       for (int a = 0; a < ob->totcol; a++) {
-               Material *ma = give_current_material(ob, a + 1);
-               if (!ma) continue;
-               if (ma->adt && ma->adt->action) {
-                       /* isMatAnim = true; */
-                       FCurve *fcu = (FCurve *)ma->adt->action->curves.first;
-                       while (fcu) {
-                               transformName = extract_transform_name(fcu->rna_path);
-
-                               if ((STREQ(transformName, "specular_hardness")) || (STREQ(transformName, "specular_color")) ||
-                                   (STREQ(transformName, "diffuse_color")) || (STREQ(transformName, "alpha")) ||
-                                   (STREQ(transformName, "ior")))
-                               {
-                                       create_keyframed_animation(ob, fcu, transformName, true, ma);
-                               }
-                               fcu = fcu->next;
-                       }
+               BCAnimationCurve *mcurve = get_modified_export_curve(ob, curve, *curves);
+               if (mcurve) {
+                       export_curve_animation(ob, *mcurve);
+                       delete mcurve;
+               }
+               else {
+                       export_curve_animation(ob, curve);
                }
        }
 }
 
-void AnimationExporter::export_object_constraint_animation(Object *ob)
-{
-       std::vector<float> fra;
-       //Takes frames of target animations
-       make_anim_frames_from_targets(ob, fra);
-
-       if (fra.size())
-               dae_baked_object_animation(fra, ob);
-}
-
-void AnimationExporter::export_morph_animation(Object *ob)
+void AnimationExporter::export_matrix_animation(Object *ob, BCAnimationSampler &sampler)
 {
-       FCurve *fcu;
-       char *transformName;
-       Key *key = BKE_key_from_object(ob);
-       if (!key) return;
-
-       if (key->adt && key->adt->action) {
-               fcu = (FCurve *)key->adt->action->curves.first;
+       std::vector<float> frames;
+       sampler.get_object_frames(frames, ob);
+       if (frames.size() > 0) {
+               BCMatrixSampleMap samples;
+               bool is_animated = sampler.get_object_samples(samples, ob);
+               if (is_animated) {
+                       bAction *action = bc_getSceneObjectAction(ob);
+                       std::string name = encode_xml(id_name(ob));
+                       std::string action_name = (action == NULL) ? name + "-action" : id_name(action);
+                       std::string channel_type = "transform";
+                       std::string axis = "";
+                       std::string id = bc_get_action_id(action_name, name, channel_type, axis);
 
-               while (fcu) {
-                       transformName = extract_transform_name(fcu->rna_path);
-
-                       create_keyframed_animation(ob, fcu, transformName, true);
+                       std::string target = translate_id(name) + '/' + channel_type;
 
-                       fcu = fcu->next;
+                       export_collada_matrix_animation(id, name, target, frames, samples);
                }
        }
-
 }
 
-void AnimationExporter::make_anim_frames_from_targets(Object *ob, std::vector<float> &frames )
+//write bone animations in transform matrix sources
+void AnimationExporter::export_bone_animations_recursive(Object *ob, Bone *bone, BCAnimationSampler &sampler)
 {
-       ListBase *conlist = get_active_constraints(ob);
-       if (conlist == NULL) return;
-       bConstraint *con;
-       for (con = (bConstraint *)conlist->first; con; con = con->next) {
-               ListBase targets = {NULL, NULL};
-
-               const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
-
-               if (!validateConstraints(con)) continue;
-
-               if (cti && cti->get_constraint_targets) {
-                       bConstraintTarget *ct;
-                       Object *obtar;
-                       /* get targets
-                        * - constraints should use ct->matrix, not directly accessing values
-                        * - ct->matrix members have not yet been calculated here!
-                        */
-                       cti->get_constraint_targets(con, &targets);
-
-                       for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
-                               obtar = ct->tar;
-
-                               if (obtar)
-                                       find_keyframes(obtar, frames);
-                       }
-
-                       if (cti->flush_constraint_targets)
-                               cti->flush_constraint_targets(con, &targets, 1);
+       std::vector<float> frames;
+       sampler.get_bone_frames(frames, ob, bone);
+       
+       if (frames.size()) {
+               BCMatrixSampleMap samples;
+               bool is_animated = sampler.get_bone_samples(samples, ob, bone);
+               if (is_animated) {
+                       export_bone_animation(ob, bone, frames, samples);
                }
        }
+
+       for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next)
+               export_bone_animations_recursive(ob, child, sampler);
 }
 
-//euler sources from quternion sources
-float *AnimationExporter::get_eul_source_for_quat(Object *ob)
-{
-       FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
-       const int keys = fcu->totvert;
-       float *quat = (float *)MEM_callocN(sizeof(float) * fcu->totvert * 4, "quat output source values");
-       float *eul = (float *)MEM_callocN(sizeof(float) * fcu->totvert * 3, "quat output source values");
-       float temp_quat[4];
-       float temp_eul[3];
-       while (fcu) {
-               char *transformName = extract_transform_name(fcu->rna_path);
-
-               if (STREQ(transformName, "rotation_quaternion") ) {
-                       for (int i = 0; i < fcu->totvert; i++) {
-                               *(quat + (i * 4) + fcu->array_index) = fcu->bezt[i].vec[1][1];
+/*
+* In some special cases the exported Curve needs to be replaced
+* by a modified curve (for collada purposes)
+* This method checks if a conversion is necessary and if applicable
+* returns a pointer to the modified BCAnimationCurve.
+* IMPORTANT: the modified curve must be deleted by the caller when no longer needed
+* if no conversion is needed this method returns a NULL;
+*/
+BCAnimationCurve *AnimationExporter::get_modified_export_curve(Object *ob, BCAnimationCurve &curve, BCAnimationCurveMap &curves)
+{
+       std::string channel_target = curve.get_channel_target();
+       BCAnimationCurve *mcurve = NULL;
+       if (channel_target == "lens") {
+
+               /* Create an xfov curve */
+
+               BCCurveKey key(BC_ANIMATION_TYPE_CAMERA, "xfov", 0);
+               mcurve = new BCAnimationCurve(key, ob);
+
+               // now tricky part: transform the fcurve
+               BCValueMap lens_values;
+               curve.get_value_map(lens_values);
+
+               BCAnimationCurve *sensor_curve = NULL;
+               BCCurveKey sensor_key(BC_ANIMATION_TYPE_CAMERA, "sensor_width", 0);
+               BCAnimationCurveMap::iterator cit = curves.find(sensor_key);
+               if (cit != curves.end()) {
+                       sensor_curve = cit->second;
+               }
+
+               BCValueMap::const_iterator vit;
+               for (vit = lens_values.begin(); vit != lens_values.end(); ++vit) {
+                       int frame = vit->first;
+                       float lens_value = vit->second;
+
+                       float sensor_value;
+                       if (sensor_curve) {
+                               sensor_value = sensor_curve->get_value(frame);
+                       }
+                       else {
+                               sensor_value = ((Camera *)ob->data)->sensor_x;
                        }
+                       float value = RAD2DEGF(focallength_to_fov(lens_value, sensor_value));
+                       mcurve->add_value(value, frame);
                }
-               fcu = fcu->next;
+               mcurve->clean_handles(); // to reset the handles
        }
-
-       for (int i = 0; i < keys; i++) {
-               for (int j = 0; j < 4; j++)
-                       temp_quat[j] = quat[(i * 4) + j];
-
-               quat_to_eul(temp_eul, temp_quat);
-
-               for (int k = 0; k < 3; k++)
-                       eul[i * 3 + k] = temp_eul[k];
-
-       }
-       MEM_freeN(quat);
-       return eul;
-
-}
-
-//Get proper name for bones
-std::string AnimationExporter::getObjectBoneName(Object *ob, const FCurve *fcu)
-{
-       //hard-way to derive the bone name from rna_path. Must find more compact method
-       std::string rna_path = std::string(fcu->rna_path);
-
-       char *boneName = strtok((char *)rna_path.c_str(), "\"");
-       boneName = strtok(NULL, "\"");
-
-       if (boneName != NULL)
-               return /*id_name(ob) + "_" +*/ std::string(boneName);
-       else
-               return id_name(ob);
+       return mcurve;
 }
 
-std::string AnimationExporter::getAnimationPathId(const FCurve *fcu)
+void AnimationExporter::export_curve_animation(
+       Object *ob,
+       BCAnimationCurve &curve)
 {
-       std::string rna_path = std::string(fcu->rna_path);
-       return translate_id(rna_path);
-}
-
-/* convert f-curves to animation curves and write */
-void AnimationExporter::create_keyframed_animation(Object *ob, FCurve *fcu, char *transformName, bool is_param, Material *ma)
-{
-       const char *axis_name = NULL;
-       char anim_id[200];
-
-       bool has_tangents = false;
-       bool quatRotation = false;
-
-       Object *obj = NULL;
-
-       if (STREQ(transformName, "rotation_quaternion") ) {
-               fprintf(stderr, "quaternion rotation curves are not supported. rotation curve will not be exported\n");
-               quatRotation = true;
-               return;
-       }
-
-       //axis names for colors
-       else if (STREQ(transformName, "color") ||
-                STREQ(transformName, "specular_color") ||
-                STREQ(transformName, "diffuse_color") ||
-                STREQ(transformName, "alpha"))
-       {
-               const char *axis_names[] = {"R", "G", "B"};
-               if (fcu->array_index < 3)
-                       axis_name = axis_names[fcu->array_index];
-       }
+       std::string channel_target = curve.get_channel_target();
 
        /*
-        * Note: Handle transformation animations separately (to apply matrix inverse to fcurves)
-        * We will use the object to evaluate the animation on all keyframes and calculate the
-        * resulting object matrix. We need this to incorporate the
-        * effects of the parent inverse matrix (when it contains a rotation component)
-        *
-        * TODO: try to combine exported fcurves into 3 channel animations like done
-        * in export_sampled_animation(). For now each channel is exported as separate <Animation>.
+        * Some curves can not be exported as is and need some conversion
+        * For more information see implementation oif get_modified_export_curve()
+        * note: if mcurve is not NULL then it must be deleted at end of this method;
         */
 
-       else if (
-               STREQ(transformName, "scale") ||
-               STREQ(transformName, "location") ||
-               STREQ(transformName, "rotation_euler"))
-       {
-               const char *axis_names[] = {"X", "Y", "Z"};
-               if (fcu->array_index < 3) {
-                       axis_name = axis_names[fcu->array_index];
-                       obj = ob;
-               }
-       }
-       else {
-               /* no axis name. single parameter */
-               axis_name = "";
-       }
-
-       std::string ob_name = std::string("null");
-
-       /* Create anim Id */
-       if (ob->type == OB_ARMATURE) {
-               ob_name =  getObjectBoneName(ob, fcu);
-               BLI_snprintf(
-                       anim_id,
-                       sizeof(anim_id),
-                       "%s_%s.%s",
-                       (char *)translate_id(ob_name).c_str(),
-                       (char *)translate_id(transformName).c_str(),
-                       axis_name);
-       }
-       else {
-               if (ma)
-                       ob_name = id_name(ob) + "_material";
-               else
-                       ob_name = id_name(ob);
-
-               BLI_snprintf(
-                       anim_id,
-                       sizeof(anim_id),
-                       "%s_%s_%s",
-                       (char *)translate_id(ob_name).c_str(),
-                       (char *)getAnimationPathId(fcu).c_str(),
-                       axis_name);
-       }
+       int channel_index = curve.get_channel_index();
+       std::string axis = get_axis_name(channel_target, channel_index); // RGB or XYZ or ""
 
-       openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
+       std::string action_name;
+       bAction *action = bc_getSceneObjectAction(ob);
+       action_name = (action) ? id_name(action) : "constraint_anim";
 
-       // create input source
-       std::string input_id = create_source_from_fcurve(COLLADASW::InputSemantic::INPUT, fcu, anim_id, axis_name);
+       const std::string curve_name = encode_xml(curve.get_animation_name(ob));
+       std::string id = bc_get_action_id(action_name, curve_name, channel_target, axis, ".");
 
-       // create output source
-       std::string output_id;
+       std::string collada_target = translate_id(curve_name);
 
-       //quat rotations are skipped for now, because of complications with determining axis.
-       if (quatRotation) {
-               float *eul  = get_eul_source_for_quat(ob);
-               float *eul_axis = (float *)MEM_callocN(sizeof(float) * fcu->totvert, "quat output source values");
-               for (int i = 0; i < fcu->totvert; i++) {
-                       eul_axis[i] = eul[i * 3 + fcu->array_index];
+       if (curve.is_of_animation_type(BC_ANIMATION_TYPE_MATERIAL)) {
+               int material_index = curve.get_subindex();
+               Material *ma = give_current_material(ob, material_index + 1);
+               if (ma) {
+                       collada_target = translate_id(id_name(ma)) + "-effect/common/" + get_collada_sid(curve, axis);
                }
-               output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, eul_axis, fcu->totvert, quatRotation, anim_id, axis_name);
-               MEM_freeN(eul);
-               MEM_freeN(eul_axis);
-       }
-       else if (STREQ(transformName, "lens") && (ob->type == OB_CAMERA)) {
-               output_id = create_lens_source_from_fcurve((Camera *) ob->data, COLLADASW::InputSemantic::OUTPUT, fcu, anim_id);
        }
        else {
-               output_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name, obj);
-       }
-
-       // create interpolations source
-       std::string interpolation_id = create_interpolation_source(fcu, anim_id, axis_name, &has_tangents);
-
-       // handle tangents (if required)
-       std::string intangent_id;
-       std::string outtangent_id;
-
-       if (has_tangents) {
-               // create in_tangent source
-               intangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::IN_TANGENT, fcu, anim_id, axis_name, obj);
-
-               // create out_tangent source
-               outtangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUT_TANGENT, fcu, anim_id, axis_name, obj);
-       }
-
-       std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
-       COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
-       std::string empty;
-       sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
-       sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
-
-       // this input is required
-       sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
-
-       if (has_tangents) {
-               sampler.addInput(COLLADASW::InputSemantic::IN_TANGENT, COLLADABU::URI(empty, intangent_id));
-               sampler.addInput(COLLADASW::InputSemantic::OUT_TANGENT, COLLADABU::URI(empty, outtangent_id));
+               collada_target += "/" + get_collada_sid(curve, axis);
        }
 
-       addSampler(sampler);
-
-       std::string target;
-
-       if (!is_param)
-               target = translate_id(ob_name) +
-                        "/" + get_transform_sid(fcu->rna_path, -1, axis_name, true);
-       else {
-               if (ob->type == OB_LAMP)
-                       target = get_light_id(ob) +
-                                "/" + get_light_param_sid(fcu->rna_path, -1, axis_name, true);
-
-               if (ob->type == OB_CAMERA)
-                       target = get_camera_id(ob) +
-                                "/" + get_camera_param_sid(fcu->rna_path, -1, axis_name, true);
-
-               if (ma)
-                       target = translate_id(id_name(ma)) + "-effect" +
-                                "/common/" /*profile common is only supported */ + get_transform_sid(fcu->rna_path, -1, axis_name, true);
-               //if shape key animation, this is the main problem, how to define the channel targets.
-               /*target = get_morph_id(ob) +
-                                "/value" +*/
-       }
-       addChannel(COLLADABU::URI(empty, sampler_id), target);
+       export_collada_curve_animation(id, curve_name, collada_target, axis, curve);
 
-       closeAnimation();
 }
 
-
-
-//write bone animations in transform matrix sources
-void AnimationExporter::write_bone_animation_matrix(Object *ob_arm, Bone *bone)
+void AnimationExporter::export_bone_animation(Object *ob, Bone *bone, BCFrames &frames, BCMatrixSampleMap &samples)
 {
-       if (!ob_arm->adt)
-               return;
-
-       //This will only export animations of bones in deform group.
-       /* if (!is_bone_deform_group(bone)) return; */
+       bAction* action = bc_getSceneObjectAction(ob);
+       std::string bone_name(bone->name);
+       std::string name = encode_xml(id_name(ob));
+       std::string id = bc_get_action_id(id_name(action), name, bone_name, "pose_matrix");
+       std::string target = translate_id(id_name(ob) + "_" + bone_name) + "/transform";
 
-       sample_and_write_bone_animation_matrix(ob_arm, bone);
-
-       for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next)
-               write_bone_animation_matrix(ob_arm, child);
+       export_collada_matrix_animation(id, name, target, frames, samples);
 }
 
 bool AnimationExporter::is_bone_deform_group(Bone *bone)
@@ -695,204 +377,86 @@ bool AnimationExporter::is_bone_deform_group(Bone *bone)
        return false;
 }
 
-void AnimationExporter::sample_and_write_bone_animation_matrix(Object *ob_arm, Bone *bone)
-{
-       bArmature *arm = (bArmature *)ob_arm->data;
-       int flag = arm->flag;
-       std::vector<float> fra;
-       //char prefix[256];
-
-       //Check if there is a fcurve in the armature for the bone in param
-       //when baking this check is not needed, solve every bone for every frame.
-       /*FCurve *fcu = (FCurve *)ob_arm->adt->action->curves.first;
-
-       while (fcu) {
-               std::string bone_name = getObjectBoneName(ob_arm, fcu);
-               int val = BLI_strcasecmp((char *)bone_name.c_str(), bone->name);
-               if (val == 0) break;
-               fcu = fcu->next;
-       }
 
-       if (!(fcu)) return;*/
+void AnimationExporter::export_collada_curve_animation(
+       std::string id,
+       std::string name,
+       std::string collada_target,
+       std::string axis,
+       BCAnimationCurve &curve)
+{
+       BCFrames frames;
+       BCValues values;
+       curve.get_frames(frames);
+       curve.get_values(values);
+       std::string channel_target = curve.get_channel_target();
 
-       bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name);
-       if (!pchan)
-               return;
+       fprintf(stdout, "Export animation curve %s (%d control points)\n", id.c_str(), int(frames.size()));
+       openAnimation(id, name);
+       BC_animation_source_type source_type = (curve.is_rotation_curve()) ? BC_SOURCE_TYPE_ANGLE : BC_SOURCE_TYPE_VALUE;
 
+       std::string input_id = collada_source_from_values(BC_SOURCE_TYPE_TIMEFRAME, COLLADASW::InputSemantic::INPUT, frames, id, axis);
+       std::string output_id = collada_source_from_values(source_type, COLLADASW::InputSemantic::OUTPUT, values, id, axis);
 
-       if (this->export_settings->sampling_rate < 1)
-               find_keyframes(ob_arm, fra);
+       bool has_tangents = false;
+       std::string interpolation_id;
+       if (this->export_settings->keep_smooth_curves)
+               interpolation_id = collada_interpolation_source(curve, id, axis, &has_tangents);
        else
-               find_sampleframes(ob_arm, fra);
+               interpolation_id = collada_linear_interpolation_source(frames.size(), id);
 
-       if (flag & ARM_RESTPOS) {
-               arm->flag &= ~ARM_RESTPOS;
-               BKE_pose_where_is(depsgraph, scene, ob_arm);
-       }
-
-       if (fra.size()) {
-               dae_baked_animation(fra, ob_arm, bone);
+       std::string intangent_id;
+       std::string outtangent_id;
+       if (has_tangents) {
+               intangent_id = collada_tangent_from_curve(COLLADASW::InputSemantic::IN_TANGENT, curve, id, axis);
+               outtangent_id = collada_tangent_from_curve(COLLADASW::InputSemantic::OUT_TANGENT, curve, id, axis);
        }
 
-       if (flag & ARM_RESTPOS)
-               arm->flag = flag;
-       BKE_pose_where_is(depsgraph, scene, ob_arm);
-}
-
-void AnimationExporter::dae_baked_animation(std::vector<float> &fra, Object *ob_arm, Bone *bone)
-{
-       std::string ob_name = id_name(ob_arm);
-       std::string bone_name = bone->name;
-       char anim_id[200];
-
-       if (!fra.size())
-               return;
-
-       BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char *)translate_id(ob_name).c_str(),
-                    (char *)translate_id(bone_name).c_str(), "pose_matrix");
-
-       openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
-
-       // create input source
-       std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, false, anim_id, "");
+       std::string sampler_id = std::string(id) + SAMPLER_ID_SUFFIX;
 
-       // create output source
-       std::string output_id;
-
-       output_id = create_4x4_source(fra, ob_arm, bone, anim_id);
-
-       // create interpolations source
-       std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, "");
-
-       std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
        COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
-       std::string empty;
-       sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
-       sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
 
-       // TODO create in/out tangents source
+       sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(EMPTY_STRING, input_id));
+       sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(EMPTY_STRING, output_id));
+       sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(EMPTY_STRING, interpolation_id));
 
-       // this input is required
-       sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
+       if (has_tangents) {
+               sampler.addInput(COLLADASW::InputSemantic::IN_TANGENT, COLLADABU::URI(EMPTY_STRING, intangent_id));
+               sampler.addInput(COLLADASW::InputSemantic::OUT_TANGENT, COLLADABU::URI(EMPTY_STRING, outtangent_id));
+       }
 
        addSampler(sampler);
-
-       std::string target = get_joint_id(ob_arm, bone) + "/transform";
-       addChannel(COLLADABU::URI(empty, sampler_id), target);
+       addChannel(COLLADABU::URI(EMPTY_STRING, sampler_id), collada_target);
 
        closeAnimation();
 }
 
-void AnimationExporter::dae_baked_object_animation(std::vector<float> &fra, Object *ob)
+void AnimationExporter::export_collada_matrix_animation(std::string id, std::string name, std::string target, BCFrames &frames, BCMatrixSampleMap &samples)
 {
-       std::string ob_name = id_name(ob);
-       char anim_id[200];
-
-       if (!fra.size())
-               return;
-
-       BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s", (char *)translate_id(ob_name).c_str(),
-                    "object_matrix");
+       fprintf(stdout, "Export animation matrix %s (%d control points)\n", id.c_str(), int(frames.size()));
 
-       openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
+       openAnimationWithClip(id, name);
 
-       // create input source
-       std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, false, anim_id, "");
+       std::string input_id = collada_source_from_values(BC_SOURCE_TYPE_TIMEFRAME, COLLADASW::InputSemantic::INPUT, frames, id, "");
+       std::string output_id = collada_source_from_values(samples, id);
+       std::string interpolation_id = collada_linear_interpolation_source(frames.size(), id);
 
-       // create output source
-       std::string output_id;
-       output_id = create_4x4_source( fra, ob, NULL, anim_id);
-
-       // create interpolations source
-       std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, "");
-
-       std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
+       std::string sampler_id = std::string(id) + SAMPLER_ID_SUFFIX;
        COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
-       std::string empty;
-       sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
-       sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
-
-       // TODO create in/out tangents source
-
-       // this input is required
-       sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
-
-       addSampler(sampler);
-
-       std::string target = translate_id(ob_name) + "/transform";
-       addChannel(COLLADABU::URI(empty, sampler_id), target);
-
-       closeAnimation();
-}
-
-// dae_bone_animation -> add_bone_animation
-// (blend this into dae_bone_animation)
-void AnimationExporter::dae_bone_animation(std::vector<float> &fra, float *values, int tm_type, int axis, std::string ob_name, std::string bone_name)
-{
-       const char *axis_names[] = {"X", "Y", "Z"};
-       const char *axis_name = NULL;
-       char anim_id[200];
-       bool is_rot = tm_type == 0;
 
-       if (!fra.size())
-               return;
 
-       char rna_path[200];
-       BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].%s", bone_name.c_str(),
-                    tm_type == 0 ? "rotation_quaternion" : (tm_type == 1 ? "scale" : "location"));
+       sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(EMPTY_STRING, input_id));
+       sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(EMPTY_STRING, output_id));
+       sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(EMPTY_STRING, interpolation_id));
 
-       if (axis > -1)
-               axis_name = axis_names[axis];
-
-       std::string transform_sid = get_transform_sid(NULL, tm_type, axis_name, false);
-
-       BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char *)translate_id(ob_name).c_str(),
-                    (char *)translate_id(bone_name).c_str(), (char *)transform_sid.c_str());
-
-       openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
-
-       // create input source
-       std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, is_rot, anim_id, axis_name);
-
-       // create output source
-       std::string output_id;
-       if (axis == -1)
-               output_id = create_xyz_source(values, fra.size(), anim_id);
-       else
-               output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, values, fra.size(), is_rot, anim_id, axis_name);
-
-       // create interpolations source
-       std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, axis_name);
-
-       std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
-       COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
-       std::string empty;
-       sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
-       sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
-
-       // TODO create in/out tangents source
-
-       // this input is required
-       sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
+       // Matrix animation has no tangents
 
        addSampler(sampler);
-
-       std::string target = translate_id(ob_name + "_" + bone_name) + "/" + transform_sid;
-       addChannel(COLLADABU::URI(empty, sampler_id), target);
+       addChannel(COLLADABU::URI(EMPTY_STRING, sampler_id), target);
 
        closeAnimation();
 }
 
-float AnimationExporter::convert_time(float frame)
-{
-       return FRA2TIME(frame);
-}
-
-float AnimationExporter::convert_angle(float angle)
-{
-       return COLLADABU::Math::Utils::radToDegF(angle);
-}
-
 std::string AnimationExporter::get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic)
 {
        switch (semantic) {
@@ -913,7 +477,10 @@ std::string AnimationExporter::get_semantic_suffix(COLLADASW::InputSemantic::Sem
 }
 
 void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
-                                              COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis, bool transform)
+       COLLADASW::InputSemantic::Semantics semantic,
+       bool is_rot, 
+       const std::string axis, 
+       bool transform)
 {
        switch (semantic) {
                case COLLADASW::InputSemantic::INPUT:
@@ -924,7 +491,7 @@ void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNa
                                param.push_back("ANGLE");
                        }
                        else {
-                               if (axis) {
+                               if (axis != "") {
                                        param.push_back(axis);
                                }
                                else
@@ -948,262 +515,83 @@ void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNa
        }
 }
 
-void AnimationExporter::get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool is_angle, float *values, int *length)
+std::string AnimationExporter::collada_tangent_from_curve(COLLADASW::InputSemantic::Semantics semantic, BCAnimationCurve &curve, const std::string& anim_id, std::string axis_name)
 {
-       switch (semantic) {
-               case COLLADASW::InputSemantic::INPUT:
-                       *length = 1;
-                       values[0] = convert_time(bezt->vec[1][0]);
-                       break;
-               case COLLADASW::InputSemantic::OUTPUT:
-                       *length = 1;
-                       if (is_angle) {
-                               values[0] = RAD2DEGF(bezt->vec[1][1]);
-                       }
-                       else {
-                               values[0] = bezt->vec[1][1];
-                       }
-                       break;
+       Scene *scene = blender_context.get_scene();
+       std::string channel = curve.get_channel_target();
 
-               case COLLADASW::InputSemantic::IN_TANGENT:
-                       *length = 2;
-                       values[0] = convert_time(bezt->vec[0][0]);
-                       if (bezt->ipo != BEZT_IPO_BEZ) {
-                               // We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data
-                               values[0] = 0;
-                               values[1] = 0;
-                       }
-                       else if (is_angle) {
-                               values[1] = RAD2DEGF(bezt->vec[0][1]);
-                       }
-                       else {
-                               values[1] = bezt->vec[0][1];
-                       }
-                       break;
+       const std::string source_id = anim_id + get_semantic_suffix(semantic);
 
-               case COLLADASW::InputSemantic::OUT_TANGENT:
-                       *length = 2;
-                       values[0] = convert_time(bezt->vec[2][0]);
-                       if (bezt->ipo != BEZT_IPO_BEZ) {
-                               // We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data
-                               values[0] = 0;
-                               values[1] = 0;
-                       }
-                       else if (is_angle) {
-                               values[1] = RAD2DEGF(bezt->vec[2][1]);
-                       }
-                       else {
-                               values[1] = bezt->vec[2][1];
-                       }
-                       break;
-               default:
-                       *length = 0;
-                       break;
-       }
-}
-
-// old function to keep compatibility for calls where offset and object are not needed
-std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name)
-{
-       return create_source_from_fcurve(semantic, fcu, anim_id, axis_name, NULL);
-}
-
-void AnimationExporter::evaluate_anim_with_constraints(Object *ob, float ctime)
-{
-       BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL);
-       ListBase *conlist = get_active_constraints(ob);
-       bConstraint *con;
-       for (con = (bConstraint *)conlist->first; con; con = con->next) {
-               ListBase targets = { NULL, NULL };
-
-               const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
-
-               if (cti && cti->get_constraint_targets) {
-                       bConstraintTarget *ct;
-                       Object *obtar;
-                       cti->get_constraint_targets(con, &targets);
-                       for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
-                               obtar = ct->tar;
-
-                               if (obtar) {
-                                       BKE_animsys_evaluate_animdata(depsgraph, scene, &obtar->id, obtar->adt, ctime, ADT_RECALC_ANIM);
-                                       BKE_object_where_is_calc_time(this->depsgraph, scene, obtar, ctime);
-                               }
-                       }
-
-                       if (cti->flush_constraint_targets)
-                               cti->flush_constraint_targets(con, &targets, 1);
-               }
-       }
-       BKE_object_where_is_calc_time(this->depsgraph, scene, ob, ctime);
-}
-
-/*
- * ob is needed to aply parent inverse information to fcurve.
- * TODO: Here we have to step over all keyframes for each object and for each fcurve.
- * Instead of processing each fcurve one by one,
- * step over the animation from keyframe to keyframe,
- * then create adjusted fcurves (and entries) for all affected objects.
- * Then we would need to step through the scene only once.
- */
-std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name, Object *ob)
-{
-       std::string source_id = anim_id + get_semantic_suffix(semantic);
-
-       bool is_angle = (strstr(fcu->rna_path, "rotation") || strstr(fcu->rna_path, "spot_size"));
-       bool is_euler = strstr(fcu->rna_path, "rotation_euler");
-       bool is_translation = strstr(fcu->rna_path, "location");
-       bool is_scale = strstr(fcu->rna_path, "scale");
-       bool is_tangent = false;
-       int offset_index = 0;
+       bool is_angle = (bc_startswith(channel, "rotation") || channel == "spot_size");
 
        COLLADASW::FloatSourceF source(mSW);
        source.setId(source_id);
        source.setArrayId(source_id + ARRAY_ID_SUFFIX);
-       source.setAccessorCount(fcu->totvert);
-
-       switch (semantic) {
-               case COLLADASW::InputSemantic::INPUT:
-               case COLLADASW::InputSemantic::OUTPUT:
-                       source.setAccessorStride(1);
-                       offset_index = 0;
-                       break;
-               case COLLADASW::InputSemantic::IN_TANGENT:
-               case COLLADASW::InputSemantic::OUT_TANGENT:
-                       source.setAccessorStride(2);
-                       offset_index = 1;
-                       is_tangent = true;
-                       break;
-               default:
-                       break;
-       }
+       source.setAccessorCount(curve.sample_count());
+       source.setAccessorStride(2);
 
        COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
        add_source_parameters(param, semantic, is_angle, axis_name, false);
 
        source.prepareToAppendValues();
 
-       for (unsigned int frame_index = 0; frame_index < fcu->totvert; frame_index++) {
-               float fixed_val = 0;
-               if (ob) {
-                       float fmat[4][4];
-                       float frame = fcu->bezt[frame_index].vec[1][0];
-                       float ctime = BKE_scene_frame_get_from_ctime(scene, frame);
-
-                       evaluate_anim_with_constraints(ob, ctime); // set object transforms to fcurve's i'th keyframe
-
-                       BKE_object_matrix_local_get(ob, fmat);
-                       float floc[3];
-                       float fquat[4];
-                       float fsize[3];
-                       mat4_decompose(floc, fquat, fsize, fmat);
-
-                       if (is_euler) {
-                               float eul[3];
-                               quat_to_eul(eul, fquat);
-                               fixed_val = RAD2DEGF(eul[fcu->array_index]);
-                       }
-                       else if (is_translation) {
-                               fixed_val = floc[fcu->array_index];
-                       }
-                       else if (is_scale) {
-                               fixed_val = fsize[fcu->array_index];
-                       }
-               }
-
-               float values[3]; // be careful!
-               float offset = 0;
-               int length = 0;
-               get_source_values(&fcu->bezt[frame_index], semantic, is_angle, values, &length);
-               if (is_tangent) {
-                       float bases[3];
-                       int len = 0;
-                       get_source_values(&fcu->bezt[frame_index], COLLADASW::InputSemantic::OUTPUT, is_angle, bases, &len);
-                       offset = values[offset_index] - bases[0];
-               }
+       const FCurve *fcu = curve.get_fcurve();
+       int tangent = (semantic == COLLADASW::InputSemantic::IN_TANGENT) ? 0 : 2;
 
-               for (int j = 0; j < length; j++) {
-                       float val;
-                       if (j == offset_index) {
-                               if (ob) {
-                                       val = fixed_val + offset;
-                               }
-                               else {
-                                       val = values[j] + offset;
-                               }
-                       } else {
-                               val = values[j];
-                       }
-                       source.appendValues(val);
-               }
-       }
-
-       source.finish();
-
-       return source_id;
-}
-
-/*
- * Similar to create_source_from_fcurve, but adds conversion of lens
- * animation data from focal length to FOV.
- */
-std::string AnimationExporter::create_lens_source_from_fcurve(Camera *cam, COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id)
-{
-       std::string source_id = anim_id + get_semantic_suffix(semantic);
-
-       COLLADASW::FloatSourceF source(mSW);
-       source.setId(source_id);
-       source.setArrayId(source_id + ARRAY_ID_SUFFIX);
-       source.setAccessorCount(fcu->totvert);
+       for (int i = 0; i < fcu->totvert; ++i) {
+               BezTriple &bezt = fcu->bezt[i];
 
-       source.setAccessorStride(1);
+               float sampled_time = bezt.vec[tangent][0];
+               float sampled_val = bezt.vec[tangent][1];
 
-       COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
-       add_source_parameters(param, semantic, false, "", false);
+               if (is_angle) {
+                       sampled_val = RAD2DEGF(sampled_val);
+               }
 
-       source.prepareToAppendValues();
+               source.appendValues(FRA2TIME(sampled_time));
+               source.appendValues(sampled_val);
 
-       for (unsigned int i = 0; i < fcu->totvert; i++) {
-               float values[3]; // be careful!
-               int length = 0;
-               get_source_values(&fcu->bezt[i], semantic, false, values, &length);
-               for (int j = 0; j < length; j++)
-               {
-                       float val = RAD2DEGF(focallength_to_fov(values[j], cam->sensor_x));
-                       source.appendValues(val);
-               }
        }
-
        source.finish();
-
        return source_id;
 }
 
-/*
- * only to get OUTPUT source values ( if rotation and hence the axis is also specified )
- */
-std::string AnimationExporter::create_source_from_array(COLLADASW::InputSemantic::Semantics semantic, float *v, int tot, bool is_rot, const std::string& anim_id, const char *axis_name)
+std::string AnimationExporter::collada_source_from_values(
+       BC_animation_source_type source_type,
+       COLLADASW::InputSemantic::Semantics semantic,
+       std::vector<float> &values,
+       const std::string& anim_id,
+       const std::string axis_name)
 {
+       Scene *scene = blender_context.get_scene();
+       /* T can be float, int or double */
+
+       int stride = 1;
+       int entry_count = values.size() / stride;
        std::string source_id = anim_id + get_semantic_suffix(semantic);
 
        COLLADASW::FloatSourceF source(mSW);
        source.setId(source_id);
        source.setArrayId(source_id + ARRAY_ID_SUFFIX);
-       source.setAccessorCount(tot);
-       source.setAccessorStride(1);
+       source.setAccessorCount(entry_count);
+       source.setAccessorStride(stride);
 
        COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
-       add_source_parameters(param, semantic, is_rot, axis_name,  false);
+       add_source_parameters(param, semantic, source_type== BC_SOURCE_TYPE_ANGLE, axis_name, false);
 
        source.prepareToAppendValues();
 
-       for (int i = 0; i < tot; i++) {
-               float val = v[i];
-               ////if (semantic == COLLADASW::InputSemantic::INPUT)
-               //      val = convert_time(val);
-               //else
-               if (is_rot)
+       for (int i = 0; i < entry_count; i++) {
+               float val = values[i];
+               switch (source_type) {
+               case BC_SOURCE_TYPE_TIMEFRAME:
+                       val = FRA2TIME(val);
+                       break;
+               case BC_SOURCE_TYPE_ANGLE:
                        val = RAD2DEGF(val);
+                       break;
+               default: break;
+               }
                source.appendValues(val);
        }
 
@@ -1213,39 +601,9 @@ std::string AnimationExporter::create_source_from_array(COLLADASW::InputSemantic
 }
 
 /*
- * only used for sources with INPUT semantic
- */
-std::string AnimationExporter::create_source_from_vector(COLLADASW::InputSemantic::Semantics semantic, std::vector<float> &fra, bool is_rot, const std::string& anim_id, const char *axis_name)
-{
-       std::string source_id = anim_id + get_semantic_suffix(semantic);
-
-       COLLADASW::FloatSourceF source(mSW);
-       source.setId(source_id);
-       source.setArrayId(source_id + ARRAY_ID_SUFFIX);
-       source.setAccessorCount(fra.size());
-       source.setAccessorStride(1);
-
-       COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
-       add_source_parameters(param, semantic, is_rot, axis_name, false);
-
-       source.prepareToAppendValues();
-
-       std::vector<float>::iterator it;
-       for (it = fra.begin(); it != fra.end(); it++) {
-               float val = *it;
-               //if (semantic == COLLADASW::InputSemantic::INPUT)
-               val = convert_time(val);
-               /*else if (is_rot)
-                  val = convert_angle(val);*/
-               source.appendValues(val);
-       }
-
-       source.finish();
-
-       return source_id;
-}
-
-std::string AnimationExporter::create_4x4_source(std::vector<float> &ctimes, std::vector<float> &values , const std::string &anim_id)
+ * Create a collada matrix source for a set of samples
+*/
+std::string AnimationExporter::collada_source_from_values(BCMatrixSampleMap &samples, const std::string &anim_id)
 {
        COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
        std::string source_id = anim_id + get_semantic_suffix(semantic);
@@ -1253,181 +611,38 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &ctimes, std
        COLLADASW::Float4x4Source source(mSW);
        source.setId(source_id);
        source.setArrayId(source_id + ARRAY_ID_SUFFIX);
-       source.setAccessorCount(ctimes.size());
+       source.setAccessorCount(samples.size());
        source.setAccessorStride(16);
 
        COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
-       add_source_parameters(param, semantic, false, NULL, true);
+       add_source_parameters(param, semantic, false, "", true);
 
        source.prepareToAppendValues();
 
-       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);
+       BCMatrixSampleMap::iterator it;
+       int precision = (this->export_settings->limit_precision) ? 6 : -1; // could be made configurable
+       for (it = samples.begin(); it != samples.end(); it++) {
+               const BCMatrix *sample = it->second;
+               double daemat[4][4];
+               sample->get_matrix(daemat, true, precision);
+               source.appendValues(daemat);
        }
 
        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);
-
-       COLLADASW::Float4x4Source source(mSW);
-       source.setId(source_id);
-       source.setArrayId(source_id + ARRAY_ID_SUFFIX);
-       source.setAccessorCount(frames.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;
-
-       if (is_bone_animation) {
-               bPose *pose = ob->pose;
-               pchan = BKE_pose_channel_find_name(pose, bone->name);
-               if (!pchan)
-                       return "";
-
-               parchan = pchan->parent;
-
-               enable_fcurves(ob->adt->action, bone->name);
-       }
-
-       std::vector<float>::iterator it;
-       int j = 0;
-       for (it = frames.begin(); it != frames.end(); it++) {
-               float mat[4][4], ipar[4][4];
-               float frame = *it;
-
-               float ctime = BKE_scene_frame_get_from_ctime(scene, frame);
-               bc_update_scene(m_bmain, depsgraph, scene, ctime);
-               if (is_bone_animation) {
-
-                       if (pchan->flag & POSE_CHAIN) {
-                               enable_fcurves(ob->adt->action, NULL);
-                               BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL);
-                               BKE_pose_where_is(depsgraph, scene, ob);
-                       }
-                       else {
-                               BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1);
-                       }
-
-                       // compute bone local mat
-                       if (bone->parent) {
-                               invert_m4_m4(ipar, parchan->pose_mat);
-                               mul_m4_m4m4(mat, ipar, pchan->pose_mat);
-                       }
-                       else
-                               copy_m4_m4(mat, pchan->pose_mat);
-
-                       /* OPEN_SIM_COMPATIBILITY
-                        * AFAIK animation to second life is via BVH, but no
-                        * reason to not have the collada-animation be correct
-                        */
-                       if (export_settings->open_sim) {
-                               float temp[4][4];
-                               copy_m4_m4(temp, bone->arm_mat);
-                               temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
-                               invert_m4(temp);
-
-                               mul_m4_m4m4(mat, mat, temp);
-
-                               if (bone->parent) {
-                                       copy_m4_m4(temp, bone->parent->arm_mat);
-                                       temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
-
-                                       mul_m4_m4m4(mat, temp, mat);
-                               }
-                       }
-
-               }
-               else {
-                       copy_m4_m4(mat, ob->obmat);
-               }
-
-               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);
-
-               j++;
-
-               BIK_release_tree(scene, ob, ctime);
-       }
-
-       if (ob->adt) {
-               enable_fcurves(ob->adt->action, NULL);
-       }
-
-       source.finish();
-
-       return source_id;
-}
-
-
-/*
- * only used for sources with OUTPUT semantic ( locations and scale)
- */
-std::string AnimationExporter::create_xyz_source(float *v, int tot, const std::string& anim_id)
-{
-       COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
-       std::string source_id = anim_id + get_semantic_suffix(semantic);
-
-       COLLADASW::FloatSourceF source(mSW);
-       source.setId(source_id);
-       source.setArrayId(source_id + ARRAY_ID_SUFFIX);
-       source.setAccessorCount(tot);
-       source.setAccessorStride(3);
-
-       COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
-       add_source_parameters(param, semantic, false, NULL, false);
-
-       source.prepareToAppendValues();
-
-       for (int i = 0; i < tot; i++) {
-               source.appendValues(*v, *(v + 1), *(v + 2));
-               v += 3;
-       }
-
-       source.finish();
-
-       return source_id;
-}
-
-std::string AnimationExporter::create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents)
+std::string AnimationExporter::collada_interpolation_source(const BCAnimationCurve &curve,
+       const std::string& anim_id, 
+       const std::string axis,
+       bool *has_tangents)
 {
        std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
 
        COLLADASW::NameSource source(mSW);
        source.setId(source_id);
        source.setArrayId(source_id + ARRAY_ID_SUFFIX);
-       source.setAccessorCount(fcu->totvert);
+       source.setAccessorCount(curve.sample_count());
        source.setAccessorStride(1);
 
        COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
@@ -1437,12 +652,17 @@ std::string AnimationExporter::create_interpolation_source(FCurve *fcu, const st
 
        *has_tangents = false;
 
-       for (unsigned int i = 0; i < fcu->totvert; i++) {
-               if (fcu->bezt[i].ipo == BEZT_IPO_BEZ) {
+       std::vector<float>frames;
+       curve.get_frames(frames);
+
+       for (unsigned int i = 0; i < curve.sample_count(); i++) {
+               float frame = frames[i];
+               int ipo = curve.get_interpolation_type(frame);
+               if (ipo == BEZT_IPO_BEZ) {
                        source.appendValues(BEZIER_NAME);
                        *has_tangents = true;
                }
-               else if (fcu->bezt[i].ipo == BEZT_IPO_CONST) {
+               else if (ipo == BEZT_IPO_CONST) {
                        source.appendValues(STEP_NAME);
                }
                else { // BEZT_IPO_LIN
@@ -1456,7 +676,7 @@ std::string AnimationExporter::create_interpolation_source(FCurve *fcu, const st
        return source_id;
 }
 
-std::string AnimationExporter::fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name)
+std::string AnimationExporter::collada_linear_interpolation_source(int tot, const std::string& anim_id)
 {
        std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
 
@@ -1480,474 +700,102 @@ std::string AnimationExporter::fake_interpolation_source(int tot, const std::str
        return source_id;
 }
 
-std::string AnimationExporter::get_light_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
-{
-       std::string tm_name;
-       // when given rna_path, determine tm_type from it
-       if (rna_path) {
-               char *name = extract_transform_name(rna_path);
-
-               if (STREQ(name, "color"))
-                       tm_type = 1;
-               else if (STREQ(name, "spot_size"))
-                       tm_type = 2;
-               else if (STREQ(name, "spot_blend"))
-                       tm_type = 3;
-               else if (STREQ(name, "distance"))
-                       tm_type = 4;
-               else
-                       tm_type = -1;
-       }
-
-       switch (tm_type) {
-               case 1:
-                       tm_name = "color";
-                       break;
-               case 2:
-                       tm_name = "fall_off_angle";
-                       break;
-               case 3:
-                       tm_name = "fall_off_exponent";
-                       break;
-               case 4:
-                       tm_name = "blender/blender_dist";
-                       break;
-
-               default:
-                       tm_name = "";
-                       break;
-       }
-
-       if (tm_name.size()) {
-               if (axis_name[0])
-                       return tm_name + "." + std::string(axis_name);
-               else
-                       return tm_name;
-       }
-
-       return std::string("");
-}
-
-std::string AnimationExporter::get_camera_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
+const std::string AnimationExporter::get_collada_name(std::string channel_target) const
 {
-       std::string tm_name;
-       // when given rna_path, determine tm_type from it
-       if (rna_path) {
-               char *name = extract_transform_name(rna_path);
-
-               if (STREQ(name, "lens"))
-                       tm_type = 0;
-               else if (STREQ(name, "ortho_scale"))
-                       tm_type = 1;
-               else if (STREQ(name, "clip_end"))
-                       tm_type = 2;
-               else if (STREQ(name, "clip_start"))
-                       tm_type = 3;
-
-               else
-                       tm_type = -1;
-       }
-
-       switch (tm_type) {
-               case 0:
-                       tm_name = "xfov";
-                       break;
-               case 1:
-                       tm_name = "xmag";
-                       break;
-               case 2:
-                       tm_name = "zfar";
-                       break;
-               case 3:
-                       tm_name = "znear";
-                       break;
-
-               default:
-                       tm_name = "";
-                       break;
-       }
-
-       if (tm_name.size()) {
-               if (axis_name[0])
-                       return tm_name + "." + std::string(axis_name);
-               else
-                       return tm_name;
-       }
-
-       return std::string("");
+       /*
+        * Translation table to map FCurve animation types to Collada animation.
+        * Todo: Maybe we can keep the names from the fcurves here instead of
+        * mapping. However this is what i found in the old code. So keep
+        * this map for now.
+        */
+       static std::map<std::string, std::string> BC_CHANNEL_BLENDER_TO_COLLADA = {
+               { "rotation", "rotation" },
+               { "rotation_euler", "rotation" },
+               { "rotation_quaternion", "rotation" },
+               { "scale", "scale" },
+               { "location", "location" },
+
+               /* Materials */
+               { "specular_color", "specular" },
+               { "diffuse_color", "diffuse" },
+               { "ior", "index_of_refraction" },
+               { "specular_hardness", "specular_hardness" },
+               { "alpha", "alpha" },
+
+               /* Lamps */
+               { "color", "color" },
+               { "fall_off_angle", "falloff_angle" },
+               { "spot_size", "falloff_angle" },
+               { "fall_off_exponent", "falloff_exponent" },
+               { "spot_blend", "falloff_exponent" },
+               { "blender/blender_dist", "blender/blender_dist" }, // special blender profile (todo: make this more elegant)
+               { "distance", "blender/blender_dist" }, // special blender profile (todo: make this more elegant)
+
+               /* Cameras */
+               { "lens", "xfov" },
+               { "xfov", "xfov" },
+               { "xmag", "xmag" },
+               { "zfar", "zfar" },
+               { "znear", "znear" },
+               { "ortho_scale", "xmag" },
+               { "clip_end", "zfar" },
+               { "clip_start", "znear" }
+       };
+
+       std::map<std::string, std::string>::iterator name_it = BC_CHANNEL_BLENDER_TO_COLLADA.find(channel_target);
+       if (name_it == BC_CHANNEL_BLENDER_TO_COLLADA.end())
+               return "";
+
+       std::string tm_name = name_it->second;
+       return tm_name;
 }
 
 /*
  * Assign sid of the animated parameter or transform for rotation,
  * axis name is always appended and the value of append_axis is ignored
  */
-std::string AnimationExporter::get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
+std::string AnimationExporter::get_collada_sid(const BCAnimationCurve &curve, const std::string axis_name)
 {
-       std::string tm_name;
-       bool is_angle = false;
-       // when given rna_path, determine tm_type from it
-       if (rna_path) {
-               char *name = extract_transform_name(rna_path);
-
-               if (STREQ(name, "rotation_euler"))
-                       tm_type = 0;
-               else if (STREQ(name, "rotation_quaternion"))
-                       tm_type = 1;
-               else if (STREQ(name, "scale"))
-                       tm_type = 2;
-               else if (STREQ(name, "location"))
-                       tm_type = 3;
-               else if (STREQ(name, "specular_hardness"))
-                       tm_type = 4;
-               else if (STREQ(name, "specular_color"))
-                       tm_type = 5;
-               else if (STREQ(name, "diffuse_color"))
-                       tm_type = 6;
-               else if (STREQ(name, "alpha"))
-                       tm_type = 7;
-               else if (STREQ(name, "ior"))
-                       tm_type = 8;
+       std::string channel_target = curve.get_channel_target();
+       std::string tm_name = get_collada_name(channel_target);
 
-               else
-                       tm_type = -1;
-       }
+       bool is_angle = curve.is_rotation_curve();
 
-       switch (tm_type) {
-               case 0:
-               case 1:
-                       tm_name = "rotation";
-                       is_angle = true;
-                       break;
-               case 2:
-                       tm_name = "scale";
-                       break;
-               case 3:
-                       tm_name = "location";
-                       break;
-               case 4:
-                       tm_name = "shininess";
-                       break;
-               case 5:
-                       tm_name = "specular";
-                       break;
-               case 6:
-                       tm_name = "diffuse";
-                       break;
-               case 7:
-                       tm_name = "transparency";
-                       break;
-               case 8:
-                       tm_name = "index_of_refraction";
-                       break;
-
-               default:
-                       tm_name = "";
-                       break;
-       }
 
        if (tm_name.size()) {
                if (is_angle)
                        return tm_name + std::string(axis_name) + ".ANGLE";
                else
-               if (axis_name[0])
-                       return tm_name + "." + std::string(axis_name);
-               else
-                       return tm_name;
-       }
-
-       return std::string("");
-}
-
-char *AnimationExporter::extract_transform_name(char *rna_path)
-{
-       char *dot = strrchr(rna_path, '.');
-       return dot ? (dot + 1) : rna_path;
-}
-
-/*
- * enable fcurves driving a specific bone, disable all the rest
- * if bone_name = NULL enable all fcurves
- */
-void AnimationExporter::enable_fcurves(bAction *act, char *bone_name)
-{
-       FCurve *fcu;
-       char prefix[200];
-
-       if (bone_name)
-               BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name);
-
-       for (fcu = (FCurve *)act->curves.first; fcu; fcu = fcu->next) {
-               if (bone_name) {
-                       if (STREQLEN(fcu->rna_path, prefix, strlen(prefix)))
-                               fcu->flag &= ~FCURVE_DISABLED;
+                       if (axis_name != "")
+                               return tm_name + "." + std::string(axis_name);
                        else
-                               fcu->flag |= FCURVE_DISABLED;
-               }
-               else {
-                       fcu->flag &= ~FCURVE_DISABLED;
-               }
-       }
-}
-
-bool AnimationExporter::hasAnimations(Scene *sce)
-{
-       LinkNode *node;
-
-       for (node=this->export_settings->export_set; node; node=node->next) {
-               Object *ob = (Object *)node->link;
-
-               FCurve *fcu = 0;
-               //Check for object transform animations
-               if (ob->adt && ob->adt->action)
-                       fcu = (FCurve *)ob->adt->action->curves.first;
-               //Check for Lamp parameter animations
-               else if ( (ob->type == OB_LAMP) && ((Lamp *)ob->data)->adt && ((Lamp *)ob->data)->adt->action)
-                       fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first);
-               //Check for Camera parameter animations
-               else if ( (ob->type == OB_CAMERA) && ((Camera *)ob->data)->adt && ((Camera *)ob->data)->adt->action)
-                       fcu = (FCurve *)(((Camera *)ob->data)->adt->action->curves.first);
-
-               //Check Material Effect parameter animations.
-               for (int a = 0; a < ob->totcol; a++) {
-                       Material *ma = give_current_material(ob, a + 1);
-                       if (!ma) continue;
-                       if (ma->adt && ma->adt->action) {
-                               fcu = (FCurve *)ma->adt->action->curves.first;
-                       }
-               }
-
-               //check shape key animation
-               if (!fcu) {
-                       Key *key = BKE_key_from_object(ob);
-                       if (key && key->adt && key->adt->action)
-                               fcu = (FCurve *)key->adt->action->curves.first;
-               }
-               if (fcu)
-                       return true;
-       }
-       return false;
-}
-
-//------------------------------- Not used in the new system.--------------------------------------------------------
-void AnimationExporter::find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode)
-{
-       if (rotmode > 0)
-               find_keyframes(ob, fra, prefix, "rotation_euler");
-       else if (rotmode == ROT_MODE_QUAT)
-               find_keyframes(ob, fra, prefix, "rotation_quaternion");
-       /*else if (rotmode == ROT_MODE_AXISANGLE)
-          ;*/
-}
-
-/* Take care to always have the first frame and the last frame in the animation
- * regardless of the sampling_rate setting
- */
-void AnimationExporter::find_sampleframes(Object *ob, std::vector<float> &fra)
-{
-       int frame = scene->r.sfra;
-       do {
-               float ctime = BKE_scene_frame_get_from_ctime(scene, frame);
-               fra.push_back(ctime);
-               if (frame == scene->r.efra)
-                       break;
-               frame += this->export_settings->sampling_rate;
-               if (frame > scene->r.efra)
-                       frame = scene->r.efra; // make sure the last frame is always exported
-
-       } while (true);
-}
-
-/*
- * find keyframes of all the objects animations
- */
-void AnimationExporter::find_keyframes(Object *ob, std::vector<float> &fra)
-{
-       if (ob->adt && ob->adt->action) {
-               FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
-
-               for (; fcu; fcu = fcu->next) {
-                       for (unsigned int i = 0; i < fcu->totvert; i++) {
-                               float f = fcu->bezt[i].vec[1][0];
-                               if (std::find(fra.begin(), fra.end(), f) == fra.end())
-                                       fra.push_back(f);
-                       }
-               }
-
-               // keep the keys in ascending order
-               std::sort(fra.begin(), fra.end());
+                               return tm_name;
        }
-}
 
-void AnimationExporter::find_keyframes(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name)
-{
-       if (ob->adt && ob->adt->action) {
-               FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
-
-               for (; fcu; fcu = fcu->next) {
-                       if (prefix && !STREQLEN(prefix, fcu->rna_path, strlen(prefix)))
-                               continue;
-
-                       char *name = extract_transform_name(fcu->rna_path);
-                       if (STREQ(name, tm_name)) {
-                               for (unsigned int i = 0; i < fcu->totvert; i++) {
-                                       float f = fcu->bezt[i].vec[1][0];
-                                       if (std::find(fra.begin(), fra.end(), f) == fra.end())
-                                               fra.push_back(f);
-                               }
-                       }
-               }
-
-               // keep the keys in ascending order
-               std::sort(fra.begin(), fra.end());
-       }
+       return tm_name;
 }
 
-void AnimationExporter::write_bone_animation(Object *ob_arm, Bone *bone)
+#ifdef WITH_MORPH_ANIMATION
+/* TODO: This function needs to be implemented similar to the material animation export
+So we have to update BCSample for this to work.
+*/
+void AnimationExporter::export_morph_animation(Object *ob, BCAnimationSampler &sampler)
 {
-       if (!ob_arm->adt)
-               return;
-
-       //write bone animations for 3 transform types
-       //i=0 --> rotations
-       //i=1 --> scale
-       //i=2 --> location
-       for (int i = 0; i < 3; i++)
-               sample_and_write_bone_animation(ob_arm, bone, i);
-
-       for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next)
-               write_bone_animation(ob_arm, child);
-}
-
-void AnimationExporter::sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type)
-{
-       bArmature *arm = (bArmature *)ob_arm->data;
-       int flag = arm->flag;
-       std::vector<float> fra;
-       char prefix[256];
-
-       BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone->name);
-
-       bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name);
-       if (!pchan)
-               return;
-       //Fill frame array with key frame values framed at \param:transform_type
-       switch (transform_type) {
-               case 0:
-                       find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode);
-                       break;
-               case 1:
-                       find_keyframes(ob_arm, fra, prefix, "scale");
-                       break;
-               case 2:
-                       find_keyframes(ob_arm, fra, prefix, "location");
-                       break;
-               default:
-                       return;
-       }
-
-       // exit rest position
-       if (flag & ARM_RESTPOS) {
-               arm->flag &= ~ARM_RESTPOS;
-               BKE_pose_where_is(depsgraph, scene, ob_arm);
-       }
-       //v array will hold all values which will be exported.
-       if (fra.size()) {
-               float *values = (float *)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames");
-               sample_animation(values, fra, transform_type, bone, ob_arm, pchan);
-
-               if (transform_type == 0) {
-                       // write x, y, z curves separately if it is rotation
-                       float *axisValues = (float *)MEM_callocN(sizeof(float) * fra.size(), "temp. anim frames");
-
-                       for (int i = 0; i < 3; i++) {
-                               for (unsigned int j = 0; j < fra.size(); j++)
-                                       axisValues[j] = values[j * 3 + i];
-
-                               dae_bone_animation(fra, axisValues, transform_type, i, id_name(ob_arm), bone->name);
-                       }
-                       MEM_freeN(axisValues);
-               }
-               else {
-                       // write xyz at once if it is location or scale
-                       dae_bone_animation(fra, values, transform_type, -1, id_name(ob_arm), bone->name);
-               }
-
-               MEM_freeN(values);
-       }
-
-       // restore restpos
-       if (flag & ARM_RESTPOS)
-               arm->flag = flag;
-       BKE_pose_where_is(depsgraph, scene, ob_arm);
-}
-
-void AnimationExporter::sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm, bPoseChannel *pchan)
-{
-       bPoseChannel *parchan = NULL;
-       bPose *pose = ob_arm->pose;
-
-       pchan = BKE_pose_channel_find_name(pose, bone->name);
-
-       if (!pchan)
-               return;
-
-       parchan = pchan->parent;
-
-       enable_fcurves(ob_arm->adt->action, bone->name);
-
-       std::vector<float>::iterator it;
-       for (it = frames.begin(); it != frames.end(); it++) {
-               float mat[4][4], ipar[4][4];
+       FCurve *fcu;
+       Key *key = BKE_key_from_object(ob);
+       if (!key) return;
 
-               float ctime = BKE_scene_frame_get_from_ctime(scene, *it);
+       if (key->adt && key->adt->action) {
+               fcu = (FCurve *)key->adt->action->curves.first;
 
+               while (fcu) {
+                       BC_animation_transform_type tm_type = get_transform_type(fcu->rna_path);
 
-               BKE_animsys_evaluate_animdata(depsgraph, scene, &ob_arm->id, ob_arm->adt, ctime, ADT_RECALC_ANIM);
-               BKE_pose_where_is_bone(depsgraph, scene, ob_arm, pchan, ctime, 1);
+                       create_keyframed_animation(ob, fcu, tm_type, true, sampler);
 
-               // compute bone local mat
-               if (bone->parent) {
-                       invert_m4_m4(ipar, parchan->pose_mat);
-                       mul_m4_m4m4(mat, ipar, pchan->pose_mat);
-               }
-               else
-                       copy_m4_m4(mat, pchan->pose_mat);
-
-               switch (type) {
-                       case 0:
-                               mat4_to_eul(v, mat);
-                               break;
-                       case 1:
-                               mat4_to_size(v, mat);
-                               break;
-                       case 2:
-                               copy_v3_v3(v, mat[3]);
-                               break;
+                       fcu = fcu->next;
                }
-
-               v += 3;
        }
 
-       enable_fcurves(ob_arm->adt->action, NULL);
-}
-
-bool AnimationExporter::validateConstraints(bConstraint *con)
-{
-       const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
-       /* these we can skip completely (invalid constraints...) */
-       if (cti == NULL)
-               return false;
-       if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF))
-               return false;
-
-       /* these constraints can't be evaluated anyway */
-       if (cti->evaluate_constraint == NULL)
-               return false;
-
-       /* influence == 0 should be ignored */
-       if (con->enforce == 0.0f)
-               return false;
-
-       /* validation passed */
-       return true;
 }
+#endif
index f5e96dbd8135155c0a48338abb23535cc106baa8..a5d3780af635761323ca077005f30c92bde4960d 100644 (file)
  * ***** END GPL LICENSE BLOCK *****
  */
 
-/** \file AnimationExporter.h
- *  \ingroup collada
- */
+#ifndef __BC_ANIMATION_EXPORTER_H__
+#define __BC_ANIMATION_EXPORTER_H__
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <math.h>
+
+#include "BCAnimationCurve.h"
+
 extern "C"
 {
 #include "DNA_scene_types.h"
@@ -74,35 +76,40 @@ extern "C"
 #include "COLLADASWBaseInputElement.h"
 
 #include "EffectExporter.h"
-
+#include "BCAnimationSampler.h"
 #include "collada_internal.h"
 
 #include "IK_solver.h"
 
 #include <vector>
+#include <map>
 #include <algorithm> // std::find
 
 struct Depsgraph;
 
+typedef enum BC_animation_source_type {
+       BC_SOURCE_TYPE_VALUE,
+       BC_SOURCE_TYPE_ANGLE,
+       BC_SOURCE_TYPE_TIMEFRAME
+} BC_animation_source_type;
+
 class AnimationExporter: COLLADASW::LibraryAnimations
 {
 private:
-       Main *m_bmain;
-       Scene *scene;
-       Depsgraph *depsgraph;
+       BlenderContext &blender_context;
        COLLADASW::StreamWriter *sw;
 
 public:
 
-       AnimationExporter(Depsgraph *depsgraph, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings):
+       AnimationExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings):
+               blender_context(blender_context),
                COLLADASW::LibraryAnimations(sw),
-               depsgraph(depsgraph),
                export_settings(export_settings)
        {
                this->sw = sw;
        }
 
-       bool exportAnimations(Main *bmain, Scene *sce);
+       bool exportAnimations();
 
        // called for each exported object
        void operator() (Object *ob);
@@ -110,7 +117,6 @@ public:
 protected:
        const ExportSettings *export_settings;
 
-
        void export_object_constraint_animation(Object *ob);
 
        void export_morph_animation(Object *ob);
@@ -121,8 +127,6 @@ protected:
 
        void sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type);
 
-       bool is_bone_deform_group(Bone * bone);
-
        void sample_and_write_bone_animation_matrix(Object *ob_arm, Bone *bone);
 
        void sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm, bPoseChannel *pChan);
@@ -141,70 +145,123 @@ protected:
 
        float convert_angle(float angle);
 
+       std::vector<std::vector<std::string>> anim_meta;
+
+       /* Main entry point into Animation export (called for each exported object) */
+       void exportAnimation(Object *ob, BCAnimationSampler &sampler);
+
+       /* export animation as separate trans/rot/scale curves */
+       void export_curve_animation_set(
+               Object *ob,
+               BCAnimationSampler &sampler,
+               bool export_tm_curves);
+
+       /* export one single curve */
+       void export_curve_animation(
+               Object *ob,
+               BCAnimationCurve &curve);
+
+       /* export animation as matrix data */
+       void export_matrix_animation(
+               Object *ob,
+               BCAnimationSampler &sampler);
+
+       /* step through the bone hierarchy */
+       void export_bone_animations_recursive(
+               Object *ob_arm, 
+               Bone *bone, 
+               BCAnimationSampler &sampler);
+
+       /* Export for one bone */
+       void export_bone_animation(
+               Object *ob,
+               Bone *bone,
+               BCFrames &frames,
+               BCMatrixSampleMap &outmats);
+
+       /* call to the low level collada exporter */
+       void export_collada_curve_animation(
+               std::string id,
+               std::string name,
+               std::string target,
+               std::string axis,
+               BCAnimationCurve &curve);
+
+       /* call to the low level collada exporter */
+       void export_collada_matrix_animation(
+               std::string id,
+               std::string name,
+               std::string target,
+               BCFrames &frames,
+               BCMatrixSampleMap &outmats);
+
+       BCAnimationCurve *get_modified_export_curve(Object *ob, BCAnimationCurve &curve, BCAnimationCurveMap &curves);
+
+       /* Helper functions */
+       void openAnimationWithClip(std::string id, std::string name);
+       bool open_animation_container(bool has_container, Object *ob);
+       void close_animation_container(bool has_container);
+
+       /* Input and Output sources (single valued) */
+       std::string collada_source_from_values(
+               BC_animation_source_type tm_channel,
+               COLLADASW::InputSemantic::Semantics semantic,
+               std::vector<float> &values,  
+               const std::string& anim_id, 
+               const std::string axis_name);
+       
+       /* Output sources (matrix data) */
+       std::string collada_source_from_values(
+               BCMatrixSampleMap &samples,
+               const std::string& anim_id);
+
+       /* Interpolation sources */
+       std::string collada_linear_interpolation_source(
+               int tot, 
+               const std::string& anim_id);
+
+       /* source ID = animation_name + semantic_suffix */
+
        std::string get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic);
 
        void add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
-                                  COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis, bool transform);
-
-       void get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool is_angle, float *values, int *length);
-
-       float* get_eul_source_for_quat(Object *ob );
-
-       bool is_flat_line(std::vector<float> &values, int channel_count);
-       void export_keyframed_animation_set(Object *ob);
-       void create_keyframed_animation(Object *ob, FCurve *fcu, char *transformName, bool is_param, Material *ma = NULL);
-       void export_sampled_animation_set(Object *ob);
-       void export_sampled_transrotloc_animation(Object *ob, std::vector<float> &ctimes);
-       void export_sampled_matrix_animation(Object *ob, std::vector<float> &ctimes);
-       void create_sampled_animation(int channel_count, std::vector<float> &times, std::vector<float> &values, std::string, std::string label, std::string axis_name, bool is_rot);
-
-       void evaluate_anim_with_constraints(Object *ob, float ctime);
-
-       std::string create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name);
-       std::string create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name, Object *ob);
-
-       std::string create_lens_source_from_fcurve(Camera *cam, COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id);
-
-       std::string create_source_from_array(COLLADASW::InputSemantic::Semantics semantic, float *v, int tot, bool is_rot, const std::string& anim_id, const char *axis_name);
+               COLLADASW::InputSemantic::Semantics semantic,
+               bool is_rot,
+               const std::string axis,
+               bool transform);
+
+       int get_point_in_curve(BCBezTriple &bezt, COLLADASW::InputSemantic::Semantics semantic, bool is_angle, float *values);
+       int get_point_in_curve(const BCAnimationCurve &curve, float sample_frame, COLLADASW::InputSemantic::Semantics semantic, bool is_angle, float *values);
+
+       std::string collada_tangent_from_curve(
+               COLLADASW::InputSemantic::Semantics semantic,
+               BCAnimationCurve &curve,
+               const std::string& anim_id,
+               const std::string axis_name);
+
+       std::string collada_interpolation_source(const BCAnimationCurve &curve, const std::string& anim_id, std::string axis_name, bool *has_tangents);
+               
+       std::string get_axis_name(std::string channel, int id);
+       const std::string get_collada_name(std::string channel_target) const;
+       std::string get_collada_sid(const BCAnimationCurve &curve, const std::string axis_name);
+
+       /* ===================================== */
+       /* Currently unused or not (yet?) needed */
+       /* ===================================== */
 
-       std::string create_source_from_vector(COLLADASW::InputSemantic::Semantics semantic, std::vector<float> &fra, bool is_rot, const std::string& anim_id, const char *axis_name);
-
-       std::string create_xyz_source(float *v, int tot, const std::string& anim_id);
-       std::string create_4x4_source(std::vector<float> &times, std::vector<float> &values, const std::string& anim_id);
-       std::string create_4x4_source(std::vector<float> &frames, Object * ob_arm, Bone *bone, const std::string& anim_id);
-
-       std::string create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents);
-
-       std::string fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name);
-
-       // for rotation, axis name is always appended and the value of append_axis is ignored
-       std::string get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis);
-       std::string get_light_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis);
-       std::string get_camera_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis);
-
-       void find_keyframes(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name);
-       void find_keyframes(Object *ob, std::vector<float> &fra);
-       void find_sampleframes(Object *ob, std::vector<float> &fra);
-
-
-       void make_anim_frames_from_targets(Object *ob, std::vector<float> &frames );
-
-       void find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode);
-
-       // enable fcurves driving a specific bone, disable all the rest
-       // if bone_name = NULL enable all fcurves
-       void enable_fcurves(bAction *act, char *bone_name);
-
-       bool hasAnimations(Scene *sce);
-
-       char *extract_transform_name(char *rna_path);
-
-       std::string getObjectBoneName(Object *ob, const FCurve * fcu);
-       std::string getAnimationPathId(const FCurve *fcu);
-
-       void getBakedPoseData(Object *obarm, int startFrame, int endFrame, bool ActionBake, bool ActionBakeFirstFrame);
+       bool is_bone_deform_group(Bone * bone);
 
-       bool validateConstraints(bConstraint *con);
+#if 0
+       BC_animation_transform_type _get_transform_type(const std::string path);
+       void get_eul_source_for_quat(std::vector<float> &cache, Object *ob);
+#endif
 
+#ifdef WITH_MORPH_ANIMATION
+       void export_morph_animation(
+               Object *ob,
+               BCAnimationSampler &sampler);
+#endif
 
 };
+
+#endif
index e57f8c2f652328eef1b3a4cf1e536deb6ecb56c7..b581c6647bab9a5e8cf8abc4857111e1517abc99 100644 (file)
@@ -107,11 +107,9 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve)
                                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();
+                               fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL;
 
-                               // create beztriple for each key
                                for (unsigned int j = 0; j < curve->getKeyCount(); j++) {
                                        BezTriple bez;
                                        memset(&bez, 0, sizeof(BezTriple));
@@ -120,7 +118,7 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve)
                                        // input, output
                                        bez.vec[1][0] = bc_get_float_value(input, j) * fps;
                                        bez.vec[1][1] = bc_get_float_value(output, j * dim + i);
-
+                                       bez.h1 = bez.h2 = HD_AUTO;
 
                                        if (curve->getInterpolationType() == COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER ||
                                            curve->getInterpolationType() == COLLADAFW::AnimationCurve::INTERPOLATION_STEP)
@@ -135,14 +133,15 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve)
                                                // outtangent
                                                bez.vec[2][0] = bc_get_float_value(outtan, (j * 2 * dim) + (2 * i)) * fps;
                                                bez.vec[2][1] = bc_get_float_value(outtan, (j * 2 * dim) + (2 * i) + 1);
-                                               if (curve->getInterpolationType() == COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER)
+                                               if (curve->getInterpolationType() == COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER) {
                                                        bez.ipo = BEZT_IPO_BEZ;
-                                               else
+                                                       bez.h1 = bez.h2 = HD_AUTO_ANIM;
+                                               }
+                                               else {
                                                        bez.ipo = BEZT_IPO_CONST;
-                                               //bez.h1 = bez.h2 = HD_AUTO;
+                                               }
                                        }
                                        else {
-                                               bez.h1 = bez.h2 = HD_AUTO;
                                                bez.ipo = BEZT_IPO_LIN;
                                        }
                                        // bez.ipo = U.ipo_new; /* use default interpolation mode here... */
@@ -245,7 +244,8 @@ void AnimationImporter::add_fcurves_to_object(Main *bmain, Object *ob, std::vect
        }
 }
 
-AnimationImporter::AnimationImporter(UnitConverter *conv, ArmatureImporter *arm, Scene *scene) :
+AnimationImporter::AnimationImporter(bContext *C, UnitConverter *conv, ArmatureImporter *arm, Scene *scene) :
+       mContext(C),
        TransformReader(conv), armature_importer(arm), scene(scene) {
 }
 
@@ -304,7 +304,6 @@ bool AnimationImporter::write_animation(const COLLADAFW::Animation *anim)
 bool AnimationImporter::write_animation_list(const COLLADAFW::AnimationList *animlist)
 {
        const COLLADAFW::UniqueId& animlist_id = animlist->getUniqueId();
-
        animlist_map[animlist_id] = animlist;
 
 #if 0
@@ -725,7 +724,7 @@ void AnimationImporter::Assign_lens_animations(const COLLADAFW::UniqueId& listid
        }
 }
 
-void AnimationImporter::apply_matrix_curves(Main *bmain, Object *ob, std::vector<FCurve *>& animcurves, COLLADAFW::Node *root, COLLADAFW::Node *node,
+void AnimationImporter::apply_matrix_curves(Object *ob, std::vector<FCurve *>& animcurves, COLLADAFW::Node *root, COLLADAFW::Node *node,
                                             COLLADAFW::Transformation *tm)
 {
        bool is_joint = node->getType() == COLLADAFW::Node::JOINT;
@@ -840,6 +839,7 @@ void AnimationImporter::apply_matrix_curves(Main *bmain, Object *ob, std::vector
                                add_bezt(newcu[i], fra, scale[i - 7]);
                }
        }
+       Main *bmain = CTX_data_main(mContext);
        verify_adt_action(bmain, (ID *)&ob->id, 1);
 
        ListBase *curves = &ob->adt->action->curves;
@@ -908,7 +908,7 @@ static ListBase &get_animation_curves(Main *bmain, Material *ma)
        return act->curves;
 }
 
-void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node,
+void AnimationImporter::translate_Animations(COLLADAFW::Node *node,
                                              std::map<COLLADAFW::UniqueId, COLLADAFW::Node *>& root_map,
                                              std::multimap<COLLADAFW::UniqueId, Object *>& object_map,
                                              std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map,
@@ -932,6 +932,7 @@ void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node,
 
        AnimationImporter::AnimMix *animType = get_animation_type(node, FW_object_map);
        bAction *act;
+       Main *bmain = CTX_data_main(mContext);
 
        if ( (animType->transform) != 0) {
                /* const char *bone_name = is_joint ? bc_get_joint_name(node) : NULL; */ /* UNUSED */
@@ -940,9 +941,11 @@ void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node,
                if (is_joint)
                        armature_importer->get_rna_path_for_joint(node, joint_path, sizeof(joint_path));
 
+               if (!ob->adt || !ob->adt->action)
+                       act = verify_adt_action(bmain, (ID *)&ob->id, 1);
 
-               if (!ob->adt || !ob->adt->action) act = verify_adt_action(bmain, (ID *)&ob->id, 1);
-               else act = ob->adt->action;
+               else
+                       act = ob->adt->action;
 
                //Get the list of animation curves of the object
                ListBase *AnimCurves = &(act->curves);
@@ -972,11 +975,11 @@ void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node,
                                for (unsigned int j = 0; j < bindings.getCount(); j++) {
                                        animcurves = curve_map[bindings[j].animation];
                                        if (is_matrix) {
-                                               apply_matrix_curves(bmain, ob, animcurves, root, node,  transform);
+                                               apply_matrix_curves(ob, animcurves, root, node,  transform);
                                        }
                                        else {
                                                if (is_joint) {
-                                                       add_bone_animation_sampled(bmain, ob, animcurves, root, node, transform);
+                                                       add_bone_animation_sampled(ob, animcurves, root, node, transform);
                                                }
                                                else {
                                                        //calculate rnapaths and array index of fcurves according to transformation and animation class
@@ -1003,9 +1006,10 @@ void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node,
 
        if ((animType->light) != 0) {
                Lamp *lamp  = (Lamp *) ob->data;
-
-               if (!lamp->adt || !lamp->adt->action) act = verify_adt_action(bmain, (ID *)&lamp->id, 1);
-               else act = lamp->adt->action;
+               if (!lamp->adt || !lamp->adt->action)
+                       act = verify_adt_action(bmain, (ID *)&lamp->id, 1);
+               else
+                       act = lamp->adt->action;
 
                ListBase *AnimCurves = &(act->curves);
                const COLLADAFW::InstanceLightPointerArray& nodeLights = node->getInstanceLights();
@@ -1036,6 +1040,7 @@ void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node,
        }
 
        if (animType->camera != 0) {
+
                Camera *cam  = (Camera *) ob->data;
                if (!cam->adt || !cam->adt->action)
                        act = verify_adt_action(bmain, (ID *)&cam->id, 1);
@@ -1090,6 +1095,12 @@ void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node,
        }
        if (animType->material != 0) {
 
+               Material *ma = give_current_material(ob, 1);
+               if (!ma->adt || !ma->adt->action)
+                       act = verify_adt_action(bmain, (ID *)&ma->id, 1);
+               else
+                       act = ma->adt->action;
+
                const COLLADAFW::InstanceGeometryPointerArray& nodeGeoms = node->getInstanceGeometries();
                for (unsigned int i = 0; i < nodeGeoms.getCount(); i++) {
                        const COLLADAFW::MaterialBindingArray& matBinds = nodeGeoms[i]->getMaterialBindings();
@@ -1136,7 +1147,7 @@ void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node,
        delete animType;
 }
 
-void AnimationImporter::add_bone_animation_sampled(Main *bmain, Object *ob, std::vector<FCurve *>& animcurves, COLLADAFW::Node *root, COLLADAFW::Node *node, COLLADAFW::Transformation *tm)
+void AnimationImporter::add_bone_animation_sampled(Object *ob, std::vector<FCurve *>& animcurves, COLLADAFW::Node *root, COLLADAFW::Node *node, COLLADAFW::Transformation *tm)
 {
        const char *bone_name = bc_get_joint_name(node);
        char joint_path[200];
@@ -1259,6 +1270,7 @@ void AnimationImporter::add_bone_animation_sampled(Main *bmain, Object *ob, std:
                                add_bezt(newcu[i], fra, scale[i - 7]);
                }
        }
+       Main *bmain = CTX_data_main(mContext);
        verify_adt_action(bmain, (ID *)&ob->id, 1);
 
        // add curves
@@ -1291,7 +1303,7 @@ AnimationImporter::AnimMix *AnimationImporter::get_animation_type(const COLLADAF
                        continue;
                }
                else {
-                       types->transform = types->transform | NODE_TRANSFORM;
+                       types->transform = types->transform | BC_NODE_TRANSFORM;
                        break;
                }
        }
@@ -1435,7 +1447,7 @@ void AnimationImporter::find_frames_old(std::vector<float> *frames, COLLADAFW::N
 // prerequisites:
 // animlist_map - map animlist id -> animlist
 // curve_map - map anim id -> curve(s)
-Object *AnimationImporter::translate_animation_OLD(Main *bmain, COLLADAFW::Node *node,
+Object *AnimationImporter::translate_animation_OLD(COLLADAFW::Node *node,
                                                    std::map<COLLADAFW::UniqueId, Object *>& object_map,
                                                    std::map<COLLADAFW::UniqueId, COLLADAFW::Node *>& root_map,
                                                    COLLADAFW::Transformation::TransformationType tm_type,
@@ -1657,7 +1669,7 @@ Object *AnimationImporter::translate_animation_OLD(Main *bmain, COLLADAFW::Node
                }
 #endif
        }
-
+       Main *bmain = CTX_data_main(mContext);
        verify_adt_action(bmain, (ID *)&ob->id, 1);
 
        ListBase *curves = &ob->adt->action->curves;
@@ -1775,24 +1787,24 @@ bool AnimationImporter::evaluate_animation(COLLADAFW::Transformation *tm, float
                else if (is_translate)
                        dae_translate_to_v3(tm, vec);
 
-               for (unsigned int j = 0; j < bindings.getCount(); j++) {
-                       const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[j];
+               for (unsigned int index = 0; index < bindings.getCount(); index++) {
+                       const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[index];
                        std::vector<FCurve *>& curves = curve_map[binding.animation];
                        COLLADAFW::AnimationList::AnimationClass animclass = binding.animationClass;
                        char path[100];
 
                        switch (type) {
                                case COLLADAFW::Transformation::ROTATE:
-                                       BLI_snprintf(path, sizeof(path), "%s.rotate (binding %u)", node_id, j);
+                                       BLI_snprintf(path, sizeof(path), "%s.rotate (binding %u)", node_id, index);
                                        break;
                                case COLLADAFW::Transformation::SCALE:
-                                       BLI_snprintf(path, sizeof(path), "%s.scale (binding %u)", node_id, j);
+                                       BLI_snprintf(path, sizeof(path), "%s.scale (binding %u)", node_id, index);
                                        break;
                                case COLLADAFW::Transformation::TRANSLATE:
-                                       BLI_snprintf(path, sizeof(path), "%s.translate (binding %u)", node_id, j);
+                                       BLI_snprintf(path, sizeof(path), "%s.translate (binding %u)", node_id, index);
                                        break;
                                case COLLADAFW::Transformation::MATRIX:
-                                       BLI_snprintf(path, sizeof(path), "%s.matrix (binding %u)", node_id, j);
+                                       BLI_snprintf(path, sizeof(path), "%s.matrix (binding %u)", node_id, index);
                                        break;
                                default:
                                        break;
index ff49bc369cf8da07fe5c08071ca06f6b9651b915..4fa4864cbb089b1305fddc63c84b43b9392032d6 100644 (file)
@@ -42,6 +42,7 @@
 #include "COLLADAFWInstanceGeometry.h"
 
 extern "C" {
+#include "BKE_context.h"
 #include "DNA_anim_types.h"
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"
@@ -65,7 +66,7 @@ public:
 class AnimationImporter : private TransformReader, public AnimationImporterBase
 {
 private:
-
+       bContext *mContext;
        ArmatureImporter *armature_importer;
        Scene *scene;
 
@@ -124,8 +125,8 @@ private:
 
        enum AnimationType
                {
-                       INANIMATE = 0,
-                       NODE_TRANSFORM = 1,
+                       BC_INANIMATE = 0,
+                       BC_NODE_TRANSFORM = 1
                };
 
        struct AnimMix
@@ -138,7 +139,7 @@ private:
        };
 public:
 
-       AnimationImporter(UnitConverter *conv, ArmatureImporter *arm, Scene *scene);
+       AnimationImporter(bContext *C, UnitConverter *conv, ArmatureImporter *arm, Scene *scene);
 
        ~AnimationImporter();
 
@@ -153,7 +154,7 @@ public:
        virtual void change_eul_to_quat(Object *ob, bAction *act);
 #endif
 
-       void translate_Animations(Main *bmain, COLLADAFW::Node * Node,
+       void translate_Animations(COLLADAFW::Node * Node,
                                  std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map,
                                  std::multimap<COLLADAFW::UniqueId, Object*>& object_map,
                                  std::map<COLLADAFW::UniqueId, const COLLADAFW::Object*> FW_object_map,
@@ -161,10 +162,10 @@ public:
 
        AnimMix* get_animation_type( const COLLADAFW::Node * node, std::map<COLLADAFW::UniqueId, const COLLADAFW::Object*> FW_object_map );
 
-       void apply_matrix_curves(Main *bmain, Object *ob, std::vector<FCurve*>& animcurves, COLLADAFW::Node* root, COLLADAFW::Node* node,
+       void apply_matrix_curves(Object *ob, std::vector<FCurve*>& animcurves, COLLADAFW::Node* root, COLLADAFW::Node* node,
                                 COLLADAFW::Transformation * tm );
 
-       void add_bone_animation_sampled(Main *bmain, Object *ob, std::vector<FCurve*>& animcurves, COLLADAFW::Node* root, COLLADAFW::Node* node, COLLADAFW::Transformation * tm);
+       void add_bone_animation_sampled(Object *ob, std::vector<FCurve*>& animcurves, COLLADAFW::Node* root, COLLADAFW::Node* node, COLLADAFW::Transformation * tm);
 
        void Assign_transform_animations(COLLADAFW::Transformation* transform,
                                         const COLLADAFW::AnimationList::AnimationBinding *binding,
@@ -181,12 +182,11 @@ public:
        // prerequisites:
        // animlist_map - map animlist id -> animlist
        // curve_map - map anim id -> curve(s)
-       Object *translate_animation_OLD(
-               Main *bmain, 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);
+       Object *AnimationImporter::translate_animation_OLD(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);
 
        void find_frames( std::vector<float>* frames, std::vector<FCurve*>* curves );
        void find_frames_old( std::vector<float>* frames, COLLADAFW::Node * node, COLLADAFW::Transformation::TransformationType tm_type );
index 45628054ad2a00f20870c14cfc9815d650095e47..efeca5aec35abb12a10f2fe2f8b72b141825d2a7 100644 (file)
@@ -56,39 +56,47 @@ extern "C" {
 // XXX exporter writes wrong data for shared armatures.  A separate
 // controller should be written for each armature-mesh binding how do
 // we make controller ids then?
-ArmatureExporter::ArmatureExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryControllers(sw), export_settings(export_settings) {
+ArmatureExporter::ArmatureExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) :
+       blender_context(blender_context),
+       COLLADASW::LibraryControllers(sw), export_settings(export_settings)
+{
 }
 
 // write bone nodes
-void ArmatureExporter::add_armature_bones(bContext *C, Depsgraph *depsgraph, Object *ob_arm,
-                                          Scene *sce, SceneExporter *se,
-                                          std::list<Object *>& child_objects)
+void ArmatureExporter::add_armature_bones(
+       Object *ob_arm,
+       ViewLayer *view_layer,
+       SceneExporter *se,
+       std::vector<Object *>& child_objects)
+
 {
-       Main *bmain = CTX_data_main(C);
        // write bone nodes
 
        bArmature *armature = (bArmature *)ob_arm->data;
        bool is_edited = armature->edbo != NULL;
 
-       if (!is_edited)
+       if (!is_edited) {
                ED_armature_to_edit(armature);
+       }
 
        for (Bone *bone = (Bone *)armature->bonebase.first; bone; bone = bone->next) {
                // start from root bones
-               if (!bone->parent)
-                       add_bone_node(C, depsgraph, bone, ob_arm, sce, se, child_objects);
+               if (!bone->parent) {
+                       add_bone_node(bone, ob_arm, se, child_objects);
+               }
        }
 
        if (!is_edited) {
-               ED_armature_from_edit(bmain, armature);
                ED_armature_edit_free(armature);
        }
 }
 
 void ArmatureExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone)
 {
-       if (bc_is_root_bone(bone, this->export_settings->deform_bones_only))
-               ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(ob_arm, bone)));
+       if (bc_is_root_bone(bone, this->export_settings->deform_bones_only)) {
+               std::string joint_id = translate_id(id_name(ob_arm) + "_" + bone->name);
+               ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, joint_id));
+       }
        else {
                for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
                        write_bone_URLs(ins, ob_arm, child);
@@ -156,12 +164,14 @@ void ArmatureExporter::find_objects_using_armature(Object *ob_arm, std::vector<O
 #endif
 
 // parent_mat is armature-space
-void ArmatureExporter::add_bone_node(bContext *C, Depsgraph *depsgraph, Bone *bone, Object *ob_arm, Scene *sce,
-                                     SceneExporter *se,
-                                     std::list<Object *>& child_objects)
+void ArmatureExporter::add_bone_node(
+       Bone *bone,
+       Object *ob_arm,
+    SceneExporter *se,
+    std::vector<Object *>& child_objects)
 {
        if (!(this->export_settings->deform_bones_only && bone->flag & BONE_NO_DEFORM)) {
-               std::string node_id = get_joint_id(ob_arm, bone);
+               std::string node_id = translate_id(id_name(ob_arm) + "_" + bone->name);
                std::string node_name = std::string(bone->name);
                std::string node_sid = get_joint_sid(bone);
 
@@ -201,7 +211,7 @@ void ArmatureExporter::add_bone_node(bContext *C, Depsgraph *depsgraph, Bone *bo
                        add_bone_transform(ob_arm, bone, node);
 
                        // Write nodes of childobjects, remove written objects from list
-                       std::list<Object *>::iterator i = child_objects.begin();
+                       std::vector<Object *>::iterator i = child_objects.begin();
 
                        while (i != child_objects.end()) {
                                if ((*i)->partype == PARBONE && STREQ((*i)->parsubstr, bone->name)) {
@@ -230,8 +240,7 @@ void ArmatureExporter::add_bone_node(bContext *C, Depsgraph *depsgraph, Bone *bo
                                                mul_m4_m4m4((*i)->parentinv, temp, (*i)->parentinv);
                                        }
 
-                                       se->writeNodes(C, depsgraph, *i, sce);
-
+                                       se->writeNodes(*i);
                                        copy_m4_m4((*i)->parentinv, backup_parinv);
                                        child_objects.erase(i++);
                                }
@@ -239,13 +248,13 @@ void ArmatureExporter::add_bone_node(bContext *C, Depsgraph *depsgraph, Bone *bo
                        }
 
                        for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
-                               add_bone_node(C, depsgraph, child, ob_arm, sce, se, child_objects);
+                               add_bone_node(child, ob_arm, se, child_objects);
                        }
                        node.end();
                }
                else {
                        for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
-                               add_bone_node(C, depsgraph, child, ob_arm, sce, se, child_objects);
+                               add_bone_node(child, ob_arm, se, child_objects);
                        }
                }
 }
index 7efa8b70e435bfb28455bac2c5c1510a80740f46..977a8b9b4a51380a89fba9251bfa9ec7d9d7a18b 100644 (file)
@@ -57,21 +57,20 @@ class SceneExporter;
 class ArmatureExporter : public COLLADASW::LibraryControllers, protected TransformWriter, protected InstanceWriter
 {
 public:
-       ArmatureExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
+       ArmatureExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
 
-       // write bone nodes
-       void add_armature_bones(bContext *C, struct Depsgraph *depsgraph, Object *ob_arm, Scene *sce, SceneExporter *se,
-                               std::list<Object *>& child_objects);
+       void add_armature_bones(
+               Object *ob_arm,
+               ViewLayer *view_layer,
+               SceneExporter *se,
+               std::vector<Object *>& child_objects);
 
        bool add_instance_controller(Object *ob);
 
-       //void export_controllers(Scene *sce);*/
-
-       //void operator()(Object *ob);
-
 private:
        UnitConverter converter;
        const ExportSettings *export_settings;
+       BlenderContext &blender_context;
 
 #if 0
        std::vector<Object *> written_armatures;
@@ -85,8 +84,11 @@ private:
 
        // Scene, SceneExporter and the list of child_objects
        // are required for writing bone parented objects
-       void add_bone_node(bContext *C, struct Depsgraph *depsgraph, Bone *bone, Object *ob_arm, Scene *sce, SceneExporter *se,
-                          std::list<Object *>& child_objects);
+       void add_bone_node(
+               Bone *bone,
+               Object *ob_arm,
+               SceneExporter *se,
+               std::vector<Object *>& child_objects);
 
        void add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node);
 
diff --git a/source/blender/collada/BCAnimationCurve.cpp b/source/blender/collada/BCAnimationCurve.cpp
new file mode 100644 (file)
index 0000000..3925cde
--- /dev/null
@@ -0,0 +1,679 @@
+/*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* The Original Code is Copyright (C) 2008 Blender Foundation.
+* All rights reserved.
+*
+* Contributor(s): Blender Foundation
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+#include "BCAnimationCurve.h"
+
+BCAnimationCurve::BCAnimationCurve()
+{
+       this->curve_key.set_object_type(BC_ANIMATION_TYPE_OBJECT);
+       this->fcurve = NULL;
+       this->curve_is_local_copy = false;
+}
+
+BCAnimationCurve::BCAnimationCurve(const BCAnimationCurve &other)
+{
+       this->min = other.min;
+       this->max = other.max;
+       this->fcurve = other.fcurve;
+       this->curve_key = other.curve_key;
+       this->curve_is_local_copy = false;
+       this->id_ptr = other.id_ptr;
+
+       /* The fcurve of the new instance is a copy and can be modified */
+
+       get_edit_fcurve();
+}
+
+BCAnimationCurve::BCAnimationCurve(BCCurveKey key, Object *ob, FCurve *fcu)
+{
+       this->min = 0;
+       this->max = 0;
+       this->curve_key = key;
+       this->fcurve = fcu;
+       this->curve_is_local_copy = false;
+       init_pointer_rna(ob);
+}
+
+BCAnimationCurve::BCAnimationCurve(const BCCurveKey &key, Object *ob)
+{
+       this->curve_key = key;
+       this->fcurve = NULL;
+       this->curve_is_local_copy = false;
+       init_pointer_rna(ob);
+}
+
+void BCAnimationCurve::init_pointer_rna(Object *ob)
+{
+       switch (this->curve_key.get_animation_type()) {
+       case BC_ANIMATION_TYPE_BONE:
+       {
+               bArmature * arm = (bArmature *)ob->data;
+               RNA_id_pointer_create(&arm->id, &id_ptr);
+       }
+       break;
+       case BC_ANIMATION_TYPE_OBJECT:
+       {
+               RNA_id_pointer_create(&ob->id, &id_ptr);
+       }
+       break;
+       case BC_ANIMATION_TYPE_MATERIAL:
+       {
+               Material *ma = give_current_material(ob, curve_key.get_subindex() + 1);
+               RNA_id_pointer_create(&ma->id, &id_ptr);
+       }
+       break;
+       case BC_ANIMATION_TYPE_CAMERA:
+       {
+               Camera * camera = (Camera *)ob->data;
+               RNA_id_pointer_create(&camera->id, &id_ptr);
+       }
+       break;
+       case BC_ANIMATION_TYPE_LIGHT:
+       {
+               Lamp * lamp = (Lamp *)ob->data;
+               RNA_id_pointer_create(&lamp->id, &id_ptr);
+       }
+       break;
+       default:
+               fprintf(stderr, "BC_animation_curve_type %d not supported", this->curve_key.get_array_index());
+               break;
+       }
+}
+
+void BCAnimationCurve::delete_fcurve(FCurve *fcu)
+{
+       free_fcurve(fcu);
+}
+
+FCurve *BCAnimationCurve::create_fcurve(int array_index, const char *rna_path)
+{
+       FCurve *fcu = (FCurve *)MEM_callocN(sizeof(FCurve), "FCurve");
+       fcu->flag = (FCURVE_VISIBLE | FCURVE_AUTO_HANDLES | FCURVE_SELECTED);
+       fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
+       fcu->array_index = array_index;
+       return fcu;
+}
+
+void BCAnimationCurve::create_bezt(float frame, float output)
+{
+       FCurve *fcu = get_edit_fcurve();
+       BezTriple bez;
+       memset(&bez, 0, sizeof(BezTriple));
+       bez.vec[1][0] = frame;
+       bez.vec[1][1] = output;
+       bez.ipo = U.ipo_new; /* use default interpolation mode here... */
+       bez.f1 = bez.f2 = bez.f3 = SELECT;
+       bez.h1 = bez.h2 = HD_AUTO;
+       insert_bezt_fcurve(fcu, &bez, INSERTKEY_NOFLAGS);
+       calchandles_fcurve(fcu);
+}
+
+BCAnimationCurve::~BCAnimationCurve()
+{
+       if (curve_is_local_copy && fcurve) {
+               //fprintf(stderr, "removed fcurve %s\n", fcurve->rna_path);
+               delete_fcurve(fcurve);
+               this->fcurve = NULL;
+       }
+}
+
+const bool BCAnimationCurve::is_of_animation_type(BC_animation_type type) const
+{
+       return curve_key.get_animation_type() == type;
+}
+
+const std::string BCAnimationCurve::get_channel_target() const
+{
+       const std::string path = curve_key.get_path();
+       return bc_string_after(path, '.');
+}
+
+const std::string BCAnimationCurve::get_animation_name(Object *ob) const
+{
+       std::string name;
+
+       switch (curve_key.get_animation_type()) {
+               case BC_ANIMATION_TYPE_OBJECT:
+               {
+                       name = id_name(ob);
+               }
+               break;
+
+               case BC_ANIMATION_TYPE_BONE:
+               {
+                       if (fcurve == NULL || fcurve->rna_path == NULL)
+                               name = "";
+                       else {
+                               const char *boneName = BLI_str_quoted_substrN(fcurve->rna_path, "pose.bones[");
+                               name = (boneName) ? std::string(boneName) : "";
+                       }
+               }
+               break;
+
+               case BC_ANIMATION_TYPE_CAMERA:
+               {
+                       Camera *camera = (Camera *)ob->data;
+                       name = id_name(ob) + "-" + id_name(camera) + "-camera";
+               }
+               break;
+
+               case BC_ANIMATION_TYPE_LIGHT:
+               {
+                       Lamp *lamp = (Lamp *)ob->data;
+                       name = id_name(ob) + "-" + id_name(lamp) + "-light";
+               }
+               break;
+
+               case BC_ANIMATION_TYPE_MATERIAL:
+               {
+                       Material * ma = give_current_material(ob, this->curve_key.get_subindex() + 1);
+                       name = id_name(ob) + "-" + id_name(ma) + "-material";
+               }
+               break;
+
+               default:
+               {
+                       name = "";
+               }
+       }
+
+       return name;
+}
+
+const int BCAnimationCurve::get_channel_index() const
+{
+       return curve_key.get_array_index();
+}
+
+const int BCAnimationCurve::get_subindex() const
+{
+       return curve_key.get_subindex();
+}
+
+const std::string BCAnimationCurve::get_rna_path() const
+{
+       return curve_key.get_path();
+}
+
+const int BCAnimationCurve::sample_count() const
+{
+       if (fcurve == NULL)
+               return 0;
+       return fcurve->totvert;
+}
+
+const int BCAnimationCurve::closest_index_above(const float sample_frame, const int start_at) const
+{
+       if (fcurve == NULL)
+               return -1;
+
+       const int cframe = fcurve->bezt[start_at].vec[1][0]; // inacurate!
+
+       if (fabs(cframe - sample_frame) < 0.00001)
+               return start_at;
+       return (fcurve->totvert > start_at + 1) ? start_at + 1 : start_at;
+}
+
+const int BCAnimationCurve::closest_index_below(const float sample_frame) const
+{
+       if (fcurve == NULL)
+               return -1;
+
+       float lower_frame = sample_frame;
+       float upper_frame = sample_frame;
+       int lower_index = 0;
+       int upper_index = 0;
+
+       for (int fcu_index = 0; fcu_index < fcurve->totvert; ++fcu_index) {
+               upper_index = fcu_index;
+
+               const int cframe = fcurve->bezt[fcu_index].vec[1][0]; // inacurate!
+               if (cframe <= sample_frame) {
+                       lower_frame = cframe;
+                       lower_index = fcu_index;
+               }
+               if (cframe >= sample_frame) {
+                       upper_frame = cframe;
+                       break;
+               }
+       }
+
+       if (lower_index == upper_index)
+               return lower_index;
+
+       const float fraction = float(sample_frame - lower_frame) / (upper_frame - lower_frame);
+       return (fraction < 0.5) ? lower_index : upper_index;
+}
+
+const int BCAnimationCurve::get_interpolation_type(float sample_frame) const
+{
+       const int index = closest_index_below(sample_frame);
+       if (index < 0)
+               return BEZT_IPO_BEZ;
+       return fcurve->bezt[index].ipo;
+}
+
+const FCurve *BCAnimationCurve::get_fcurve() const
+{
+       return fcurve;
+}
+
+FCurve *BCAnimationCurve::get_edit_fcurve()
+{
+       if (!curve_is_local_copy) {
+               const int index = curve_key.get_array_index();
+               const std::string &path = curve_key.get_path();
+               fcurve = create_fcurve(index, path.c_str());
+
+               /* Caution here:
+               Replacing the pointer here is OK only because the original value
+               of FCurve was a const pointer into Blender territory. We do not
+               touch that! We use the local copy to prepare data for export.
+               */
+
+               curve_is_local_copy = true;
+       }
+       return fcurve;
+}
+
+void BCAnimationCurve::clean_handles()
+{
+       if (fcurve == NULL)
+               fcurve = get_edit_fcurve();
+
+       /* Keep old bezt data for copy)*/
+       BezTriple *old_bezts = fcurve->bezt;
+       int totvert = fcurve->totvert;
+       fcurve->bezt = NULL;
+       fcurve->totvert = 0;
+
+       for (int i = 0; i < totvert; i++) {
+               BezTriple *bezt = &old_bezts[i];
+               float x = bezt->vec[1][0];
+               float y = bezt->vec[1][1];
+               insert_vert_fcurve(fcurve, x, y, (eBezTriple_KeyframeType)BEZKEYTYPE(bezt), INSERTKEY_NOFLAGS);
+               BezTriple *lastb = fcurve->bezt + (fcurve->totvert - 1);
+               lastb->f1 = lastb->f2 = lastb->f3 = 0;
+       }
+
+       /* now free the memory used by the old BezTriples */
+       if (old_bezts)
+               MEM_freeN(old_bezts);
+}
+
+const bool BCAnimationCurve::is_transform_curve() const
+{
+       std::string channel_target = this->get_channel_target();
+       return (
+               is_rotation_curve() ||
+               channel_target == "scale" ||
+               channel_target == "location"
+               );
+}
+
+const bool BCAnimationCurve::is_rotation_curve() const
+{
+       std::string channel_target = this->get_channel_target();
+       return (
+               channel_target == "rotation" ||
+               channel_target == "rotation_euler" ||
+               channel_target == "rotation_quaternion"
+               );
+}
+
+const float BCAnimationCurve::get_value(const float frame)
+{
+       if (fcurve) {
+               return evaluate_fcurve(fcurve, frame);
+       }
+       return 0; // TODO: handle case where neither sample nor fcu exist
+}
+
+void BCAnimationCurve::update_range(float val)
+{
+       if (val < min) {
+                       min = val;
+       }
+       if (val > max) {
+               max = val;
+       }
+}
+
+void BCAnimationCurve::init_range(float val)
+{
+       min = max = val;
+}
+
+void BCAnimationCurve::adjust_range(const int frame_index)
+{
+       if (fcurve && fcurve->totvert > 1) {
+               const float eval = evaluate_fcurve(fcurve, frame_index);
+
+               int first_frame = fcurve->bezt[0].vec[1][0];
+               if (first_frame == frame_index) {
+                       init_range(eval);
+               }
+               else {
+                       update_range(eval);
+               }
+       }
+}
+
+void BCAnimationCurve::add_value(const float val, const int frame_index)
+{
+       FCurve *fcu = get_edit_fcurve();
+       fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL;
+       insert_vert_fcurve(
+               fcu, 
+               frame_index, val, 
+               BEZT_KEYTYPE_KEYFRAME,
+               INSERTKEY_NOFLAGS);
+
+       if (fcu->totvert == 1) {
+               init_range(val);
+       }
+       else {
+               update_range(val);
+       }
+}
+
+bool BCAnimationCurve::add_value_from_matrix(const BCSample &sample, const int frame_index)
+{
+       int array_index = curve_key.get_array_index();
+
+       /* transformation curves are feeded directly from the transformation matrix
+       * to resolve parent inverse matrix issues with object hierarchies.
+       * Maybe this can be unified with the
+       */
+       const std::string channel_target = get_channel_target();
+       float val = 0;
+       /* Pick the value from the sample according to the definition of the FCurve */
+       bool good = sample.get_value(channel_target, array_index, &val);
+       if (good) {
+               add_value(val, frame_index);
+       }
+       return good;
+}
+
+bool BCAnimationCurve::add_value_from_rna(const int frame_index)
+{
+       PointerRNA ptr;
+       PropertyRNA *prop;
+       float value = 0.0f;
+       int array_index = curve_key.get_array_index();
+       const std::string full_path = curve_key.get_full_path();
+
+       /* get property to read from, and get value as appropriate */
+       bool path_resolved = RNA_path_resolve_full(&id_ptr, full_path.c_str(), &ptr, &prop, &array_index);
+       if (!path_resolved && array_index == 0) {
+               const std::string rna_path = curve_key.get_path();
+               path_resolved = RNA_path_resolve_full(&id_ptr, rna_path.c_str(), &ptr, &prop, &array_index);
+       }
+
+       if (path_resolved) {
+               bool is_array = RNA_property_array_check(prop);
+               if (is_array) {
+                       /* array */
+                       if ((array_index >= 0) && (array_index < RNA_property_array_length(&ptr, prop))) {
+                               switch (RNA_property_type(prop)) {
+                               case PROP_BOOLEAN:
+                                       value = (float)RNA_property_boolean_get_index(&ptr, prop, array_index);
+                                       break;
+                               case PROP_INT:
+                                       value = (float)RNA_property_int_get_index(&ptr, prop, array_index);
+                                       break;
+                               case PROP_FLOAT:
+                                       value = RNA_property_float_get_index(&ptr, prop, array_index);
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+                       else {
+                               fprintf(stderr, "Out of Bounds while reading data for Curve %s\n", curve_key.get_full_path().c_str());
+                               return false;
+                       }
+               }
+               else {
+                       /* not an array */
+                       switch (RNA_property_type(prop)) {
+                       case PROP_BOOLEAN:
+                               value = (float)RNA_property_boolean_get(&ptr, prop);
+                               break;
+                       case PROP_INT:
+                               value = (float)RNA_property_int_get(&ptr, prop);
+                               break;
+                       case PROP_FLOAT:
+                               value = RNA_property_float_get(&ptr, prop);
+                               break;
+                       case PROP_ENUM:
+                               value = (float)RNA_property_enum_get(&ptr, prop);
+                               break;
+                       default:
+                               fprintf(stderr, "property type %d not supported for Curve %s\n", RNA_property_type(prop), curve_key.get_full_path().c_str());
+                               return false;
+                               break;
+                       }
+               }
+       }
+       else {
+               /* path couldn't be resolved */
+               fprintf(stderr, "Path not recognized for Curve %s\n", curve_key.get_full_path().c_str());
+               return false;
+       }
+
+       add_value(value, frame_index);
+       return true;
+}
+
+void BCAnimationCurve::get_value_map(BCValueMap &value_map)
+{
+       value_map.clear();
+       if (fcurve == NULL) {
+               return;
+       }
+
+       for (int i = 0; i < fcurve->totvert; i++) {
+               const float frame = fcurve->bezt[i].vec[1][0];
+               const float val = fcurve->bezt[i].vec[1][1];
+               value_map[frame] = val;
+       }
+}
+
+void BCAnimationCurve::get_frames(BCFrames &frames) const
+{
+       frames.clear();
+       if (fcurve) {
+               for (int i = 0; i < fcurve->totvert; i++) {
+                       const float val = fcurve->bezt[i].vec[1][0];
+                       frames.push_back(val);
+               }
+       }
+}
+
+void BCAnimationCurve::get_values(BCValues &values) const
+{
+       values.clear();
+       if (fcurve) {
+               for (int i = 0; i < fcurve->totvert; i++) {
+                       const float val = fcurve->bezt[i].vec[1][1];
+                       values.push_back(val);
+               }
+       }
+}
+
+bool BCAnimationCurve::is_animated()
+{
+       static float MIN_DISTANCE = 0.00001;
+       return fabs(max - min) > MIN_DISTANCE;
+}
+
+
+bool BCAnimationCurve::is_keyframe(int frame) {
+       if (this->fcurve == NULL)
+               return false;
+
+       for (int i = 0; i < fcurve->totvert; ++i) {
+               const int cframe = nearbyint(fcurve->bezt[i].vec[1][0]);
+               if (cframe == frame)
+                       return true;
+               if (cframe > frame)
+                       break;
+       }
+       return false;
+}
+
+/* Needed for adding a BCAnimationCurve into a BCAnimationCurveSet */
+inline bool operator< (const BCAnimationCurve& lhs, const BCAnimationCurve& rhs) {
+       std::string lhtgt = lhs.get_channel_target();
+       std::string rhtgt = rhs.get_channel_target();
+       if (lhtgt == rhtgt)
+       {
+               const int lha = lhs.get_channel_index();
+               const int rha = rhs.get_channel_index();
+               return lha < rha;
+       }
+       else
+               return lhtgt < rhtgt;
+}
+
+BCCurveKey::BCCurveKey()
+{
+       this->key_type = BC_ANIMATION_TYPE_OBJECT;
+       this->rna_path = "";
+       this->curve_array_index = 0;
+       this->curve_subindex = -1;
+}
+
+BCCurveKey::BCCurveKey(const BC_animation_type type, const std::string path, const int array_index, const int subindex)
+{
+       this->key_type = type;
+       this->rna_path = path;
+       this->curve_array_index = array_index;
+       this->curve_subindex = subindex;
+}
+
+void BCCurveKey::operator=(const BCCurveKey &other)
+{
+       this->key_type = other.key_type;
+       this->rna_path = other.rna_path;
+       this->curve_array_index = other.curve_array_index;
+       this->curve_subindex = other.curve_subindex;
+}
+
+const std::string BCCurveKey::get_full_path() const
+{
+       return this->rna_path + '[' + std::to_string(this->curve_array_index) + ']';
+}
+
+const std::string BCCurveKey::get_path() const
+{
+       return this->rna_path;
+}
+
+const int BCCurveKey::get_array_index() const
+{
+       return this->curve_array_index;
+}
+
+const int BCCurveKey::get_subindex() const
+{
+       return this->curve_subindex;
+}
+
+void BCCurveKey::set_object_type(BC_animation_type object_type)
+{
+       this->key_type = object_type;
+}
+
+const BC_animation_type BCCurveKey::get_animation_type() const
+{
+       return this->key_type;
+}
+
+const bool BCCurveKey::operator<(const BCCurveKey &other) const
+{
+       /* needed for using this class as key in maps and sets */
+       if (this->key_type != other.key_type)
+               return this->key_type < other.key_type;
+
+       if (this->curve_subindex != other.curve_subindex)
+               return this->curve_subindex < other.curve_subindex;
+
+       if (this->rna_path != other.rna_path)
+               return this->rna_path < other.rna_path;
+
+       return this->curve_array_index < other.curve_array_index;
+}
+
+BCBezTriple::BCBezTriple(BezTriple bezt) :
+       bezt(bezt) {}
+
+const float BCBezTriple::get_frame() const
+{
+       return bezt.vec[1][0];
+}
+
+const float BCBezTriple::get_time(Scene *scene) const
+{
+       return FRA2TIME(bezt.vec[1][0]);
+}
+
+const float BCBezTriple::get_value() const
+{
+       return bezt.vec[1][1];
+}
+
+const float BCBezTriple::get_angle() const
+{
+       return RAD2DEGF(get_value());
+}
+
+void BCBezTriple::get_in_tangent(Scene *scene, float point[2], bool as_angle) const
+{
+       get_tangent(scene, point, as_angle, 0);
+}
+
+void BCBezTriple::get_out_tangent(Scene *scene, float point[2], bool as_angle) const
+{
+       get_tangent(scene, point, as_angle, 2);
+}
+
+void BCBezTriple::get_tangent(Scene *scene, float point[2], bool as_angle, int index) const
+{
+       point[0] = FRA2TIME(bezt.vec[index][0]);
+       if (bezt.ipo != BEZT_IPO_BEZ) {
+               /* We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data */
+               point[0] = 0;
+               point[1] = 0;
+       }
+       else if (as_angle) {
+               point[1] = RAD2DEGF(bezt.vec[index][1]);
+       }
+       else {
+               point[1] = bezt.vec[index][1];
+       }
+}
+
diff --git a/source/blender/collada/BCAnimationCurve.h b/source/blender/collada/BCAnimationCurve.h
new file mode 100644 (file)
index 0000000..5d05802
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* The Original Code is Copyright (C) 2008 Blender Foundation.
+* All rights reserved.
+*
+* Contributor(s): Blender Foundation
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+#ifndef __BC_ANIMATION_CURVE_H__
+#define __BC_ANIMATION_CURVE_H__
+
+#include "collada_utils.h"
+#include "BCSampleData.h"
+
+extern "C"
+{
+#include "MEM_guardedalloc.h"
+#include "BKE_fcurve.h"
+#include "BKE_armature.h"
+#include "BKE_material.h"
+#include "ED_anim_api.h"
+#include "ED_keyframing.h"
+#include "ED_keyframes_edit.h"
+}
+
+typedef float(TangentPoint)[2];
+
+typedef std::set<float> BCFrameSet;
+typedef std::vector<float> BCFrames;
+typedef std::vector<float> BCValues;
+typedef std::vector<float> BCTimes;
+typedef std::map<int, float> BCValueMap;
+
+typedef enum BC_animation_type {
+       BC_ANIMATION_TYPE_OBJECT,
+       BC_ANIMATION_TYPE_BONE,
+       BC_ANIMATION_TYPE_CAMERA,
+       BC_ANIMATION_TYPE_MATERIAL,
+       BC_ANIMATION_TYPE_LIGHT
+} BC_animation_type;
+
+class BCCurveKey {
+private:
+       BC_animation_type key_type;
+       std::string rna_path;
+       int curve_array_index;
+       int curve_subindex; /* only needed for materials */
+
+public:
+
+       BCCurveKey();
+       BCCurveKey(const BC_animation_type type, const std::string path, const int array_index, const int subindex = -1);
+       void operator=(const BCCurveKey &other);
+       const std::string get_full_path() const;
+       const std::string get_path() const;
+       const int get_array_index() const;
+       const int get_subindex() const;
+       void set_object_type(BC_animation_type object_type);
+       const BC_animation_type get_animation_type() const;
+       const bool operator<(const BCCurveKey &other) const;
+
+};
+
+class BCBezTriple {
+public:
+       BezTriple & bezt;
+
+       BCBezTriple(BezTriple bezt);
+       const float get_frame() const;
+       const float get_time(Scene *scene) const;
+       const float get_value() const;
+       const float get_angle() const;
+       void get_in_tangent(Scene *scene, float point[2], bool as_angle) const;
+       void get_out_tangent(Scene *scene, float point[2], bool as_angle) const;
+       void get_tangent(Scene *scene, float point[2], bool as_angle, int index) const;
+
+};
+
+class BCAnimationCurve {
+private:
+       BCCurveKey curve_key;
+       float min = 0;
+       float max = 0;
+
+       bool curve_is_local_copy = false;
+       FCurve *fcurve;
+       PointerRNA id_ptr;
+       void init_pointer_rna(Object *ob);
+       void delete_fcurve(FCurve *fcu);
+       FCurve *create_fcurve(int array_index, const char *rna_path);
+       void create_bezt(float frame, float output);
+       void update_range(float val);
+       void init_range(float val);
+
+public:
+       BCAnimationCurve();
+       BCAnimationCurve(const BCAnimationCurve &other);
+       BCAnimationCurve(const BCCurveKey &key, Object *ob);
+       BCAnimationCurve(BCCurveKey key, Object *ob, FCurve *fcu);
+       ~BCAnimationCurve();
+
+       const bool is_of_animation_type(BC_animation_type type) const;
+       const int get_interpolation_type(float sample_frame) const;
+       bool is_animated();
+       const bool is_transform_curve() const;
+       const bool is_rotation_curve() const;
+       bool is_keyframe(int frame);
+       void adjust_range(int frame);
+
+       const std::string get_animation_name(Object *ob) const; /* xxx: this is collada specific */
+       const std::string get_channel_target() const;
+       const int get_channel_index() const;
+       const int get_subindex() const;
+       const std::string get_rna_path() const;
+       const FCurve *get_fcurve() const;
+       const int sample_count() const;
+
+       const float get_value(const float frame);
+       void get_values(BCValues &values) const;
+       void get_value_map(BCValueMap &value_map);
+
+       void get_frames(BCFrames &frames) const;
+
+       /* Curve edit functions create a copy of the underlaying FCurve */
+       FCurve *get_edit_fcurve();
+       bool add_value_from_rna(const int frame);
+       bool add_value_from_matrix(const BCSample &sample, const int frame);
+       void add_value(const float val, const int frame);
+       void clean_handles();
+
+       /* experimental stuff */
+       const int closest_index_above(const float sample_frame, const int start_at) const;
+       const int closest_index_below(const float sample_frame) const;
+
+};
+
+typedef std::map<BCCurveKey, BCAnimationCurve *> BCAnimationCurveMap;
+
+#endif
diff --git a/source/blender/collada/BCAnimationSampler.cpp b/source/blender/collada/BCAnimationSampler.cpp
new file mode 100644 (file)
index 0000000..e736569
--- /dev/null
@@ -0,0 +1,645 @@
+/*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* The Original Code is Copyright (C) 2008 Blender Foundation.
+* All rights reserved.
+*
+* Contributor(s): Blender Foundation
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+#include <vector>
+#include <map>
+#include <algorithm> // std::find
+
+#include "ExportSettings.h"
+#include "BCAnimationCurve.h"
+#include "BCAnimationSampler.h"
+#include "collada_utils.h"
+
+extern "C" {
+#include "BKE_action.h"
+#include "BKE_constraint.h"
+#include "BKE_key.h"
+#include "BKE_main.h"
+#include "BKE_library.h"
+#include "BKE_material.h"
+#include "BLI_listbase.h"
+#include "DNA_anim_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_key_types.h"
+#include "DNA_constraint_types.h"
+#include "ED_object.h"
+}
+
+static std::string EMPTY_STRING;
+static BCAnimationCurveMap BCEmptyAnimationCurves;
+
+BCAnimationSampler::BCAnimationSampler(BlenderContext &blender_context, BCObjectSet &object_set):
+       blender_context(blender_context)
+{
+       BCObjectSet::iterator it;
+       for (it = object_set.begin(); it != object_set.end(); ++it) {
+               Object *ob = *it;
+               add_object(ob);
+       }
+}
+
+BCAnimationSampler::~BCAnimationSampler()
+{
+       BCAnimationObjectMap::iterator it;
+       for (it = objects.begin(); it != objects.end(); ++it) {
+               BCAnimation *animation = it->second;
+               delete animation;
+       }
+}
+
+void BCAnimationSampler::add_object(Object *ob)
+{
+       BCAnimation *animation = new BCAnimation(blender_context.get_context(), ob);
+       objects[ob] = animation;
+
+       initialize_keyframes(animation->frame_set, ob);
+       initialize_curves(animation->curve_map, ob);
+}
+
+BCAnimationCurveMap *BCAnimationSampler::get_curves(Object *ob)
+{
+       BCAnimation &animation = *objects[ob];
+       if (animation.curve_map.size() == 0)
+               initialize_curves(animation.curve_map, ob);
+       return &animation.curve_map;
+}
+
+static void get_sample_frames(BCFrameSet &sample_frames, int sampling_rate, bool keyframe_at_end, Scene *scene)
+{
+       sample_frames.clear();
+
+       if (sampling_rate < 1)
+               return; // no sample frames in this case
+
+       float sfra = scene->r.sfra;
+       float efra = scene->r.efra;
+
+       int frame_index;
+       for (frame_index = nearbyint(sfra); frame_index < efra; frame_index += sampling_rate) {
+               sample_frames.insert(frame_index);
+       }
+
+       if (frame_index >= efra && keyframe_at_end)
+       {
+               sample_frames.insert(efra);
+       }
+}
+
+static bool is_object_keyframe(Object *ob, int frame_index)
+{
+       return false;
+}
+
+static void add_keyframes_from(bAction *action, BCFrameSet &frameset)
+{
+       if (action) {
+               FCurve *fcu = NULL;
+               for (fcu = (FCurve *)action->curves.first; fcu; fcu = fcu->next) {
+                       BezTriple  *bezt = fcu->bezt;
+                       for (int i = 0; i < fcu->totvert; bezt++, i++) {
+                               int frame_index = nearbyint(bezt->vec[1][0]);
+                               frameset.insert(frame_index);
+                       }
+               }
+       }
+}
+
+void BCAnimationSampler::check_property_is_animated(BCAnimation &animation, float *ref, float *val, std::string data_path, int length)
+{
+       for (int array_index =0; array_index < length; ++array_index) {
+               if (!bc_in_range(ref[length], val[length], 0.00001)) {
+                       BCCurveKey key(BC_ANIMATION_TYPE_OBJECT, data_path, array_index);
+                       BCAnimationCurveMap::iterator it = animation.curve_map.find(key);
+                       if (it == animation.curve_map.end()) {
+                               animation.curve_map[key] = new BCAnimationCurve(key, animation.get_reference());
+                       }
+               }
+       }
+}
+
+void BCAnimationSampler::update_animation_curves(BCAnimation &animation, BCSample &sample, Object *ob, int frame)
+{
+       BCAnimationCurveMap::iterator it;
+       for (it = animation.curve_map.begin(); it != animation.curve_map.end(); ++it) {
+               BCAnimationCurve *curve = it->second;
+               if (curve->is_transform_curve()) {
+                       curve->add_value_from_matrix(sample, frame);
+               }
+               else {
+                       curve->add_value_from_rna(frame);
+               }
+       }
+}
+
+BCSample &BCAnimationSampler::sample_object(Object *ob, int frame_index, bool for_opensim)
+{
+       BCSample &ob_sample = sample_data.add(ob, frame_index);
+
+       if (ob->type == OB_ARMATURE) {
+               bPoseChannel *pchan;
+               for (pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+                       Bone *bone = pchan->bone;
+                       Matrix bmat;
+                       if (bc_bone_matrix_local_get(ob, bone, bmat, for_opensim)) {
+                               ob_sample.add_bone_matrix(bone, bmat);
+                       }
+               }
+       }
+       return ob_sample;
+}
+
+void BCAnimationSampler::sample_scene(
+       int sampling_rate,
+       int keyframe_at_end,
+       bool for_opensim,
+       bool keep_keyframes,
+       BC_export_animation_type export_animation_type)
+{
+       Scene *scene = blender_context.get_scene();
+       BCFrameSet scene_sample_frames;
+       get_sample_frames(scene_sample_frames, sampling_rate, keyframe_at_end, scene);
+       BCFrameSet::iterator it;
+
+       int startframe = scene->r.sfra;
+       int endframe = scene->r.efra;
+
+       for (int frame_index = startframe; frame_index <= endframe; ++frame_index) {
+               /* Loop over all frames and decide for each frame if sampling is necessary */
+               bool is_scene_sample_frame = false;
+               bool needs_update = true;
+               if (scene_sample_frames.find(frame_index) != scene_sample_frames.end()) {
+                       bc_update_scene(blender_context, frame_index);
+                       needs_update = false;
+                       is_scene_sample_frame = true;
+               }
+
+               bool needs_sampling = is_scene_sample_frame || keep_keyframes || export_animation_type == BC_ANIMATION_EXPORT_KEYS;
+               if (!needs_sampling) {
+                       continue;
+               }
+
+               BCAnimationObjectMap::iterator obit;
+               for (obit = objects.begin(); obit != objects.end(); ++obit) {
+                       Object *ob = obit->first;
+                       BCAnimation *animation = obit->second;
+                       BCFrameSet &object_keyframes = animation->frame_set;
+                       if (is_scene_sample_frame || object_keyframes.find(frame_index) != object_keyframes.end()) {
+
+                               if (needs_update) {
+                                       bc_update_scene(blender_context, frame_index);
+                                       needs_update = false;
+                               }
+
+                               BCSample &sample = sample_object(ob, frame_index, for_opensim);
+                               update_animation_curves(*animation, sample, ob, frame_index);
+                       }
+               }
+       }
+}
+
+bool BCAnimationSampler::is_animated_by_constraint(Object *ob, ListBase *conlist, std::set<Object *> &animated_objects)
+{
+       bConstraint *con;
+       for (con = (bConstraint *)conlist->first; con; con = con->next) {
+               ListBase targets = { NULL, NULL };
+
+               const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+
+               if (!bc_validateConstraints(con))
+                       continue;
+
+               if (cti && cti->get_constraint_targets) {
+                       bConstraintTarget *ct;
+                       Object *obtar;
+                       cti->get_constraint_targets(con, &targets);
+                       for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
+                               obtar = ct->tar;
+                               if (obtar) {
+                                       if (animated_objects.find(obtar) != animated_objects.end())
+                                               return true;
+                               }
+                       }
+               }
+       }
+       return false;
+}
+
+void BCAnimationSampler::find_depending_animated(std::set<Object *> &animated_objects, std::set<Object *> &candidates)
+{
+       bool found_more;
+       do {
+               found_more = false;
+               std::set<Object *>::iterator it;
+               for (it = candidates.begin(); it != candidates.end(); ++it) {
+                       Object *cob = *it;
+                       ListBase *conlist = get_active_constraints(cob);
+                       if (is_animated_by_constraint(cob, conlist, animated_objects)) {
+                               animated_objects.insert(cob);
+                               candidates.erase(cob);
+                               found_more = true;
+                               break;
+                       }
+               }
+       } while (found_more && candidates.size() > 0);
+}
+
+void BCAnimationSampler::get_animated_from_export_set(std::set<Object *> &animated_objects, LinkNode &export_set)
+{
+       /*
+       Check if this object is animated. That is: Check if it has its own action, or
+
+       - Check if it has constraints to other objects
+       - at least one of the other objects is animated as well
+       */
+
+       animated_objects.clear();
+       std::set<Object *> static_objects;
+       std::set<Object *> candidates;
+
+       LinkNode *node;
+       for (node = &export_set; node; node = node->next) {
+               Object *cob = (Object *)node->link;
+               if (bc_has_animations(cob)) {
+                       animated_objects.insert(cob);
+               }
+               else {
+                       ListBase conlist = cob->constraints;
+                       if (conlist.first)
+                               candidates.insert(cob);
+               }
+       }
+       find_depending_animated(animated_objects, candidates);
+}
+
+void BCAnimationSampler::get_object_frames(BCFrames &frames, Object *ob)
+{
+       sample_data.get_frames(ob, frames);
+}
+
+void BCAnimationSampler::get_bone_frames(BCFrames &frames, Object *ob, Bone *bone)
+{
+       sample_data.get_frames(ob, bone, frames);
+}
+
+bool BCAnimationSampler::get_bone_samples(BCMatrixSampleMap &samples, Object *ob, Bone *bone)
+{
+       sample_data.get_matrices(ob, bone, samples);
+       return bc_is_animated(samples);
+}
+
+bool BCAnimationSampler::get_object_samples(BCMatrixSampleMap &samples, Object *ob)
+{
+       sample_data.get_matrices(ob, samples);
+       return bc_is_animated(samples);
+}
+
+#if 0
+/*
+   Add sampled values to FCurve 
+   If no FCurve exists, create a temporary FCurve;
+   Note: The temporary FCurve will later be removed when the
+   BCAnimationSampler is removed (by its destructor)
+
+   curve: The curve to whioch the data is added
+   matrices: The set of matrix values from where the data is taken
+   animation_type BC_ANIMATION_EXPORT_SAMPLES: Use all matrix data
+   animation_type BC_ANIMATION_EXPORT_KEYS: Only take data from matrices for keyframes
+*/
+
+void BCAnimationSampler::add_value_set(
+       BCAnimationCurve &curve,
+       BCFrameSampleMap &samples,
+       BC_export_animation_type animation_type)
+{
+       int array_index = curve.get_array_index();
+       const BC_animation_transform_type tm_type = curve.get_transform_type();
+
+       BCFrameSampleMap::iterator it;
+       for (it = samples.begin(); it != samples.end(); ++it) {
+               const int frame_index = nearbyint(it->first);
+               if (animation_type == BC_ANIMATION_EXPORT_SAMPLES || curve.is_keyframe(frame_index)) {
+
+                       const BCSample *sample = it->second;
+                       float val = 0;
+
+                       int subindex = curve.get_subindex();
+                       bool good;
+                       if (subindex == -1) {
+                               good = sample->get_value(tm_type, array_index, &val);
+                       }
+                       else {
+                               good = sample->get_value(tm_type, array_index, &val, subindex);
+                       }
+                       
+                       if (good) {
+                               curve.add_value(val, frame_index);
+                       }
+               }
+       }
+       curve.remove_unused_keyframes();
+       curve.calchandles();
+}
+#endif
+
+void BCAnimationSampler::generate_transform(
+       Object *ob,
+    const BCCurveKey &key,
+       BCAnimationCurveMap &curves)
+{
+       BCAnimationCurveMap::const_iterator it = curves.find(key);
+       if (it == curves.end()) {
+               curves[key] = new BCAnimationCurve(key, ob);
+       }
+}
+
+void BCAnimationSampler::generate_transforms(
+       Object *ob,
+       const std::string prep,
+       const BC_animation_type type,
+       BCAnimationCurveMap &curves)
+{
+       generate_transform(ob, BCCurveKey(type, prep+"location", 0), curves);
+       generate_transform(ob, BCCurveKey(type, prep+"location", 1), curves);
+       generate_transform(ob, BCCurveKey(type, prep+"location", 2), curves);
+       generate_transform(ob, BCCurveKey(type, prep+"rotation_euler", 0), curves);
+       generate_transform(ob, BCCurveKey(type, prep+"rotation_euler", 1), curves);
+       generate_transform(ob, BCCurveKey(type, prep+"rotation_euler", 2), curves);
+       generate_transform(ob, BCCurveKey(type, prep+"scale", 0), curves);
+       generate_transform(ob, BCCurveKey(type, prep+"scale", 1), curves);
+       generate_transform(ob, BCCurveKey(type, prep+"scale", 2), curves);
+}
+
+void BCAnimationSampler::generate_transforms(Object *ob, Bone *bone, BCAnimationCurveMap &curves)
+{
+       std::string prep = "pose.bones[\"" + std::string(bone->name) + "\"].";
+       generate_transforms(ob, prep, BC_ANIMATION_TYPE_BONE, curves);
+
+       for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next)
+               generate_transforms(ob, child, curves);
+}
+
+/*
+* Collect all keyframes from all animation curves related to the object
+* The bc_get... functions check for NULL and correct object type
+* The add_keyframes_from() function checks for NULL
+*/
+void BCAnimationSampler::initialize_keyframes(BCFrameSet &frameset, Object *ob)
+{
+       frameset.clear();
+       add_keyframes_from(bc_getSceneObjectAction(ob), frameset);
+       add_keyframes_from(bc_getSceneCameraAction(ob), frameset);
+       add_keyframes_from(bc_getSceneLampAction(ob), frameset);
+
+       for (int a = 0; a < ob->totcol; a++) {
+               Material *ma = give_current_material(ob, a + 1);
+               add_keyframes_from(bc_getSceneMaterialAction(ma), frameset);
+       }
+}
+
+void BCAnimationSampler::initialize_curves(BCAnimationCurveMap &curves, Object *ob)
+{
+       BC_animation_type object_type = BC_ANIMATION_TYPE_OBJECT;
+
+       bAction *action = bc_getSceneObjectAction(ob);
+       if (action) {
+               FCurve *fcu = (FCurve *)action->curves.first;
+
+               for (; fcu; fcu = fcu->next) {
+                       object_type = BC_ANIMATION_TYPE_OBJECT;
+                       if (ob->type == OB_ARMATURE) {
+                               char *boneName = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
+                               if (boneName) {
+                                       object_type = BC_ANIMATION_TYPE_BONE;
+                               }
+                       }
+
+                       /* Adding action curves on object */
+                       BCCurveKey key(object_type, fcu->rna_path, fcu->array_index);
+                       curves[key] = new BCAnimationCurve(key, ob, fcu);
+               }
+       }
+
+       /* Add missing curves */
+       object_type = BC_ANIMATION_TYPE_OBJECT;
+       generate_transforms(ob, EMPTY_STRING, object_type, curves);
+       if (ob->type == OB_ARMATURE) {
+               bArmature *arm = (bArmature *)ob->data;
+               for (Bone *root_bone = (Bone *)arm->bonebase.first; root_bone; root_bone = root_bone->next)
+                       generate_transforms(ob, root_bone, curves);
+       }
+
+       /* Add curves on Object->data actions */
+       action = NULL;
+       if (ob->type == OB_CAMERA) {
+               action = bc_getSceneCameraAction(ob);
+               object_type = BC_ANIMATION_TYPE_CAMERA;
+       }
+       else if (ob->type == OB_LAMP) {
+               action = bc_getSceneLampAction(ob);
+               object_type = BC_ANIMATION_TYPE_LIGHT;
+       }
+
+       if (action) {
+               /* Add lamp action or Camera action */
+               FCurve *fcu = (FCurve *)action->curves.first;
+               for (; fcu; fcu = fcu->next) {
+                       BCCurveKey key(object_type, fcu->rna_path, fcu->array_index);
+                       curves[key] = new BCAnimationCurve(key, ob, fcu);
+               }
+       }
+
+       /* Add curves on Object->material actions*/
+       object_type = BC_ANIMATION_TYPE_MATERIAL;
+       for (int a = 0; a < ob->totcol; a++) {
+               /* Export Material parameter animations. */
+               Material *ma = give_current_material(ob, a + 1);
+               if (ma) {
+                       action = bc_getSceneMaterialAction(ma);
+                       if (action) {
+                               /* isMatAnim = true; */
+                               FCurve *fcu = (FCurve *)action->curves.first;
+                               for (; fcu; fcu = fcu->next) {
+                                       BCCurveKey key(object_type, fcu->rna_path, fcu->array_index, a);
+                                       curves[key] = new BCAnimationCurve(key, ob, fcu);
+                               }
+                       }
+               }
+       }
+}
+
+/* ==================================================================== */
+
+BCSample &BCSampleFrame::add(Object *ob)
+{
+       BCSample *sample = new BCSample(ob);
+       sampleMap[ob] = sample;
+       return *sample;
+}
+
+/* Get the matrix for the given key, returns Unity when the key does not exist */
+const BCSample *BCSampleFrame::get_sample(Object *ob) const
+{
+       BCSampleMap::const_iterator it = sampleMap.find(ob);
+       if (it == sampleMap.end()) {
+               return NULL;
+       }
+       return it->second;
+}
+
+const BCMatrix *BCSampleFrame::get_sample_matrix(Object *ob) const
+{
+       BCSampleMap::const_iterator it = sampleMap.find(ob);
+       if (it == sampleMap.end()) {
+               return NULL;
+       }
+       BCSample *sample = it->second;
+       return &sample->get_matrix();
+}
+
+/* Get the matrix for the given Bone, returns Unity when the Objewct is not sampled */
+const BCMatrix *BCSampleFrame::get_sample_matrix(Object *ob, Bone *bone) const
+{
+       BCSampleMap::const_iterator it = sampleMap.find(ob);
+       if (it == sampleMap.end()) {
+               return NULL;
+       }
+
+       BCSample *sample = it->second;
+       const BCMatrix *bc_bone = sample->get_matrix(bone);
+       return bc_bone;
+}
+
+/* Check if the key is in this BCSampleFrame */
+const bool BCSampleFrame::has_sample_for(Object *ob) const
+{
+       return sampleMap.find(ob) != sampleMap.end();
+}
+
+/* Check if the Bone is in this BCSampleFrame */
+const bool BCSampleFrame::has_sample_for(Object *ob, Bone *bone) const
+{
+       const BCMatrix *bc_bone = get_sample_matrix(ob, bone);
+       return (bc_bone);
+}
+
+/* ==================================================================== */
+
+BCSample &BCSampleFrameContainer::add(Object *ob, int frame_index)
+{
+       BCSampleFrame &frame = sample_frames[frame_index];
+       return frame.add(ob);
+}
+
+
+/* ====================================================== */
+/* Below are the getters which we need to export the data */
+/* ====================================================== */
+
+/* Return either the BCSampleFrame or NULL if frame does not exist*/
+BCSampleFrame * BCSampleFrameContainer::get_frame(int frame_index)
+{
+       BCSampleFrameMap::iterator it = sample_frames.find(frame_index);
+       BCSampleFrame *frame = (it == sample_frames.end()) ? NULL : &it->second;
+       return frame;
+}
+
+/* Return a list of all frames that need to be sampled */
+const int BCSampleFrameContainer::get_frames(std::vector<int> &frames) const
+{
+       frames.clear(); // safety;
+       BCSampleFrameMap::const_iterator it;
+       for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
+               frames.push_back(it->first);
+       }
+       return frames.size();
+}
+
+const int BCSampleFrameContainer::get_frames(Object *ob, BCFrames &frames) const
+{
+       frames.clear(); // safety;
+       BCSampleFrameMap::const_iterator it;
+       for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
+               const BCSampleFrame &frame = it->second;
+               if (frame.has_sample_for(ob)) {
+                       frames.push_back(it->first);
+               }
+       }
+       return frames.size();
+}
+
+const int BCSampleFrameContainer::get_frames(Object *ob, Bone *bone, BCFrames &frames) const
+{
+       frames.clear(); // safety;
+       BCSampleFrameMap::const_iterator it;
+       for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
+               const BCSampleFrame &frame = it->second;
+               if (frame.has_sample_for(ob, bone)) {
+                       frames.push_back(it->first);
+               }
+       }
+       return frames.size();
+}
+
+const int BCSampleFrameContainer::get_samples(Object *ob, BCFrameSampleMap &samples) const
+{
+       samples.clear(); // safety;
+       BCSampleFrameMap::const_iterator it;
+       for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
+               const BCSampleFrame &frame = it->second;
+               const BCSample *sample = frame.get_sample(ob);
+               if (sample) {
+                       samples[it->first] = sample;
+               }
+       }
+       return samples.size();
+}
+
+const int BCSampleFrameContainer::get_matrices(Object *ob, BCMatrixSampleMap &samples) const
+{
+       samples.clear(); // safety;
+       BCSampleFrameMap::const_iterator it;
+       for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
+               const BCSampleFrame &frame = it->second;
+               const BCMatrix *matrix = frame.get_sample_matrix(ob);
+               if (matrix) {
+                       samples[it->first] = matrix;
+               }
+       }
+       return samples.size();
+}
+
+const int BCSampleFrameContainer::get_matrices(Object *ob, Bone *bone, BCMatrixSampleMap &samples) const
+{
+       samples.clear(); // safety;
+       BCSampleFrameMap::const_iterator it;
+       for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
+               const BCSampleFrame &frame = it->second;
+               const BCMatrix *sample = frame.get_sample_matrix(ob, bone);
+               if (sample) {
+                       samples[it->first] = sample;
+               }
+       }
+       return samples.size();
+}
diff --git a/source/blender/collada/BCAnimationSampler.h b/source/blender/collada/BCAnimationSampler.h
new file mode 100644 (file)
index 0000000..4becafb
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* The Original Code is Copyright (C) 2008 Blender Foundation.
+* All rights reserved.
+*
+* Contributor(s): Blender Foundation
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+#ifndef __BC_ANIMATION_CURVE_CONTAINER_H__
+#define __BC_ANIMATION_CURVE_CONTAINER_H__
+
+#include "BCAnimationCurve.h"
+#include "BCSampleData.h"
+#include "collada_utils.h"
+
+extern "C" {
+#include "BKE_action.h"
+#include "BKE_library.h"
+#include "BLI_math_rotation.h"
+#include "DNA_action_types.h"
+}
+
+/* Collection of animation curves */
+class BCAnimation {
+private:
+       Object *reference = NULL;
+       bContext *mContext;
+
+
+public:
+       BCFrameSet frame_set;
+       BCAnimationCurveMap curve_map;
+
+       BCAnimation(bContext *C, Object *ob):
+               mContext(C)
+       {
+               Main *bmain = CTX_data_main(mContext);
+               reference = BKE_object_copy(bmain, ob);
+       }
+
+       ~BCAnimation()
+       {
+               BCAnimationCurveMap::iterator it;
+               for (it = curve_map.begin(); it != curve_map.end(); ++it) {
+                       delete it->second;
+               }
+
+               if (reference && reference->id.us == 0)
+               {
+                       Main *bmain = CTX_data_main(mContext);
+                       BKE_libblock_delete(bmain, &reference->id);
+               }
+               curve_map.clear();
+       }
+
+       Object *get_reference()
+       {
+               return reference;
+       }
+};
+
+typedef std::map<Object *, BCAnimation *> BCAnimationObjectMap;
+
+class BCSampleFrame {
+
+       /*
+       Each frame on the timeline that needs to be sampled will have
+       one BCSampleFrame where we collect sample information about all objects
+       that need to be sampled for that frame.
+       */
+
+private:
+       BCSampleMap sampleMap;
+
+public:
+
+       ~BCSampleFrame()
+       {
+               BCSampleMap::iterator it;
+               for (it = sampleMap.begin(); it != sampleMap.end(); ++it) {
+                       BCSample *sample = it->second;
+                       delete sample;
+               }
+               sampleMap.clear();
+       }
+
+       BCSample &add(Object *ob);
+
+       /* Following methods return NULL if object is not in the sampleMap*/
+       const BCSample *get_sample(Object *ob) const;
+       const BCMatrix *get_sample_matrix(Object *ob) const;
+       const BCMatrix *get_sample_matrix(Object *ob, Bone *bone) const;
+
+       const bool has_sample_for(Object *ob) const;
+       const bool has_sample_for(Object *ob, Bone *bone) const;
+};
+
+typedef std::map<int, BCSampleFrame> BCSampleFrameMap;
+
+class BCSampleFrameContainer {
+
+       /*
+       * The BCSampleFrameContainer stores a map of BCSampleFrame objects
+       * with the timeline frame as key.
+       *
+       * Some details on the purpose:
+       * An Animation is made of multiple FCurves where each FCurve can 
+       * have multiple keyframes. When we want to export the animation we
+       * also can decide whether we want to export the keyframes or a set
+       * of sample frames at equidistant locations (sample period). 
+       * In any case we must resample first need to resample it fully 
+       * to resolve things like:
+       *
+       * - animations by constraints
+       * - animations by drivers
+       *
+       * For this purpose we need to step through the entire animation and
+       * then sample each frame that contains at least one keyFrame or 
+       * sampleFrame. Then for each frame we have to store the transform
+       * information for all exported objects in a BCSampleframe
+       *
+       * The entire set of BCSampleframes is finally collected into 
+       * a BCSampleframneContainer
+       */
+
+private:
+       BCSampleFrameMap sample_frames;
+
+public:
+
+       ~BCSampleFrameContainer()
+       {
+       }
+
+       BCSample &add(Object *ob, int frame_index);
+       BCSampleFrame * get_frame(int frame_index); // returns NULL if frame does not exist
+
+       const int get_frames(std::vector<int> &frames) const;
+       const int get_frames(Object *ob, BCFrames &frames) const;
+       const int get_frames(Object *ob, Bone *bone, BCFrames &frames) const;
+
+       const int get_samples(Object *ob, BCFrameSampleMap &samples) const;
+       const int get_matrices(Object *ob, BCMatrixSampleMap &matrices) const;
+       const int get_matrices(Object *ob, Bone *bone, BCMatrixSampleMap &bones) const;
+};
+
+class BCAnimationSampler {
+private:
+       BlenderContext &blender_context;
+       BCSampleFrameContainer sample_data;
+       BCAnimationObjectMap objects;
+
+       void generate_transform(Object *ob, const BCCurveKey &key, BCAnimationCurveMap &curves);
+       void generate_transforms(Object *ob, const std::string prep, const BC_animation_type type, BCAnimationCurveMap &curves);
+       void generate_transforms(Object *ob, Bone *bone, BCAnimationCurveMap &curves);
+
+       void initialize_curves(BCAnimationCurveMap &curves, Object *ob);
+       void initialize_keyframes(BCFrameSet &frameset, Object *ob);
+       BCSample &sample_object(Object *ob, int frame_index, bool for_opensim);
+       void update_animation_curves(BCAnimation &animation, BCSample &sample, Object *ob, int frame_index);
+       void check_property_is_animated(BCAnimation &animation, float *ref, float *val, std::string data_path, int length);
+
+public:
+       BCAnimationSampler(BlenderContext &blender_context, BCObjectSet &animated_subset);
+       ~BCAnimationSampler();
+
+       void add_object(Object *ob);
+
+       void sample_scene(
+               int sampling_rate,
+               int keyframe_at_end,
+               bool for_opensim,
+               bool keep_keyframes,
+               BC_export_animation_type export_animation_type);
+
+       BCAnimationCurveMap *get_curves(Object *ob);
+       void get_object_frames(BCFrames &frames, Object *ob);
+       bool get_object_samples(BCMatrixSampleMap &samples, Object *ob);
+       void get_bone_frames(BCFrames &frames, Object *ob, Bone *bone);
+       bool get_bone_samples(BCMatrixSampleMap &samples, Object *ob, Bone *bone);
+
+       static void get_animated_from_export_set(std::set<Object *> &animated_objects, LinkNode &export_set);
+       static void find_depending_animated(std::set<Object *> &animated_objects, std::set<Object *> &candidates);
+       static bool is_animated_by_constraint(Object *ob, ListBase *conlist, std::set<Object *> &animated_objects);
+
+};
+
+#endif
diff --git a/source/blender/collada/BCSampleData.cpp b/source/blender/collada/BCSampleData.cpp
new file mode 100644 (file)
index 0000000..32210c9
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* The Original Code is Copyright (C) 2008 Blender Foundation.
+* All rights reserved.
+*
+* Contributor(s): Blender Foundation
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+#include "BCSampleData.h"
+#include "collada_utils.h"
+
+BCSample::BCSample(Object *ob):
+       obmat(ob)
+{}
+
+BCSample::~BCSample()
+{
+       BCBoneMatrixMap::iterator it;
+       for (it = bonemats.begin(); it != bonemats.end(); ++it) {
+               delete it->second;
+       }
+}
+
+void BCSample::add_bone_matrix(Bone *bone, Matrix &mat)
+{
+       BCMatrix *matrix;
+       BCBoneMatrixMap::const_iterator it = bonemats.find(bone);
+       if (it != bonemats.end()) {
+               throw std::invalid_argument("bone " + std::string(bone->name) + " already defined before");
+       }
+       matrix = new BCMatrix(mat);
+       bonemats[bone] = matrix;
+}
+
+BCMatrix::BCMatrix(Matrix &mat)
+{
+       set_transform(mat);
+}
+
+BCMatrix::BCMatrix(Object *ob)
+{
+       set_transform(ob);
+}
+
+void BCMatrix::set_transform(Matrix &mat)
+{
+       copy_m4_m4(matrix, mat);
+       mat4_decompose(this->loc, this->q, this->size, mat);
+       quat_to_eul(this->rot, this->q);
+}
+
+void BCMatrix::set_transform(Object *ob)
+{
+       Matrix lmat;
+
+       BKE_object_matrix_local_get(ob, lmat);
+       copy_m4_m4(matrix, lmat);
+
+       mat4_decompose(this->loc, this->q, this->size, lmat);
+       quat_to_compatible_eul(this->rot, ob->rot, this->q);
+}
+
+const BCMatrix *BCSample::get_matrix(Bone *bone) const
+{
+       BCBoneMatrixMap::const_iterator it = bonemats.find(bone);
+       if (it == bonemats.end()) {
+               return NULL;
+       }
+       return it->second;
+}
+
+const BCMatrix &BCSample::get_matrix() const
+{
+       return obmat;
+}
+
+
+/* Get channel value */
+const bool BCSample::get_value(std::string channel_target, const int array_index, float *val) const
+{
+       if (channel_target == "location") {
+               *val = obmat.location()[array_index];
+       }
+       else if (channel_target == "scale") {
+               *val = obmat.scale()[array_index];
+       }
+       else if (
+               channel_target == "rotation" ||
+               channel_target == "rotation_euler") {
+               *val = obmat.rotation()[array_index];
+       }
+       else if (channel_target == "rotation_quat") {
+               *val = obmat.quat()[array_index];
+       }
+       else {
+               *val = 0;
+               return false;
+       }
+
+       return true;
+}
+
+void BCMatrix::copy(Matrix &out, Matrix &in)
+{
+       /* destination comes first: */
+       memcpy(out, in, sizeof(Matrix));
+}
+
+void BCMatrix::transpose(Matrix &mat)
+{
+       transpose_m4(mat);
+}
+
+void BCMatrix::sanitize(Matrix &mat, int precision)
+{
+       bc_sanitize_mat(mat, precision);
+}
+
+void BCMatrix::unit()
+{
+       unit_m4(matrix);
+}
+
+/*
+We need double here because the OpenCollada API needs it.
+precision = -1 indicates to not limit the precision
+*/
+void BCMatrix::get_matrix(double(&mat)[4][4], const bool transposed, const int precision) const
+{
+       for (int i = 0; i < 4; i++)
+               for (int j = 0; j < 4; j++) {
+                       float val = (transposed) ? matrix[j][i] : matrix[i][j];
+                       if (precision >= 0)
+                               val = floor((val * pow(10, precision) + 0.5)) / pow(10, precision);
+                       mat[i][j] = val;
+               }
+}
+
+const bool BCMatrix::in_range(const BCMatrix &other, float distance) const
+{
+       for (int i = 0; i < 4; i++) {
+               for (int j = 0; j < 4; j++) {
+                       if (fabs(other.matrix[i][j] - matrix[i][j]) > distance) {
+                               return false;
+                       }
+               }
+       }
+       return true;
+}
+
+float(&BCMatrix::location() const)[3]
+{
+       return loc;
+}
+
+float(&BCMatrix::rotation() const)[3]
+{
+       return rot;
+}
+
+float(&BCMatrix::scale() const)[3]
+{
+       return size;
+}
+
+float(&BCMatrix::quat() const)[4]
+{
+       return q;
+}
+
+
diff --git a/source/blender/collada/BCSampleData.h b/source/blender/collada/BCSampleData.h
new file mode 100644 (file)
index 0000000..a685cb3
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* The Original Code is Copyright (C) 2008 Blender Foundation.
+* All rights reserved.
+*
+* Contributor(s): Blender Foundation
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+#ifndef __BC_SAMPLE_H__
+#define __BC_SAMPLE_H__
+
+#include <string>
+#include <map>
+#include <algorithm>
+
+extern "C"
+{
+#include "BKE_object.h"
+#include "BLI_math_rotation.h"
+#include "DNA_object_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_material_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_camera_types.h"
+}
+
+typedef float(Matrix)[4][4];
+
+class BCMatrix {
+
+private:
+       mutable float matrix[4][4];
+       mutable float size[3];
+       mutable float rot[3];
+       mutable float loc[3];
+       mutable float q[4];
+
+       void unit();
+       void copy(Matrix &r, Matrix &a);
+       void set_transform(Object *ob);
+       void set_transform(Matrix &mat);
+
+public:
+
+       float(&location() const)[3];
+       float(&rotation() const)[3];
+       float(&scale() const)[3];
+       float(&quat() const)[4];
+
+       BCMatrix(Matrix &mat);
+       BCMatrix(Object *ob);
+
+       void get_matrix(double(&mat)[4][4], const bool transposed = false, const int precision = -1) const;
+
+       const bool in_range(const BCMatrix &other, float distance) const;
+       static void sanitize(Matrix &matrix, int precision);
+       static void transpose(Matrix &matrix);
+
+};
+
+typedef std::map<Bone *, BCMatrix *> BCBoneMatrixMap;
+
+class BCSample{
+private:
+
+       BCMatrix obmat;
+       BCBoneMatrixMap bonemats; /* For Armature animation */
+
+public:
+       BCSample(Object *ob);
+       ~BCSample();
+
+       void add_bone_matrix(Bone *bone, Matrix &mat);
+
+       const bool get_value(std::string channel_target, const int array_index, float *val) const;
+       const BCMatrix &get_matrix() const;
+       const BCMatrix *get_matrix(Bone *bone) const; // returns NULL if bone is not animated
+
+};
+
+typedef std::map<Object *, BCSample *> BCSampleMap;
+typedef std::map<int, const BCSample *> BCFrameSampleMap;
+typedef std::map<int, const BCMatrix *> BCMatrixSampleMap;
+
+#endif
diff --git a/source/blender/collada/BlenderContext.cpp b/source/blender/collada/BlenderContext.cpp
new file mode 100644 (file)
index 0000000..536d517
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Gaia Clary,
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+ /** \file CameraExporter.h
+  *  \ingroup collada
+  */
+
+#include "BlenderContext.h"
+
+BlenderContext::BlenderContext(bContext *C)
+{
+       context = C;
+       main = CTX_data_main(C);
+       depsgraph = CTX_data_depsgraph(C);
+       scene = CTX_data_scene(C);
+       view_layer = DEG_get_evaluated_view_layer(depsgraph);
+}
+
+bContext *BlenderContext::get_context()
+{
+       return context;
+}
+
+Depsgraph *BlenderContext::get_depsgraph()
+{
+       return depsgraph;
+}
+
+Scene *BlenderContext::get_scene()
+{
+       return scene;
+}
+
+ViewLayer *BlenderContext::get_view_layer()
+{
+       return view_layer;
+}
+
+Main *BlenderContext::get_main()
+{
+       return main;
+}
diff --git a/source/blender/collada/BlenderContext.h b/source/blender/collada/BlenderContext.h
new file mode 100644 (file)
index 0000000..648d97a
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Gaia Clary,
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+ /** \file CameraExporter.h
+  *  \ingroup collada
+  */
+
+#ifndef __BLENDERCONTEXT_H__
+#define __BLENDERCONTEXT_H__
+
+extern "C" {
+#include "DNA_object_types.h"
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+}
+
+class BlenderContext
+{
+private:
+       bContext *context;
+       Depsgraph *depsgraph;
+       Scene *scene;
+       ViewLayer *view_layer;
+       Main *main;
+
+public:
+       BlenderContext(bContext *C);
+       bContext *get_context();
+       Depsgraph *get_depsgraph();
+       Scene *get_scene();
+       ViewLayer *get_view_layer();
+       Main *get_main();
+};
+
+#endif
index 8642bbee6985c235cffafcca74a2640ed78688ee..f860dfac08b30750a86d25a351dd6be1e6a53d7f 100644 (file)
@@ -49,8 +49,13 @@ set(INC_SYS
 set(SRC
        AnimationImporter.cpp
        AnimationExporter.cpp
+       AnimationClipExporter.cpp
        ArmatureExporter.cpp
        ArmatureImporter.cpp
+       BlenderContext.cpp
+       BCAnimationCurve.cpp
+       BCAnimationSampler.cpp
+       BCSampleData.cpp
        CameraExporter.cpp
        ControllerExporter.cpp
        DocumentExporter.cpp
@@ -68,6 +73,7 @@ set(SRC
        MaterialExporter.cpp
        MeshImporter.cpp
        SkinInfo.cpp
+       Materials.cpp
        SceneExporter.cpp
        TransformReader.cpp
        TransformWriter.cpp
@@ -77,8 +83,13 @@ set(SRC
 
        AnimationImporter.h
        AnimationExporter.h
+       AnimationClipExporter.h
        ArmatureExporter.h
        ArmatureImporter.h
+       BlenderContext.h
+       BCAnimationCurve.h
+       BCAnimationSampler.h
+       BCSampleData.h
        CameraExporter.h
        ControllerExporter.h
        DocumentExporter.h
@@ -95,6 +106,7 @@ set(SRC
        LightExporter.h
        MaterialExporter.h
        MeshImporter.h
+       Materials.h
        SkinInfo.h
        SceneExporter.h
        TransformReader.h
index 862ce30640968619c6ce09230e3c7a9b9ecff05e..0aed344062041d6e5ae7f891a5bd3663826e1c91 100644 (file)
@@ -58,7 +58,9 @@ extern "C" {
 // XXX exporter writes wrong data for shared armatures.  A separate
 // controller should be written for each armature-mesh binding how do
 // we make controller ids then?
-ControllerExporter::ControllerExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryControllers(sw), export_settings(export_settings) {
+ControllerExporter::ControllerExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : 
+       blender_context(blender_context),
+       COLLADASW::LibraryControllers(sw), export_settings(export_settings) {
 }
 
 bool ControllerExporter::is_skinned_mesh(Object *ob)
@@ -66,11 +68,12 @@ bool ControllerExporter::is_skinned_mesh(Object *ob)
        return bc_get_assigned_armature(ob) != NULL;
 }
 
-
 void ControllerExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone)
 {
-       if (bc_is_root_bone(bone, this->export_settings->deform_bones_only))
-               ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(ob_arm, bone)));
+       if (bc_is_root_bone(bone, this->export_settings->deform_bones_only)) {
+               std::string node_id = translate_id(id_name(ob_arm) + "_" + bone->name);
+               ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, node_id));
+       }
        else {
                for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
                        write_bone_URLs(ins, ob_arm, child);
@@ -103,12 +106,9 @@ bool ControllerExporter::add_instance_controller(Object *ob)
        return true;
 }
 
-void ControllerExporter::export_controllers(Main *bmain, Depsgraph *depsgraph, Scene *sce)
+void ControllerExporter::export_controllers()
 {
-       this->depsgraph = depsgraph;
-       m_bmain = bmain;
-       scene = sce;
-
+       Scene *sce = blender_context.get_scene();
        openLibrary();
 
        GeometryFunctor gf;
@@ -203,8 +203,7 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
        }
 
        me = bc_get_mesh_copy(
-                               depsgraph,
-                               scene,
+                               blender_context,
                                ob,
                                this->export_settings->export_mesh_type,
                                this->export_settings->apply_modifiers,
@@ -305,8 +304,7 @@ void ControllerExporter::export_morph_controller(Object *ob, Key *key)
        Mesh *me;
 
        me = bc_get_mesh_copy(
-                               depsgraph,
-                               scene,
+                               blender_context,
                                ob,
                                this->export_settings->export_mesh_type,
                                this->export_settings->apply_modifiers,
@@ -499,6 +497,9 @@ std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBas
 
        // put armature in rest position
        if (!(arm->flag & ARM_RESTPOS)) {
+               Depsgraph *depsgraph = blender_context.get_depsgraph();
+               Scene *scene = blender_context.get_scene();
+
                arm->flag |= ARM_RESTPOS;
                BKE_pose_where_is(depsgraph, scene, ob_arm);
        }
@@ -547,6 +548,8 @@ std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBas
 
        // back from rest position
        if (!(flag & ARM_RESTPOS)) {
+               Depsgraph *depsgraph = blender_context.get_depsgraph();
+               Scene *scene = blender_context.get_scene();
                arm->flag = flag;
                BKE_pose_where_is(depsgraph, scene, ob_arm);
        }
index 2b6853901be8aa31fd2a25d3d2a2b0ecb9204cbc..6a3ea7cc023904632373cdbba7dd872cacb936d2 100644 (file)
@@ -60,20 +60,18 @@ class SceneExporter;
 class ControllerExporter : public COLLADASW::LibraryControllers, protected TransformWriter, protected InstanceWriter
 {
 public:
-       ControllerExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
+       ControllerExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
 
        bool is_skinned_mesh(Object *ob);
 
        bool add_instance_controller(Object *ob);
 
-       void export_controllers(Main *bmain, Depsgraph *depsgraph, Scene *sce);
+       void export_controllers();
 
        void operator()(Object *ob);
 
 private:
-       Depsgraph *depsgraph;
-       Main *m_bmain;
-       Scene *scene;
+       BlenderContext &blender_context;
        UnitConverter converter;
        const ExportSettings *export_settings;
 
index 8d9f67a8eab73d6766adc0b4041a8916094d32ad..a69e522a9dd80825f2e6a276f342ccdd10f9f2d8 100644 (file)
@@ -151,8 +151,8 @@ char *bc_CustomData_get_active_layer_name(const CustomData *data, int type)
        return data->layers[layer_index].name;
 }
 
-DocumentExporter::DocumentExporter(Depsgraph *depsgraph, const ExportSettings *export_settings) :
-       depsgraph(depsgraph),
+DocumentExporter::DocumentExporter(BlenderContext &blender_context, const ExportSettings *export_settings) :
+       blender_context(blender_context),
        export_settings(export_settings) {
 }
 
@@ -180,9 +180,13 @@ static COLLADABU::NativeString make_temp_filepath(const char *name, const char *
 // COLLADA allows this through multiple <channel>s in <animation>.
 // For this to work, we need to know objects that use a certain action.
 
-int DocumentExporter::exportCurrentScene(bContext *C, Scene *sce)
+int DocumentExporter::exportCurrentScene()
 {
-       Main *bmain = CTX_data_main(C);
+       Main *bmain = blender_context.get_main();
+       Scene *sce = blender_context.get_scene();
+       bContext *C = blender_context.get_context();
+       Depsgraph *depsgraph = blender_context.get_depsgraph(); \
+
        PointerRNA sceneptr, unit_settings;
        PropertyRNA *system; /* unused , *scale; */
 
@@ -272,42 +276,43 @@ int DocumentExporter::exportCurrentScene(bContext *C, Scene *sce)
                le.exportLights(sce);
        }
 
+       // <library_effects>
+       EffectsExporter ee(writer, this->export_settings, key_image_map);
+       ee.exportEffects(C, sce);
+
        // <library_images>
-       ImagesExporter ie(writer, this->export_settings);
+       ImagesExporter ie(writer, this->export_settings, key_image_map);
        ie.exportImages(sce);
 
-       // <library_effects>
-       EffectsExporter ee(writer, this->export_settings);
-       ee.exportEffects(sce);
-
        // <library_materials>
        MaterialsExporter me(writer, this->export_settings);
        me.exportMaterials(sce);
 
        // <library_geometries>
        if (bc_has_object_type(export_set, OB_MESH)) {
-               GeometryExporter ge(writer, this->export_settings);
-               ge.exportGeom(bmain, depsgraph, sce);
+               GeometryExporter ge(blender_context, writer, this->export_settings);
+               ge.exportGeom();
        }
 
        // <library_controllers>
-       ArmatureExporter arm_exporter(writer, this->export_settings);
-       ControllerExporter controller_exporter(writer, this->export_settings);
+       ArmatureExporter arm_exporter(blender_context, writer, this->export_settings);
+       ControllerExporter controller_exporter(blender_context, writer, this->export_settings);
        if (bc_has_object_type(export_set, OB_ARMATURE) || this->export_settings->include_shapekeys)
        {
-               controller_exporter.export_controllers(bmain, depsgraph, sce);
+               controller_exporter.export_controllers();
        }
 
        // <library_visual_scenes>
 
-       SceneExporter se(writer, &arm_exporter, this->export_settings);
+       SceneExporter se(blender_context, writer, &arm_exporter, this->export_settings);
 
        if (this->export_settings->include_animations) {
                // <library_animations>
-               AnimationExporter ae(depsgraph, writer, this->export_settings);
-               ae.exportAnimations(bmain, sce);
+               AnimationExporter ae(blender_context, writer, this->export_settings);
+               ae.exportAnimations();
        }
-       se.exportScene(C, depsgraph, sce);
+
+       se.exportScene();
 
        // <scene>
        std::string scene_name(translate_id(id_name(sce)));
index 8a48ca29090183f025116bb49a550a28c2fc5ad5..cb55dbc459ec0e5ec30b7b90d194b63f537c1988 100644 (file)
 #define __DOCUMENTEXPORTER_H__
 
 #include "collada.h"
+#include "collada_utils.h"
+#include "BlenderContext.h"
 
 extern "C" {
 #include "DNA_customdata_types.h"
 
 }
 
-struct Scene;
-
 class DocumentExporter
 {
  public:
-       DocumentExporter(Depsgraph *depsgraph, const ExportSettings *export_settings);
-       int  exportCurrentScene(bContext *C, Scene *sce);
-
+       DocumentExporter(BlenderContext &blender_context, const ExportSettings *export_settings);
+       int  exportCurrentScene();
        void exportScenes(const char *filename);
 private:
-       Depsgraph *depsgraph;
+       BlenderContext &blender_context;
        const ExportSettings *export_settings;
+       KeyImageMap key_image_map;
 };
 
 #endif
index f10252c01c5010cb543ef80cec045632f1f90fe0..658015ab912bdecfb2f81608d5f5f041fcd5c24f 100644 (file)
@@ -91,7 +91,7 @@ extern "C" {
 
 #include "collada_internal.h"
 #include "collada_utils.h"
-
+#include "materials.h"
 
 /*
  * COLLADA Importer limitations:
@@ -104,12 +104,12 @@ extern "C" {
 
 DocumentImporter::DocumentImporter(bContext *C, const ImportSettings *import_settings) :
        import_settings(import_settings),
-       mImportStage(General),
+       mImportStage(Fetching_Scene_data),
        mContext(C),
        view_layer(CTX_data_view_layer(mContext)),
        armature_importer(&unit_converter, &mesh_importer, CTX_data_main(C), CTX_data_scene(C), view_layer, import_settings),
        mesh_importer(&unit_converter, &armature_importer, CTX_data_main(C), CTX_data_scene(C), view_layer),
-       anim_importer(&unit_converter, &armature_importer, CTX_data_scene(C))
+       anim_importer(C, &unit_converter, &armature_importer, CTX_data_scene(C))
 {
 }
 
@@ -149,9 +149,7 @@ bool DocumentImporter::import()
        }
 
        /** TODO set up scene graph and such here */
-
-       mImportStage = Controller;
-
+       mImportStage = Fetching_Controller_data;
        COLLADASaxFWL::Loader loader2;
        COLLADAFW::Root root2(&loader2, this);
 
@@ -182,7 +180,7 @@ void DocumentImporter::start()
 
 void DocumentImporter::finish()
 {
-       if (mImportStage != General)
+       if (mImportStage == Fetching_Controller_data)
                return;
 
        Main *bmain = CTX_data_main(mContext);
@@ -225,12 +223,14 @@ void DocumentImporter::finish()
                }
 
                // Write nodes to scene
+               fprintf(stderr, "+-- Import Scene --------\n");
                const COLLADAFW::NodePointerArray& roots = (*sit)->getRootNodes();
                for (unsigned int i = 0; i < roots.getCount(); i++) {
                        std::vector<Object *> *objects_done = write_node(roots[i], NULL, sce, NULL, false);
                        objects_to_scale->insert(objects_to_scale->end(), objects_done->begin(), objects_done->end());
                        delete objects_done;
                }
+
        }
 
 
@@ -254,7 +254,7 @@ void DocumentImporter::finish()
 
        if (libnode_ob.size()) {
 
-               fprintf(stderr, "got %d library nodes to free\n", (int)libnode_ob.size());
+               fprintf(stderr, "| Cleanup: free %d library nodes\n", (int)libnode_ob.size());
                // free all library_nodes
                std::vector<Object *>::iterator it;
                for (it = libnode_ob.begin(); it != libnode_ob.end(); it++) {
@@ -277,7 +277,6 @@ void DocumentImporter::finish()
 
 void DocumentImporter::translate_anim_recursive(COLLADAFW::Node *node, COLLADAFW::Node *par = NULL, Object *parob = NULL)
 {
-       Main *bmain = CTX_data_main(mContext);
        // The split in #29246, rootmap must point at actual root when
        // calculating bones in apply_curves_as_matrix. - actual root is the root node.
        // This has to do with inverse bind poses being world space
@@ -312,7 +311,7 @@ void DocumentImporter::translate_anim_recursive(COLLADAFW::Node *node, COLLADAFW
                translate_anim_recursive(node, node, parob);
        }
        else {
-               anim_importer.translate_Animations(bmain, node, root_map, object_map, FW_object_map, uid_material_map);
+               anim_importer.translate_Animations(node, root_map, object_map, FW_object_map, uid_material_map);
                COLLADAFW::NodePointerArray &children = node->getChildNodes();
                for (i = 0; i < children.getCount(); i++) {
                        translate_anim_recursive(children[i], node, NULL);
@@ -403,7 +402,7 @@ Object *DocumentImporter::create_lamp_object(COLLADAFW::InstanceLight *lamp, Sce
 
 Object *DocumentImporter::create_instance_node(Object *source_ob, COLLADAFW::Node *source_node, COLLADAFW::Node *instance_node, Scene *sce, bool is_library_node)
 {
-       fprintf(stderr, "create <instance_node> under node id=%s from node id=%s\n", instance_node ? instance_node->getOriginalId().c_str() : NULL, source_node ? source_node->getOriginalId().c_str() : NULL);
+       //fprintf(stderr, "create <instance_node> under node id=%s from node id=%s\n", instance_node ? instance_node->getOriginalId().c_str() : NULL, source_node ? source_node->getOriginalId().c_str() : NULL);
 
        Main *bmain = CTX_data_main(mContext);
        Object *obn = BKE_object_copy(bmain, source_ob);
@@ -503,9 +502,10 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA
        std::vector<Object *> *root_objects = new std::vector<Object *>();
 
        fprintf(stderr,
-               "Writing node id='%s', name='%s'\n",
-               id.c_str(),
-               name.c_str());
+               "| %s id='%s', name='%s'\n",
+               is_joint ? "JOINT" : "NODE ",
+               id.c_str(),
+        name.c_str() );
 
        if (is_joint) {
                if (parent_node == NULL && !is_library_node) {
@@ -700,7 +700,7 @@ finally:
  */
 bool DocumentImporter::writeVisualScene(const COLLADAFW::VisualScene *visualScene)
 {
-       if (mImportStage != General)
+       if (mImportStage == Fetching_Controller_data)
                return true;
 
        // this method called on post process after writeGeometry, writeMaterial, etc.
@@ -723,19 +723,19 @@ bool DocumentImporter::writeVisualScene(const COLLADAFW::VisualScene *visualScen
  * \return The writer should return true, if writing succeeded, false otherwise.*/
 bool DocumentImporter::writeLibraryNodes(const COLLADAFW::LibraryNodes *libraryNodes)
 {
-       if (mImportStage != General)
+       if (mImportStage == Fetching_Controller_data)
                return true;
 
        Scene *sce = CTX_data_scene(mContext);
 
        const COLLADAFW::NodePointerArray& nodes = libraryNodes->getNodes();
 
+       fprintf(stderr, "+-- Read Library nodes ----------\n");
        for (unsigned int i = 0; i < nodes.getCount(); i++) {
                std::vector<Object *> *child_objects;
                child_objects = write_node(nodes[i], NULL, sce, NULL, true);
                delete child_objects;
        }
-
        return true;
 }
 
@@ -743,7 +743,7 @@ bool DocumentImporter::writeLibraryNodes(const COLLADAFW::LibraryNodes *libraryN
  * \return The writer should return true, if writing succeeded, false otherwise.*/
 bool DocumentImporter::writeGeometry(const COLLADAFW::Geometry *geom)
 {
-       if (mImportStage != General)
+       if (mImportStage == Fetching_Controller_data)
                return true;
 
        return mesh_importer.write_geometry(geom);
@@ -753,7 +753,7 @@ bool DocumentImporter::writeGeometry(const COLLADAFW::Geometry *geom)
  * \return The writer should return true, if writing succeeded, false otherwise.*/
 bool DocumentImporter::writeMaterial(const COLLADAFW::Material *cmat)
 {
-       if (mImportStage != General)
+       if (mImportStage == Fetching_Controller_data)
                return true;
 
        Main *bmain = CTX_data_main(mContext);
@@ -766,136 +766,18 @@ bool DocumentImporter::writeMaterial(const COLLADAFW::Material *cmat)
        return true;
 }
 
+
 void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Material *ma)
 {
-       COLLADAFW::EffectCommon::ShaderType shader = ef->getShaderType();
-
-       // TODO: add back texture and extended material parameter support
-
-       // blinn
-       if (shader == COLLADAFW::EffectCommon::SHADER_BLINN) {
-#if 0
-               ma->spec_shader = MA_SPEC_BLINN;
-               ma->spec = ef->getShininess().getFloatValue();
-#endif
-       }
-       // phong
-       else if (shader == COLLADAFW::EffectCommon::SHADER_PHONG) {
-#if 0
-               ma->spec_shader = MA_SPEC_PHONG;
-               ma->har = ef->getShininess().getFloatValue();
-#endif
-       }
-       // lambert
-       else if (shader == COLLADAFW::EffectCommon::SHADER_LAMBERT) {
-#if 0
-               ma->diff_shader = MA_DIFF_LAMBERT;
-#endif
-       }
-       // default - lambert
-       else {
-#if 0
-               ma->diff_shader = MA_DIFF_LAMBERT;
-               fprintf(stderr, "Current shader type is not supported, default to lambert.\n");
-#endif
-       }
-       // reflectivity
-       ma->metallic = ef->getReflectivity().getFloatValue();
-       // index of refraction
-#if 0
-       ma->ang = ef->getIndexOfRefraction().getFloatValue();
-#endif
-
-       COLLADAFW::Color col;
-
-       // DIFFUSE
-       // color
-       if (ef->getDiffuse().isColor()) {
-               col = ef->getDiffuse().getColor();
-               ma->r = col.getRed();
-               ma->g = col.getGreen();
-               ma->b = col.getBlue();
-       }
-       // texture
-       else if (ef->getDiffuse().isTexture()) {
-#if 0
-               COLLADAFW::Texture ctex = ef->getDiffuse().getTexture();
-#endif
-       }
-       // AMBIENT
-       // color
-       if (ef->getAmbient().isColor()) {
-#if 0
-               col = ef->getAmbient().getColor();
-#endif
-       }
-       // texture
-       else if (ef->getAmbient().isTexture()) {
-#if 0
-               COLLADAFW::Texture ctex = ef->getAmbient().getTexture();
-#endif
-       }
-       // SPECULAR
-       // color
-       if (ef->getSpecular().isColor()) {
-               col = ef->getSpecular().getColor();
-               ma->specr = col.getRed();
-               ma->specg = col.getGreen();
-               ma->specb = col.getBlue();
-       }
-       // texture
-       else if (ef->getSpecular().isTexture()) {
-#if 0
-               COLLADAFW::Texture ctex = ef->getSpecular().getTexture();
-#endif
-       }
-       // REFLECTIVE
-       // color
-       if (ef->getReflective().isColor()) {
-#if 0
-               col = ef->getReflective().getColor();
-#endif
-       }
-       // texture
-       else if (ef->getReflective().isTexture()) {
-#if 0
-               COLLADAFW::Texture ctex = ef->getReflective().getTexture();
-#endif
-       }
-
-       // EMISSION
-       // color
-       if (ef->getEmission().isColor()) {
-               // XXX there is no emission color in blender
-               // but I am not sure
-       }
-       // texture
-       else if (ef->getEmission().isTexture()) {
-#if 0
-               COLLADAFW::Texture ctex = ef->getEmission().getTexture();
-#endif
-       }
-
-       // TRANSPARENT
-       // color
-       if (ef->getOpacity().isColor()) {
-#if 0
-               col = ef->getTransparent().getColor();
-               float alpha = ef->getTransparency().getFloatValue();
-               if (col.isValid()) {
-                       alpha *= col.getAlpha(); // Assuming A_ONE opaque mode
-               }
-               if (col.isValid() || alpha < 1.0) {
-                       ...
-               }
-#endif
-       }
-       // texture
-       else if (ef->getOpacity().isTexture()) {
-#if 0
-               COLLADAFW::Texture ctex = ef->getOpacity().getTexture();
-#endif
-       }
+       MaterialNode matNode = MaterialNode(mContext, ef, ma, uid_image_map);
+       matNode.set_reflectivity(ef->getReflectivity().getFloatValue());
+       matNode.set_ior(ef->getIndexOfRefraction().getFloatValue());
+       matNode.set_diffuse(ef->getDiffuse(), "Diffuse");
+       matNode.set_ambient(ef->getAmbient(), "Ambient");
+       matNode.set_specular(ef->getSpecular(), "Specular");
+       matNode.set_reflective(ef->getReflective(), "Reflective");
+       matNode.set_emission(ef->getEmission(), "Emission");
+       matNode.set_opacity(ef->getOpacity(), "Opacity");
 }
 
 /** When this method is called, the writer must write the effect.
@@ -903,7 +785,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia
 
 bool DocumentImporter::writeEffect(const COLLADAFW::Effect *effect)
 {
-       if (mImportStage != General)
+       if (mImportStage == Fetching_Controller_data)
                return true;
 
        const COLLADAFW::UniqueId& uid = effect->getUniqueId();
@@ -940,7 +822,7 @@ bool DocumentImporter::writeEffect(const COLLADAFW::Effect *effect)
  * \return The writer should return true, if writing succeeded, false otherwise.*/
 bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera)
 {
-       if (mImportStage != General)
+       if (mImportStage == Fetching_Controller_data)
                return true;
 
        Main *bmain = CTX_data_main(mContext);
@@ -1066,7 +948,7 @@ bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera)
  * \return The writer should return true, if writing succeeded, false otherwise.*/
 bool DocumentImporter::writeImage(const COLLADAFW::Image *image)
 {
-       if (mImportStage != General)
+       if (mImportStage == Fetching_Controller_data)
                return true;
 
        const std::string& imagepath = image->getImageURI().toNativePath();
@@ -1083,7 +965,7 @@ bool DocumentImporter::writeImage(const COLLADAFW::Image *image)
        else {
                // Maybe imagepath was already absolute ?
                if (!BLI_exists(imagepath.c_str())) {
-                       fprintf(stderr, "Image not found: %s.\n", imagepath.c_str() );
+                       fprintf(stderr, "|! Image not found: %s\n", imagepath.c_str() );
                        return true;
                }
                workpath = imagepath.c_str();
@@ -1091,11 +973,11 @@ bool DocumentImporter::writeImage(const COLLADAFW::Image *image)
 
        Image *ima = BKE_image_load_exists(CTX_data_main(mContext), workpath);
        if (!ima) {
-               fprintf(stderr, "Cannot create image: %s\n", workpath);
+               fprintf(stderr, "|! Cannot create image: %s\n", workpath);
                return true;
        }
        this->uid_image_map[image->getUniqueId()] = ima;
-
+       fprintf(stderr, "| import Image: %s\n", workpath);
        return true;
 }
 
@@ -1103,7 +985,7 @@ bool DocumentImporter::writeImage(const COLLADAFW::Image *image)
  * \return The writer should return true, if writing succeeded, false otherwise.*/
 bool DocumentImporter::writeLight(const COLLADAFW::Light *light)
 {
-       if (mImportStage != General)
+       if (mImportStage == Fetching_Controller_data)
                return true;
 
        Main *bmain = CTX_data_main(mContext);
@@ -1196,12 +1078,10 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light)
                lamp->energy = e;
                lamp->dist = d;
 
-               COLLADAFW::Light::LightType type = light->getLightType();
-               switch (type) {
+               switch (light->getLightType()) {
                        case COLLADAFW::Light::AMBIENT_LIGHT:
                        {
-                               /* TODO Fix */
-                               // lamp->type = LA_HEMI;
+                               lamp->type = LA_SUN; //TODO needs more thoughts
                        }
                        break;
                        case COLLADAFW::Light::SPOT_LIGHT:
@@ -1251,7 +1131,7 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light)
 // this function is called only for animations that pass COLLADAFW::validate
 bool DocumentImporter::writeAnimation(const COLLADAFW::Animation *anim)
 {
-       if (mImportStage != General)
+       if (mImportStage == Fetching_Controller_data)
                return true;
 
        // return true;
@@ -1261,7 +1141,7 @@ bool DocumentImporter::writeAnimation(const COLLADAFW::Animation *anim)
 // called on post-process stage after writeVisualScenes
 bool DocumentImporter::writeAnimationList(const COLLADAFW::AnimationList *animationList)
 {
-       if (mImportStage != General)
+       if (mImportStage == Fetching_Controller_data)
                return true;
 
        // return true;
@@ -1278,7 +1158,7 @@ bool DocumentImporter::writeSkinControllerData(const COLLADAFW::SkinControllerDa
 // this is called on postprocess, before writeVisualScenes
 bool DocumentImporter::writeController(const COLLADAFW::Controller *controller)
 {
-       if (mImportStage != General)
+       if (mImportStage == Fetching_Controller_data)
                return true;
 
        return armature_importer.write_controller(controller);
index d726cd55c1cdcf97d4469db65046c7ba9850e7d5..26ded417aa66545ce985cf205efec6642e083aca 100644 (file)
@@ -59,8 +59,8 @@ class DocumentImporter : COLLADAFW::IWriter
 public:
        //! Enumeration to denote the stage of import
        enum ImportStage {
-               General,                //!< First pass to collect all data except controller
-               Controller,             //!< Second pass to collect controller data
+               Fetching_Scene_data, /* First pass to collect all data except controller */
+               Fetching_Controller_data, /* Second pass to collect controller data */
        };
        /** Constructor */
        DocumentImporter(bContext *C, const ImportSettings *import_settings);
@@ -155,7 +155,7 @@ private:
        /** Tags map of unique id as a string and ExtraTags instance. */
        TagsMap uid_tags_map;
 
-       std::map<COLLADAFW::UniqueId, Image*> uid_image_map;
+       UidImageMap uid_image_map;
        std::map<COLLADAFW::UniqueId, Material*> uid_material_map;
        std::map<COLLADAFW::UniqueId, Material*> uid_effect_map;
        std::map<COLLADAFW::UniqueId, Camera*> uid_camera_map;
@@ -172,6 +172,7 @@ private:
        std::string import_from_version;
 
        void report_unknown_reference(const COLLADAFW::Node &node, const std::string object_type);
+
 };
 
 #endif
index 271dab5deea5b58fa947e096437a6146877ea2e0..5c702304e27db452ca34ae5e6eaf433d71af3031 100644 (file)
@@ -49,7 +49,6 @@ extern "C" {
        #include "BKE_material.h"
 }
 
-// OB_MESH is assumed
 static std::string getActiveUVLayerName(Object *ob)
 {
        Mesh *me = (Mesh *)ob->data;
@@ -61,8 +60,12 @@ static std::string getActiveUVLayerName(Object *ob)
        return "";
 }
 
-EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryEffects(sw), export_settings(export_settings) {
-}
+EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings, KeyImageMap &key_image_map) :
+       COLLADASW::LibraryEffects(sw),
+       export_settings(export_settings),
+       key_image_map(key_image_map)
+{}
+
 
 bool EffectsExporter::hasEffects(Scene *sce)
 {
@@ -82,9 +85,10 @@ bool EffectsExporter::hasEffects(Scene *sce)
        return false;
 }
 
-void EffectsExporter::exportEffects(Scene *sce)
+void EffectsExporter::exportEffects(bContext *C, Scene *sce)
 {
        if (hasEffects(sce)) {
+               this->mContext = C;
                this->scene = sce;
                openLibrary();
                MaterialFunctor mf;
@@ -94,61 +98,105 @@ void EffectsExporter::exportEffects(Scene *sce)
        }
 }
 
-void EffectsExporter::writeLambert(COLLADASW::EffectProfile &ep, Material *ma)
+void EffectsExporter::set_shader_type(COLLADASW::EffectProfile &ep, Material *ma)
 {
-       COLLADASW::ColorOrTexture cot;
-       ep.setShaderType(COLLADASW::EffectProfile::LAMBERT);
+       ep.setShaderType(COLLADASW::EffectProfile::LAMBERT); //XXX check if BLINN and PHONG can be supported as well
 }
 
-void EffectsExporter::operator()(Material *ma, Object *ob)
+void EffectsExporter::set_transparency(COLLADASW::EffectProfile &ep, Material *ma)
 {
-       // TODO: add back texture and extended material parameter support
+       if (ma->alpha == 1.0f) {
+               return; // have no transparency
+       }
 
-       openEffect(translate_id(id_name(ma)) + "-effect");
+       // Tod: because we are in A_ONE mode transparency is calculated like this:
+       COLLADASW::ColorOrTexture cot = getcol(1.0f, 1.0f, 1.0f, ma->alpha);
+       ep.setTransparent(cot);
+       ep.setOpaque(COLLADASW::EffectProfile::A_ONE);
+}
+void EffectsExporter::set_diffuse_color(COLLADASW::EffectProfile &ep, Material *ma)
+{
+       // get diffuse color
+       COLLADASW::ColorOrTexture cot = bc_get_base_color(ma);
+       ep.setDiffuse(cot, false, "diffuse");
+}
 
-       COLLADASW::EffectProfile ep(mSW);
-       ep.setProfileType(COLLADASW::EffectProfile::COMMON);
-       ep.openProfile();
-       writeLambert(ep, ma);
+void EffectsExporter::set_specular_color(COLLADASW::EffectProfile &ep, Material *ma)
+{
+       bool use_fallback = ep.getShaderType() != COLLADASW::EffectProfile::LAMBERT;
+       COLLADASW::ColorOrTexture cot = bc_get_specular_color(ma, use_fallback);
+       ep.setSpecular(cot, false, "specular");
+}
 
-       COLLADASW::ColorOrTexture cot;
+void EffectsExporter::set_emission(COLLADASW::EffectProfile &ep, Material *ma)
+{
+       // not yet supported (needs changes in principled shader
+}
 
-       // transparency
-       if (ma->alpha != 1.0f) {
-               // Tod: because we are in A_ONE mode transparency is calculated like this:
-               cot = getcol(1.0f, 1.0f, 1.0f, ma->alpha);
-               ep.setTransparent(cot);
-               ep.setOpaque(COLLADASW::EffectProfile::A_ONE);
+void EffectsExporter::get_images(Material *ma, KeyImageMap &material_image_map)
+{
+       if (!ma->use_nodes) {
+               return;
        }
 
-       // emission
-#if 0
-       cot = getcol(ma->emit, ma->emit, ma->emit, 1.0f);
-#endif
+       MaterialNode material = MaterialNode(mContext, ma, key_image_map);
+       Image *image = material.get_diffuse_image();
+       if (image == nullptr) {
+               return;
+       }
 
-       // diffuse
-       cot = getcol(ma->r, ma->g, ma->b, 1.0f);
-       ep.setDiffuse(cot, false, "diffuse");
+       std::string uid(id_name(image));
+       std::string key = translate_id(uid);
 
-       // specular
-       if (ep.getShaderType() != COLLADASW::EffectProfile::LAMBERT) {
-               cot = getcol(ma->specr * ma->spec, ma->specg * ma->spec, ma->specb * ma->spec, 1.0f);
-               ep.setSpecular(cot, false, "specular");
+       if (material_image_map.find(key) == material_image_map.end()) {
+               material_image_map[key] = image;
+               key_image_map[key] = image;
        }
+}
 
-       // XXX make this more readable if possible
+void EffectsExporter::create_image_samplers(COLLADASW::EffectProfile &ep, KeyImageMap &material_image_map, std::string &active_uv)
+{
+       KeyImageMap::iterator iter;
 
-#if 0
-       // create <sampler> and <surface> for each image
-       COLLADASW::Sampler samplers[MAX_MTEX];
-       //COLLADASW::Surface surfaces[MAX_MTEX];
-       //void *samp_surf[MAX_MTEX][2];
-       void *samp_surf[MAX_MTEX];
+       for (iter = material_image_map.begin(); iter != material_image_map.end(); iter++) {
 
-       // image to index to samp_surf map
-       // samp_surf[index] stores 2 pointers, sampler and surface
-       std::map<std::string, int> im_samp_map;
+               Image *image = iter->second;
+               std::string uid(id_name(image));
+               std::string key = translate_id(uid);
 
+               COLLADASW::Sampler *sampler = new COLLADASW::Sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D,
+                       key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
+                       key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
+
+               sampler->setImageId(key);
+
+               ep.setDiffuse(createTexture(image, active_uv, sampler), false, "diffuse");
+       }
+}
+
+void EffectsExporter::operator()(Material *ma, Object *ob)
+{
+       KeyImageMap material_image_map;
+
+       openEffect(get_effect_id(ma));
+
+       COLLADASW::EffectProfile ep(mSW);
+       ep.setProfileType(COLLADASW::EffectProfile::COMMON);
+       ep.openProfile();
+       set_shader_type(ep, ma);
+
+       COLLADASW::ColorOrTexture cot;
+
+       set_transparency(ep, ma);
+       set_diffuse_color(ep, ma);
+       set_specular_color(ep, ma);
+       set_emission(ep, ma);
+
+       get_images(ma, material_image_map);
+       std::string active_uv(getActiveUVLayerName(ob));
+       create_image_samplers(ep, material_image_map, active_uv);
+
+#if 0
        unsigned int a, b;
        for (a = 0, b = 0; a < tex_indices.size(); a++) {
                MTex *t = ma->mtex[tex_indices[a]];
@@ -162,24 +210,13 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
 
                // create only one <sampler>/<surface> pair for each unique image
                if (im_samp_map.find(key) == im_samp_map.end()) {
-                       // //<newparam> <surface> <init_from>
-                       // COLLADASW::Surface surface(COLLADASW::Surface::SURFACE_TYPE_2D,
-                       //                         key + COLLADASW::Surface::SURFACE_SID_SUFFIX);
-                       // COLLADASW::SurfaceInitOption sio(COLLADASW::SurfaceInitOption::INIT_FROM);
-                       // sio.setImageReference(key);
-                       // surface.setInitOption(sio);
-
-                       // COLLADASW::NewParamSurface surface(mSW);
-                       // surface->setParamType(COLLADASW::CSW_SURFACE_TYPE_2D);
-
                        //<newparam> <sampler> <source>
                        COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D,
-                                                  key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
-                                                  key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
+                               key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
+                               key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
                        sampler.setImageId(key);
                        // copy values to arrays since they will live longer
                        samplers[a] = sampler;
-                       //surfaces[a] = surface;
 
                        // store pointers so they can be used later when we create <texture>s
                        samp_surf[b] = &samplers[a];
@@ -189,15 +226,7 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
                        b++;
                }
        }
-#endif
 
-       // used as fallback when MTex->uvname is "" (this is pretty common)
-       // it is indeed the correct value to use in that case
-       std::string active_uv(getActiveUVLayerName(ob));
-
-       // write textures
-       // XXX very slow
-#if 0
        for (a = 0; a < tex_indices.size(); a++) {
                MTex *t = ma->mtex[tex_indices[a]];
                Image *ima = t->tex->ima;
@@ -210,7 +239,7 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
                key = translate_id(key);
                int i = im_samp_map[key];
                std::string uvname = strlen(t->uvname) ? t->uvname : active_uv;
-               COLLADASW::Sampler *sampler = (COLLADASW::Sampler *)samp_surf[i];
+               COLLADASW::Sampler *sampler = (COLLADASW::Sampler *)samp_surf[i]; // possibly uninitialised memory ...
                writeTextures(ep, key, sampler, t, ima, uvname);
        }
 #endif
index a1395bfde9f1319768cfcadf5c9825a5019bde61..462f1548586d4c71f73dfd6422e909cbf317c747 100644 (file)
 #include "DNA_scene_types.h"
 
 #include "ExportSettings.h"
+#include "collada_utils.h"
 
 class EffectsExporter: COLLADASW::LibraryEffects
 {
 public:
-       EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
-       void exportEffects(Scene *sce);
+       EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings, KeyImageMap &key_image_map);
+       void exportEffects(bContext *C, Scene *sce);
 
        void operator()(Material *ma, Object *ob);
 
@@ -58,7 +59,14 @@ public:
 
        COLLADASW::ColorOrTexture getcol(float r, float g, float b, float a);
 private:
-       void writeLambert(COLLADASW::EffectProfile &ep, Material *ma);
+       void set_shader_type(COLLADASW::EffectProfile &ep, Material *ma);
+       void set_transparency(COLLADASW::EffectProfile &ep, Material *ma);
+       void set_diffuse_color(COLLADASW::EffectProfile &ep, Material *ma);
+       void set_specular_color(COLLADASW::EffectProfile &ep, Material *ma);
+       void set_emission(COLLADASW::EffectProfile &ep, Material *ma);
+       void get_images(Material *ma, KeyImageMap &uid_image_map);
+       void create_image_samplers(COLLADASW::EffectProfile &ep, KeyImageMap &uid_image_map, std::string &active_uv);
+
        void writeTextures(COLLADASW::EffectProfile &ep,
                        std::string &key,
                        COLLADASW::Sampler *sampler,
@@ -68,8 +76,9 @@ private:
        bool hasEffects(Scene *sce);
 
        const ExportSettings *export_settings;
-
+       KeyImageMap &key_image_map;
        Scene *scene;
+       bContext *mContext;
 };
 
 #endif
index caa739006322d6a85a61567b2993f1c48ff4d472..d567127879c43f7df7b8e75cab560bd94c42ef0b 100644 (file)
@@ -49,47 +49,66 @@ ErrorHandler::~ErrorHandler()
 //--------------------------------------------------------------------
 bool ErrorHandler::handleError(const COLLADASaxFWL::IError *error)
 {
-       /* This method must return true when Collada should continue.
+       /* This method must return false when Collada should continue.
         * See https://github.com/KhronosGroup/OpenCOLLADA/issues/442
         */
-       bool isWarning = false;
+       bool isError = true;
+       std::string error_context;
+       std::string error_message;
 
        if (error->getErrorClass() == COLLADASaxFWL::IError::ERROR_SAXPARSER) {
+               error_context = "Schema validation";
+
                COLLADASaxFWL::SaxParserError *saxParserError = (COLLADASaxFWL::SaxParserError *) error;
                const GeneratedSaxParser::ParserError& parserError = saxParserError->getError();
+               error_message = parserError.getErrorMessage();
 
-               // Workaround to avoid wrong error
                if (parserError.getErrorType() == GeneratedSaxParser::ParserError::ERROR_VALIDATION_MIN_OCCURS_UNMATCHED) {
                        if (STREQ(parserError.getElement(), "effect")) {
-                               isWarning = true;
+                               isError = false;
                        }
                }
-               if (parserError.getErrorType() == GeneratedSaxParser::ParserError::ERROR_VALIDATION_SEQUENCE_PREVIOUS_SIBLING_NOT_PRESENT) {
+
+               else if (parserError.getErrorType() == GeneratedSaxParser::ParserError::ERROR_VALIDATION_SEQUENCE_PREVIOUS_SIBLING_NOT_PRESENT) {
                        if (!(STREQ(parserError.getElement(), "extra") &&
                              STREQ(parserError.getAdditionalText().c_str(), "sibling: fx_profile_abstract")))
                        {
-                               isWarning = true;
+                               isError = false;
                        }
                }
 
-               if (parserError.getErrorType() == GeneratedSaxParser::ParserError::ERROR_COULD_NOT_OPEN_FILE) {
-                       std::cout << "Couldn't open file" << std::endl;
+               else if (parserError.getErrorType() == GeneratedSaxParser::ParserError::ERROR_COULD_NOT_OPEN_FILE) {
+                       isError = true;
+                       error_context = "File access";
                }
 
-               std::cout << "Schema validation error: " << parserError.getErrorMessage() << std::endl;
+               else isError = (parserError.getSeverity() != COLLADASaxFWL::IError::SEVERITY_ERROR_NONCRITICAL);
        }
        else if (error->getErrorClass() == COLLADASaxFWL::IError::ERROR_SAXFWL) {
+               error_context = "Sax FWL";
                COLLADASaxFWL::SaxFWLError *saxFWLError = (COLLADASaxFWL::SaxFWLError *) error;
+               error_message = saxFWLError->getErrorMessage();
+
                /*
                 * Accept non critical errors as warnings (i.e. texture not found)
                 * This makes the importer more graceful, so it now imports what makes sense.
                 */
-               isWarning = (saxFWLError->getSeverity() == COLLADASaxFWL::IError::SEVERITY_ERROR_NONCRITICAL);
-               std::cout << "Sax FWL Error: " << saxFWLError->getErrorMessage() << std::endl;
+
+               isError = (saxFWLError->getSeverity() != COLLADASaxFWL::IError::SEVERITY_ERROR_NONCRITICAL);
+               
        }
        else {
-               std::cout << "opencollada error: " << error->getFullErrorMessage() << std::endl;
+               error_context = "OpenCollada";
+               error_message = error->getFullErrorMessage();
+               isError = true;
        }
 
-       return isWarning;
+       std::string severity = (isError) ? "Error" : "Warning";
+       std::cout << error_context << " (" << severity << "): " << error_message << std::endl;
+       if (isError) {
+               std::cout << "The Collada import has been forced to stop." << std::endl;
+               std::cout << "Please fix the reported error and then try again.";
+               mError = true;
+       }
+       return isError;
 }
index b6a7c1f1b4e829e925cae95a420fca25f0f3c667..3b4397a6093191a7ccf9d057d78d8de3cd947912 100644 (file)
@@ -44,6 +44,19 @@ typedef enum BC_export_transformation_type {
 } BC_export_transformation_type;
 
 
+typedef enum BC_export_animation_type {
+       BC_ANIMATION_EXPORT_SAMPLES,
+       BC_ANIMATION_EXPORT_KEYS
+} BC_export_animation_type;
+
+typedef enum BC_ui_export_section {
+       BC_UI_SECTION_MAIN,
+       BC_UI_SECTION_GEOMETRY,
+       BC_UI_SECTION_ARMATURE,
+       BC_UI_SECTION_ANIMATION,
+       BC_UI_SECTION_COLLADA
+} BC_ui_export_section;
+
 typedef struct ExportSettings {
        bool apply_modifiers;
        BC_export_mesh_type export_mesh_type;
@@ -54,10 +67,13 @@ typedef struct ExportSettings {
        bool include_shapekeys;
        bool deform_bones_only;
        bool include_animations;
+       bool include_all_actions;
        int sampling_rate;
+       bool keep_smooth_curves;
+       bool keep_keyframes;
 
        bool active_uv_only;
-       bool include_material_textures;
+       BC_export_animation_type export_animation_type;
        bool use_texture_copies;
 
        bool triangulate;
index 928509cbef954d65c733e7bb3b791bdd3c3bd66c..f4ea82044a3f1107bcf460ceb52fb0dcd2fb3c0a 100644 (file)
@@ -51,17 +51,17 @@ extern "C" {
 #include "collada_utils.h"
 
 // TODO: optimize UV sets by making indexed list with duplicates removed
-GeometryExporter::GeometryExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryGeometries(sw), export_settings(export_settings)
+GeometryExporter::GeometryExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : 
+       blender_context(blender_context),
+       COLLADASW::LibraryGeometries(sw), export_settings(export_settings)
 {
 }
 
-void GeometryExporter::exportGeom(Main *bmain, struct Depsgraph *depsgraph, Scene *sce)
+void GeometryExporter::exportGeom()
 {
+       Scene *sce = blender_context.get_scene();
        openLibrary();
 
-       mDepsgraph = depsgraph;
-       m_bmain = bmain;
-       mScene = sce;
        GeometryFunctor gf;
        gf.forEachMeshObjectInExportSet<GeometryExporter>(sce, *this, this->export_settings->export_set);
 
@@ -72,8 +72,7 @@ void GeometryExporter::operator()(Object *ob)
 {
        bool use_instantiation = this->export_settings->use_object_instantiation;
        Mesh *me = bc_get_mesh_copy(
-                                       mDepsgraph,
-                                       mScene,
+                                       blender_context,
                                        ob,
                                        this->export_settings->export_mesh_type,
                                        this->export_settings->apply_modifiers,
@@ -91,6 +90,7 @@ void GeometryExporter::operator()(Object *ob)
        }
 
        std::string geom_name = (use_instantiation) ? id_name(ob->data) : id_name(ob);
+       geom_name = encode_xml(geom_name);
 
        exportedGeometry.insert(geom_id);
 
index e47b3f4eee81795418a69c0e7681d3bd32a43810..a48319d778c173208b0f4c646cb3b02ded8d6517 100644 (file)
@@ -43,7 +43,7 @@
 
 #include "ExportSettings.h"
 #include "collada_utils.h"
-
+#include "BlenderContext.h"
 #include "BKE_key.h"
 
 struct Depsgraph;
@@ -74,14 +74,10 @@ class GeometryExporter : COLLADASW::LibraryGeometries
 
        Normal n;
 
-       struct Depsgraph *mDepsgraph;
-       Main *m_bmain;
-       Scene *mScene;
-
 public:
-       GeometryExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
+       GeometryExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
 
-       void exportGeom(Main *bmain, Depsgraph *depsgraph, Scene *sce);
+       void exportGeom();
 
        void operator()(Object *ob);
 
@@ -125,7 +121,7 @@ public:
 
 private:
        std::set<std::string> exportedGeometry;
-
+       BlenderContext &blender_context;
        const ExportSettings *export_settings;
 
        Mesh *get_mesh(Scene *sce, Object *ob, int apply_modifiers);
index c2666f591b5811414b12cd4ed9517fc0d0f84488..d7ab16f81e7fdbb3441d249ae0b0f69aba22c63a 100644 (file)
@@ -51,7 +51,10 @@ extern "C" {
 #include "MaterialExporter.h"
 
 
-ImagesExporter::ImagesExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryImages(sw), export_settings(export_settings)
+ImagesExporter::ImagesExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings, KeyImageMap &key_image_map) :
+       COLLADASW::LibraryImages(sw),
+       export_settings(export_settings),
+       key_image_map(key_image_map)
 {
 }
 
@@ -59,135 +62,110 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies)
 {
        std::string name(id_name(image));
        std::string translated_name(translate_id(name));
-       bool not_yet_exported = find(mImages.begin(), mImages.end(), translated_name) == mImages.end();
 
-       if (not_yet_exported) {
-
-               ImBuf *imbuf       = BKE_image_acquire_ibuf(image, NULL, NULL);
-               if (!imbuf) {
-                       fprintf(stderr, "Collada export: image does not exist:\n%s\n", image->name);
-                       return;
-               }
+       ImBuf *imbuf       = BKE_image_acquire_ibuf(image, NULL, NULL);
+       if (!imbuf) {
+               fprintf(stderr, "Collada export: image does not exist:\n%s\n", image->name);
+               return;
+       }
 
-               bool  is_dirty     = (imbuf->userflags & IB_BITMAPDIRTY) != 0;
+       bool  is_dirty     = (imbuf->userflags & IB_BITMAPDIRTY) != 0;
 
-               ImageFormatData imageFormat;
-               BKE_imbuf_to_image_format(&imageFormat, imbuf);
+       ImageFormatData imageFormat;
+       BKE_imbuf_to_image_format(&imageFormat, imbuf);
 
-               short image_source = image->source;
-               bool  is_generated = image_source == IMA_SRC_GENERATED;
-               bool  is_packed    = BKE_image_has_packedfile(image);
+       short image_source = image->source;
+       bool  is_generated = image_source == IMA_SRC_GENERATED;
+       bool  is_packed    = BKE_image_has_packedfile(image);
 
-               char export_path[FILE_MAX];
-               char source_path[FILE_MAX];
-               char export_dir[FILE_MAX];
-               char export_file[FILE_MAX];
+       char export_path[FILE_MAX];
+       char source_path[FILE_MAX];
+       char export_dir[FILE_MAX];
+       char export_file[FILE_MAX];
 
-               // Destination folder for exported assets
-               BLI_split_dir_part(this->export_settings->filepath, export_dir, sizeof(export_dir));
+       // Destination folder for exported assets
+       BLI_split_dir_part(this->export_settings->filepath, export_dir, sizeof(export_dir));
 
-               if (is_generated || is_dirty || use_copies || is_packed) {
+       if (is_generated || is_dirty || use_copies || is_packed) {
 
-                       // make absolute destination path
+               // make absolute destination path
 
-                       BLI_strncpy(export_file, name.c_str(), sizeof(export_file));
-                       BKE_image_path_ensure_ext_from_imformat(export_file, &imageFormat);
+               BLI_strncpy(export_file, name.c_str(), sizeof(export_file));
+               BKE_image_path_ensure_ext_from_imformat(export_file, &imageFormat);
 
-                       BLI_join_dirfile(export_path, sizeof(export_path), export_dir, export_file);
+               BLI_join_dirfile(export_path, sizeof(export_path), export_dir, export_file);
 
-                       // make dest directory if it doesn't exist
-                       BLI_make_existing_file(export_path);
-               }
+               // make dest directory if it doesn't exist
+               BLI_make_existing_file(export_path);
+       }
 
-               if (is_generated || is_dirty || is_packed) {
+       if (is_generated || is_dirty || is_packed) {
 
-                       // This image in its current state only exists in Blender memory.
-                       // So we have to export it. The export will keep the image state intact,
-                       // so the exported file will not be associated with the image.
+               // This image in its current state only exists in Blender memory.
+               // So we have to export it. The export will keep the image state intact,
+               // so the exported file will not be associated with the image.
 
-                       if (BKE_imbuf_write_as(imbuf, export_path, &imageFormat, true) == 0) {
-                               fprintf(stderr, "Collada export: Cannot export image to:\n%s\n", export_path);
-                               return;
-                       }
-                       BLI_strncpy(export_path, export_file, sizeof(export_path));
+               if (BKE_imbuf_write_as(imbuf, export_path, &imageFormat, true) == 0) {
+                       fprintf(stderr, "Collada export: Cannot export image to:\n%s\n", export_path);
+                       return;
                }
-               else {
+               BLI_strncpy(export_path, export_file, sizeof(export_path));
+       }
+       else {
 
-                       // make absolute source path
-                       BLI_strncpy(source_path, image->name, sizeof(source_path));
-                       BLI_path_abs(source_path, BKE_main_blendfile_path_from_global());
-                       BLI_cleanup_path(NULL, source_path);
+               // make absolute source path
+               BLI_strncpy(source_path, image->name, sizeof(source_path));
+               BLI_path_abs(source_path, BKE_main_blendfile_path_from_global());
+               BLI_cleanup_path(NULL, source_path);
 
-                       if (use_copies) {
+               if (use_copies) {
 
-                               // This image is already located on the file system.
-                               // But we want to create copies here.
-                               // To move images into the same export directory.
-                               // Note: If an image is already located in the export folder,
-                               // then skip the copy (as it would result in a file copy error).
+                       // This image is already located on the file system.
+                       // But we want to create copies here.
+                       // To move images into the same export directory.
+                       // Note: If an image is already located in the export folder,
+                       // then skip the copy (as it would result in a file copy error).
 
-                               if (BLI_path_cmp(source_path, export_path) != 0) {
-                                       if (BLI_copy(source_path, export_path) != 0) {
-                                               fprintf(stderr, "Collada export: Cannot copy image:\n source:%s\ndest :%s\n", source_path, export_path);
-                                               return;
-                                       }
+                       if (BLI_path_cmp(source_path, export_path) != 0) {
+                               if (BLI_copy(source_path, export_path) != 0) {
+                                       fprintf(stderr, "Collada export: Cannot copy image:\n source:%s\ndest :%s\n", source_path, export_path);
+                                       return;
                                }
-
-                               BLI_strncpy(export_path, export_file, sizeof(export_path));
-
                        }
-                       else {
 
-                               // Do not make any copies, but use the source path directly as reference
-                               // to the original image
+                       BLI_strncpy(export_path, export_file, sizeof(export_path));
 
-                               BLI_strncpy(export_path, source_path, sizeof(export_path));
-                       }
                }
+               else {
 
-               COLLADASW::Image img(COLLADABU::URI(COLLADABU::URI::nativePathToUri(export_path)), translated_name, translated_name); /* set name also to mNameNC. This helps other viewers import files exported from Blender better */
-               img.add(mSW);
-               fprintf(stdout, "Collada export: Added image: %s\n", export_file);
-               mImages.push_back(translated_name);
+                       // Do not make any copies, but use the source path directly as reference
+                       // to the original image
 
-               BKE_image_release_ibuf(image, imbuf, NULL);
+                       BLI_strncpy(export_path, source_path, sizeof(export_path));
+               }
        }
-}
-
-bool ImagesExporter::hasImages(Scene *sce)
-{
-       LinkNode *node;
-
-       for (node = this->export_settings->export_set; node; node = node->next) {
-               Object *ob = (Object *)node->link;
 
-               for (int a = 0; a < ob->totcol; a++) {
-                       Material *ma = give_current_material(ob, a + 1);
+       COLLADASW::Image img(COLLADABU::URI(COLLADABU::URI::nativePathToUri(export_path)), translated_name, translated_name); /* set name also to mNameNC. This helps other viewers import files exported from Blender better */
+       img.add(mSW);
+       fprintf(stdout, "Collada export: Added image: %s\n", export_file);
 
-                       // no material, but check all of the slots
-                       if (!ma) continue;
-                       // TODO: find image textures in shader nodes
-               }
-       }
-       return false;
+       BKE_image_release_ibuf(image, imbuf, NULL);
 }
 
 void ImagesExporter::exportImages(Scene *sce)
 {
+       bool use_texture_copies = this->export_settings->use_texture_copies;
        openLibrary();
 
-       MaterialFunctor mf;
-       if (this->export_settings->include_material_textures) {
-               mf.forEachMaterialInExportSet<ImagesExporter>(sce, *this, this->export_settings->export_set);
-       }
-
-       closeLibrary();
-}
+       KeyImageMap::iterator iter;
+       for (iter = key_image_map.begin(); iter != key_image_map.end(); iter++) {
 
+               Image *image = iter->second;
+               std::string uid(id_name(image));
+               std::string key = translate_id(uid);
 
+               export_UV_Image(image, use_texture_copies);
+       }
 
-void ImagesExporter::operator()(Material *ma, Object *ob)
-{
-       // bool use_texture_copies = this->export_settings->use_texture_copies;
-       // TODO call export_UV_Image for every image in shader nodes
+       closeLibrary();
 }
index 1867c44ac9c4cfd7be195735f697c71347e4845e..7ce312a52b19865a1fba7c90314a65e6b89c47c2 100644 (file)
 #include "DNA_scene_types.h"
 
 #include "ExportSettings.h"
+#include "collada_utils.h"
 
 class ImagesExporter: COLLADASW::LibraryImages
 {
 public:
-       ImagesExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
-
+       ImagesExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings, KeyImageMap &key_image_map);
        void exportImages(Scene *sce);
-       void operator()(Material *ma, Object *ob);
-private:
-       std::vector<std::string> mImages; // contains list of written images, to avoid duplicates
 
-       void export_UV_Image(Image *image, bool use_texture_copies);
-       bool hasImages(Scene *sce);
+private:
        const ExportSettings *export_settings;
+       KeyImageMap &key_image_map;
+       void export_UV_Image(Image *image, bool use_texture_copies);
+
 };
 
 #endif
index 53fcbd1bb1a36c500861e39dd38cd85c39479eda..b1f805bfb878489d6b7018fc6432fcbe561cff3f 100644 (file)
@@ -89,15 +89,7 @@ void LightsExporter::operator()(Object *ob)
                exportBlenderProfile(cla, la);
                addLight(cla);
        }
-       // hemi
-       /* Hemi were removed from 2.8 */
-       // else if (la->type == LA_HEMI) {
-       //      COLLADASW::AmbientLight cla(mSW, la_id, la_name);
-       //      cla.setColor(col, false, "color");
-       //      cla.setConstantAttenuation(constatt);
-       //      exportBlenderProfile(cla, la);
-       //      addLight(cla);
-       // }
+
        // spot
        else if (la->type == LA_SPOT) {
                COLLADASW::SpotLight cla(mSW, la_id, la_name);
index 4aece997f72d6ef1962de215a4d788a18a2855de..2fa71817ac8c7057670d61f461a809bd8d9b53f4 100644 (file)
@@ -68,12 +68,12 @@ bool MaterialsExporter::hasMaterials(Scene *sce)
 
 void MaterialsExporter::operator()(Material *ma, Object *ob)
 {
-       std::string name(id_name(ma));
+       std::string mat_name = encode_xml(id_name(ma));
+       std::string mat_id = get_material_id(ma);
+       std::string eff_id = get_effect_id(ma);
 
-       openMaterial(get_material_id(ma), translate_id(name));
-
-       std::string efid = translate_id(name) + "-effect";
-       addInstanceEffect(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, efid));
+       openMaterial(mat_id, mat_name);
+       addInstanceEffect(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, eff_id));
 
        closeMaterial();
 }
index e830a433432cc5fe1f5f363c6892c63f850b2f44..3fef70254174c8697558e1986ba702a6c554fc1a 100644 (file)
@@ -44,6 +44,7 @@ extern "C" {
 #include "GeometryExporter.h"
 #include "collada_internal.h"
 #include "ExportSettings.h"
+#include "materials.h"
 
 class MaterialsExporter: COLLADASW::LibraryMaterials
 {
diff --git a/source/blender/collada/Materials.cpp b/source/blender/collada/Materials.cpp
new file mode 100644 (file)
index 0000000..de0405d
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* Contributor(s): Gaia Clary.
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+#include "Materials.h"
+
+MaterialNode::MaterialNode(bContext *C, Material *ma, KeyImageMap &key_image_map) :
+       mContext(C),
+       effect(nullptr),
+       material(ma),
+       key_image_map(&key_image_map)
+{
+       ntree = prepare_material_nodetree();
+       setShaderType();
+}
+
+MaterialNode::MaterialNode(bContext *C, COLLADAFW::EffectCommon *ef, Material *ma, UidImageMap &uid_image_map) :
+       mContext(C),
+       effect(ef),
+       material(ma),
+       uid_image_map(&uid_image_map)
+{
+       ntree = prepare_material_nodetree();
+       setShaderType();
+
+       std::map<std::string, bNode *> nmap;
+#if 0
+       nmap["main"] = add_node(C, ntree, SH_NODE_BSDF_PRINCIPLED, -300, 300);
+       nmap["emission"] = add_node(C, ntree, SH_NODE_EMISSION, -300, 500, "emission");
+       nmap["add"] = add_node(C, ntree, SH_NODE_ADD_SHADER, 100, 400);
+       nmap["transparent"] = add_node(C, ntree, SH_NODE_BSDF_TRANSPARENT, 100, 200);
+       nmap["mix"] = add_node(C, ntree, SH_NODE_MIX_SHADER, 400, 300, "transparency");
+       nmap["out"] = add_node(C, ntree, SH_NODE_OUTPUT_MATERIAL, 600, 300);
+       nmap["out"]->flag &= ~NODE_SELECT;
+
+       add_link(ntree, nmap["emission"], 0, nmap["add"], 0);
+       add_link(ntree, nmap["main"], 0, nmap["add"], 1);
+       add_link(ntree, nmap["add"], 0, nmap["mix"], 1);
+       add_link(ntree, nmap["transparent"], 0, nmap["mix"], 2);
+
+       add_link(ntree, nmap["mix"], 0, nmap["out"], 0);
+       // experimental, probably not used.
+       make_group(C, ntree, nmap);
+#else
+       shader_node = add_node(SH_NODE_BSDF_PRINCIPLED, 0, 300, "");
+       output_node = add_node(SH_NODE_OUTPUT_MATERIAL, 300, 300, "");
+       add_link(shader_node, 0, output_node, 0);
+#endif
+}
+
+void MaterialNode::setShaderType()
+{
+#if 0
+       COLLADAFW::EffectCommon::ShaderType shader = ef->getShaderType();
+       // Currently we only support PBR based shaders
+       // TODO: simulate the effects with PBR
+
+       // blinn
+       if (shader == COLLADAFW::EffectCommon::SHADER_BLINN) {
+               ma->spec_shader = MA_SPEC_BLINN;
+               ma->spec = ef->getShininess().getFloatValue();
+       }
+       // phong
+       else if (shader == COLLADAFW::EffectCommon::SHADER_PHONG) {
+               ma->spec_shader = MA_SPEC_PHONG;
+               ma->har = ef->getShininess().getFloatValue();
+       }
+       // lambert
+       else if (shader == COLLADAFW::EffectCommon::SHADER_LAMBERT) {
+               ma->diff_shader = MA_DIFF_LAMBERT;
+       }
+       // default - lambert
+       else {
+               ma->diff_shader = MA_DIFF_LAMBERT;
+               fprintf(stderr, "Current shader type is not supported, default to lambert.\n");
+       }
+#endif
+}
+
+bNodeTree *MaterialNode::prepare_material_nodetree()
+{
+       if (material->nodetree == NULL) {
+               material->nodetree = ntreeAddTree(NULL, "Shader Nodetree", "ShaderNodeTree");
+               material->use_nodes = true;