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