COLLADA: report #32237 fixed Camera exporter and Importer to use correct camera...
[blender.git] / source / blender / collada / AnimationExporter.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed.
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 #include "GeometryExporter.h"
24 #include "AnimationExporter.h"
25 #include "MaterialExporter.h"
26
27 template<class Functor>
28 void forEachObjectInExportSet(Scene *sce, Functor &f, LinkNode *export_set)
29 {
30         LinkNode *node;
31         for (node = export_set; node; node = node->next) {
32                 Object *ob = (Object *)node->link;
33                 f(ob);
34         }
35 }
36
37 void AnimationExporter::exportAnimations(Scene *sce)
38 {
39         if (hasAnimations(sce)) {
40                 this->scene = sce;
41
42                 openLibrary();
43
44                 forEachObjectInExportSet(sce, *this, this->export_settings->export_set);
45
46                 closeLibrary();
47         }
48 }
49
50 // called for each exported object
51 void AnimationExporter::operator()(Object *ob)
52 {
53         FCurve *fcu;
54         char *transformName;
55         /* bool isMatAnim = false; */ /* UNUSED */
56
57         //Export transform animations
58         if (ob->adt && ob->adt->action) {
59                 fcu = (FCurve *)ob->adt->action->curves.first;
60
61                 //transform matrix export for bones are temporarily disabled here.
62                 if (ob->type == OB_ARMATURE) {
63                         bArmature *arm = (bArmature *)ob->data;
64                         for (Bone *bone = (Bone *)arm->bonebase.first; bone; bone = bone->next)
65                                 write_bone_animation_matrix(ob, bone);
66                 }
67
68                 while (fcu) {
69                         //for armature animations as objects
70                         if (ob->type == OB_ARMATURE)
71                                 transformName =  fcu->rna_path;
72                         else 
73                                 transformName = extract_transform_name(fcu->rna_path);
74
75                         if ((!strcmp(transformName, "location") || !strcmp(transformName, "scale")) ||
76                             (!strcmp(transformName, "rotation_euler") && ob->rotmode == ROT_MODE_EUL) ||
77                             (!strcmp(transformName, "rotation_quaternion")))
78                         {
79                                 dae_animation(ob, fcu, transformName, false);
80                         }
81                         fcu = fcu->next;
82                 }
83
84         }
85
86         //Export Lamp parameter animations
87         if ( (ob->type == OB_LAMP) && ((Lamp *)ob->data)->adt && ((Lamp *)ob->data)->adt->action) {
88                 fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first);
89                 while (fcu) {
90                         transformName = extract_transform_name(fcu->rna_path);
91
92                         if ((!strcmp(transformName, "color")) || (!strcmp(transformName, "spot_size")) ||
93                             (!strcmp(transformName, "spot_blend")) || (!strcmp(transformName, "distance")))
94                         {
95                                 dae_animation(ob, fcu, transformName, true);
96                         }
97                         fcu = fcu->next;
98                 }
99         }
100
101         //Export Camera parameter animations
102         if ( (ob->type == OB_CAMERA) && ((Camera *)ob->data)->adt && ((Camera *)ob->data)->adt->action) {
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")) || 
110                                 (!strcmp(transformName, "clip_start")))
111                         {
112                                 dae_animation(ob, fcu, transformName, true);
113                         }
114                         fcu = fcu->next;
115                 }
116         }
117
118         //Export Material parameter animations.
119         for (int a = 0; a < ob->totcol; a++) {
120                 Material *ma = give_current_material(ob, a + 1);
121                 if (!ma) continue;
122                 if (ma->adt && ma->adt->action) {
123                         /* isMatAnim = true; */
124                         fcu = (FCurve *)ma->adt->action->curves.first;
125                         while (fcu) {
126                                 transformName = extract_transform_name(fcu->rna_path);
127
128                                 if ((!strcmp(transformName, "specular_hardness")) || (!strcmp(transformName, "specular_color")) ||
129                                     (!strcmp(transformName, "diffuse_color")) || (!strcmp(transformName, "alpha")) ||
130                                     (!strcmp(transformName, "ior")))
131                                 {
132                                         dae_animation(ob, fcu, transformName, true, ma);
133                                 }
134                                 fcu = fcu->next;
135                         }
136                 }
137
138         }
139 }
140
141 //euler sources from quternion sources
142 float *AnimationExporter::get_eul_source_for_quat(Object *ob)
143 {
144         FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
145         const int keys = fcu->totvert;  
146         float *quat = (float *)MEM_callocN(sizeof(float) * fcu->totvert * 4, "quat output source values");
147         float *eul = (float *)MEM_callocN(sizeof(float) * fcu->totvert * 3, "quat output source values");
148         float temp_quat[4];
149         float temp_eul[3];
150         while (fcu) {
151                 char *transformName = extract_transform_name(fcu->rna_path);
152
153                 if (!strcmp(transformName, "rotation_quaternion") ) {
154                         for (int i = 0; i < fcu->totvert; i++) {
155                                 *(quat + (i * 4) + fcu->array_index) = fcu->bezt[i].vec[1][1];
156                         }
157                 }
158                 fcu = fcu->next;
159         }
160
161         for (int i = 0; i < keys; i++) {
162                 for (int j = 0; j < 4; j++)
163                         temp_quat[j] = quat[(i * 4) + j];
164
165                 quat_to_eul(temp_eul, temp_quat);
166
167                 for (int k = 0; k < 3; k++)
168                         eul[i * 3 + k] = temp_eul[k];
169
170         }
171         MEM_freeN(quat);
172         return eul;
173
174 }
175
176 //Get proper name for bones
177 std::string AnimationExporter::getObjectBoneName(Object *ob, const FCurve *fcu)
178 {
179         //hard-way to derive the bone name from rna_path. Must find more compact method
180         std::string rna_path = std::string(fcu->rna_path);
181
182         char *boneName = strtok((char *)rna_path.c_str(), "\"");
183         boneName = strtok(NULL, "\"");
184
185         if (boneName != NULL)
186                 return /*id_name(ob) + "_" +*/ std::string(boneName);
187         else            
188                 return id_name(ob);
189 }
190
191 //convert f-curves to animation curves and write
192 void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformName, bool is_param, Material *ma)
193 {
194         const char *axis_name = NULL;
195         char anim_id[200];
196
197         bool has_tangents = false;
198         bool quatRotation = false;
199
200         if (!strcmp(transformName, "rotation_quaternion") ) {
201                 fprintf(stderr, "quaternion rotation curves are not supported. rotation curve will not be exported\n");
202                 quatRotation = true;
203                 return;
204         }
205
206         //axis names for colors
207         else if (!strcmp(transformName, "color") ||
208                          !strcmp(transformName, "specular_color") ||
209                          !strcmp(transformName, "diffuse_color") ||
210                  !strcmp(transformName, "alpha"))
211         {
212                 const char *axis_names[] = {"R", "G", "B"};
213                 if (fcu->array_index < 3)
214                         axis_name = axis_names[fcu->array_index];
215         }
216
217         //axis names for transforms
218         else if (!strcmp(transformName, "location") ||
219                          !strcmp(transformName, "scale") ||
220                  !strcmp(transformName, "rotation_euler") ||
221                          !strcmp(transformName, "rotation_quaternion"))
222         {
223                 const char *axis_names[] = {"X", "Y", "Z"};
224                 if (fcu->array_index < 3)
225                         axis_name = axis_names[fcu->array_index];
226         }
227         else {
228                 /* no axis name. single parameter */
229                 axis_name = "";
230         }
231
232         std::string ob_name = std::string("null");
233
234         //Create anim Id
235         if (ob->type == OB_ARMATURE) {
236                 ob_name =  getObjectBoneName(ob, fcu);
237                 BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s.%s", (char *)translate_id(ob_name).c_str(),
238                              transformName, axis_name);
239         }
240         else {
241                 if (ma)
242                         ob_name = id_name(ob) + "_material";
243                 else
244                         ob_name = id_name(ob);
245                 BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char *)translate_id(ob_name).c_str(),
246                              fcu->rna_path, axis_name);
247         }
248
249         openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
250
251         // create input source
252         std::string input_id = create_source_from_fcurve(COLLADASW::InputSemantic::INPUT, fcu, anim_id, axis_name);
253
254         // create output source
255         std::string output_id;
256
257         //quat rotations are skipped for now, because of complications with determining axis.
258         if (quatRotation) {
259                 float *eul  = get_eul_source_for_quat(ob);
260                 float *eul_axis = (float *)MEM_callocN(sizeof(float) * fcu->totvert, "quat output source values");
261                 for (int i = 0; i < fcu->totvert; i++) {
262                         eul_axis[i] = eul[i * 3 + fcu->array_index];
263                 }
264                 output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, eul_axis, fcu->totvert, quatRotation, anim_id, axis_name);
265                 MEM_freeN(eul);
266                 MEM_freeN(eul_axis);
267         }
268         else if(!strcmp(transformName, "lens") && (ob->type == OB_CAMERA)) {
269                 output_id = create_lens_source_from_fcurve((Camera *) ob->data, COLLADASW::InputSemantic::OUTPUT, fcu, anim_id);
270         }
271         else {
272                 output_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name);
273         }
274
275         // create interpolations source
276         std::string interpolation_id = create_interpolation_source(fcu, anim_id, axis_name, &has_tangents);
277
278         // handle tangents (if required)
279         std::string intangent_id;
280         std::string outtangent_id;
281
282         if (has_tangents) {
283                 // create in_tangent source
284                 intangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::IN_TANGENT, fcu, anim_id, axis_name);
285
286                 // create out_tangent source
287                 outtangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUT_TANGENT, fcu, anim_id, axis_name);
288         }
289
290         std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
291         COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
292         std::string empty;
293         sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
294         sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
295
296         // this input is required
297         sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
298
299         if (has_tangents) {
300                 sampler.addInput(COLLADASW::InputSemantic::IN_TANGENT, COLLADABU::URI(empty, intangent_id));
301                 sampler.addInput(COLLADASW::InputSemantic::OUT_TANGENT, COLLADABU::URI(empty, outtangent_id));
302         }
303
304         addSampler(sampler);
305
306         std::string target;
307
308         if (!is_param)
309                 target = translate_id(ob_name) +
310                          "/" + get_transform_sid(fcu->rna_path, -1, axis_name, true);
311         else {
312                 if (ob->type == OB_LAMP)
313                         target = get_light_id(ob) +
314                                  "/" + get_light_param_sid(fcu->rna_path, -1, axis_name, true);
315
316                 if (ob->type == OB_CAMERA)
317                         target = get_camera_id(ob) +
318                                  "/" + get_camera_param_sid(fcu->rna_path, -1, axis_name, true);
319
320                 if (ma)
321                         target = translate_id(id_name(ma)) + "-effect" +
322                                  "/common/" /*profile common is only supported */ + get_transform_sid(fcu->rna_path, -1, axis_name, true);
323         }
324         addChannel(COLLADABU::URI(empty, sampler_id), target);
325
326         closeAnimation();
327 }
328
329
330
331 //write bone animations in transform matrix sources
332 void AnimationExporter::write_bone_animation_matrix(Object *ob_arm, Bone *bone)
333 {
334         if (!ob_arm->adt)
335                 return;
336
337         //This will only export animations of bones in deform group.
338         /* if (!is_bone_deform_group(bone)) return; */
339
340         sample_and_write_bone_animation_matrix(ob_arm, bone);
341
342         for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next)
343                 write_bone_animation_matrix(ob_arm, child);
344 }
345
346 bool AnimationExporter::is_bone_deform_group(Bone *bone)
347 {   
348         bool is_def;
349         //Check if current bone is deform
350         if ((bone->flag & BONE_NO_DEFORM) == 0) return true;
351         //Check child bones
352         else {
353                 for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
354                         //loop through all the children until deform bone is found, and then return
355                         is_def = is_bone_deform_group(child);
356                         if (is_def) return true;
357                 }
358         }
359         //no deform bone found in children also
360         return false;
361 }
362
363 void AnimationExporter::sample_and_write_bone_animation_matrix(Object *ob_arm, Bone *bone)
364 {
365         bArmature *arm = (bArmature *)ob_arm->data;
366         int flag = arm->flag;
367         std::vector<float> fra;
368         //char prefix[256];
369
370         FCurve *fcu = (FCurve *)ob_arm->adt->action->curves.first;
371         while (fcu) {
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 = BKE_pose_channel_find_name(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                 BKE_pose_where_is(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         BKE_pose_where_is(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                                         param.push_back("TRANSFORM");
547                                 }
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 is_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 (is_rotation) {
575                                 values[0] = RAD2DEGF(bezt->vec[1][1]);
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 (is_rotation) {
591                                 values[1] = RAD2DEGF(bezt->vec[0][1]);
592                         }
593                         else {
594                                 values[1] = bezt->vec[0][1];
595                         }
596                         break;
597
598                 case COLLADASW::InputSemantic::OUT_TANGENT:
599                         *length = 2;
600                         values[0] = convert_time(bezt->vec[2][0]);
601                         if (bezt->ipo != BEZT_IPO_BEZ) {
602                                 // We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data
603                                 values[0] = 0;  
604                                 values[1] = 0;  
605                         }
606                         else if (is_rotation) {
607                                 values[1] = RAD2DEGF(bezt->vec[2][1]);
608                         }
609                         else {
610                                 values[1] = bezt->vec[2][1];
611                         }
612                         break;
613                         break;
614                 default:
615                         *length = 0;
616                         break;
617         }
618 }
619
620 std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name)
621 {
622         std::string source_id = anim_id + get_semantic_suffix(semantic);
623
624         //bool is_rotation = !strcmp(fcu->rna_path, "rotation");
625         bool is_angle = false;
626
627         if (strstr(fcu->rna_path, "rotation")) is_angle = true;
628
629         COLLADASW::FloatSourceF source(mSW);
630         source.setId(source_id);
631         source.setArrayId(source_id + ARRAY_ID_SUFFIX);
632         source.setAccessorCount(fcu->totvert);
633
634         switch (semantic) {
635                 case COLLADASW::InputSemantic::INPUT:
636                 case COLLADASW::InputSemantic::OUTPUT:
637                         source.setAccessorStride(1);                    
638                         break;
639                 case COLLADASW::InputSemantic::IN_TANGENT:
640                 case COLLADASW::InputSemantic::OUT_TANGENT:
641                         source.setAccessorStride(2);                    
642                         break;
643                 default:
644                         break;
645         }
646
647
648         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
649         add_source_parameters(param, semantic, is_angle, axis_name, false);
650
651         source.prepareToAppendValues();
652
653         for (unsigned int i = 0; i < fcu->totvert; i++) {
654                 float values[3]; // be careful!
655                 int length = 0;
656                 get_source_values(&fcu->bezt[i], semantic, is_angle, values, &length);
657                 for (int j = 0; j < length; j++)
658                         source.appendValues(values[j]);
659         }
660
661         source.finish();
662
663         return source_id;
664 }
665
666 /*
667  * Similar to create_source_from_fcurve, but adds conversion of lens
668  * animation data from focal length to FOV.
669  */
670 std::string AnimationExporter::create_lens_source_from_fcurve(Camera *cam, COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id)
671 {
672         std::string source_id = anim_id + get_semantic_suffix(semantic);
673
674         COLLADASW::FloatSourceF source(mSW);
675         source.setId(source_id);
676         source.setArrayId(source_id + ARRAY_ID_SUFFIX);
677         source.setAccessorCount(fcu->totvert);
678
679         source.setAccessorStride(1);
680
681         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
682         add_source_parameters(param, semantic, false, "", false);
683
684         source.prepareToAppendValues();
685
686         for (unsigned int i = 0; i < fcu->totvert; i++) {
687                 float values[3]; // be careful!
688                 int length = 0;
689                 get_source_values(&fcu->bezt[i], semantic, false, values, &length);
690                 for (int j = 0; j < length; j++)
691                 {
692                         float val = RAD2DEGF(focallength_to_fov(values[j], cam->sensor_x));
693                         source.appendValues(val);
694                 }
695         }
696
697         source.finish();
698
699         return source_id;
700 }
701
702
703
704 //Currently called only to get OUTPUT source values ( if rotation and hence the axis is also specified )
705 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)
706 {
707         std::string source_id = anim_id + get_semantic_suffix(semantic);
708
709         COLLADASW::FloatSourceF source(mSW);
710         source.setId(source_id);
711         source.setArrayId(source_id + ARRAY_ID_SUFFIX);
712         source.setAccessorCount(tot);
713         source.setAccessorStride(1);
714
715         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
716         add_source_parameters(param, semantic, is_rot, axis_name,  false);
717
718         source.prepareToAppendValues();
719
720         for (int i = 0; i < tot; i++) {
721                 float val = v[i];
722                 ////if (semantic == COLLADASW::InputSemantic::INPUT)
723                 //      val = convert_time(val);
724                 //else
725                 if (is_rot)
726                         val = RAD2DEGF(val);
727                 source.appendValues(val);
728         }
729
730         source.finish();
731
732         return source_id;
733 }
734 // only used for sources with INPUT semantic
735 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)
736 {
737         std::string source_id = anim_id + get_semantic_suffix(semantic);
738
739         COLLADASW::FloatSourceF source(mSW);
740         source.setId(source_id);
741         source.setArrayId(source_id + ARRAY_ID_SUFFIX);
742         source.setAccessorCount(fra.size());
743         source.setAccessorStride(1);
744
745         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
746         add_source_parameters(param, semantic, is_rot, axis_name, false);
747
748         source.prepareToAppendValues();
749
750         std::vector<float>::iterator it;
751         for (it = fra.begin(); it != fra.end(); it++) {
752                 float val = *it;
753                 //if (semantic == COLLADASW::InputSemantic::INPUT)
754                 val = convert_time(val);
755                 /*else if (is_rot)
756                    val = convert_angle(val);*/
757                 source.appendValues(val);
758         }
759
760         source.finish();
761
762         return source_id;
763 }
764
765 std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Object *ob_arm, Bone *bone, const std::string& anim_id)
766 {
767         COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
768         std::string source_id = anim_id + get_semantic_suffix(semantic);
769
770         COLLADASW::Float4x4Source source(mSW);
771         source.setId(source_id);
772         source.setArrayId(source_id + ARRAY_ID_SUFFIX);
773         source.setAccessorCount(frames.size());
774         source.setAccessorStride(16);
775
776         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
777         add_source_parameters(param, semantic, false, NULL, true);
778
779         source.prepareToAppendValues();
780
781         bPoseChannel *parchan = NULL;
782         bPoseChannel *pchan = NULL;
783         bPose *pose = ob_arm->pose;
784
785         pchan = BKE_pose_channel_find_name(pose, bone->name);
786
787         if (!pchan)
788                 return "";
789
790         parchan = pchan->parent;
791
792         enable_fcurves(ob_arm->adt->action, bone->name);
793
794         std::vector<float>::iterator it;
795         int j = 0;
796         for (it = frames.begin(); it != frames.end(); it++) {
797                 float mat[4][4], ipar[4][4];
798
799                 float ctime = BKE_scene_frame_get_from_ctime(scene, *it);
800
801                 BKE_animsys_evaluate_animdata(scene, &ob_arm->id, ob_arm->adt, ctime, ADT_RECALC_ANIM);
802                 BKE_pose_where_is_bone(scene, ob_arm, pchan, ctime, 1);
803
804                 // compute bone local mat
805                 if (bone->parent) {
806                         invert_m4_m4(ipar, parchan->pose_mat);
807                         mult_m4_m4m4(mat, ipar, pchan->pose_mat);
808                 }
809                 else
810                         copy_m4_m4(mat, pchan->pose_mat);
811                 UnitConverter converter;
812
813                 // SECOND_LIFE_COMPATIBILITY
814                 // AFAIK animation to second life is via BVH, but no
815                 // reason to not have the collada-animation be correct
816                 if (export_settings->second_life) {
817                         float temp[4][4];
818                         copy_m4_m4(temp, bone->arm_mat);
819                         temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
820                         invert_m4(temp);
821
822                         mult_m4_m4m4(mat, mat, temp);
823
824                         if (bone->parent) {
825                                 copy_m4_m4(temp, bone->parent->arm_mat);
826                                 temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
827
828                                 mult_m4_m4m4(mat, temp, mat);
829                         }
830                 }
831
832                 float outmat[4][4];
833                 converter.mat4_to_dae(outmat, mat);
834
835
836                 source.appendValues(outmat);
837
838
839                 j++;
840         }
841
842         enable_fcurves(ob_arm->adt->action, NULL);
843
844         source.finish();
845
846         return source_id;
847 }
848 // only used for sources with OUTPUT semantic ( locations and scale)
849 std::string AnimationExporter::create_xyz_source(float *v, int tot, const std::string& anim_id)
850 {
851         COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
852         std::string source_id = anim_id + get_semantic_suffix(semantic);
853
854         COLLADASW::FloatSourceF source(mSW);
855         source.setId(source_id);
856         source.setArrayId(source_id + ARRAY_ID_SUFFIX);
857         source.setAccessorCount(tot);
858         source.setAccessorStride(3);
859
860         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
861         add_source_parameters(param, semantic, false, NULL, false);
862
863         source.prepareToAppendValues();
864
865         for (int i = 0; i < tot; i++) {
866                 source.appendValues(*v, *(v + 1), *(v + 2));
867                 v += 3;
868         }
869
870         source.finish();
871
872         return source_id;
873 }
874
875 std::string AnimationExporter::create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents)
876 {
877         std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
878
879         COLLADASW::NameSource source(mSW);
880         source.setId(source_id);
881         source.setArrayId(source_id + ARRAY_ID_SUFFIX);
882         source.setAccessorCount(fcu->totvert);
883         source.setAccessorStride(1);
884
885         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
886         param.push_back("INTERPOLATION");
887
888         source.prepareToAppendValues();
889
890         *has_tangents = false;
891
892         for (unsigned int i = 0; i < fcu->totvert; i++) {
893                 if (fcu->bezt[i].ipo == BEZT_IPO_BEZ) {
894                         source.appendValues(BEZIER_NAME);
895                         *has_tangents = true;
896                 }
897                 else if (fcu->bezt[i].ipo == BEZT_IPO_CONST) {
898                         source.appendValues(STEP_NAME);
899                 }
900                 else { // BEZT_IPO_LIN
901                         source.appendValues(LINEAR_NAME);
902                 }
903         }
904         // unsupported? -- HERMITE, CARDINAL, BSPLINE, NURBS
905
906         source.finish();
907
908         return source_id;
909 }
910
911 std::string AnimationExporter::fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name)
912 {
913         std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
914
915         COLLADASW::NameSource source(mSW);
916         source.setId(source_id);
917         source.setArrayId(source_id + ARRAY_ID_SUFFIX);
918         source.setAccessorCount(tot);
919         source.setAccessorStride(1);
920
921         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
922         param.push_back("INTERPOLATION");
923
924         source.prepareToAppendValues();
925
926         for (int i = 0; i < tot; i++) {
927                 source.appendValues(LINEAR_NAME);
928         }
929
930         source.finish();
931
932         return source_id;
933 }
934
935 std::string AnimationExporter::get_light_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
936 {
937         std::string tm_name;
938         // when given rna_path, determine tm_type from it
939         if (rna_path) {
940                 char *name = extract_transform_name(rna_path);
941
942                 if (!strcmp(name, "color"))
943                         tm_type = 1;
944                 else if (!strcmp(name, "spot_size"))
945                         tm_type = 2;
946                 else if (!strcmp(name, "spot_blend"))
947                         tm_type = 3;
948                 else if (!strcmp(name, "distance"))
949                         tm_type = 4;
950                 else
951                         tm_type = -1;
952         }
953
954         switch (tm_type) {
955                 case 1:
956                         tm_name = "color";
957                         break;
958                 case 2:
959                         tm_name = "fall_off_angle";
960                         break;
961                 case 3:
962                         tm_name = "fall_off_exponent";
963                         break;
964                 case 4:
965                         tm_name = "blender/blender_dist";
966                         break;
967
968                 default:
969                         tm_name = "";
970                         break;
971         }
972
973         if (tm_name.size()) {
974                 if (axis_name[0])
975                         return tm_name + "." + std::string(axis_name);
976                 else 
977                         return tm_name;
978         }
979
980         return std::string("");
981 }
982
983 std::string AnimationExporter::get_camera_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
984 {
985         std::string tm_name;
986         // when given rna_path, determine tm_type from it
987         if (rna_path) {
988                 char *name = extract_transform_name(rna_path);
989
990                 if (!strcmp(name, "lens"))
991                         tm_type = 0;
992                 else if (!strcmp(name, "ortho_scale"))
993                         tm_type = 1;
994                 else if (!strcmp(name, "clip_end"))
995                         tm_type = 2;
996                 else if (!strcmp(name, "clip_start"))
997                         tm_type = 3;
998
999                 else
1000                         tm_type = -1;
1001         }
1002
1003         switch (tm_type) {
1004                 case 0:
1005                         tm_name = "xfov";
1006                         break;
1007                 case 1:
1008                         tm_name = "xmag";
1009                         break;
1010                 case 2:
1011                         tm_name = "zfar";
1012                         break;
1013                 case 3:
1014                         tm_name = "znear";
1015                         break;
1016
1017                 default:
1018                         tm_name = "";
1019                         break;
1020         }
1021
1022         if (tm_name.size()) {
1023                 if (axis_name[0])
1024                         return tm_name + "." + std::string(axis_name);
1025                 else 
1026                         return tm_name;
1027         }
1028
1029         return std::string("");
1030 }
1031
1032 // Assign sid of the animated parameter or transform 
1033 // for rotation, axis name is always appended and the value of append_axis is ignored
1034 std::string AnimationExporter::get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
1035 {
1036         std::string tm_name;
1037         bool is_rotation = false;
1038         // when given rna_path, determine tm_type from it
1039         if (rna_path) {
1040                 char *name = extract_transform_name(rna_path);
1041
1042                 if (!strcmp(name, "rotation_euler"))
1043                         tm_type = 0;
1044                 else if (!strcmp(name, "rotation_quaternion"))
1045                         tm_type = 1;
1046                 else if (!strcmp(name, "scale"))
1047                         tm_type = 2;
1048                 else if (!strcmp(name, "location"))
1049                         tm_type = 3;
1050                 else if (!strcmp(name, "specular_hardness"))
1051                         tm_type = 4;
1052                 else if (!strcmp(name, "specular_color"))
1053                         tm_type = 5;
1054                 else if (!strcmp(name, "diffuse_color"))
1055                         tm_type = 6;
1056                 else if (!strcmp(name, "alpha"))
1057                         tm_type = 7;
1058                 else if (!strcmp(name, "ior"))
1059                         tm_type = 8;
1060
1061                 else
1062                         tm_type = -1;
1063         }
1064
1065         switch (tm_type) {
1066                 case 0:
1067                 case 1:
1068                         tm_name = "rotation";
1069                         is_rotation = true;
1070                         break;
1071                 case 2:
1072                         tm_name = "scale";
1073                         break;
1074                 case 3:
1075                         tm_name = "location";
1076                         break;
1077                 case 4:
1078                         tm_name = "shininess";
1079                         break;
1080                 case 5:
1081                         tm_name = "specular";
1082                         break;
1083                 case 6:
1084                         tm_name = "diffuse";
1085                         break;  
1086                 case 7:
1087                         tm_name = "transparency";
1088                         break;  
1089                 case 8:
1090                         tm_name = "index_of_refraction";
1091                         break;  
1092
1093                 default:
1094                         tm_name = "";
1095                         break;
1096         }
1097
1098         if (tm_name.size()) {
1099                 if (is_rotation)
1100                         return tm_name + std::string(axis_name) + ".ANGLE";
1101                 else
1102                 if (axis_name[0])
1103                         return tm_name + "." + std::string(axis_name);
1104                 else
1105                         return tm_name;
1106         }
1107
1108         return std::string("");
1109 }
1110
1111 char *AnimationExporter::extract_transform_name(char *rna_path)
1112 {
1113         char *dot = strrchr(rna_path, '.');
1114         return dot ? (dot + 1) : rna_path;
1115 }
1116
1117 //find keyframes of all the objects animations
1118 void AnimationExporter::find_frames(Object *ob, std::vector<float> &fra)
1119 {
1120         FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
1121
1122         for (; fcu; fcu = fcu->next) {
1123
1124                 for (unsigned int i = 0; i < fcu->totvert; i++) {
1125                         float f = fcu->bezt[i].vec[1][0];
1126                         if (std::find(fra.begin(), fra.end(), f) == fra.end())   
1127                                 fra.push_back(f);
1128                 }
1129         }
1130
1131         // keep the keys in ascending order
1132         std::sort(fra.begin(), fra.end());
1133 }
1134
1135
1136
1137 // enable fcurves driving a specific bone, disable all the rest
1138 // if bone_name = NULL enable all fcurves
1139 void AnimationExporter::enable_fcurves(bAction *act, char *bone_name)
1140 {
1141         FCurve *fcu;
1142         char prefix[200];
1143
1144         if (bone_name)
1145                 BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name);
1146
1147         for (fcu = (FCurve *)act->curves.first; fcu; fcu = fcu->next) {
1148                 if (bone_name) {
1149                         if (!strncmp(fcu->rna_path, prefix, strlen(prefix)))
1150                                 fcu->flag &= ~FCURVE_DISABLED;
1151                         else
1152                                 fcu->flag |= FCURVE_DISABLED;
1153                 }
1154                 else {
1155                         fcu->flag &= ~FCURVE_DISABLED;
1156                 }
1157         }
1158 }
1159
1160 bool AnimationExporter::hasAnimations(Scene *sce)
1161 {
1162         LinkNode *node;
1163
1164         for (node=this->export_settings->export_set; node; node=node->next) {
1165                 Object *ob = (Object *)node->link;
1166
1167                 FCurve *fcu = 0;
1168                 //Check for object transform animations
1169                 if (ob->adt && ob->adt->action)
1170                         fcu = (FCurve *)ob->adt->action->curves.first;
1171                 //Check for Lamp parameter animations
1172                 else if ( (ob->type == OB_LAMP) && ((Lamp *)ob->data)->adt && ((Lamp *)ob->data)->adt->action)
1173                         fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first);
1174                 //Check for Camera parameter animations
1175                 else if ( (ob->type == OB_CAMERA) && ((Camera *)ob->data)->adt && ((Camera *)ob->data)->adt->action)
1176                         fcu = (FCurve *)(((Camera *)ob->data)->adt->action->curves.first);
1177
1178                 //Check Material Effect parameter animations.
1179                 for (int a = 0; a < ob->totcol; a++) {
1180                         Material *ma = give_current_material(ob, a + 1);
1181                         if (!ma) continue;
1182                         if (ma->adt && ma->adt->action) {
1183                                 fcu = (FCurve *)ma->adt->action->curves.first;
1184                         }
1185                 }
1186
1187                 if (fcu)
1188                         return true;
1189         }
1190         return false;
1191 }
1192
1193 //------------------------------- Not used in the new system.--------------------------------------------------------
1194 void AnimationExporter::find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode)
1195 {
1196         if (rotmode > 0)
1197                 find_frames(ob, fra, prefix, "rotation_euler");
1198         else if (rotmode == ROT_MODE_QUAT)
1199                 find_frames(ob, fra, prefix, "rotation_quaternion");
1200         /*else if (rotmode == ROT_MODE_AXISANGLE)
1201            ;*/
1202 }
1203
1204 void AnimationExporter::find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name)
1205 {
1206         FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
1207
1208         for (; fcu; fcu = fcu->next) {
1209                 if (prefix && strncmp(prefix, fcu->rna_path, strlen(prefix)))
1210                         continue;
1211
1212                 char *name = extract_transform_name(fcu->rna_path);
1213                 if (!strcmp(name, tm_name)) {
1214                         for (unsigned int i = 0; i < fcu->totvert; i++) {
1215                                 float f = fcu->bezt[i].vec[1][0];
1216                                 if (std::find(fra.begin(), fra.end(), f) == fra.end())   
1217                                         fra.push_back(f);
1218                         }
1219                 }
1220         }
1221
1222         // keep the keys in ascending order
1223         std::sort(fra.begin(), fra.end());
1224 }
1225
1226 void AnimationExporter::write_bone_animation(Object *ob_arm, Bone *bone)
1227 {
1228         if (!ob_arm->adt)
1229                 return;
1230
1231         //write bone animations for 3 transform types
1232         //i=0 --> rotations
1233         //i=1 --> scale
1234         //i=2 --> location
1235         for (int i = 0; i < 3; i++)
1236                 sample_and_write_bone_animation(ob_arm, bone, i);
1237
1238         for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next)
1239                 write_bone_animation(ob_arm, child);
1240 }
1241
1242 void AnimationExporter::sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type)
1243 {
1244         bArmature *arm = (bArmature *)ob_arm->data;
1245         int flag = arm->flag;
1246         std::vector<float> fra;
1247         char prefix[256];
1248
1249         BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone->name);
1250
1251         bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name);
1252         if (!pchan)
1253                 return;
1254         //Fill frame array with key frame values framed at \param:transform_type
1255         switch (transform_type) {
1256                 case 0:
1257                         find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode);
1258                         break;
1259                 case 1:
1260                         find_frames(ob_arm, fra, prefix, "scale");
1261                         break;
1262                 case 2:
1263                         find_frames(ob_arm, fra, prefix, "location");
1264                         break;
1265                 default:
1266                         return;
1267         }
1268
1269         // exit rest position
1270         if (flag & ARM_RESTPOS) {
1271                 arm->flag &= ~ARM_RESTPOS;
1272                 BKE_pose_where_is(scene, ob_arm);
1273         }
1274         //v array will hold all values which will be exported. 
1275         if (fra.size()) {
1276                 float *values = (float *)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames");
1277                 sample_animation(values, fra, transform_type, bone, ob_arm, pchan);
1278
1279                 if (transform_type == 0) {
1280                         // write x, y, z curves separately if it is rotation
1281                         float *axisValues = (float *)MEM_callocN(sizeof(float) * fra.size(), "temp. anim frames");
1282
1283                         for (int i = 0; i < 3; i++) {
1284                                 for (unsigned int j = 0; j < fra.size(); j++)
1285                                         axisValues[j] = values[j * 3 + i];
1286
1287                                 dae_bone_animation(fra, axisValues, transform_type, i, id_name(ob_arm), bone->name);
1288                         }
1289                         MEM_freeN(axisValues);
1290                 }
1291                 else {
1292                         // write xyz at once if it is location or scale
1293                         dae_bone_animation(fra, values, transform_type, -1, id_name(ob_arm), bone->name);
1294                 }
1295
1296                 MEM_freeN(values);
1297         }
1298
1299         // restore restpos
1300         if (flag & ARM_RESTPOS) 
1301                 arm->flag = flag;
1302         BKE_pose_where_is(scene, ob_arm);
1303 }
1304
1305 void AnimationExporter::sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm, bPoseChannel *pchan)
1306 {
1307         bPoseChannel *parchan = NULL;
1308         bPose *pose = ob_arm->pose;
1309
1310         pchan = BKE_pose_channel_find_name(pose, bone->name);
1311
1312         if (!pchan)
1313                 return;
1314
1315         parchan = pchan->parent;
1316
1317         enable_fcurves(ob_arm->adt->action, bone->name);
1318
1319         std::vector<float>::iterator it;
1320         for (it = frames.begin(); it != frames.end(); it++) {
1321                 float mat[4][4], ipar[4][4];
1322
1323                 float ctime = BKE_scene_frame_get_from_ctime(scene, *it);
1324
1325
1326                 BKE_animsys_evaluate_animdata(scene, &ob_arm->id, ob_arm->adt, ctime, ADT_RECALC_ANIM);
1327                 BKE_pose_where_is_bone(scene, ob_arm, pchan, ctime, 1);
1328
1329                 // compute bone local mat
1330                 if (bone->parent) {
1331                         invert_m4_m4(ipar, parchan->pose_mat);
1332                         mult_m4_m4m4(mat, ipar, pchan->pose_mat);
1333                 }
1334                 else
1335                         copy_m4_m4(mat, pchan->pose_mat);
1336
1337                 switch (type) {
1338                         case 0:
1339                                 mat4_to_eul(v, mat);
1340                                 break;
1341                         case 1:
1342                                 mat4_to_size(v, mat);
1343                                 break;
1344                         case 2:
1345                                 copy_v3_v3(v, mat[3]);
1346                                 break;
1347                 }
1348
1349                 v += 3;
1350         }
1351
1352         enable_fcurves(ob_arm->adt->action, NULL);
1353 }