53f3cc9aae31c338687e6bd194ff1f44c6a0a6de
[blender.git] / source / blender / collada / AnimationExporter.cpp
1 /*
2  * $Id: DocumentExporter.cpp 36898 2011-05-25 17:14:31Z phabtar $
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed.
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 #include "GeometryExporter.h"
26 #include "AnimationExporter.h"
27 #include "MaterialExporter.h"
28
29 template<class Functor>
30 void forEachObjectInScene(Scene *sce, Functor &f)
31 {
32         Base *base= (Base*) sce->base.first;
33         
34         while(base) {
35                 Object *ob = base->object;
36                         
37                 f(ob);
38
39                 base= base->next;
40         }
41 }
42
43 void AnimationExporter::exportAnimations(Scene *sce)
44         {
45                 if(hasAnimations(sce)) {
46                         this->scene = sce;
47
48                         openLibrary();
49
50                         forEachObjectInScene(sce, *this);
51
52                         closeLibrary();
53                 }
54         }
55
56         // called for each exported object
57         void AnimationExporter::operator() (Object *ob) 
58         {
59                 FCurve *fcu;
60                 char * transformName ;
61                 bool isMatAnim = false;
62         if(ob->adt && ob->adt->action)      
63                 {
64                         if ( ob->type == OB_ARMATURE )
65                         {
66                                 bArmature *arm = (bArmature*)ob->data;
67                                 for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next)
68                                         bake_bone_animation(ob, bone);
69                             
70                         }
71                         fcu = (FCurve*)ob->adt->action->curves.first;
72                     while (fcu) {
73                         transformName = extract_transform_name( fcu->rna_path );
74                                 
75                                 if ((!strcmp(transformName, "location") || !strcmp(transformName, "scale")) ||
76                                         (!strcmp(transformName, "rotation_euler") && ob->rotmode == ROT_MODE_EUL)||
77                                         (!strcmp(transformName, "rotation_quaternion"))) 
78                                         dae_animation(ob ,fcu, transformName, false);
79                                 fcu = fcu->next;
80                         }
81                 }
82                 if( (ob->type == OB_LAMP ) && ((Lamp*)ob ->data)->adt && ((Lamp*)ob ->data)->adt->action )
83                 {
84                         fcu = (FCurve*)(((Lamp*)ob ->data)->adt->action->curves.first);
85                         while (fcu) {
86                         transformName = extract_transform_name( fcu->rna_path );
87                                 
88                                 if ((!strcmp(transformName, "color")) ||
89                                         (!strcmp(transformName, "spot_size"))||
90                                         (!strcmp(transformName, "spot_blend"))) 
91                                         dae_animation(ob , fcu, transformName, true );
92                                 fcu = fcu->next;
93                         }
94                 }
95
96                 if( (ob->type == OB_CAMERA ) && ((Camera*)ob ->data)->adt && ((Camera*)ob ->data)->adt->action )
97                 {               
98                         fcu = (FCurve*)(((Camera*)ob ->data)->adt->action->curves.first);
99                         while (fcu) {
100                         transformName = extract_transform_name( fcu->rna_path );
101                                 
102                                 if ((!strcmp(transformName, "lens"))||
103                                         (!strcmp(transformName, "ortho_scale"))||
104                                         (!strcmp(transformName, "clip_end"))||(!strcmp(transformName, "clip_start"))) 
105                                         dae_animation(ob , fcu, transformName, true );
106                                 fcu = fcu->next;
107                         }
108                 }
109
110                 for(int a = 0; a < ob->totcol; a++)
111                 {
112                         Material *ma = give_current_material(ob, a+1);
113                         if (!ma) continue;
114                         if(ma->adt && ma->adt->action)
115                         {
116                                 isMatAnim = true;
117                                 fcu = (FCurve*)ma->adt->action->curves.first;
118                                 while (fcu) {
119                                         transformName = extract_transform_name( fcu->rna_path );
120                                         
121                                         if ((!strcmp(transformName, "specular_hardness"))||(!strcmp(transformName, "specular_color"))
122                                                 ||(!strcmp(transformName, "diffuse_color"))||(!strcmp(transformName, "alpha"))||
123                                                 (!strcmp(transformName, "ior"))) 
124                                                 dae_animation(ob ,fcu, transformName, true, ma );
125                                         fcu = fcu->next;
126                                 }
127                         }
128                         
129                 }
130                 //if (!ob->adt || !ob->adt->action) 
131                 //      fcu = (FCurve*)((Lamp*)ob->data)->adt->action->curves.first;  //this is already checked in hasAnimations()
132                 //else
133                 //    fcu = (FCurve*)ob->adt->action->curves.first;
134                                                         
135                 //if (ob->type == OB_ARMATURE) {
136                 //      if (!ob->data) return;
137                 //      bArmature *arm = (bArmature*)ob->data;
138                 //      while(fcu)
139                 //      {               
140                 //              transformName = extract_transform_name( fcu->rna_path );
141                 //      //      std::string ob_name =  getObjectBoneName( ob , fcu);
142                 //      //      for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next)
143                 //      //              write_bone_animation(ob, bone);
144                 //              dae_animation(ob, fcu, ob_name, transformName);
145                 //              fcu = fcu->next;
146                 //      }
147                 //}
148                 //else {
149                 
150         }
151
152         float * AnimationExporter::get_eul_source_for_quat(Object *ob )
153         {
154                 FCurve *fcu = (FCurve*)ob->adt->action->curves.first;
155                 const int keys = fcu->totvert;  
156                 float *quat = (float*)MEM_callocN(sizeof(float) * fcu->totvert * 4, "quat output source values");  
157                 float *eul = (float*)MEM_callocN(sizeof(float) * fcu->totvert * 3, "quat output source values");
158                 float temp_quat[4];
159                 float temp_eul[3];
160                         while(fcu)
161                         {
162                                 char * transformName = extract_transform_name( fcu->rna_path );
163                                 
164                                 if( !strcmp(transformName, "rotation_quaternion") )     { 
165                                         for ( int i = 0 ; i < fcu->totvert ; i++){
166                                                 *(quat + ( i * 4 ) + fcu->array_index) = fcu->bezt[i].vec[1][1];
167                                         }
168                                 }
169                                         fcu = fcu->next;
170                         }
171
172                         for ( int i = 0 ; i < fcu->totvert ; i++){
173                                 for ( int j = 0;j<4;j++)
174                                         temp_quat[j] = quat[(i*4)+j];
175
176                                 quat_to_eul(temp_eul,temp_quat);
177
178                                 for (int k = 0;k<3;k++)
179                                         eul[i*3 + k] = temp_eul[k];
180
181                         }
182
183                 return eul;
184
185         }
186         std::string AnimationExporter::getObjectBoneName( Object* ob,const FCurve* fcu ) 
187         {
188                 //hard-way to derive the bone name from rna_path. Must find more compact method
189                 std::string rna_path = std::string(fcu->rna_path);
190
191                 char* boneName = strtok((char *)rna_path.c_str(), "\"");
192                 boneName = strtok(NULL,"\"");
193                 
194                 if( boneName != NULL )
195                         return /*id_name(ob) + "_" +*/ std::string(boneName);
196                 else            
197                         return id_name(ob);
198         }
199
200         void AnimationExporter::dae_animation(Object* ob, FCurve *fcu, char* transformName , bool is_param, Material * ma )
201         {
202                 
203                 const char *axis_name = NULL;
204                 char anim_id[200];
205                 
206                 bool has_tangents = false;
207                 bool quatRotation = false;
208                 
209                 if ( !strcmp(transformName, "rotation_quaternion") )
210                 {
211                         quatRotation = true;
212                         /*const char *axis_names[] = {"", "X", "Y", "Z"};
213                         if (fcu->array_index < 4)
214                         axis_name = axis_names[fcu->array_index];*/
215                 }
216                 //maybe a list or a vector of float animations
217                 else if ( !strcmp(transformName, "color")||!strcmp(transformName, "specular_color")||!strcmp(transformName, "diffuse_color")||
218                               (!strcmp(transformName, "alpha")))
219                 {
220                         const char *axis_names[] = {"R", "G", "B"};
221                         if (fcu->array_index < 3)
222                         axis_name = axis_names[fcu->array_index];
223                 }
224                 else if ((!strcmp(transformName, "location") || !strcmp(transformName, "scale")) ||
225                                 (!strcmp(transformName, "rotation_euler")))
226                 {
227                         const char *axis_names[] = {"X", "Y", "Z"};
228                         if (fcu->array_index < 3)
229                         axis_name = axis_names[fcu->array_index];
230                 }
231                 else{
232                         axis_name = "";
233                 }
234                 
235                 std::string ob_name = std::string("null");
236                 if (ob->type == OB_ARMATURE) 
237                 {   
238                     ob_name =  getObjectBoneName( ob , fcu);
239                         BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s.%s", (char*)translate_id(ob_name).c_str(),
240                                 transformName, axis_name);
241                 }
242                 else 
243                 {
244                         if (ma)
245                                 ob_name = id_name(ob) + "_material";
246                         else
247                                 ob_name = id_name(ob);
248                         BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
249                                  fcu->rna_path, axis_name);
250                 }
251                 
252                 // check rna_path is one of: rotation, scale, location
253
254                 openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
255
256                 // create input source
257                 std::string input_id = create_source_from_fcurve(COLLADASW::InputSemantic::INPUT, fcu, anim_id, axis_name);
258
259                 // create output source
260                 std::string output_id ;
261             
262                 /*if(quatRotation) 
263                 {
264             float * eul  = get_eul_source_for_quat(ob);
265                         float * eul_axis = 
266                                 for ( int i = 0 ; i< fcu->totvert ; i++)
267                                         eul_axis[i] = eul[i*3 + fcu->array_index];
268                         output_id= create_source_from_array(COLLADASW::InputSemantic::OUTPUT, eul_axis , fcu->totvert, quatRotation, anim_id, axis_name);
269                 }
270                  else*/ 
271                 
272                 output_id= create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name);
273
274                 // create interpolations source
275                 std::string interpolation_id = create_interpolation_source(fcu, anim_id, axis_name, &has_tangents);
276
277                 // handle tangents (if required)
278                 std::string intangent_id;
279                 std::string outtangent_id;
280                 
281                 if (has_tangents) {
282                         // create in_tangent source
283                         intangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::IN_TANGENT, fcu, anim_id, axis_name);
284
285                         // create out_tangent source
286                         outtangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUT_TANGENT, fcu, anim_id, axis_name);
287                 }
288
289
290                 std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
291                 COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
292                 std::string empty;
293                 sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
294                 sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
295
296                 // this input is required
297                 sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
298
299                 if (has_tangents) {
300                         sampler.addInput(COLLADASW::InputSemantic::IN_TANGENT, COLLADABU::URI(empty, intangent_id));
301                         sampler.addInput(COLLADASW::InputSemantic::OUT_TANGENT, COLLADABU::URI(empty, outtangent_id));
302                 }
303
304                 addSampler(sampler);
305
306                 std::string target ;
307
308                 if ( !is_param )
309                         target = translate_id(ob_name)
310                         + "/" + get_transform_sid(fcu->rna_path, -1, axis_name, true);
311                 else 
312                 {
313                         if ( ob->type == OB_LAMP )
314                                 target = get_light_id(ob)
315                                 + "/" + get_transform_sid(fcu->rna_path, -1, axis_name, true);
316
317                         if ( ob->type == OB_CAMERA )
318                                 target = get_camera_id(ob)
319                                 + "/" + get_transform_sid(fcu->rna_path, -1, axis_name, true);
320
321                         if( ma ) 
322                                 target = translate_id(id_name(ma)) + "-effect"
323                                                 +"/common/" /*profile common is only supported */ + get_transform_sid(fcu->rna_path, -1, axis_name, true);
324                 }
325                 addChannel(COLLADABU::URI(empty, sampler_id), target);
326
327                 closeAnimation();
328         }
329
330         void AnimationExporter::bake_bone_animation(Object *ob_arm, Bone *bone)
331         {
332                 if (!ob_arm->adt)
333                         return;
334         
335                 sample_and_bake_bone_animation(ob_arm, bone);
336
337         for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next)
338                         bake_bone_animation(ob_arm, child);
339         }
340
341         void AnimationExporter::write_bone_animation(Object *ob_arm, Bone *bone)
342         {
343                 if (!ob_arm->adt)
344                         return;
345         
346                 //write bone animations for 3 transform types
347                 //i=0 --> rotations
348                 //i=1 --> scale
349                 //i=2 --> location
350                 for (int i = 0; i < 3; i++)
351                         sample_and_write_bone_animation(ob_arm, bone, i);
352         
353                 for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next)
354                         write_bone_animation(ob_arm, child);
355         }
356
357         void AnimationExporter::sample_and_bake_bone_animation(Object *ob_arm, Bone *bone)
358         {
359                 bArmature *arm = (bArmature*)ob_arm->data;
360                 int flag = arm->flag;
361                 std::vector<float> fra;
362                 char prefix[256];
363
364                 BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone->name);
365
366                 bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name);
367                 if (!pchan)
368                         return;
369     
370                 find_all_frames(ob_arm, fra);
371
372                 if (flag & ARM_RESTPOS) {
373                         arm->flag &= ~ARM_RESTPOS;
374                         where_is_pose(scene, ob_arm);
375                 }
376
377                 if (fra.size()) {
378                         //int total = fra.back() - fra.front();
379                         float *values = (float*)MEM_callocN(sizeof(float) * 16 * fra.size(), "temp. anim frames");
380                         sample_animation(values, fra, bone, ob_arm, pchan);
381
382                         dae_baked_animation(fra ,values, id_name(ob_arm), bone->name );
383
384                 }
385         }
386
387         void AnimationExporter::sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type)
388         {
389                 bArmature *arm = (bArmature*)ob_arm->data;
390                 int flag = arm->flag;
391                 std::vector<float> fra;
392                 char prefix[256];
393
394                 BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone->name);
395
396                 bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name);
397                 if (!pchan)
398                         return;
399         //Fill frame array with key frame values framed at @param:transform_type
400                 switch (transform_type) {
401                 case 0:
402                         find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode);
403                         break;
404                 case 1:
405                         find_frames(ob_arm, fra, prefix, "scale");
406                         break;
407                 case 2:
408                         find_frames(ob_arm, fra, prefix, "location");
409                         break;
410                 default:
411                         return;
412                 }
413
414                 // exit rest position
415                 if (flag & ARM_RESTPOS) {
416                         arm->flag &= ~ARM_RESTPOS;
417                         where_is_pose(scene, ob_arm);
418                 }
419         //v array will hold all values which will be exported. 
420                 if (fra.size()) {
421                         float *values = (float*)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames");
422                         sample_animation(values, fra, transform_type, bone, ob_arm, pchan);
423
424                         if (transform_type == 0) {
425                                 // write x, y, z curves separately if it is rotation
426                                 float *axisValues = (float*)MEM_callocN(sizeof(float) * fra.size(), "temp. anim frames");   
427                         
428                                 for (int i = 0; i < 3; i++) {
429                                         for (unsigned int j = 0; j < fra.size(); j++)
430                                                 axisValues[j] = values[j * 3 + i];
431
432                                         dae_bone_animation(fra, axisValues, transform_type, i, id_name(ob_arm), bone->name);
433                                 }
434                                 MEM_freeN(axisValues);
435                         }
436                         else {
437                                 // write xyz at once if it is location or scale
438                                 dae_bone_animation(fra, values, transform_type, -1, id_name(ob_arm), bone->name);
439                         }
440
441                         MEM_freeN(values);
442                 }
443
444                 // restore restpos
445                 if (flag & ARM_RESTPOS) 
446                         arm->flag = flag;
447                 where_is_pose(scene, ob_arm);
448         }
449
450         void AnimationExporter::sample_animation(float *v, std::vector<float> &frames, Bone *bone, Object *ob_arm, bPoseChannel *pchan)
451         {
452                 bPoseChannel *parchan = NULL;
453                 bPose *pose = ob_arm->pose;
454
455                 pchan = get_pose_channel(pose, bone->name);
456
457                 if (!pchan)
458                         return;
459
460                 parchan = pchan->parent;
461
462                 enable_fcurves(ob_arm->adt->action, bone->name);
463
464                 std::vector<float>::iterator it;
465             int j = 0;
466                 for (it = frames.begin(); it != frames.end(); it++) {
467                         float mat[4][4], ipar[4][4];
468
469                         float ctime = bsystem_time(scene, ob_arm, *it, 0.0f);
470
471                         //BKE_animsys_evaluate_animdata(&ob_arm->id, ob_arm->adt, *it, ADT_RECALC_ANIM);
472                         BKE_animsys_evaluate_animdata(scene , &ob_arm->id, ob_arm->adt, ctime, ADT_RECALC_ANIM);
473                         where_is_pose_bone(scene, ob_arm, pchan, ctime, 1);
474
475                         // compute bone local mat
476                         if (bone->parent) {
477                                 invert_m4_m4(ipar, parchan->pose_mat);
478                                 mul_m4_m4m4(mat, pchan->pose_mat, ipar);
479                         }
480                         else
481                                 copy_m4_m4(mat, pchan->pose_mat);
482             
483                         for ( int i = 0; i < 4 ; i++)
484                         {
485                                 for ( int k = 0;  k<4 ; k++ )
486                                 {
487                                         v[j*16 + 4*i + k] = mat[i][k];
488                                 }
489                                 
490                         }  
491                 //      copy_m4_m4(v[j*16 + i], mat ) ;
492                         
493                         j++;
494                 }
495
496                 enable_fcurves(ob_arm->adt->action, NULL);
497
498
499         }
500         void AnimationExporter::sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm, bPoseChannel *pchan)
501         {
502                 bPoseChannel *parchan = NULL;
503                 bPose *pose = ob_arm->pose;
504
505                 pchan = get_pose_channel(pose, bone->name);
506
507                 if (!pchan)
508                         return;
509
510                 parchan = pchan->parent;
511
512                 enable_fcurves(ob_arm->adt->action, bone->name);
513
514                 std::vector<float>::iterator it;
515                 for (it = frames.begin(); it != frames.end(); it++) {
516                         float mat[4][4], ipar[4][4];
517
518                         float ctime = bsystem_time(scene, ob_arm, *it, 0.0f);
519
520                         //BKE_animsys_evaluate_animdata(&ob_arm->id, ob_arm->adt, *it, ADT_RECALC_ANIM);
521                         //BKE_animsys_evaluate_animdata(scene , &ob_arm->id, ob_arm->adt, ctime, ADT_RECALC_ANIM);
522                         where_is_pose_bone(scene, ob_arm, pchan, ctime, 1);
523
524                         // compute bone local mat
525                         if (bone->parent) {
526                                 invert_m4_m4(ipar, parchan->pose_mat);
527                                 mul_m4_m4m4(mat, pchan->pose_mat, ipar);
528                         }
529                         else
530                                 copy_m4_m4(mat, pchan->pose_mat);
531
532                         switch (type) {
533                         case 0:
534                                 mat4_to_eul(v, mat);
535                                 break;
536                         case 1:
537                                 mat4_to_size(v, mat);
538                                 break;
539                         case 2:
540                                 copy_v3_v3(v, mat[3]);
541                                 break;
542                         }
543
544                         v += 3;
545                 }
546
547                 enable_fcurves(ob_arm->adt->action, NULL);
548         }
549
550         void AnimationExporter::dae_baked_animation(std::vector<float> &fra, float *values, std::string ob_name, std::string bone_name)
551         {
552                 char anim_id[200];
553                 
554                 if (!fra.size())
555                         return;
556
557                 BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
558                                          (char*)translate_id(bone_name).c_str(), "pose_matrix");
559
560                 openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
561
562                 // create input source
563                 std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, false, anim_id, "");
564
565                 // create output source
566                 std::string output_id;
567                 output_id = create_4x4_source( values, fra.size(), anim_id);
568
569                 // create interpolations source
570                 std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, "");
571
572                 std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
573                 COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
574                 std::string empty;
575                 sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
576                 sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
577
578                 // TODO create in/out tangents source
579
580                 // this input is required
581                 sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
582
583                 addSampler(sampler);
584
585                 std::string target = translate_id(ob_name + "_" + bone_name) + "/transform";
586                 addChannel(COLLADABU::URI(empty, sampler_id), target);
587
588                 closeAnimation();
589         }
590
591         // dae_bone_animation -> add_bone_animation
592         // (blend this into dae_bone_animation)
593         void AnimationExporter::dae_bone_animation(std::vector<float> &fra, float *values, int tm_type, int axis, std::string ob_name, std::string bone_name)
594         {
595                 const char *axis_names[] = {"X", "Y", "Z"};
596                 const char *axis_name = NULL;
597                 char anim_id[200];
598                 bool is_rot = tm_type == 0;
599                 
600                 if (!fra.size())
601                         return;
602
603                 char rna_path[200];
604                 BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].%s", bone_name.c_str(),
605                                          tm_type == 0 ? "rotation_quaternion" : (tm_type == 1 ? "scale" : "location"));
606
607                 if (axis > -1)
608                         axis_name = axis_names[axis];
609                 
610                 std::string transform_sid = get_transform_sid(NULL, tm_type, axis_name, false);
611                 
612                 BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
613                                          (char*)translate_id(bone_name).c_str(), (char*)transform_sid.c_str());
614
615                 openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
616
617                 // create input source
618                 std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, is_rot, anim_id, axis_name);
619
620                 // create output source
621                 std::string output_id;
622                 if (axis == -1)
623                         output_id = create_xyz_source(values, fra.size(), anim_id);
624                 else
625                         output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, values, fra.size(), is_rot, anim_id, axis_name);
626
627                 // create interpolations source
628                 std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, axis_name);
629
630                 std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
631                 COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
632                 std::string empty;
633                 sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
634                 sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
635
636                 // TODO create in/out tangents source
637
638                 // this input is required
639                 sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
640
641                 addSampler(sampler);
642
643                 std::string target = translate_id(ob_name + "_" + bone_name) + "/" + transform_sid;
644                 addChannel(COLLADABU::URI(empty, sampler_id), target);
645
646                 closeAnimation();
647         }
648
649         float AnimationExporter::convert_time(float frame)
650         {
651                 return FRA2TIME(frame);
652         }
653
654         float AnimationExporter::convert_angle(float angle)
655         {
656                 return COLLADABU::Math::Utils::radToDegF(angle);
657         }
658
659         std::string AnimationExporter::get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic)
660         {
661                 switch(semantic) {
662                 case COLLADASW::InputSemantic::INPUT:
663                         return INPUT_SOURCE_ID_SUFFIX;
664                 case COLLADASW::InputSemantic::OUTPUT:
665                         return OUTPUT_SOURCE_ID_SUFFIX;
666                 case COLLADASW::InputSemantic::INTERPOLATION:
667                         return INTERPOLATION_SOURCE_ID_SUFFIX;
668                 case COLLADASW::InputSemantic::IN_TANGENT:
669                         return INTANGENT_SOURCE_ID_SUFFIX;
670                 case COLLADASW::InputSemantic::OUT_TANGENT:
671                         return OUTTANGENT_SOURCE_ID_SUFFIX;
672                 default:
673                         break;
674                 }
675                 return "";
676         }
677
678         void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
679                                                            COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis, bool transform)
680         {
681                 switch(semantic) {
682                 case COLLADASW::InputSemantic::INPUT:
683                         param.push_back("TIME");
684                         break;
685                 case COLLADASW::InputSemantic::OUTPUT:
686                         if (is_rot) {
687                                 param.push_back("ANGLE");
688                         }
689                         else {
690                                 if (axis) {
691                                         param.push_back(axis);
692                                 }
693                                 else 
694                                 if ( transform )
695                                 {
696                                         param.push_back("TRANSFORM");  
697                                 }else{                           //assumes if axis isn't specified all axises are added
698                                         param.push_back("X");
699                                         param.push_back("Y");
700                                         param.push_back("Z");
701                                 }
702                         }
703                         break;
704                 case COLLADASW::InputSemantic::IN_TANGENT:
705                 case COLLADASW::InputSemantic::OUT_TANGENT:
706                         param.push_back("X");
707                         param.push_back("Y");
708                         break;
709                 default:
710                         break;
711                 }
712         }
713
714         void AnimationExporter::get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool rotation, float *values, int *length)
715         {
716                 switch (semantic) {
717                 case COLLADASW::InputSemantic::INPUT:
718                         *length = 1;
719                         values[0] = convert_time(bezt->vec[1][0]);
720                         break;
721                 case COLLADASW::InputSemantic::OUTPUT:
722                         *length = 1;
723                         if (rotation) {
724                                 values[0] = (bezt->vec[1][1]) * 180.0f/M_PI;
725                         }
726                         else {
727                                 values[0] = bezt->vec[1][1];
728                         }
729                         break;
730                 
731                 case COLLADASW::InputSemantic::IN_TANGENT:
732                 *length = 2;
733                         values[0] = convert_time(bezt->vec[0][0]);
734                         if (bezt->ipo != BEZT_IPO_BEZ) {
735                                 // We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data
736                                 values[0] = 0;  
737                                 values[1] = 0;  
738                     }
739                     else if (rotation) {
740                                 values[1] = (bezt->vec[0][1]) * 180.0f/M_PI;
741                         } else {
742                                 values[1] = bezt->vec[0][1];
743                         }
744                         break;
745                 
746                 case COLLADASW::InputSemantic::OUT_TANGENT:
747                         *length = 2;
748                         values[0] = convert_time(bezt->vec[2][0]);
749                         if (bezt->ipo != BEZT_IPO_BEZ) {
750                                 // We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data
751                                 values[0] = 0;  
752                                 values[1] = 0;  
753                         }
754                         else if (rotation) {
755                                 values[1] = (bezt->vec[2][1]) * 180.0f/M_PI;
756                         } else {
757                                 values[1] = bezt->vec[2][1];
758                         }
759                         break;
760                         break;
761                 default:
762                         *length = 0;
763                         break;
764                 }
765         }
766
767         std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name)
768         {
769                 std::string source_id = anim_id + get_semantic_suffix(semantic);
770
771                 //bool is_rotation = !strcmp(fcu->rna_path, "rotation");
772                 bool is_angle = false;
773                 
774                 if (strstr(fcu->rna_path, "rotation")) is_angle = true;
775                 
776                 COLLADASW::FloatSourceF source(mSW);
777                 source.setId(source_id);
778                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
779                 source.setAccessorCount(fcu->totvert);
780                 
781                 switch (semantic) {
782                 case COLLADASW::InputSemantic::INPUT:
783                 case COLLADASW::InputSemantic::OUTPUT:
784                 source.setAccessorStride(1);                    
785                         break;
786                 case COLLADASW::InputSemantic::IN_TANGENT:
787                 case COLLADASW::InputSemantic::OUT_TANGENT:
788                 source.setAccessorStride(2);                    
789                         break;
790                 }
791                 
792                 
793                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
794                 add_source_parameters(param, semantic, is_angle, axis_name, false);
795
796                 source.prepareToAppendValues();
797
798                 for (unsigned int i = 0; i < fcu->totvert; i++) {
799                         float values[3]; // be careful!
800                         int length = 0;
801                         get_source_values(&fcu->bezt[i], semantic, is_angle, values, &length);
802                                 for (int j = 0; j < length; j++)
803                                 source.appendValues(values[j]);
804                 }
805
806                 source.finish();
807
808                 return source_id;
809         }
810
811     //Currently called only to get OUTPUT source values ( if rotation and hence the axis is also specified )
812         std::string AnimationExporter::create_source_from_array(COLLADASW::InputSemantic::Semantics semantic, float *v, int tot, bool is_rot, const std::string& anim_id, const char *axis_name)
813         {
814                 std::string source_id = anim_id + get_semantic_suffix(semantic);
815
816                 COLLADASW::FloatSourceF source(mSW);
817                 source.setId(source_id);
818                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
819                 source.setAccessorCount(tot);
820                 source.setAccessorStride(1);
821                 
822                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
823                 add_source_parameters(param, semantic, is_rot, axis_name,  false);
824
825                 source.prepareToAppendValues();
826
827                 for (int i = 0; i < tot; i++) {
828                         float val = v[i];
829                         ////if (semantic == COLLADASW::InputSemantic::INPUT)
830                         //      val = convert_time(val);
831                         //else
832                                 if (is_rot)                       
833                                 val *= 180.0f / M_PI;
834                         source.appendValues(val);
835                 }
836
837                 source.finish();
838
839                 return source_id;
840         }
841 // only used for sources with INPUT semantic
842         std::string AnimationExporter::create_source_from_vector(COLLADASW::InputSemantic::Semantics semantic, std::vector<float> &fra, bool is_rot, const std::string& anim_id, const char *axis_name)
843         {
844                 std::string source_id = anim_id + get_semantic_suffix(semantic);
845
846                 COLLADASW::FloatSourceF source(mSW);
847                 source.setId(source_id);
848                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
849                 source.setAccessorCount(fra.size());
850                 source.setAccessorStride(1);
851                 
852                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
853                 add_source_parameters(param, semantic, is_rot, axis_name, false);
854
855                 source.prepareToAppendValues();
856
857                 std::vector<float>::iterator it;
858                 for (it = fra.begin(); it != fra.end(); it++) {
859                         float val = *it;
860                         //if (semantic == COLLADASW::InputSemantic::INPUT)
861                                 val = convert_time(val);
862                         /*else if (is_rot)
863                                 val = convert_angle(val);*/
864                         source.appendValues(val);
865                 }
866
867                 source.finish();
868
869                 return source_id;
870         }
871
872         std::string AnimationExporter::create_4x4_source(float *v, int tot, const std::string& anim_id)
873         {
874                 COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
875                 std::string source_id = anim_id + get_semantic_suffix(semantic);
876
877                 COLLADASW::Float4x4Source source(mSW);
878                 source.setId(source_id);
879                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
880                 source.setAccessorCount(tot);
881                 source.setAccessorStride(16);
882                 
883                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
884                 add_source_parameters(param, semantic, false, NULL, false);
885
886                 source.prepareToAppendValues();
887
888                 for (int i = 0; i < tot; i++) {
889                         for ( int j  = 0 ; j < 4 ; j++ )
890                                 source.appendValues(*(v+j*4), *(v + 4*j +1), *(v + 2 + 4*j), *(v+3 + 4*j));
891                         v += 16;
892                 }
893
894                 source.finish();
895
896                 return source_id;
897         }
898         // only used for sources with OUTPUT semantic ( locations and scale)
899         std::string AnimationExporter::create_xyz_source(float *v, int tot, const std::string& anim_id)
900         {
901                 COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
902                 std::string source_id = anim_id + get_semantic_suffix(semantic);
903
904                 COLLADASW::FloatSourceF source(mSW);
905                 source.setId(source_id);
906                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
907                 source.setAccessorCount(tot);
908                 source.setAccessorStride(3);
909                 
910                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
911                 add_source_parameters(param, semantic, false, NULL, false);
912
913                 source.prepareToAppendValues();
914
915                 for (int i = 0; i < tot; i++) {
916                         source.appendValues(*v, *(v + 1), *(v + 2));
917                         v += 3;
918                 }
919
920                 source.finish();
921
922                 return source_id;
923         }
924
925         std::string AnimationExporter::create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents)
926         {
927                 std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
928
929                 COLLADASW::NameSource source(mSW);
930                 source.setId(source_id);
931                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
932                 source.setAccessorCount(fcu->totvert);
933                 source.setAccessorStride(1);
934                 
935                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
936                 param.push_back("INTERPOLATION");
937
938                 source.prepareToAppendValues();
939
940                 *has_tangents = false;
941
942                 for (unsigned int i = 0; i < fcu->totvert; i++) {
943                         if (fcu->bezt[i].ipo==BEZT_IPO_BEZ) {
944                                 source.appendValues(BEZIER_NAME);
945                                 *has_tangents = true;
946                         } else if (fcu->bezt[i].ipo==BEZT_IPO_CONST) {
947                                 source.appendValues(STEP_NAME);
948                         } else { // BEZT_IPO_LIN
949                                 source.appendValues(LINEAR_NAME);
950                         }
951                 }
952                 // unsupported? -- HERMITE, CARDINAL, BSPLINE, NURBS
953
954                 source.finish();
955
956                 return source_id;
957         }
958
959         std::string AnimationExporter::fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name)
960         {
961                 std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
962
963                 COLLADASW::NameSource source(mSW);
964                 source.setId(source_id);
965                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
966                 source.setAccessorCount(tot);
967                 source.setAccessorStride(1);
968                 
969                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
970                 param.push_back("INTERPOLATION");
971
972                 source.prepareToAppendValues();
973
974                 for (int i = 0; i < tot; i++) {
975                         source.appendValues(LINEAR_NAME);
976                 }
977
978                 source.finish();
979
980                 return source_id;
981         }
982
983         // for rotation, axis name is always appended and the value of append_axis is ignored
984         std::string AnimationExporter::get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
985         {
986                 std::string tm_name;
987         bool is_rotation =false;
988                 // when given rna_path, determine tm_type from it
989                 if (rna_path) {
990                         char *name = extract_transform_name(rna_path);
991
992                         if (!strcmp(name, "rotation_euler"))
993                                 tm_type = 0;
994                         else if (!strcmp(name, "rotation_quaternion"))
995                                 tm_type = 1;
996                         else if (!strcmp(name, "scale"))
997                                 tm_type = 2;
998                         else if (!strcmp(name, "location"))
999                                 tm_type = 3;
1000                         else if (!strcmp(name, "color"))
1001                                 tm_type = 4;
1002                         else if (!strcmp(name, "spot_size"))
1003                                 tm_type = 5;
1004                         else if (!strcmp(name, "spot_blend"))
1005                                 tm_type = 6;
1006                         else if (!strcmp(name, "lens"))
1007                                 tm_type = 7;
1008             else if (!strcmp(name, "ortho_scale"))
1009                                 tm_type = 8;
1010                         else if (!strcmp(name, "clip_end"))
1011                                 tm_type = 9;
1012                         else if (!strcmp(name, "clip_start"))
1013                                 tm_type = 10;
1014                         else if (!strcmp(name, "specular_hardness"))
1015                                 tm_type = 11;
1016                         else if (!strcmp(name, "specular_color"))
1017                                 tm_type = 12;
1018                         else if (!strcmp(name, "diffuse_color"))
1019                                 tm_type = 13;
1020                         else if (!strcmp(name, "alpha"))
1021                                 tm_type = 14;
1022                         else if (!strcmp(name, "ior"))
1023                                 tm_type = 15;
1024                         
1025                         else
1026                                 tm_type = -1;
1027                 }
1028
1029                 switch (tm_type) {
1030                 case 0:
1031                 case 1:
1032                         tm_name = "rotation";
1033                         is_rotation = true;
1034                         break;
1035             case 2:
1036                         tm_name = "scale";
1037                         break;
1038                 case 3:
1039                         tm_name = "location";
1040                         break;
1041                 case 4:
1042                         tm_name = "color";
1043                         break;
1044                 case 5:
1045                         tm_name = "fall_off_angle";
1046                         break;
1047                 case 6:
1048                         tm_name = "fall_off_exponent";
1049                         break;
1050                 case 7:
1051                         tm_name = "xfov";
1052                         break;
1053                 case 8:
1054                         tm_name = "xmag";
1055                         break;
1056                 case 9:
1057                         tm_name = "zfar";
1058                         break;
1059                 case 10:
1060                         tm_name = "znear";
1061                         break;
1062                 case 11:
1063                         tm_name = "shininess";
1064                         break;
1065                 case 12:
1066                         tm_name = "specular";
1067                         break;
1068                 case 13:
1069                         tm_name = "diffuse";
1070                         break;  
1071                 case 14:
1072                         tm_name = "transparency";
1073                         break;  
1074                 case 15:
1075                         tm_name = "index_of_refraction";
1076                         break;  
1077                 
1078                 default:
1079                         tm_name = "";
1080                         break;
1081                 }
1082
1083                 if (tm_name.size()) {
1084                         if (is_rotation)
1085                                 return tm_name + std::string(axis_name);
1086                         else
1087                                 return tm_name;
1088                 }
1089
1090                 return std::string("");
1091         }
1092
1093         char* AnimationExporter::extract_transform_name(char *rna_path)
1094         {
1095                 char *dot = strrchr(rna_path, '.');
1096                 return dot ? (dot + 1) : rna_path;
1097         }
1098
1099         void AnimationExporter::find_all_frames(Object *ob, std::vector<float> &fra)
1100         {
1101                 FCurve *fcu= (FCurve*)ob->adt->action->curves.first;
1102                 std::vector<float> keys;
1103                 for (unsigned int i = 0; i < fcu->totvert; i++) {
1104                                         float f = fcu->bezt[i].vec[1][0];     //
1105                                         if (std::find(keys.begin(), keys.end(), f) == keys.end())   
1106                                                 keys.push_back(f);
1107                 }
1108
1109                 std::sort(keys.begin(), keys.end());
1110                 float first, last;
1111                 std::vector<float>::reference ref = keys.front();
1112                 first = ref;
1113                 ref = keys.back();
1114                 last = ref;
1115                 for (float i = first ; i != last ; i+=1.0f )
1116                 {
1117                         fra.push_back(i); 
1118                 }
1119                 return;
1120
1121         }
1122         void AnimationExporter::find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name)
1123         {
1124                 FCurve *fcu= (FCurve*)ob->adt->action->curves.first;
1125
1126                 for (; fcu; fcu = fcu->next) {
1127                         if (prefix && strncmp(prefix, fcu->rna_path, strlen(prefix)))
1128                                 continue;
1129
1130                         char *name = extract_transform_name(fcu->rna_path);
1131                         if (!strcmp(name, tm_name)) {
1132                                 for (unsigned int i = 0; i < fcu->totvert; i++) {
1133                                         float f = fcu->bezt[i].vec[1][0];     //
1134                                         if (std::find(fra.begin(), fra.end(), f) == fra.end())   
1135                                                 fra.push_back(f);
1136                                 }
1137                         }
1138                 }
1139
1140                 // keep the keys in ascending order
1141                 std::sort(fra.begin(), fra.end());
1142         }
1143
1144         void AnimationExporter::find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode)
1145         {
1146                 if (rotmode > 0)
1147                         find_frames(ob, fra, prefix, "rotation_euler");
1148                 else if (rotmode == ROT_MODE_QUAT)
1149                         find_frames(ob, fra, prefix, "rotation_quaternion");
1150                 /*else if (rotmode == ROT_MODE_AXISANGLE)
1151                         ;*/
1152         }
1153
1154         // enable fcurves driving a specific bone, disable all the rest
1155         // if bone_name = NULL enable all fcurves
1156         void AnimationExporter::enable_fcurves(bAction *act, char *bone_name)
1157         {
1158                 FCurve *fcu;
1159                 char prefix[200];
1160
1161                 if (bone_name)
1162                         BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name);
1163
1164                 for (fcu = (FCurve*)act->curves.first; fcu; fcu = fcu->next) {
1165                         if (bone_name) {
1166                                 if (!strncmp(fcu->rna_path, prefix, strlen(prefix)))
1167                                         fcu->flag &= ~FCURVE_DISABLED;
1168                                 else
1169                                         fcu->flag |= FCURVE_DISABLED;
1170                         }
1171                         else {
1172                                 fcu->flag &= ~FCURVE_DISABLED;
1173                         }
1174                 }
1175         }
1176         
1177         bool AnimationExporter::hasAnimations(Scene *sce)
1178         {
1179                 Base *base= (Base*) sce->base.first;
1180                 
1181                 while(base) {
1182                         Object *ob = base->object;
1183                         
1184                         FCurve *fcu = 0;
1185                         if(ob->adt && ob->adt->action)      
1186                                 fcu = (FCurve*)ob->adt->action->curves.first;
1187                         else if( (ob->type == OB_LAMP ) && ((Lamp*)ob ->data)->adt && ((Lamp*)ob ->data)->adt->action )
1188                                 fcu = (FCurve*)(((Lamp*)ob ->data)->adt->action->curves.first);
1189                         else if( (ob->type == OB_CAMERA ) && ((Camera*)ob ->data)->adt && ((Camera*)ob ->data)->adt->action )
1190                                 fcu = (FCurve*)(((Camera*)ob ->data)->adt->action->curves.first);
1191                         
1192                     for(int a = 0; a < ob->totcol; a++)
1193                         {
1194                                 Material *ma = give_current_material(ob, a+1);
1195                                 if (!ma) continue;
1196                         if(ma->adt && ma->adt->action)
1197                                 {
1198                                         fcu = (FCurve*)ma->adt->action->curves.first;   
1199                                 }
1200                         }
1201
1202                         if ( fcu) return true;
1203                         base= base->next;
1204                 }
1205                 return false;
1206         }