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