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