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