Incompatible usage of the Collada transparency value
[blender.git] / source / blender / collada / AnimationExporter.cpp
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16
17 /** \file
18  * \ingroup collada
19  */
20
21 #include "GeometryExporter.h"
22 #include "AnimationExporter.h"
23 #include "AnimationClipExporter.h"
24 #include "BCAnimationSampler.h"
25 #include "MaterialExporter.h"
26 #include "collada_utils.h"
27
28 std::string EMPTY_STRING;
29
30 std::string AnimationExporter::get_axis_name(std::string channel_type, int id)
31 {
32
33   static std::map<std::string, std::vector<std::string>> BC_COLLADA_AXIS_FROM_TYPE = {
34       {"color", {"R", "G", "B"}},
35       {"specular_color", {"R", "G", "B"}},
36       {"diffuse_color", {"R", "G", "B"}},
37       {"alpha", {"R", "G", "B"}},
38       {"scale", {"X", "Y", "Z"}},
39       {"location", {"X", "Y", "Z"}},
40       {"rotation_euler", {"X", "Y", "Z"}}};
41
42   std::map<std::string, std::vector<std::string>>::const_iterator it;
43
44   it = BC_COLLADA_AXIS_FROM_TYPE.find(channel_type);
45   if (it == BC_COLLADA_AXIS_FROM_TYPE.end()) {
46     return "";
47   }
48
49   const std::vector<std::string> &subchannel = it->second;
50   if (id >= subchannel.size()) {
51     return "";
52   }
53   return subchannel[id];
54 }
55
56 bool AnimationExporter::open_animation_container(bool has_container, Object *ob)
57 {
58   if (!has_container) {
59     char anim_id[200];
60     sprintf(anim_id, "action_container-%s", translate_id(id_name(ob)).c_str());
61     openAnimation(anim_id, encode_xml(id_name(ob)));
62   }
63   return true;
64 }
65
66 void AnimationExporter::openAnimationWithClip(std::string action_id, std::string action_name)
67 {
68   std::vector<std::string> anim_meta_entry;
69   anim_meta_entry.push_back(translate_id(action_id));
70   anim_meta_entry.push_back(action_name);
71   anim_meta.push_back(anim_meta_entry);
72
73   openAnimation(translate_id(action_id), action_name);
74 }
75
76 void AnimationExporter::close_animation_container(bool has_container)
77 {
78   if (has_container) {
79     closeAnimation();
80   }
81 }
82
83 bool AnimationExporter::exportAnimations()
84 {
85   Scene *sce = export_settings.get_scene();
86
87   LinkNode *export_set = this->export_settings.get_export_set();
88   bool has_anim_data = bc_has_animations(sce, export_set);
89   int animation_count = 0;
90   if (has_anim_data) {
91
92     BCObjectSet animated_subset;
93     BCAnimationSampler::get_animated_from_export_set(animated_subset, *export_set);
94     animation_count = animated_subset.size();
95     BCAnimationSampler animation_sampler(export_settings, animated_subset);
96
97     try {
98       animation_sampler.sample_scene(export_settings, /*keyframe_at_end = */ true);
99
100       openLibrary();
101
102       BCObjectSet::iterator it;
103       for (it = animated_subset.begin(); it != animated_subset.end(); ++it) {
104         Object *ob = *it;
105         exportAnimation(ob, animation_sampler);
106       }
107     }
108     catch (std::invalid_argument &iae) {
109       fprintf(stderr, "Animation export interrupted");
110       fprintf(stderr, "Exception was: %s", iae.what());
111     }
112
113     closeLibrary();
114
115 #if 0
116     /* TODO: If all actions shall be exported, we need to call the
117      * AnimationClipExporter which will figure out which actions
118      * need to be exported for which objects
119      */
120     if (this->export_settings->include_all_actions) {
121       AnimationClipExporter ace(eval_ctx, sw, export_settings, anim_meta);
122       ace.exportAnimationClips(sce);
123     }
124 #endif
125   }
126   return animation_count;
127 }
128
129 /* called for each exported object */
130 void AnimationExporter::exportAnimation(Object *ob, BCAnimationSampler &sampler)
131 {
132   bool container_is_open = false;
133
134   /* Transform animations (trans, rot, scale). */
135   container_is_open = open_animation_container(container_is_open, ob);
136
137   /* Now take care of the Object Animations
138    * Note: For Armatures the skeletal animation has already been exported (see above)
139    * However Armatures also can have Object animation.
140    */
141   bool export_as_matrix = this->export_settings.get_animation_transformation_type() ==
142                           BC_TRANSFORMATION_TYPE_MATRIX;
143
144   if (export_as_matrix) {
145     /* export all transform_curves as one single matrix animation */
146     export_matrix_animation(ob, sampler);
147   }
148
149   export_curve_animation_set(ob, sampler, export_as_matrix);
150
151   if (ob->type == OB_ARMATURE && export_as_matrix) {
152
153 #ifdef WITH_MORPH_ANIMATION
154     /* TODO: This needs to be handled by extra profiles, postponed for now */
155     export_morph_animation(ob);
156 #endif
157
158     /* Export skeletal animation (if any) */
159     bArmature *arm = (bArmature *)ob->data;
160     for (Bone *root_bone = (Bone *)arm->bonebase.first; root_bone; root_bone = root_bone->next) {
161       export_bone_animations_recursive(ob, root_bone, sampler);
162     }
163   }
164
165   close_animation_container(container_is_open);
166 }
167
168 /*
169  * Export all animation FCurves of an Object.
170  *
171  * Note: This uses the keyframes as sample points,
172  * and exports "baked keyframes" while keeping the tangent information
173  * of the FCurves intact. This works for simple cases, but breaks
174  * especially when negative scales are involved in the animation.
175  * And when parent inverse matrices are involved (when exporting
176  * object hierarchies)
177  */
178 void AnimationExporter::export_curve_animation_set(Object *ob,
179                                                    BCAnimationSampler &sampler,
180                                                    bool export_as_matrix)
181 {
182   BCAnimationCurveMap *curves = sampler.get_curves(ob);
183   bool keep_flat_curves = this->export_settings.get_keep_flat_curves();
184
185   BCAnimationCurveMap::iterator it;
186   for (it = curves->begin(); it != curves->end(); ++it) {
187     BCAnimationCurve &curve = *it->second;
188     std::string channel_type = curve.get_channel_type();
189     if (channel_type == "rotation_quaternion") {
190       /* Can not export Quaternion animation in Collada as far as i know)
191        * Maybe automatically convert to euler rotation?
192        * Discard for now. */
193       continue;
194     }
195
196     if (export_as_matrix && curve.is_transform_curve()) {
197       /* All Transform curves will be exported within a single matrix animation,
198        * see export_matrix_animation()
199        * No need to export the curves here again.
200        */
201       continue;
202     }
203
204     if (!keep_flat_curves && !curve.is_animated()) {
205       continue;
206     }
207
208     BCAnimationCurve *mcurve = get_modified_export_curve(ob, curve, *curves);
209     if (mcurve) {
210       export_curve_animation(ob, *mcurve);
211       delete mcurve;
212     }
213     else {
214       export_curve_animation(ob, curve);
215     }
216   }
217 }
218
219 void AnimationExporter::export_matrix_animation(Object *ob, BCAnimationSampler &sampler)
220 {
221   bool keep_flat_curves = this->export_settings.get_keep_flat_curves();
222
223   std::vector<float> frames;
224   sampler.get_object_frames(frames, ob);
225   if (frames.size() > 0) {
226     BCMatrixSampleMap samples;
227     bool is_animated = sampler.get_object_samples(samples, ob);
228     if (keep_flat_curves || is_animated) {
229       bAction *action = bc_getSceneObjectAction(ob);
230       std::string name = encode_xml(id_name(ob));
231       std::string action_name = (action == NULL) ? name + "-action" : id_name(action);
232       std::string channel_type = "transform";
233       std::string axis = "";
234       std::string id = bc_get_action_id(action_name, name, channel_type, axis);
235
236       std::string target = translate_id(name) + '/' + channel_type;
237
238       BC_global_rotation_type global_rotation_type = get_global_rotation_type(ob);
239       export_collada_matrix_animation(
240           id, name, target, frames, samples, global_rotation_type, ob->parentinv);
241     }
242   }
243 }
244
245 BC_global_rotation_type AnimationExporter::get_global_rotation_type(Object *ob)
246 {
247   bool is_export_root = this->export_settings.is_export_root(ob);
248   if (!is_export_root) {
249     return BC_NO_ROTATION;
250   }
251
252   bool apply_global_rotation = this->export_settings.get_apply_global_orientation();
253
254   return (apply_global_rotation) ? BC_DATA_ROTATION : BC_OBJECT_ROTATION;
255 }
256
257 /* Write bone animations in transform matrix sources. */
258 void AnimationExporter::export_bone_animations_recursive(Object *ob,
259                                                          Bone *bone,
260                                                          BCAnimationSampler &sampler)
261 {
262   bool keep_flat_curves = this->export_settings.get_keep_flat_curves();
263
264   std::vector<float> frames;
265   sampler.get_bone_frames(frames, ob, bone);
266
267   if (frames.size()) {
268     BCMatrixSampleMap samples;
269     bool is_animated = sampler.get_bone_samples(samples, ob, bone);
270     if (keep_flat_curves || is_animated) {
271       export_bone_animation(ob, bone, frames, samples);
272     }
273   }
274
275   for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
276     export_bone_animations_recursive(ob, child, sampler);
277   }
278 }
279
280 /**
281  * In some special cases the exported Curve needs to be replaced
282  * by a modified curve (for collada purposes)
283  * This method checks if a conversion is necessary and if applicable
284  * returns a pointer to the modified BCAnimationCurve.
285  * IMPORTANT: the modified curve must be deleted by the caller when no longer needed
286  * if no conversion is needed this method returns a NULL;
287  */
288 BCAnimationCurve *AnimationExporter::get_modified_export_curve(Object *ob,
289                                                                BCAnimationCurve &curve,
290                                                                BCAnimationCurveMap &curves)
291 {
292   std::string channel_type = curve.get_channel_type();
293   BCAnimationCurve *mcurve = NULL;
294   if (channel_type == "lens") {
295
296     /* Create an xfov curve */
297
298     BCCurveKey key(BC_ANIMATION_TYPE_CAMERA, "xfov", 0);
299     mcurve = new BCAnimationCurve(key, ob);
300
301     /* now tricky part: transform the fcurve */
302     BCValueMap lens_values;
303     curve.get_value_map(lens_values);
304
305     BCAnimationCurve *sensor_curve = NULL;
306     BCCurveKey sensor_key(BC_ANIMATION_TYPE_CAMERA, "sensor_width", 0);
307     BCAnimationCurveMap::iterator cit = curves.find(sensor_key);
308     if (cit != curves.end()) {
309       sensor_curve = cit->second;
310     }
311
312     BCValueMap::const_iterator vit;
313     for (vit = lens_values.begin(); vit != lens_values.end(); ++vit) {
314       int frame = vit->first;
315       float lens_value = vit->second;
316
317       float sensor_value;
318       if (sensor_curve) {
319         sensor_value = sensor_curve->get_value(frame);
320       }
321       else {
322         sensor_value = ((Camera *)ob->data)->sensor_x;
323       }
324       float value = RAD2DEGF(focallength_to_fov(lens_value, sensor_value));
325       mcurve->add_value(value, frame);
326     }
327     /* to reset the handles */
328     mcurve->clean_handles();
329   }
330   return mcurve;
331 }
332
333 void AnimationExporter::export_curve_animation(Object *ob, BCAnimationCurve &curve)
334 {
335   std::string channel_target = curve.get_channel_target();
336
337   /*
338    * Some curves can not be exported as is and need some conversion
339    * For more information see implementation oif get_modified_export_curve()
340    * note: if mcurve is not NULL then it must be deleted at end of this method;
341    */
342
343   int channel_index = curve.get_channel_index();
344   /* RGB or XYZ or "" */
345   std::string channel_type = curve.get_channel_type();
346   std::string axis = get_axis_name(channel_type, channel_index);
347
348   std::string action_name;
349   bAction *action = bc_getSceneObjectAction(ob);
350   action_name = (action) ? id_name(action) : "constraint_anim";
351
352   const std::string curve_name = encode_xml(curve.get_animation_name(ob));
353   std::string id = bc_get_action_id(action_name, curve_name, channel_target, axis, ".");
354
355   std::string collada_target = translate_id(curve_name);
356
357   if (curve.is_of_animation_type(BC_ANIMATION_TYPE_MATERIAL)) {
358     int material_index = curve.get_subindex();
359     Material *ma = give_current_material(ob, material_index + 1);
360     if (ma) {
361       collada_target = translate_id(id_name(ma)) + "-effect/common/" +
362                        get_collada_sid(curve, axis);
363     }
364   }
365   else {
366     collada_target += "/" + get_collada_sid(curve, axis);
367   }
368
369   BC_global_rotation_type global_rotation_type = get_global_rotation_type(ob);
370   export_collada_curve_animation(
371       id, curve_name, collada_target, axis, curve, global_rotation_type);
372 }
373
374 void AnimationExporter::export_bone_animation(Object *ob,
375                                               Bone *bone,
376                                               BCFrames &frames,
377                                               BCMatrixSampleMap &samples)
378 {
379   bAction *action = bc_getSceneObjectAction(ob);
380   std::string bone_name(bone->name);
381   std::string name = encode_xml(id_name(ob));
382   std::string id = bc_get_action_id(id_name(action), name, bone_name, "pose_matrix");
383   std::string target = translate_id(id_name(ob) + "_" + bone_name) + "/transform";
384
385   BC_global_rotation_type global_rotation_type = get_global_rotation_type(ob);
386   export_collada_matrix_animation(
387       id, name, target, frames, samples, global_rotation_type, ob->parentinv);
388 }
389
390 bool AnimationExporter::is_bone_deform_group(Bone *bone)
391 {
392   bool is_def;
393   /* Check if current bone is deform */
394   if ((bone->flag & BONE_NO_DEFORM) == 0) {
395     return true;
396   }
397   /* Check child bones */
398   else {
399     for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
400       /* loop through all the children until deform bone is found, and then return */
401       is_def = is_bone_deform_group(child);
402       if (is_def) {
403         return true;
404       }
405     }
406   }
407   /* no deform bone found in children also */
408   return false;
409 }
410
411 void AnimationExporter::export_collada_curve_animation(
412     std::string id,
413     std::string name,
414     std::string collada_target,
415     std::string axis,
416     BCAnimationCurve &curve,
417     BC_global_rotation_type global_rotation_type)
418 {
419   BCFrames frames;
420   BCValues values;
421   curve.get_frames(frames);
422   curve.get_values(values);
423   std::string channel_target = curve.get_channel_target();
424
425   fprintf(
426       stdout, "Export animation curve %s (%d control points)\n", id.c_str(), int(frames.size()));
427   openAnimation(id, name);
428   BC_animation_source_type source_type = (curve.is_rotation_curve()) ? BC_SOURCE_TYPE_ANGLE :
429                                                                        BC_SOURCE_TYPE_VALUE;
430
431   std::string input_id = collada_source_from_values(
432       BC_SOURCE_TYPE_TIMEFRAME, COLLADASW::InputSemantic::INPUT, frames, id, axis);
433   std::string output_id = collada_source_from_values(
434       source_type, COLLADASW::InputSemantic::OUTPUT, values, id, axis);
435
436   bool has_tangents = false;
437   std::string interpolation_id;
438   if (this->export_settings.get_keep_smooth_curves()) {
439     interpolation_id = collada_interpolation_source(curve, id, axis, &has_tangents);
440   }
441   else {
442     interpolation_id = collada_linear_interpolation_source(frames.size(), id);
443   }
444
445   std::string intangent_id;
446   std::string outtangent_id;
447   if (has_tangents) {
448     intangent_id = collada_tangent_from_curve(
449         COLLADASW::InputSemantic::IN_TANGENT, curve, id, axis);
450     outtangent_id = collada_tangent_from_curve(
451         COLLADASW::InputSemantic::OUT_TANGENT, curve, id, axis);
452   }
453
454   std::string sampler_id = std::string(id) + SAMPLER_ID_SUFFIX;
455
456   COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
457
458   sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(EMPTY_STRING, input_id));
459   sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(EMPTY_STRING, output_id));
460   sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION,
461                    COLLADABU::URI(EMPTY_STRING, interpolation_id));
462
463   if (has_tangents) {
464     sampler.addInput(COLLADASW::InputSemantic::IN_TANGENT,
465                      COLLADABU::URI(EMPTY_STRING, intangent_id));
466     sampler.addInput(COLLADASW::InputSemantic::OUT_TANGENT,
467                      COLLADABU::URI(EMPTY_STRING, outtangent_id));
468   }
469
470   addSampler(sampler);
471   addChannel(COLLADABU::URI(EMPTY_STRING, sampler_id), collada_target);
472
473   closeAnimation();
474 }
475
476 void AnimationExporter::export_collada_matrix_animation(
477     std::string id,
478     std::string name,
479     std::string target,
480     BCFrames &frames,
481     BCMatrixSampleMap &samples,
482     BC_global_rotation_type global_rotation_type,
483     Matrix &parentinv)
484 {
485   fprintf(
486       stdout, "Export animation matrix %s (%d control points)\n", id.c_str(), int(frames.size()));
487
488   openAnimationWithClip(id, name);
489
490   std::string input_id = collada_source_from_values(
491       BC_SOURCE_TYPE_TIMEFRAME, COLLADASW::InputSemantic::INPUT, frames, id, "");
492   std::string output_id = collada_source_from_values(samples, id, global_rotation_type, parentinv);
493   std::string interpolation_id = collada_linear_interpolation_source(frames.size(), id);
494
495   std::string sampler_id = std::string(id) + SAMPLER_ID_SUFFIX;
496   COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
497
498   sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(EMPTY_STRING, input_id));
499   sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(EMPTY_STRING, output_id));
500   sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION,
501                    COLLADABU::URI(EMPTY_STRING, interpolation_id));
502
503   /* Matrix animation has no tangents */
504
505   addSampler(sampler);
506   addChannel(COLLADABU::URI(EMPTY_STRING, sampler_id), target);
507
508   closeAnimation();
509 }
510
511 std::string AnimationExporter::get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic)
512 {
513   switch (semantic) {
514     case COLLADASW::InputSemantic::INPUT:
515       return INPUT_SOURCE_ID_SUFFIX;
516     case COLLADASW::InputSemantic::OUTPUT:
517       return OUTPUT_SOURCE_ID_SUFFIX;
518     case COLLADASW::InputSemantic::INTERPOLATION:
519       return INTERPOLATION_SOURCE_ID_SUFFIX;
520     case COLLADASW::InputSemantic::IN_TANGENT:
521       return INTANGENT_SOURCE_ID_SUFFIX;
522     case COLLADASW::InputSemantic::OUT_TANGENT:
523       return OUTTANGENT_SOURCE_ID_SUFFIX;
524     default:
525       break;
526   }
527   return "";
528 }
529
530 void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNameList &param,
531                                               COLLADASW::InputSemantic::Semantics semantic,
532                                               bool is_rot,
533                                               const std::string axis,
534                                               bool transform)
535 {
536   switch (semantic) {
537     case COLLADASW::InputSemantic::INPUT:
538       param.push_back("TIME");
539       break;
540     case COLLADASW::InputSemantic::OUTPUT:
541       if (is_rot) {
542         param.push_back("ANGLE");
543       }
544       else {
545         if (axis != "") {
546           param.push_back(axis);
547         }
548         else if (transform) {
549           param.push_back("TRANSFORM");
550         }
551         else {
552           /* assumes if axis isn't specified all axises are added */
553           param.push_back("X");
554           param.push_back("Y");
555           param.push_back("Z");
556         }
557       }
558       break;
559     case COLLADASW::InputSemantic::IN_TANGENT:
560     case COLLADASW::InputSemantic::OUT_TANGENT:
561       param.push_back("X");
562       param.push_back("Y");
563       break;
564     default:
565       break;
566   }
567 }
568
569 std::string AnimationExporter::collada_tangent_from_curve(
570     COLLADASW::InputSemantic::Semantics semantic,
571     BCAnimationCurve &curve,
572     const std::string &anim_id,
573     std::string axis_name)
574 {
575   Scene *scene = this->export_settings.get_scene();
576
577   std::string channel = curve.get_channel_target();
578
579   const std::string source_id = anim_id + get_semantic_suffix(semantic);
580
581   bool is_angle = (bc_startswith(channel, "rotation") || channel == "spot_size");
582
583   COLLADASW::FloatSourceF source(mSW);
584   source.setId(source_id);
585   source.setArrayId(source_id + ARRAY_ID_SUFFIX);
586   source.setAccessorCount(curve.sample_count());
587   source.setAccessorStride(2);
588
589   COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
590   add_source_parameters(param, semantic, is_angle, axis_name, false);
591
592   source.prepareToAppendValues();
593
594   const FCurve *fcu = curve.get_fcurve();
595   int tangent = (semantic == COLLADASW::InputSemantic::IN_TANGENT) ? 0 : 2;
596
597   for (int i = 0; i < fcu->totvert; ++i) {
598     BezTriple &bezt = fcu->bezt[i];
599
600     float sampled_time = bezt.vec[tangent][0];
601     float sampled_val = bezt.vec[tangent][1];
602
603     if (is_angle) {
604       sampled_val = RAD2DEGF(sampled_val);
605     }
606
607     source.appendValues(FRA2TIME(sampled_time));
608     source.appendValues(sampled_val);
609   }
610   source.finish();
611   return source_id;
612 }
613
614 std::string AnimationExporter::collada_source_from_values(
615     BC_animation_source_type source_type,
616     COLLADASW::InputSemantic::Semantics semantic,
617     std::vector<float> &values,
618     const std::string &anim_id,
619     const std::string axis_name)
620 {
621   BlenderContext &blender_context = this->export_settings.get_blender_context();
622   Scene *scene = blender_context.get_scene();
623   /* T can be float, int or double */
624
625   int stride = 1;
626   int entry_count = values.size() / stride;
627   std::string source_id = anim_id + get_semantic_suffix(semantic);
628
629   COLLADASW::FloatSourceF source(mSW);
630   source.setId(source_id);
631   source.setArrayId(source_id + ARRAY_ID_SUFFIX);
632   source.setAccessorCount(entry_count);
633   source.setAccessorStride(stride);
634
635   COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
636   add_source_parameters(param, semantic, source_type == BC_SOURCE_TYPE_ANGLE, axis_name, false);
637
638   source.prepareToAppendValues();
639
640   for (int i = 0; i < entry_count; i++) {
641     float val = values[i];
642     switch (source_type) {
643       case BC_SOURCE_TYPE_TIMEFRAME:
644         val = FRA2TIME(val);
645         break;
646       case BC_SOURCE_TYPE_ANGLE:
647         val = RAD2DEGF(val);
648         break;
649       default:
650         break;
651     }
652     source.appendValues(val);
653   }
654
655   source.finish();
656
657   return source_id;
658 }
659
660 /*
661  * Create a collada matrix source for a set of samples
662  */
663 std::string AnimationExporter::collada_source_from_values(
664     BCMatrixSampleMap &samples,
665     const std::string &anim_id,
666     BC_global_rotation_type global_rotation_type,
667     Matrix &parentinv)
668 {
669   COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
670   std::string source_id = anim_id + get_semantic_suffix(semantic);
671
672   COLLADASW::Float4x4Source source(mSW);
673   source.setId(source_id);
674   source.setArrayId(source_id + ARRAY_ID_SUFFIX);
675   source.setAccessorCount(samples.size());
676   source.setAccessorStride(16);
677
678   COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
679   add_source_parameters(param, semantic, false, "", true);
680
681   source.prepareToAppendValues();
682
683   BCMatrixSampleMap::iterator it;
684   /* could be made configurable */
685   int precision = (this->export_settings.get_limit_precision()) ? 6 : -1;
686   for (it = samples.begin(); it != samples.end(); it++) {
687     BCMatrix sample = BCMatrix(*it->second);
688     BCMatrix global_transform = this->export_settings.get_global_transform();
689     DMatrix daemat;
690     if (this->export_settings.get_apply_global_orientation()) {
691       sample.apply_transform(global_transform);
692     }
693     else {
694       sample.add_transform(global_transform);
695     }
696     sample.get_matrix(daemat, true, precision);
697     source.appendValues(daemat);
698   }
699
700   source.finish();
701   return source_id;
702 }
703
704 std::string AnimationExporter::collada_interpolation_source(const BCAnimationCurve &curve,
705                                                             const std::string &anim_id,
706                                                             const std::string axis,
707                                                             bool *has_tangents)
708 {
709   std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
710
711   COLLADASW::NameSource source(mSW);
712   source.setId(source_id);
713   source.setArrayId(source_id + ARRAY_ID_SUFFIX);
714   source.setAccessorCount(curve.sample_count());
715   source.setAccessorStride(1);
716
717   COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
718   param.push_back("INTERPOLATION");
719
720   source.prepareToAppendValues();
721
722   *has_tangents = false;
723
724   std::vector<float> frames;
725   curve.get_frames(frames);
726
727   for (unsigned int i = 0; i < curve.sample_count(); i++) {
728     float frame = frames[i];
729     int ipo = curve.get_interpolation_type(frame);
730     if (ipo == BEZT_IPO_BEZ) {
731       source.appendValues(BEZIER_NAME);
732       *has_tangents = true;
733     }
734     else if (ipo == BEZT_IPO_CONST) {
735       source.appendValues(STEP_NAME);
736     }
737     else {
738       /* BEZT_IPO_LIN */
739       source.appendValues(LINEAR_NAME);
740     }
741   }
742   /* unsupported? -- HERMITE, CARDINAL, BSPLINE, NURBS */
743
744   source.finish();
745
746   return source_id;
747 }
748
749 std::string AnimationExporter::collada_linear_interpolation_source(int tot,
750                                                                    const std::string &anim_id)
751 {
752   std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
753
754   COLLADASW::NameSource source(mSW);
755   source.setId(source_id);
756   source.setArrayId(source_id + ARRAY_ID_SUFFIX);
757   source.setAccessorCount(tot);
758   source.setAccessorStride(1);
759
760   COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
761   param.push_back("INTERPOLATION");
762
763   source.prepareToAppendValues();
764
765   for (int i = 0; i < tot; i++) {
766     source.appendValues(LINEAR_NAME);
767   }
768
769   source.finish();
770
771   return source_id;
772 }
773
774 const std::string AnimationExporter::get_collada_name(std::string channel_type) const
775 {
776   /*
777    * Translation table to map FCurve animation types to Collada animation.
778    * Todo: Maybe we can keep the names from the fcurves here instead of
779    * mapping. However this is what i found in the old code. So keep
780    * this map for now.
781    */
782   static std::map<std::string, std::string> BC_CHANNEL_BLENDER_TO_COLLADA = {
783       {"rotation", "rotation"},
784       {"rotation_euler", "rotation"},
785       {"rotation_quaternion", "rotation"},
786       {"scale", "scale"},
787       {"location", "location"},
788
789       /* Materials */
790       {"specular_color", "specular"},
791       {"diffuse_color", "diffuse"},
792       {"ior", "index_of_refraction"},
793       {"specular_hardness", "specular_hardness"},
794       {"alpha", "alpha"},
795
796       /* Lights */
797       {"color", "color"},
798       {"fall_off_angle", "falloff_angle"},
799       {"spot_size", "falloff_angle"},
800       {"fall_off_exponent", "falloff_exponent"},
801       {"spot_blend", "falloff_exponent"},
802       /* Special blender profile (todo: make this more elegant). */
803       {"blender/blender_dist", "blender/blender_dist"},
804       /* Special blender profile (todo: make this more elegant). */
805       {"distance", "blender/blender_dist"},
806
807       /* Cameras */
808       {"lens", "xfov"},
809       {"xfov", "xfov"},
810       {"xmag", "xmag"},
811       {"zfar", "zfar"},
812       {"znear", "znear"},
813       {"ortho_scale", "xmag"},
814       {"clip_end", "zfar"},
815       {"clip_start", "znear"}};
816
817   std::map<std::string, std::string>::iterator name_it = BC_CHANNEL_BLENDER_TO_COLLADA.find(
818       channel_type);
819   if (name_it == BC_CHANNEL_BLENDER_TO_COLLADA.end()) {
820     return "";
821   }
822   std::string tm_name = name_it->second;
823   return tm_name;
824 }
825
826 /*
827  * Assign sid of the animated parameter or transform for rotation,
828  * axis name is always appended and the value of append_axis is ignored
829  */
830 std::string AnimationExporter::get_collada_sid(const BCAnimationCurve &curve,
831                                                const std::string axis_name)
832 {
833   std::string channel_target = curve.get_channel_target();
834   std::string channel_type = curve.get_channel_type();
835   std::string tm_name = get_collada_name(channel_type);
836
837   bool is_angle = curve.is_rotation_curve();
838
839   if (tm_name.size()) {
840     if (is_angle) {
841       return tm_name + std::string(axis_name) + ".ANGLE";
842     }
843     else if (axis_name != "") {
844       return tm_name + "." + std::string(axis_name);
845     }
846     else {
847       return tm_name;
848     }
849   }
850
851   return tm_name;
852 }
853
854 #ifdef WITH_MORPH_ANIMATION
855 /* TODO: This function needs to be implemented similar to the material animation export
856  * So we have to update BCSample for this to work. */
857 void AnimationExporter::export_morph_animation(Object *ob, BCAnimationSampler &sampler)
858 {
859   FCurve *fcu;
860   Key *key = BKE_key_from_object(ob);
861   if (!key) {
862     return;
863   }
864
865   if (key->adt && key->adt->action) {
866     fcu = (FCurve *)key->adt->action->curves.first;
867
868     while (fcu) {
869       BC_animation_transform_type tm_type = get_transform_type(fcu->rna_path);
870
871       create_keyframed_animation(ob, fcu, tm_type, true, sampler);
872
873       fcu = fcu->next;
874     }
875   }
876 }
877 #endif