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