I made multitude of fixes based on the comments provided online:
[blender.git] / source / blender / collada / AnimationExporter.cpp
1 /*
2 * $Id$
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; */ /* UNUSED */
62
63         //Export transform animations
64         if(ob->adt && ob->adt->action)
65         {
66                 fcu = (FCurve*)ob->adt->action->curves.first;
67
68                 //transform matrix export for bones are temporarily disabled here.
69                 if ( ob->type == OB_ARMATURE )
70                 {
71                         bArmature *arm = (bArmature*)ob->data;
72                         for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next)
73                                 write_bone_animation_matrix(ob, bone);
74                 }
75
76                 while (fcu) {
77                         //for armature animations as objects
78                         if ( ob->type == OB_ARMATURE )
79                                 transformName =  fcu->rna_path;
80                         else 
81                                 transformName = extract_transform_name( fcu->rna_path );
82
83                         if ((!strcmp(transformName, "location") || !strcmp(transformName, "scale")) ||
84                                 (!strcmp(transformName, "rotation_euler") && ob->rotmode == ROT_MODE_EUL)||
85                                 (!strcmp(transformName, "rotation_quaternion"))) 
86                                 dae_animation(ob ,fcu, transformName, false);
87                         fcu = fcu->next;
88                 }
89
90         }
91
92         //Export Lamp parameter animations
93         if( (ob->type == OB_LAMP ) && ((Lamp*)ob ->data)->adt && ((Lamp*)ob ->data)->adt->action )
94         {
95                 fcu = (FCurve*)(((Lamp*)ob ->data)->adt->action->curves.first);
96                 while (fcu) {
97                         transformName = extract_transform_name( fcu->rna_path );
98
99                         if ((!strcmp(transformName, "color")) || (!strcmp(transformName, "spot_size"))|| (!strcmp(transformName, "spot_blend"))||
100                                 (!strcmp(transformName, "distance")) ) 
101                                 dae_animation(ob , fcu, transformName, true );
102                         fcu = fcu->next;
103                 }
104         }
105
106         //Export Camera parameter animations
107         if( (ob->type == OB_CAMERA ) && ((Camera*)ob ->data)->adt && ((Camera*)ob ->data)->adt->action )
108         {               
109                 fcu = (FCurve*)(((Camera*)ob ->data)->adt->action->curves.first);
110                 while (fcu) {
111                         transformName = extract_transform_name( fcu->rna_path );
112
113                         if ((!strcmp(transformName, "lens"))||
114                                 (!strcmp(transformName, "ortho_scale"))||
115                                 (!strcmp(transformName, "clip_end"))||(!strcmp(transformName, "clip_start"))) 
116                                 dae_animation(ob , fcu, transformName, true );
117                         fcu = fcu->next;
118                 }
119         }
120
121         //Export Material parameter animations.
122         for(int a = 0; a < ob->totcol; a++)
123         {
124                 Material *ma = give_current_material(ob, a+1);
125                 if (!ma) continue;
126                 if(ma->adt && ma->adt->action)
127                 {
128                         /* isMatAnim = true; */
129                         fcu = (FCurve*)ma->adt->action->curves.first;
130                         while (fcu) {
131                                 transformName = extract_transform_name( fcu->rna_path );
132
133                                 if ((!strcmp(transformName, "specular_hardness"))||(!strcmp(transformName, "specular_color"))
134                                         ||(!strcmp(transformName, "diffuse_color"))||(!strcmp(transformName, "alpha"))||
135                                         (!strcmp(transformName, "ior"))) 
136                                         dae_animation(ob ,fcu, transformName, true, ma );
137                                 fcu = fcu->next;
138                         }
139                 }
140
141         }
142 }
143
144 //euler sources from quternion sources
145 float * AnimationExporter::get_eul_source_for_quat(Object *ob )
146 {
147         FCurve *fcu = (FCurve*)ob->adt->action->curves.first;
148         const int keys = fcu->totvert;  
149         float *quat = (float*)MEM_callocN(sizeof(float) * fcu->totvert * 4, "quat output source values");  
150         float *eul = (float*)MEM_callocN(sizeof(float) * fcu->totvert * 3, "quat output source values");
151         float temp_quat[4];
152         float temp_eul[3];
153         while(fcu)
154         {
155                 char * transformName = extract_transform_name( fcu->rna_path );
156
157                 if( !strcmp(transformName, "rotation_quaternion") )     { 
158                         for ( int i = 0 ; i < fcu->totvert ; i++){
159                                 *(quat + ( i * 4 ) + fcu->array_index) = fcu->bezt[i].vec[1][1];
160                         }
161                 }
162                 fcu = fcu->next;
163         }
164
165         for ( int i = 0 ; i < keys ; i++){
166                 for ( int j = 0;j<4;j++)
167                         temp_quat[j] = quat[(i*4)+j];
168
169                 quat_to_eul(temp_eul,temp_quat);
170
171                 for (int k = 0;k<3;k++)
172                         eul[i*3 + k] = temp_eul[k];
173
174         }
175         MEM_freeN(quat);
176         return eul;
177
178 }
179
180 //Get proper name for bones
181 std::string AnimationExporter::getObjectBoneName( Object* ob,const FCurve* fcu ) 
182 {
183         //hard-way to derive the bone name from rna_path. Must find more compact method
184         std::string rna_path = std::string(fcu->rna_path);
185
186         char* boneName = strtok((char *)rna_path.c_str(), "\"");
187         boneName = strtok(NULL,"\"");
188
189         if( boneName != NULL )
190                 return /*id_name(ob) + "_" +*/ std::string(boneName);
191         else            
192                 return id_name(ob);
193 }
194
195 //convert f-curves to animation curves and write
196 void AnimationExporter::dae_animation(Object* ob, FCurve *fcu, char* transformName , bool is_param, Material * ma )
197 {
198         const char *axis_name = NULL;
199         char anim_id[200];
200
201         bool has_tangents = false;
202         bool quatRotation = false;
203
204         if ( !strcmp(transformName, "rotation_quaternion") )
205         {
206                 fprintf(stderr, "quaternion rotation curves are not supported. rotation curve will not be exported\n");
207                 quatRotation = true;
208                 return;
209         }
210
211         //axis names for colors
212         else if ( !strcmp(transformName, "color")||!strcmp(transformName, "specular_color")||!strcmp(transformName, "diffuse_color")||
213                 (!strcmp(transformName, "alpha")))
214         {
215                 const char *axis_names[] = {"R", "G", "B"};
216                 if (fcu->array_index < 3)
217                         axis_name = axis_names[fcu->array_index];
218         }
219
220         //axis names for transforms
221         else if ((!strcmp(transformName, "location") || !strcmp(transformName, "scale")) ||
222                 (!strcmp(transformName, "rotation_euler"))||(!strcmp(transformName, "rotation_quaternion")))
223         {
224                 const char *axis_names[] = {"X", "Y", "Z"};
225                 if (fcu->array_index < 3)
226                         axis_name = axis_names[fcu->array_index];
227         }
228
229         //no axis name. single parameter.
230         else{
231                 axis_name = "";
232         }
233
234         std::string ob_name = std::string("null");
235
236         //Create anim Id
237         if (ob->type == OB_ARMATURE) 
238         {   
239                 ob_name =  getObjectBoneName( ob , fcu);
240                 BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s.%s", (char*)translate_id(ob_name).c_str(),
241                         transformName, axis_name);
242         }
243         else 
244         {
245                 if (ma)
246                         ob_name = id_name(ob) + "_material";
247                 else
248                         ob_name = id_name(ob);
249                 BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
250                         fcu->rna_path, axis_name);
251         }
252
253         openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
254
255         // create input source
256         std::string input_id = create_source_from_fcurve(COLLADASW::InputSemantic::INPUT, fcu, anim_id, axis_name);
257
258         // create output source
259         std::string output_id ;
260
261         //quat rotations are skipped for now, because of complications with determining axis.
262         if(quatRotation) 
263         {
264                 float * eul  = get_eul_source_for_quat(ob);
265                 float * eul_axis = (float*)MEM_callocN(sizeof(float) * fcu->totvert, "quat output source values");
266                 for ( int i = 0 ; i< fcu->totvert ; i++)
267                         eul_axis[i] = eul[i*3 + fcu->array_index];
268                 output_id= create_source_from_array(COLLADASW::InputSemantic::OUTPUT, eul_axis , fcu->totvert, quatRotation, anim_id, axis_name);
269                 MEM_freeN(eul);
270                 MEM_freeN(eul_axis);
271         }
272         else 
273         {
274                 output_id= create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name);
275         }
276         // create interpolations source
277         std::string interpolation_id = create_interpolation_source(fcu, anim_id, axis_name, &has_tangents);
278
279         // handle tangents (if required)
280         std::string intangent_id;
281         std::string outtangent_id;
282
283         if (has_tangents) {
284                 // create in_tangent source
285                 intangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::IN_TANGENT, fcu, anim_id, axis_name);
286
287                 // create out_tangent source
288                 outtangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUT_TANGENT, fcu, anim_id, axis_name);
289         }
290
291         std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
292         COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
293         std::string empty;
294         sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
295         sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
296
297         // this input is required
298         sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
299
300         if (has_tangents) {
301                 sampler.addInput(COLLADASW::InputSemantic::IN_TANGENT, COLLADABU::URI(empty, intangent_id));
302                 sampler.addInput(COLLADASW::InputSemantic::OUT_TANGENT, COLLADABU::URI(empty, outtangent_id));
303         }
304
305         addSampler(sampler);
306
307         std::string target ;
308
309         if ( !is_param )
310                 target = translate_id(ob_name)
311                 + "/" + get_transform_sid(fcu->rna_path, -1, axis_name, true);
312         else 
313         {
314                 if ( ob->type == OB_LAMP )
315                         target = get_light_id(ob)
316                         + "/" + get_light_param_sid(fcu->rna_path, -1, axis_name, true);
317
318                 if ( ob->type == OB_CAMERA )
319                         target = get_camera_id(ob)
320                         + "/" + get_camera_param_sid(fcu->rna_path, -1, axis_name, true);
321
322                 if( ma ) 
323                         target = translate_id(id_name(ma)) + "-effect"
324                         +"/common/" /*profile common is only supported */ + get_transform_sid(fcu->rna_path, -1, axis_name, true);
325         }
326         addChannel(COLLADABU::URI(empty, sampler_id), target);
327
328         closeAnimation();
329 }
330
331
332
333 //write bone animations in transform matrix sources
334 void AnimationExporter::write_bone_animation_matrix(Object *ob_arm, Bone *bone)
335 {
336         if (!ob_arm->adt)
337                 return;
338
339         //This will only export animations of bones in deform group.
340         /*if(!is_bone_deform_group(bone))
341         return;*/
342
343         sample_and_write_bone_animation_matrix(ob_arm, bone);
344
345         for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next)
346                 write_bone_animation_matrix(ob_arm, child);
347 }
348
349 bool AnimationExporter::is_bone_deform_group(Bone * bone)
350 {   
351         bool is_def;
352         //Check if current bone is deform
353         if((bone->flag & BONE_NO_DEFORM) == 0 ) return true;
354         //Check child bones
355         else 
356         {   
357                 for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next){
358                         //loop through all the children until deform bone is found, and then return
359                         is_def = is_bone_deform_group(child);
360                         if (is_def) return true;
361                 }
362         }
363         //no deform bone found in children also
364         return false;
365 }
366
367 void AnimationExporter::sample_and_write_bone_animation_matrix(Object *ob_arm, Bone *bone)
368 {
369         bArmature *arm = (bArmature*)ob_arm->data;
370         int flag = arm->flag;
371         std::vector<float> fra;
372         //char prefix[256];
373
374         FCurve* fcu = (FCurve*)ob_arm->adt->action->curves.first;
375         while(fcu)
376         {
377                 std::string bone_name = getObjectBoneName(ob_arm,fcu);
378                 int val = BLI_strcasecmp((char*)bone_name.c_str(),bone->name);
379                 if(val==0) break;
380                 fcu = fcu->next;
381         }
382
383         if(!(fcu)) return; 
384         bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name);
385         if (!pchan)
386                 return;
387
388         find_frames(ob_arm, fra);
389
390         if (flag & ARM_RESTPOS) {
391                 arm->flag &= ~ARM_RESTPOS;
392                 where_is_pose(scene, ob_arm);
393         }
394
395         if (fra.size()) {
396                 dae_baked_animation(fra ,ob_arm, bone );
397         }
398
399         if (flag & ARM_RESTPOS) 
400                 arm->flag = flag;
401         where_is_pose(scene, ob_arm);
402 }
403
404 void AnimationExporter::dae_baked_animation(std::vector<float> &fra, Object *ob_arm , Bone *bone)
405 {
406         std::string ob_name = id_name(ob_arm);
407         std::string bone_name = bone->name;
408         char anim_id[200];
409
410         if (!fra.size())
411                 return;
412
413         BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
414                 (char*)translate_id(bone_name).c_str(), "pose_matrix");
415
416         openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
417
418         // create input source
419         std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, false, anim_id, "");
420
421         // create output source
422         std::string output_id;
423         output_id = create_4x4_source( fra, ob_arm , bone ,  anim_id);
424
425         // create interpolations source
426         std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, "");
427
428         std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
429         COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
430         std::string empty;
431         sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
432         sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
433
434         // TODO create in/out tangents source
435
436         // this input is required
437         sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
438
439         addSampler(sampler);
440
441         std::string target = translate_id(bone_name) + "/transform";
442         addChannel(COLLADABU::URI(empty, sampler_id), target);
443
444         closeAnimation();
445 }
446
447 // dae_bone_animation -> add_bone_animation
448 // (blend this into dae_bone_animation)
449 void AnimationExporter::dae_bone_animation(std::vector<float> &fra, float *values, int tm_type, int axis, std::string ob_name, std::string bone_name)
450 {
451         const char *axis_names[] = {"X", "Y", "Z"};
452         const char *axis_name = NULL;
453         char anim_id[200];
454         bool is_rot = tm_type == 0;
455
456         if (!fra.size())
457                 return;
458
459         char rna_path[200];
460         BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].%s", bone_name.c_str(),
461                 tm_type == 0 ? "rotation_quaternion" : (tm_type == 1 ? "scale" : "location"));
462
463         if (axis > -1)
464                 axis_name = axis_names[axis];
465
466         std::string transform_sid = get_transform_sid(NULL, tm_type, axis_name, false);
467
468         BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
469                 (char*)translate_id(bone_name).c_str(), (char*)transform_sid.c_str());
470
471         openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
472
473         // create input source
474         std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, is_rot, anim_id, axis_name);
475
476         // create output source
477         std::string output_id;
478         if (axis == -1)
479                 output_id = create_xyz_source(values, fra.size(), anim_id);
480         else
481                 output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, values, fra.size(), is_rot, anim_id, axis_name);
482
483         // create interpolations source
484         std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, axis_name);
485
486         std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
487         COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
488         std::string empty;
489         sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
490         sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
491
492         // TODO create in/out tangents source
493
494         // this input is required
495         sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
496
497         addSampler(sampler);
498
499         std::string target = translate_id(ob_name + "_" + bone_name) + "/" + transform_sid;
500         addChannel(COLLADABU::URI(empty, sampler_id), target);
501
502         closeAnimation();
503 }
504
505 float AnimationExporter::convert_time(float frame)
506 {
507         return FRA2TIME(frame);
508 }
509
510 float AnimationExporter::convert_angle(float angle)
511 {
512         return COLLADABU::Math::Utils::radToDegF(angle);
513 }
514
515 std::string AnimationExporter::get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic)
516 {
517         switch(semantic) {
518                 case COLLADASW::InputSemantic::INPUT:
519                         return INPUT_SOURCE_ID_SUFFIX;
520                 case COLLADASW::InputSemantic::OUTPUT:
521                         return OUTPUT_SOURCE_ID_SUFFIX;
522                 case COLLADASW::InputSemantic::INTERPOLATION:
523                         return INTERPOLATION_SOURCE_ID_SUFFIX;
524                 case COLLADASW::InputSemantic::IN_TANGENT:
525                         return INTANGENT_SOURCE_ID_SUFFIX;
526                 case COLLADASW::InputSemantic::OUT_TANGENT:
527                         return OUTTANGENT_SOURCE_ID_SUFFIX;
528                 default:
529                         break;
530         }
531         return "";
532 }
533
534 void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
535                                                                                           COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis, bool transform)
536 {
537         switch(semantic) {
538                 case COLLADASW::InputSemantic::INPUT:
539                         param.push_back("TIME");
540                         break;
541                 case COLLADASW::InputSemantic::OUTPUT:
542                         if (is_rot) {
543                                 param.push_back("ANGLE");
544                         }
545                         else {
546                                 if (axis) {
547                                         param.push_back(axis);
548                                 }
549                                 else 
550                                         if ( transform )
551                                         {
552                                                 param.push_back("TRANSFORM");  
553                                         }else{ //assumes if axis isn't specified all axises are added
554                                                 param.push_back("X");
555                                                 param.push_back("Y");
556                                                 param.push_back("Z");
557                                         }
558                         }
559                         break;
560                 case COLLADASW::InputSemantic::IN_TANGENT:
561                 case COLLADASW::InputSemantic::OUT_TANGENT:
562                         param.push_back("X");
563                         param.push_back("Y");
564                         break;
565                 default:
566                         break;
567         }
568 }
569
570 void AnimationExporter::get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool rotation, float *values, int *length)
571 {
572         switch (semantic) {
573                 case COLLADASW::InputSemantic::INPUT:
574                         *length = 1;
575                         values[0] = convert_time(bezt->vec[1][0]);
576                         break;
577                 case COLLADASW::InputSemantic::OUTPUT:
578                         *length = 1;
579                         if (rotation) {
580                                 values[0] = (bezt->vec[1][1]) * 180.0f/M_PI;
581                         }
582                         else {
583                                 values[0] = bezt->vec[1][1];
584                         }
585                         break;
586
587                 case COLLADASW::InputSemantic::IN_TANGENT:
588                         *length = 2;
589                         values[0] = convert_time(bezt->vec[0][0]);
590                         if (bezt->ipo != BEZT_IPO_BEZ) {
591                                 // We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data
592                                 values[0] = 0;  
593                                 values[1] = 0;  
594                         }
595                         else if (rotation) {
596                                 values[1] = (bezt->vec[0][1]) * 180.0f/M_PI;
597                         } else {
598                                 values[1] = bezt->vec[0][1];
599                         }
600                         break;
601
602                 case COLLADASW::InputSemantic::OUT_TANGENT:
603                         *length = 2;
604                         values[0] = convert_time(bezt->vec[2][0]);
605                         if (bezt->ipo != BEZT_IPO_BEZ) {
606                                 // We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data
607                                 values[0] = 0;  
608                                 values[1] = 0;  
609                         }
610                         else if (rotation) {
611                                 values[1] = (bezt->vec[2][1]) * 180.0f/M_PI;
612                         } else {
613                                 values[1] = bezt->vec[2][1];
614                         }
615                         break;
616                         break;
617                 default:
618                         *length = 0;
619                         break;
620         }
621 }
622
623 std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name)
624 {
625         std::string source_id = anim_id + get_semantic_suffix(semantic);
626
627         //bool is_rotation = !strcmp(fcu->rna_path, "rotation");
628         bool is_angle = false;
629
630         if (strstr(fcu->rna_path, "rotation")) is_angle = true;
631
632         COLLADASW::FloatSourceF source(mSW);
633         source.setId(source_id);
634         source.setArrayId(source_id + ARRAY_ID_SUFFIX);
635         source.setAccessorCount(fcu->totvert);
636
637         switch (semantic) {
638                 case COLLADASW::InputSemantic::INPUT:
639                 case COLLADASW::InputSemantic::OUTPUT:
640                         source.setAccessorStride(1);                    
641                         break;
642                 case COLLADASW::InputSemantic::IN_TANGENT:
643                 case COLLADASW::InputSemantic::OUT_TANGENT:
644                         source.setAccessorStride(2);                    
645                         break;
646                 default:
647                         break;
648         }
649
650
651         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
652         add_source_parameters(param, semantic, is_angle, axis_name, false);
653
654         source.prepareToAppendValues();
655
656         for (unsigned int i = 0; i < fcu->totvert; i++) {
657                 float values[3]; // be careful!
658                 int length = 0;
659                 get_source_values(&fcu->bezt[i], semantic, is_angle, values, &length);
660                 for (int j = 0; j < length; j++)
661                         source.appendValues(values[j]);
662         }
663
664         source.finish();
665
666         return source_id;
667 }
668
669 //Currently called only to get OUTPUT source values ( if rotation and hence the axis is also specified )
670 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)
671 {
672         std::string source_id = anim_id + get_semantic_suffix(semantic);
673
674         COLLADASW::FloatSourceF source(mSW);
675         source.setId(source_id);
676         source.setArrayId(source_id + ARRAY_ID_SUFFIX);
677         source.setAccessorCount(tot);
678         source.setAccessorStride(1);
679
680         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
681         add_source_parameters(param, semantic, is_rot, axis_name,  false);
682
683         source.prepareToAppendValues();
684
685         for (int i = 0; i < tot; i++) {
686                 float val = v[i];
687                 ////if (semantic == COLLADASW::InputSemantic::INPUT)
688                 //      val = convert_time(val);
689                 //else
690                 if (is_rot)
691                         val *= 180.0f / M_PI;
692                 source.appendValues(val);
693         }
694
695         source.finish();
696
697         return source_id;
698 }
699 // only used for sources with INPUT semantic
700 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)
701 {
702         std::string source_id = anim_id + get_semantic_suffix(semantic);
703
704         COLLADASW::FloatSourceF source(mSW);
705         source.setId(source_id);
706         source.setArrayId(source_id + ARRAY_ID_SUFFIX);
707         source.setAccessorCount(fra.size());
708         source.setAccessorStride(1);
709
710         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
711         add_source_parameters(param, semantic, is_rot, axis_name, false);
712
713         source.prepareToAppendValues();
714
715         std::vector<float>::iterator it;
716         for (it = fra.begin(); it != fra.end(); it++) {
717                 float val = *it;
718                 //if (semantic == COLLADASW::InputSemantic::INPUT)
719                 val = convert_time(val);
720                 /*else if (is_rot)
721                 val = convert_angle(val);*/
722                 source.appendValues(val);
723         }
724
725         source.finish();
726
727         return source_id;
728 }
729
730 std::string AnimationExporter::create_4x4_source(std::vector<float> &frames , Object * ob_arm, Bone *bone , const std::string& anim_id)
731 {
732         COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
733         std::string source_id = anim_id + get_semantic_suffix(semantic);
734
735         COLLADASW::Float4x4Source source(mSW);
736         source.setId(source_id);
737         source.setArrayId(source_id + ARRAY_ID_SUFFIX);
738         source.setAccessorCount(frames.size());
739         source.setAccessorStride(16);
740
741         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
742         add_source_parameters(param, semantic, false, NULL, true);
743
744         source.prepareToAppendValues();
745
746         bPoseChannel *parchan = NULL;
747         bPoseChannel *pchan = NULL;
748         bPose *pose = ob_arm->pose;
749
750         pchan = get_pose_channel(pose, bone->name);
751
752         if (!pchan)
753                 return "";
754
755         parchan = pchan->parent;
756
757         enable_fcurves(ob_arm->adt->action, bone->name);
758
759         std::vector<float>::iterator it;
760         int j = 0;
761         for (it = frames.begin(); it != frames.end(); it++) {
762                 float mat[4][4], ipar[4][4];
763
764                 float ctime = bsystem_time(scene, ob_arm, *it, 0.0f);
765
766                 BKE_animsys_evaluate_animdata(scene , &ob_arm->id, ob_arm->adt, ctime, ADT_RECALC_ANIM);
767                 where_is_pose_bone(scene, ob_arm, pchan, ctime, 1);
768
769                 // compute bone local mat
770                 if (bone->parent) {
771                         invert_m4_m4(ipar, parchan->pose_mat);
772                         mul_m4_m4m4(mat, pchan->pose_mat, ipar);
773                 }
774                 else
775                         copy_m4_m4(mat, pchan->pose_mat);
776                 UnitConverter converter;
777
778                 float outmat[4][4];
779                 converter.mat4_to_dae(outmat,mat);
780
781
782                 source.appendValues(outmat);
783
784
785                 j++;
786         }
787
788         enable_fcurves(ob_arm->adt->action, NULL);
789
790         source.finish();
791
792         return source_id;
793 }
794 // only used for sources with OUTPUT semantic ( locations and scale)
795 std::string AnimationExporter::create_xyz_source(float *v, int tot, const std::string& anim_id)
796 {
797         COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
798         std::string source_id = anim_id + get_semantic_suffix(semantic);
799
800         COLLADASW::FloatSourceF source(mSW);
801         source.setId(source_id);
802         source.setArrayId(source_id + ARRAY_ID_SUFFIX);
803         source.setAccessorCount(tot);
804         source.setAccessorStride(3);
805
806         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
807         add_source_parameters(param, semantic, false, NULL, false);
808
809         source.prepareToAppendValues();
810
811         for (int i = 0; i < tot; i++) {
812                 source.appendValues(*v, *(v + 1), *(v + 2));
813                 v += 3;
814         }
815
816         source.finish();
817
818         return source_id;
819 }
820
821 std::string AnimationExporter::create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents)
822 {
823         std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
824
825         COLLADASW::NameSource source(mSW);
826         source.setId(source_id);
827         source.setArrayId(source_id + ARRAY_ID_SUFFIX);
828         source.setAccessorCount(fcu->totvert);
829         source.setAccessorStride(1);
830
831         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
832         param.push_back("INTERPOLATION");
833
834         source.prepareToAppendValues();
835
836         *has_tangents = false;
837
838         for (unsigned int i = 0; i < fcu->totvert; i++) {
839                 if (fcu->bezt[i].ipo==BEZT_IPO_BEZ) {
840                         source.appendValues(BEZIER_NAME);
841                         *has_tangents = true;
842                 } else if (fcu->bezt[i].ipo==BEZT_IPO_CONST) {
843                         source.appendValues(STEP_NAME);
844                 } else { // BEZT_IPO_LIN
845                         source.appendValues(LINEAR_NAME);
846                 }
847         }
848         // unsupported? -- HERMITE, CARDINAL, BSPLINE, NURBS
849
850         source.finish();
851
852         return source_id;
853 }
854
855 std::string AnimationExporter::fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name)
856 {
857         std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
858
859         COLLADASW::NameSource source(mSW);
860         source.setId(source_id);
861         source.setArrayId(source_id + ARRAY_ID_SUFFIX);
862         source.setAccessorCount(tot);
863         source.setAccessorStride(1);
864
865         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
866         param.push_back("INTERPOLATION");
867
868         source.prepareToAppendValues();
869
870         for (int i = 0; i < tot; i++) {
871                 source.appendValues(LINEAR_NAME);
872         }
873
874         source.finish();
875
876         return source_id;
877 }
878
879 std::string AnimationExporter::get_light_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
880 {
881         std::string tm_name;
882         // when given rna_path, determine tm_type from it
883         if (rna_path) {
884                 char *name = extract_transform_name(rna_path);
885
886                 if (!strcmp(name, "color"))
887                         tm_type = 1;
888                 else if (!strcmp(name, "spot_size"))
889                         tm_type = 2;
890                 else if (!strcmp(name, "spot_blend"))
891                         tm_type = 3;
892                 else if (!strcmp(name, "distance"))
893                         tm_type = 4;
894                 else
895                         tm_type = -1;
896         }
897
898         switch (tm_type) {
899                 case 1:
900                         tm_name = "color";
901                         break;
902                 case 2:
903                         tm_name = "fall_off_angle";
904                         break;
905                 case 3:
906                         tm_name = "fall_off_exponent";
907                         break;
908                 case 4:
909                         tm_name = "blender/blender_dist";
910                         break;
911
912                 default:
913                         tm_name = "";
914                         break;
915         }
916
917         if (tm_name.size()) {
918                 if (axis_name[0])
919                         return tm_name + "." + std::string(axis_name);
920                 else 
921                         return tm_name;
922         }
923
924         return std::string("");
925 }
926
927 std::string AnimationExporter::get_camera_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
928 {
929         std::string tm_name;
930         // when given rna_path, determine tm_type from it
931         if (rna_path) {
932                 char *name = extract_transform_name(rna_path);
933
934                 if (!strcmp(name, "lens"))
935                         tm_type = 0;
936                 else if (!strcmp(name, "ortho_scale"))
937                         tm_type = 1;
938                 else if (!strcmp(name, "clip_end"))
939                         tm_type = 2;
940                 else if (!strcmp(name, "clip_start"))
941                         tm_type = 3;
942
943                 else
944                         tm_type = -1;
945         }
946
947         switch (tm_type) {
948                 case 0:
949                         tm_name = "xfov";
950                         break;
951                 case 1:
952                         tm_name = "xmag";
953                         break;
954                 case 2:
955                         tm_name = "zfar";
956                         break;
957                 case 3:
958                         tm_name = "znear";
959                         break;
960
961                 default:
962                         tm_name = "";
963                         break;
964         }
965
966         if (tm_name.size()) {
967                 if (axis_name[0])
968                         return tm_name + "." + std::string(axis_name);
969                 else 
970                         return tm_name;
971         }
972
973         return std::string("");
974 }
975
976 // Assign sid of the animated parameter or transform 
977 // for rotation, axis name is always appended and the value of append_axis is ignored
978 std::string AnimationExporter::get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
979 {
980         std::string tm_name;
981         bool is_rotation =false;
982         // when given rna_path, determine tm_type from it
983         if (rna_path) {
984                 char *name = extract_transform_name(rna_path);
985
986                 if (!strcmp(name, "rotation_euler"))
987                         tm_type = 0;
988                 else if (!strcmp(name, "rotation_quaternion"))
989                         tm_type = 1;
990                 else if (!strcmp(name, "scale"))
991                         tm_type = 2;
992                 else if (!strcmp(name, "location"))
993                         tm_type = 3;
994                 else if (!strcmp(name, "specular_hardness"))
995                         tm_type = 4;
996                 else if (!strcmp(name, "specular_color"))
997                         tm_type = 5;
998                 else if (!strcmp(name, "diffuse_color"))
999                         tm_type = 6;
1000                 else if (!strcmp(name, "alpha"))
1001                         tm_type = 7;
1002                 else if (!strcmp(name, "ior"))
1003                         tm_type = 8;
1004
1005                 else
1006                         tm_type = -1;
1007         }
1008
1009         switch (tm_type) {
1010                 case 0:
1011                 case 1:
1012                         tm_name = "rotation";
1013                         is_rotation = true;
1014                         break;
1015                 case 2:
1016                         tm_name = "scale";
1017                         break;
1018                 case 3:
1019                         tm_name = "location";
1020                         break;
1021                 case 4:
1022                         tm_name = "shininess";
1023                         break;
1024                 case 5:
1025                         tm_name = "specular";
1026                         break;
1027                 case 6:
1028                         tm_name = "diffuse";
1029                         break;  
1030                 case 7:
1031                         tm_name = "transparency";
1032                         break;  
1033                 case 8:
1034                         tm_name = "index_of_refraction";
1035                         break;  
1036
1037                 default:
1038                         tm_name = "";
1039                         break;
1040         }
1041
1042         if (tm_name.size()) {
1043                 if (is_rotation)
1044                         return tm_name + std::string(axis_name) + ".ANGLE";
1045                 else
1046                         if (axis_name[0])
1047                                 return tm_name + "." + std::string(axis_name);
1048                         else 
1049                                 return tm_name;
1050         }
1051
1052         return std::string("");
1053 }
1054
1055 char* AnimationExporter::extract_transform_name(char *rna_path)
1056 {
1057         char *dot = strrchr(rna_path, '.');
1058         return dot ? (dot + 1) : rna_path;
1059 }
1060
1061 //find keyframes of all the objects animations
1062 void AnimationExporter::find_frames(Object *ob, std::vector<float> &fra)
1063 {
1064         FCurve *fcu= (FCurve*)ob->adt->action->curves.first;
1065
1066         for (; fcu; fcu = fcu->next) {
1067
1068                 for (unsigned int i = 0; i < fcu->totvert; i++) {
1069                         float f = fcu->bezt[i].vec[1][0];
1070                         if (std::find(fra.begin(), fra.end(), f) == fra.end())   
1071                                 fra.push_back(f);
1072                 }
1073         }
1074
1075         // keep the keys in ascending order
1076         std::sort(fra.begin(), fra.end());
1077 }
1078
1079
1080
1081 // enable fcurves driving a specific bone, disable all the rest
1082 // if bone_name = NULL enable all fcurves
1083 void AnimationExporter::enable_fcurves(bAction *act, char *bone_name)
1084 {
1085         FCurve *fcu;
1086         char prefix[200];
1087
1088         if (bone_name)
1089                 BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name);
1090
1091         for (fcu = (FCurve*)act->curves.first; fcu; fcu = fcu->next) {
1092                 if (bone_name) {
1093                         if (!strncmp(fcu->rna_path, prefix, strlen(prefix)))
1094                                 fcu->flag &= ~FCURVE_DISABLED;
1095                         else
1096                                 fcu->flag |= FCURVE_DISABLED;
1097                 }
1098                 else {
1099                         fcu->flag &= ~FCURVE_DISABLED;
1100                 }
1101         }
1102 }
1103
1104 bool AnimationExporter::hasAnimations(Scene *sce)
1105 {
1106         Base *base= (Base*) sce->base.first;
1107
1108         while(base) {
1109                 Object *ob = base->object;
1110
1111                 FCurve *fcu = 0;
1112                 //Check for object transform animations
1113                 if(ob->adt && ob->adt->action)
1114                         fcu = (FCurve*)ob->adt->action->curves.first;
1115                 //Check for Lamp parameter animations
1116                 else if( (ob->type == OB_LAMP ) && ((Lamp*)ob ->data)->adt && ((Lamp*)ob ->data)->adt->action )
1117                         fcu = (FCurve*)(((Lamp*)ob ->data)->adt->action->curves.first);
1118                 //Check for Camera parameter animations
1119                 else if( (ob->type == OB_CAMERA ) && ((Camera*)ob ->data)->adt && ((Camera*)ob ->data)->adt->action )
1120                         fcu = (FCurve*)(((Camera*)ob ->data)->adt->action->curves.first);
1121
1122                 //Check Material Effect parameter animations.
1123                 for(int a = 0; a < ob->totcol; a++)
1124                 {
1125                         Material *ma = give_current_material(ob, a+1);
1126                         if (!ma) continue;
1127                         if(ma->adt && ma->adt->action)
1128                         {
1129                                 fcu = (FCurve*)ma->adt->action->curves.first;   
1130                         }
1131                 }
1132
1133                 if ( fcu) 
1134                         return true;
1135                 base= base->next;
1136         }
1137         return false;
1138 }
1139
1140 //------------------------------- Not used in the new system.--------------------------------------------------------
1141 void AnimationExporter::find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode)
1142 {
1143         if (rotmode > 0)
1144                 find_frames(ob, fra, prefix, "rotation_euler");
1145         else if (rotmode == ROT_MODE_QUAT)
1146                 find_frames(ob, fra, prefix, "rotation_quaternion");
1147         /*else if (rotmode == ROT_MODE_AXISANGLE)
1148         ;*/
1149 }
1150
1151 void AnimationExporter::find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name)
1152 {
1153         FCurve *fcu= (FCurve*)ob->adt->action->curves.first;
1154
1155         for (; fcu; fcu = fcu->next) {
1156                 if (prefix && strncmp(prefix, fcu->rna_path, strlen(prefix)))
1157                         continue;
1158
1159                 char *name = extract_transform_name(fcu->rna_path);
1160                 if (!strcmp(name, tm_name)) {
1161                         for (unsigned int i = 0; i < fcu->totvert; i++) {
1162                                 float f = fcu->bezt[i].vec[1][0];
1163                                 if (std::find(fra.begin(), fra.end(), f) == fra.end())   
1164                                         fra.push_back(f);
1165                         }
1166                 }
1167         }
1168
1169         // keep the keys in ascending order
1170         std::sort(fra.begin(), fra.end());
1171 }
1172
1173 void AnimationExporter::write_bone_animation(Object *ob_arm, Bone *bone)
1174 {
1175         if (!ob_arm->adt)
1176                 return;
1177
1178         //write bone animations for 3 transform types
1179         //i=0 --> rotations
1180         //i=1 --> scale
1181         //i=2 --> location
1182         for (int i = 0; i < 3; i++)
1183                 sample_and_write_bone_animation(ob_arm, bone, i);
1184
1185         for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next)
1186                 write_bone_animation(ob_arm, child);
1187 }
1188
1189 void AnimationExporter::sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type)
1190 {
1191         bArmature *arm = (bArmature*)ob_arm->data;
1192         int flag = arm->flag;
1193         std::vector<float> fra;
1194         char prefix[256];
1195
1196         BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone->name);
1197
1198         bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name);
1199         if (!pchan)
1200                 return;
1201         //Fill frame array with key frame values framed at @param:transform_type
1202         switch (transform_type) {
1203                 case 0:
1204                         find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode);
1205                         break;
1206                 case 1:
1207                         find_frames(ob_arm, fra, prefix, "scale");
1208                         break;
1209                 case 2:
1210                         find_frames(ob_arm, fra, prefix, "location");
1211                         break;
1212                 default:
1213                         return;
1214         }
1215
1216         // exit rest position
1217         if (flag & ARM_RESTPOS) {
1218                 arm->flag &= ~ARM_RESTPOS;
1219                 where_is_pose(scene, ob_arm);
1220         }
1221         //v array will hold all values which will be exported. 
1222         if (fra.size()) {
1223                 float *values = (float*)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames");
1224                 sample_animation(values, fra, transform_type, bone, ob_arm, pchan);
1225
1226                 if (transform_type == 0) {
1227                         // write x, y, z curves separately if it is rotation
1228                         float *axisValues = (float*)MEM_callocN(sizeof(float) * fra.size(), "temp. anim frames");   
1229
1230                         for (int i = 0; i < 3; i++) {
1231                                 for (unsigned int j = 0; j < fra.size(); j++)
1232                                         axisValues[j] = values[j * 3 + i];
1233
1234                                 dae_bone_animation(fra, axisValues, transform_type, i, id_name(ob_arm), bone->name);
1235                         }
1236                         MEM_freeN(axisValues);
1237                 }
1238                 else {
1239                         // write xyz at once if it is location or scale
1240                         dae_bone_animation(fra, values, transform_type, -1, id_name(ob_arm), bone->name);
1241                 }
1242
1243                 MEM_freeN(values);
1244         }
1245
1246         // restore restpos
1247         if (flag & ARM_RESTPOS) 
1248                 arm->flag = flag;
1249         where_is_pose(scene, ob_arm);
1250 }
1251
1252 void AnimationExporter::sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm, bPoseChannel *pchan)
1253 {
1254         bPoseChannel *parchan = NULL;
1255         bPose *pose = ob_arm->pose;
1256
1257         pchan = get_pose_channel(pose, bone->name);
1258
1259         if (!pchan)
1260                 return;
1261
1262         parchan = pchan->parent;
1263
1264         enable_fcurves(ob_arm->adt->action, bone->name);
1265
1266         std::vector<float>::iterator it;
1267         for (it = frames.begin(); it != frames.end(); it++) {
1268                 float mat[4][4], ipar[4][4];
1269
1270                 float ctime = bsystem_time(scene, ob_arm, *it, 0.0f);
1271
1272
1273                 BKE_animsys_evaluate_animdata(scene , &ob_arm->id, ob_arm->adt, ctime, ADT_RECALC_ANIM);
1274                 where_is_pose_bone(scene, ob_arm, pchan, ctime, 1);
1275
1276                 // compute bone local mat
1277                 if (bone->parent) {
1278                         invert_m4_m4(ipar, parchan->pose_mat);
1279                         mul_m4_m4m4(mat, pchan->pose_mat, ipar);
1280                 }
1281                 else
1282                         copy_m4_m4(mat, pchan->pose_mat);
1283
1284                 switch (type) {
1285                         case 0:
1286                                 mat4_to_eul(v, mat);
1287                                 break;
1288                         case 1:
1289                                 mat4_to_size(v, mat);
1290                                 break;
1291                         case 2:
1292                                 copy_v3_v3(v, mat[3]);
1293                                 break;
1294                 }
1295
1296                 v += 3;
1297         }
1298
1299         enable_fcurves(ob_arm->adt->action, NULL);
1300 }