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