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