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