4beab6f7608e0283ae2b2b48707ef834b011ce80
[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_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                 if (flag & ARM_RESTPOS) 
387                         arm->flag = flag;
388                 where_is_pose(scene, ob_arm);
389         }
390
391         void AnimationExporter::sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type)
392         {
393                 bArmature *arm = (bArmature*)ob_arm->data;
394                 int flag = arm->flag;
395                 std::vector<float> fra;
396                 char prefix[256];
397
398                 BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone->name);
399
400                 bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name);
401                 if (!pchan)
402                         return;
403         //Fill frame array with key frame values framed at @param:transform_type
404                 switch (transform_type) {
405                 case 0:
406                         find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode);
407                         break;
408                 case 1:
409                         find_frames(ob_arm, fra, prefix, "scale");
410                         break;
411                 case 2:
412                         find_frames(ob_arm, fra, prefix, "location");
413                         break;
414                 default:
415                         return;
416                 }
417
418                 // exit rest position
419                 if (flag & ARM_RESTPOS) {
420                         arm->flag &= ~ARM_RESTPOS;
421                         where_is_pose(scene, ob_arm);
422                 }
423         //v array will hold all values which will be exported. 
424                 if (fra.size()) {
425                         float *values = (float*)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames");
426                         sample_animation(values, fra, transform_type, bone, ob_arm, pchan);
427
428                         if (transform_type == 0) {
429                                 // write x, y, z curves separately if it is rotation
430                                 float *axisValues = (float*)MEM_callocN(sizeof(float) * fra.size(), "temp. anim frames");   
431                         
432                                 for (int i = 0; i < 3; i++) {
433                                         for (unsigned int j = 0; j < fra.size(); j++)
434                                                 axisValues[j] = values[j * 3 + i];
435
436                                         dae_bone_animation(fra, axisValues, transform_type, i, id_name(ob_arm), bone->name);
437                                 }
438                                 MEM_freeN(axisValues);
439                         }
440                         else {
441                                 // write xyz at once if it is location or scale
442                                 dae_bone_animation(fra, values, transform_type, -1, id_name(ob_arm), bone->name);
443                         }
444
445                         MEM_freeN(values);
446                 }
447
448                 // restore restpos
449                 if (flag & ARM_RESTPOS) 
450                         arm->flag = flag;
451                 where_is_pose(scene, ob_arm);
452         }
453
454         void AnimationExporter::sample_animation(float *v, std::vector<float> &frames, Bone *bone, Object *ob_arm, bPoseChannel *pchan)
455         {
456                 bPoseChannel *parchan = NULL;
457                 bPose *pose = ob_arm->pose;
458
459                 pchan = get_pose_channel(pose, bone->name);
460
461                 if (!pchan)
462                         return;
463
464                 parchan = pchan->parent;
465         
466                 enable_fcurves(ob_arm->adt->action, bone->name);
467
468                 std::vector<float>::iterator it;
469             int j = 0;
470                 for (it = frames.begin(); it != frames.end(); it++) {
471                         float mat[4][4], ipar[4][4];
472
473                         float ctime = bsystem_time(scene, ob_arm, *it, 0.0f);
474
475                         //BKE_animsys_evaluate_animdata(&ob_arm->id, ob_arm->adt, *it, ADT_RECALC_ANIM);
476                         BKE_animsys_evaluate_animdata(scene , &ob_arm->id, ob_arm->adt, ctime, ADT_RECALC_ANIM);
477                         where_is_pose_bone(scene, ob_arm, pchan, ctime, 1);
478
479                         // compute bone local mat
480                         if (bone->parent) {
481                                 invert_m4_m4(ipar, parchan->pose_mat);
482                                 mul_m4_m4m4(mat, pchan->pose_mat, ipar);
483                         }
484                         else
485                                 copy_m4_m4(mat, pchan->pose_mat);
486             
487                         for ( int i = 0; i < 4 ; i++)
488                         {
489                                 for ( int k = 0;  k<4 ; k++ )
490                                 {
491                                         v[j*16 + 4*i + k] = mat[i][k];
492                                 }
493                                 
494                         }  
495                 //      copy_m4_m4(v[j*16 + i], mat ) ;
496                         
497                         j++;
498                 }
499
500                 enable_fcurves(ob_arm->adt->action, NULL);
501
502
503         }
504         void AnimationExporter::sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm, bPoseChannel *pchan)
505         {
506                 bPoseChannel *parchan = NULL;
507                 bPose *pose = ob_arm->pose;
508
509                 pchan = get_pose_channel(pose, bone->name);
510
511                 if (!pchan)
512                         return;
513
514                 parchan = pchan->parent;
515
516                 enable_fcurves(ob_arm->adt->action, bone->name);
517
518                 std::vector<float>::iterator it;
519                 for (it = frames.begin(); it != frames.end(); it++) {
520                         float mat[4][4], ipar[4][4];
521
522                         float ctime = bsystem_time(scene, ob_arm, *it, 0.0f);
523
524                         //BKE_animsys_evaluate_animdata(&ob_arm->id, ob_arm->adt, *it, ADT_RECALC_ANIM);
525                         //BKE_animsys_evaluate_animdata(scene , &ob_arm->id, ob_arm->adt, ctime, ADT_RECALC_ANIM);
526                         where_is_pose_bone(scene, ob_arm, pchan, ctime, 1);
527
528                         // compute bone local mat
529                         if (bone->parent) {
530                                 invert_m4_m4(ipar, parchan->pose_mat);
531                                 mul_m4_m4m4(mat, pchan->pose_mat, ipar);
532                         }
533                         else
534                                 copy_m4_m4(mat, pchan->pose_mat);
535
536                         switch (type) {
537                         case 0:
538                                 mat4_to_eul(v, mat);
539                                 break;
540                         case 1:
541                                 mat4_to_size(v, mat);
542                                 break;
543                         case 2:
544                                 copy_v3_v3(v, mat[3]);
545                                 break;
546                         }
547
548                         v += 3;
549                 }
550
551                 enable_fcurves(ob_arm->adt->action, NULL);
552         }
553
554         void AnimationExporter::dae_baked_animation(std::vector<float> &fra, float *values, std::string ob_name, std::string bone_name)
555         {
556                 char anim_id[200];
557                 
558                 if (!fra.size())
559                         return;
560
561                 BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
562                                          (char*)translate_id(bone_name).c_str(), "pose_matrix");
563
564                 openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
565
566                 // create input source
567                 std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, false, anim_id, "");
568
569                 // create output source
570                 std::string output_id;
571                 output_id = create_4x4_source( values, fra.size(), anim_id);
572
573                 // create interpolations source
574                 std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, "");
575
576                 std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
577                 COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
578                 std::string empty;
579                 sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
580                 sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
581
582                 // TODO create in/out tangents source
583
584                 // this input is required
585                 sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
586
587                 addSampler(sampler);
588
589                 std::string target = translate_id(bone_name) + "/transform";
590                 addChannel(COLLADABU::URI(empty, sampler_id), target);
591
592                 closeAnimation();
593         }
594
595         // dae_bone_animation -> add_bone_animation
596         // (blend this into dae_bone_animation)
597         void AnimationExporter::dae_bone_animation(std::vector<float> &fra, float *values, int tm_type, int axis, std::string ob_name, std::string bone_name)
598         {
599                 const char *axis_names[] = {"X", "Y", "Z"};
600                 const char *axis_name = NULL;
601                 char anim_id[200];
602                 bool is_rot = tm_type == 0;
603                 
604                 if (!fra.size())
605                         return;
606
607                 char rna_path[200];
608                 BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].%s", bone_name.c_str(),
609                                          tm_type == 0 ? "rotation_quaternion" : (tm_type == 1 ? "scale" : "location"));
610
611                 if (axis > -1)
612                         axis_name = axis_names[axis];
613                 
614                 std::string transform_sid = get_transform_sid(NULL, tm_type, axis_name, false);
615                 
616                 BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
617                                          (char*)translate_id(bone_name).c_str(), (char*)transform_sid.c_str());
618
619                 openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
620
621                 // create input source
622                 std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, is_rot, anim_id, axis_name);
623
624                 // create output source
625                 std::string output_id;
626                 if (axis == -1)
627                         output_id = create_xyz_source(values, fra.size(), anim_id);
628                 else
629                         output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, values, fra.size(), is_rot, anim_id, axis_name);
630
631                 // create interpolations source
632                 std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, axis_name);
633
634                 std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
635                 COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
636                 std::string empty;
637                 sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
638                 sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
639
640                 // TODO create in/out tangents source
641
642                 // this input is required
643                 sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
644
645                 addSampler(sampler);
646
647                 std::string target = translate_id(ob_name + "_" + bone_name) + "/" + transform_sid;
648                 addChannel(COLLADABU::URI(empty, sampler_id), target);
649
650                 closeAnimation();
651         }
652
653         float AnimationExporter::convert_time(float frame)
654         {
655                 return FRA2TIME(frame);
656         }
657
658         float AnimationExporter::convert_angle(float angle)
659         {
660                 return COLLADABU::Math::Utils::radToDegF(angle);
661         }
662
663         std::string AnimationExporter::get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic)
664         {
665                 switch(semantic) {
666                 case COLLADASW::InputSemantic::INPUT:
667                         return INPUT_SOURCE_ID_SUFFIX;
668                 case COLLADASW::InputSemantic::OUTPUT:
669                         return OUTPUT_SOURCE_ID_SUFFIX;
670                 case COLLADASW::InputSemantic::INTERPOLATION:
671                         return INTERPOLATION_SOURCE_ID_SUFFIX;
672                 case COLLADASW::InputSemantic::IN_TANGENT:
673                         return INTANGENT_SOURCE_ID_SUFFIX;
674                 case COLLADASW::InputSemantic::OUT_TANGENT:
675                         return OUTTANGENT_SOURCE_ID_SUFFIX;
676                 default:
677                         break;
678                 }
679                 return "";
680         }
681
682         void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
683                                                            COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis, bool transform)
684         {
685                 switch(semantic) {
686                 case COLLADASW::InputSemantic::INPUT:
687                         param.push_back("TIME");
688                         break;
689                 case COLLADASW::InputSemantic::OUTPUT:
690                         if (is_rot) {
691                                 param.push_back("ANGLE");
692                         }
693                         else {
694                                 if (axis) {
695                                         param.push_back(axis);
696                                 }
697                                 else 
698                                 if ( transform )
699                                 {
700                                         param.push_back("TRANSFORM");  
701                                 }else{                           //assumes if axis isn't specified all axises are added
702                                         param.push_back("X");
703                                         param.push_back("Y");
704                                         param.push_back("Z");
705                                 }
706                         }
707                         break;
708                 case COLLADASW::InputSemantic::IN_TANGENT:
709                 case COLLADASW::InputSemantic::OUT_TANGENT:
710                         param.push_back("X");
711                         param.push_back("Y");
712                         break;
713                 default:
714                         break;
715                 }
716         }
717
718         void AnimationExporter::get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool rotation, float *values, int *length)
719         {
720                 switch (semantic) {
721                 case COLLADASW::InputSemantic::INPUT:
722                         *length = 1;
723                         values[0] = convert_time(bezt->vec[1][0]);
724                         break;
725                 case COLLADASW::InputSemantic::OUTPUT:
726                         *length = 1;
727                         if (rotation) {
728                                 values[0] = (bezt->vec[1][1]) * 180.0f/M_PI;
729                         }
730                         else {
731                                 values[0] = bezt->vec[1][1];
732                         }
733                         break;
734                 
735                 case COLLADASW::InputSemantic::IN_TANGENT:
736                 *length = 2;
737                         values[0] = convert_time(bezt->vec[0][0]);
738                         if (bezt->ipo != BEZT_IPO_BEZ) {
739                                 // We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data
740                                 values[0] = 0;  
741                                 values[1] = 0;  
742                     }
743                     else if (rotation) {
744                                 values[1] = (bezt->vec[0][1]) * 180.0f/M_PI;
745                         } else {
746                                 values[1] = bezt->vec[0][1];
747                         }
748                         break;
749                 
750                 case COLLADASW::InputSemantic::OUT_TANGENT:
751                         *length = 2;
752                         values[0] = convert_time(bezt->vec[2][0]);
753                         if (bezt->ipo != BEZT_IPO_BEZ) {
754                                 // We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data
755                                 values[0] = 0;  
756                                 values[1] = 0;  
757                         }
758                         else if (rotation) {
759                                 values[1] = (bezt->vec[2][1]) * 180.0f/M_PI;
760                         } else {
761                                 values[1] = bezt->vec[2][1];
762                         }
763                         break;
764                         break;
765                 default:
766                         *length = 0;
767                         break;
768                 }
769         }
770
771         std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name)
772         {
773                 std::string source_id = anim_id + get_semantic_suffix(semantic);
774
775                 //bool is_rotation = !strcmp(fcu->rna_path, "rotation");
776                 bool is_angle = false;
777                 
778                 if (strstr(fcu->rna_path, "rotation")) is_angle = true;
779                 
780                 COLLADASW::FloatSourceF source(mSW);
781                 source.setId(source_id);
782                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
783                 source.setAccessorCount(fcu->totvert);
784                 
785                 switch (semantic) {
786                 case COLLADASW::InputSemantic::INPUT:
787                 case COLLADASW::InputSemantic::OUTPUT:
788                 source.setAccessorStride(1);                    
789                         break;
790                 case COLLADASW::InputSemantic::IN_TANGENT:
791                 case COLLADASW::InputSemantic::OUT_TANGENT:
792                 source.setAccessorStride(2);                    
793                         break;
794                 }
795                 
796                 
797                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
798                 add_source_parameters(param, semantic, is_angle, axis_name, false);
799
800                 source.prepareToAppendValues();
801
802                 for (unsigned int i = 0; i < fcu->totvert; i++) {
803                         float values[3]; // be careful!
804                         int length = 0;
805                         get_source_values(&fcu->bezt[i], semantic, is_angle, values, &length);
806                                 for (int j = 0; j < length; j++)
807                                 source.appendValues(values[j]);
808                 }
809
810                 source.finish();
811
812                 return source_id;
813         }
814
815     //Currently called only to get OUTPUT source values ( if rotation and hence the axis is also specified )
816         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)
817         {
818                 std::string source_id = anim_id + get_semantic_suffix(semantic);
819
820                 COLLADASW::FloatSourceF source(mSW);
821                 source.setId(source_id);
822                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
823                 source.setAccessorCount(tot);
824                 source.setAccessorStride(1);
825                 
826                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
827                 add_source_parameters(param, semantic, is_rot, axis_name,  false);
828
829                 source.prepareToAppendValues();
830
831                 for (int i = 0; i < tot; i++) {
832                         float val = v[i];
833                         ////if (semantic == COLLADASW::InputSemantic::INPUT)
834                         //      val = convert_time(val);
835                         //else
836                                 if (is_rot)                       
837                                 val *= 180.0f / M_PI;
838                         source.appendValues(val);
839                 }
840
841                 source.finish();
842
843                 return source_id;
844         }
845 // only used for sources with INPUT semantic
846         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)
847         {
848                 std::string source_id = anim_id + get_semantic_suffix(semantic);
849
850                 COLLADASW::FloatSourceF source(mSW);
851                 source.setId(source_id);
852                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
853                 source.setAccessorCount(fra.size());
854                 source.setAccessorStride(1);
855                 
856                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
857                 add_source_parameters(param, semantic, is_rot, axis_name, false);
858
859                 source.prepareToAppendValues();
860
861                 std::vector<float>::iterator it;
862                 for (it = fra.begin(); it != fra.end(); it++) {
863                         float val = *it;
864                         //if (semantic == COLLADASW::InputSemantic::INPUT)
865                                 val = convert_time(val);
866                         /*else if (is_rot)
867                                 val = convert_angle(val);*/
868                         source.appendValues(val);
869                 }
870
871                 source.finish();
872
873                 return source_id;
874         }
875
876         std::string AnimationExporter::create_4x4_source(float *v, int tot, const std::string& anim_id)
877         {
878                 COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
879                 std::string source_id = anim_id + get_semantic_suffix(semantic);
880
881                 COLLADASW::Float4x4Source source(mSW);
882                 source.setId(source_id);
883                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
884                 source.setAccessorCount(tot);
885                 source.setAccessorStride(16);
886                 
887                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
888                 add_source_parameters(param, semantic, false, NULL, false);
889
890                 source.prepareToAppendValues();
891
892                 for (int i = 0; i < tot; i++) {
893                         for ( int j  = 0 ; j < 4 ; j++ )
894                                 source.appendValues(*(v+j*4), *(v + 4*j +1), *(v + 2 + 4*j), *(v+3 + 4*j));
895                         v += 16;
896                 }
897
898                 source.finish();
899
900                 return source_id;
901         }
902         // only used for sources with OUTPUT semantic ( locations and scale)
903         std::string AnimationExporter::create_xyz_source(float *v, int tot, const std::string& anim_id)
904         {
905                 COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
906                 std::string source_id = anim_id + get_semantic_suffix(semantic);
907
908                 COLLADASW::FloatSourceF source(mSW);
909                 source.setId(source_id);
910                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
911                 source.setAccessorCount(tot);
912                 source.setAccessorStride(3);
913                 
914                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
915                 add_source_parameters(param, semantic, false, NULL, false);
916
917                 source.prepareToAppendValues();
918
919                 for (int i = 0; i < tot; i++) {
920                         source.appendValues(*v, *(v + 1), *(v + 2));
921                         v += 3;
922                 }
923
924                 source.finish();
925
926                 return source_id;
927         }
928
929         std::string AnimationExporter::create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents)
930         {
931                 std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
932
933                 COLLADASW::NameSource source(mSW);
934                 source.setId(source_id);
935                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
936                 source.setAccessorCount(fcu->totvert);
937                 source.setAccessorStride(1);
938                 
939                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
940                 param.push_back("INTERPOLATION");
941
942                 source.prepareToAppendValues();
943
944                 *has_tangents = false;
945
946                 for (unsigned int i = 0; i < fcu->totvert; i++) {
947                         if (fcu->bezt[i].ipo==BEZT_IPO_BEZ) {
948                                 source.appendValues(BEZIER_NAME);
949                                 *has_tangents = true;
950                         } else if (fcu->bezt[i].ipo==BEZT_IPO_CONST) {
951                                 source.appendValues(STEP_NAME);
952                         } else { // BEZT_IPO_LIN
953                                 source.appendValues(LINEAR_NAME);
954                         }
955                 }
956                 // unsupported? -- HERMITE, CARDINAL, BSPLINE, NURBS
957
958                 source.finish();
959
960                 return source_id;
961         }
962
963         std::string AnimationExporter::fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name)
964         {
965                 std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
966
967                 COLLADASW::NameSource source(mSW);
968                 source.setId(source_id);
969                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
970                 source.setAccessorCount(tot);
971                 source.setAccessorStride(1);
972                 
973                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
974                 param.push_back("INTERPOLATION");
975
976                 source.prepareToAppendValues();
977
978                 for (int i = 0; i < tot; i++) {
979                         source.appendValues(LINEAR_NAME);
980                 }
981
982                 source.finish();
983
984                 return source_id;
985         }
986
987         // for rotation, axis name is always appended and the value of append_axis is ignored
988         std::string AnimationExporter::get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
989         {
990                 std::string tm_name;
991         bool is_rotation =false;
992                 // when given rna_path, determine tm_type from it
993                 if (rna_path) {
994                         char *name = extract_transform_name(rna_path);
995
996                         if (!strcmp(name, "rotation_euler"))
997                                 tm_type = 0;
998                         else if (!strcmp(name, "rotation_quaternion"))
999                                 tm_type = 1;
1000                         else if (!strcmp(name, "scale"))
1001                                 tm_type = 2;
1002                         else if (!strcmp(name, "location"))
1003                                 tm_type = 3;
1004                         else if (!strcmp(name, "color"))
1005                                 tm_type = 4;
1006                         else if (!strcmp(name, "spot_size"))
1007                                 tm_type = 5;
1008                         else if (!strcmp(name, "spot_blend"))
1009                                 tm_type = 6;
1010                         else if (!strcmp(name, "lens"))
1011                                 tm_type = 7;
1012             else if (!strcmp(name, "ortho_scale"))
1013                                 tm_type = 8;
1014                         else if (!strcmp(name, "clip_end"))
1015                                 tm_type = 9;
1016                         else if (!strcmp(name, "clip_start"))
1017                                 tm_type = 10;
1018                         else if (!strcmp(name, "specular_hardness"))
1019                                 tm_type = 11;
1020                         else if (!strcmp(name, "specular_color"))
1021                                 tm_type = 12;
1022                         else if (!strcmp(name, "diffuse_color"))
1023                                 tm_type = 13;
1024                         else if (!strcmp(name, "alpha"))
1025                                 tm_type = 14;
1026                         else if (!strcmp(name, "ior"))
1027                                 tm_type = 15;
1028                         
1029                         else
1030                                 tm_type = -1;
1031                 }
1032
1033                 switch (tm_type) {
1034                 case 0:
1035                 case 1:
1036                         tm_name = "rotation";
1037                         is_rotation = true;
1038                         break;
1039             case 2:
1040                         tm_name = "scale";
1041                         break;
1042                 case 3:
1043                         tm_name = "location";
1044                         break;
1045                 case 4:
1046                         tm_name = "color";
1047                         break;
1048                 case 5:
1049                         tm_name = "fall_off_angle";
1050                         break;
1051                 case 6:
1052                         tm_name = "fall_off_exponent";
1053                         break;
1054                 case 7:
1055                         tm_name = "xfov";
1056                         break;
1057                 case 8:
1058                         tm_name = "xmag";
1059                         break;
1060                 case 9:
1061                         tm_name = "zfar";
1062                         break;
1063                 case 10:
1064                         tm_name = "znear";
1065                         break;
1066                 case 11:
1067                         tm_name = "shininess";
1068                         break;
1069                 case 12:
1070                         tm_name = "specular";
1071                         break;
1072                 case 13:
1073                         tm_name = "diffuse";
1074                         break;  
1075                 case 14:
1076                         tm_name = "transparency";
1077                         break;  
1078                 case 15:
1079                         tm_name = "index_of_refraction";
1080                         break;  
1081                 
1082                 default:
1083                         tm_name = "";
1084                         break;
1085                 }
1086
1087                 if (tm_name.size()) {
1088                         if (is_rotation)
1089                                 return tm_name + std::string(axis_name);
1090                         else
1091                                 return tm_name;
1092                 }
1093
1094                 return std::string("");
1095         }
1096
1097         char* AnimationExporter::extract_transform_name(char *rna_path)
1098         {
1099                 char *dot = strrchr(rna_path, '.');
1100                 return dot ? (dot + 1) : rna_path;
1101         }
1102
1103         void AnimationExporter::find_all_frames(Object *ob, std::vector<float> &fra)
1104         {
1105                 FCurve *fcu= (FCurve*)ob->adt->action->curves.first;
1106                 std::vector<float> keys;
1107                 for (unsigned int i = 0; i < fcu->totvert; i++) {
1108                                         float f = fcu->bezt[i].vec[1][0];     //
1109                                         if (std::find(keys.begin(), keys.end(), f) == keys.end())   
1110                                                 keys.push_back(f);
1111                 }
1112
1113                 std::sort(keys.begin(), keys.end());
1114                 float first, last;
1115                 std::vector<float>::reference ref = keys.front();
1116                 first = ref;
1117                 ref = keys.back();
1118                 last = ref;
1119                 for (float i = first ; i != last ; i+=1.0f )
1120                 {
1121                         fra.push_back(i); 
1122                 }
1123                 return;
1124
1125         }
1126
1127         void AnimationExporter::find_frames(Object *ob, std::vector<float> &fra)
1128         {
1129                 FCurve *fcu= (FCurve*)ob->adt->action->curves.first;
1130
1131                 for (; fcu; fcu = fcu->next) {
1132                         
1133                         for (unsigned int i = 0; i < fcu->totvert; i++) {
1134                                 float f = fcu->bezt[i].vec[1][0];     //
1135                                 if (std::find(fra.begin(), fra.end(), f) == fra.end())   
1136                                         fra.push_back(f);
1137                         }
1138                 }
1139
1140                 // keep the keys in ascending order
1141                 std::sort(fra.begin(), fra.end());
1142         }
1143
1144
1145         void AnimationExporter::find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name)
1146         {
1147                 FCurve *fcu= (FCurve*)ob->adt->action->curves.first;
1148
1149                 for (; fcu; fcu = fcu->next) {
1150                         if (prefix && strncmp(prefix, fcu->rna_path, strlen(prefix)))
1151                                 continue;
1152
1153                         char *name = extract_transform_name(fcu->rna_path);
1154                         if (!strcmp(name, tm_name)) {
1155                                 for (unsigned int i = 0; i < fcu->totvert; i++) {
1156                                         float f = fcu->bezt[i].vec[1][0];     //
1157                                         if (std::find(fra.begin(), fra.end(), f) == fra.end())   
1158                                                 fra.push_back(f);
1159                                 }
1160                         }
1161                 }
1162
1163                 // keep the keys in ascending order
1164                 std::sort(fra.begin(), fra.end());
1165         }
1166
1167         void AnimationExporter::find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode)
1168         {
1169                 if (rotmode > 0)
1170                         find_frames(ob, fra, prefix, "rotation_euler");
1171                 else if (rotmode == ROT_MODE_QUAT)
1172                         find_frames(ob, fra, prefix, "rotation_quaternion");
1173                 /*else if (rotmode == ROT_MODE_AXISANGLE)
1174                         ;*/
1175         }
1176
1177         // enable fcurves driving a specific bone, disable all the rest
1178         // if bone_name = NULL enable all fcurves
1179         void AnimationExporter::enable_fcurves(bAction *act, char *bone_name)
1180         {
1181                 FCurve *fcu;
1182                 char prefix[200];
1183
1184                 if (bone_name)
1185                         BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name);
1186
1187                 for (fcu = (FCurve*)act->curves.first; fcu; fcu = fcu->next) {
1188                         if (bone_name) {
1189                                 if (!strncmp(fcu->rna_path, prefix, strlen(prefix)))
1190                                         fcu->flag &= ~FCURVE_DISABLED;
1191                                 else
1192                                         fcu->flag |= FCURVE_DISABLED;
1193                         }
1194                         else {
1195                                 fcu->flag &= ~FCURVE_DISABLED;
1196                         }
1197                 }
1198         }
1199         
1200         bool AnimationExporter::hasAnimations(Scene *sce)
1201         {
1202                 Base *base= (Base*) sce->base.first;
1203                 
1204                 while(base) {
1205                         Object *ob = base->object;
1206                         
1207                         FCurve *fcu = 0;
1208                         if(ob->adt && ob->adt->action)      
1209                                 fcu = (FCurve*)ob->adt->action->curves.first;
1210                         else if( (ob->type == OB_LAMP ) && ((Lamp*)ob ->data)->adt && ((Lamp*)ob ->data)->adt->action )
1211                                 fcu = (FCurve*)(((Lamp*)ob ->data)->adt->action->curves.first);
1212                         else if( (ob->type == OB_CAMERA ) && ((Camera*)ob ->data)->adt && ((Camera*)ob ->data)->adt->action )
1213                                 fcu = (FCurve*)(((Camera*)ob ->data)->adt->action->curves.first);
1214                         
1215                     for(int a = 0; a < ob->totcol; a++)
1216                         {
1217                                 Material *ma = give_current_material(ob, a+1);
1218                                 if (!ma) continue;
1219                         if(ma->adt && ma->adt->action)
1220                                 {
1221                                         fcu = (FCurve*)ma->adt->action->curves.first;   
1222                                 }
1223                         }
1224
1225                         if ( fcu) return true;
1226                         base= base->next;
1227                 }
1228                 return false;
1229         }