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