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