doxygen: blender/collada tagged.
[blender-staging.git] / source / blender / collada / DocumentExporter.cpp
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed.
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 /** \file blender/collada/DocumentExporter.cpp
26  *  \ingroup collada
27  */
28
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <math.h>
32
33 extern "C" 
34 {
35 #include "DNA_scene_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_meshdata_types.h"
38 #include "DNA_mesh_types.h"
39 #include "DNA_image_types.h"
40 #include "DNA_material_types.h"
41 #include "DNA_texture_types.h"
42 #include "DNA_anim_types.h"
43 #include "DNA_action_types.h"
44 #include "DNA_curve_types.h"
45 #include "DNA_armature_types.h"
46 #include "DNA_modifier_types.h"
47 #include "DNA_userdef_types.h"
48
49 #include "BKE_DerivedMesh.h"
50 #include "BKE_fcurve.h"
51 #include "BKE_animsys.h"
52 #include "BLI_path_util.h"
53 #include "BLI_fileops.h"
54 #include "ED_keyframing.h"
55 #ifdef NAN_BUILDINFO
56 extern char build_rev[];
57 #endif
58 }
59
60 #include "MEM_guardedalloc.h"
61
62 #include "BKE_blender.h" // version info
63 #include "BKE_scene.h"
64 #include "BKE_global.h"
65 #include "BKE_main.h"
66 #include "BKE_material.h"
67 #include "BKE_action.h" // pose functions
68 #include "BKE_armature.h"
69 #include "BKE_image.h"
70 #include "BKE_utildefines.h"
71 #include "BKE_object.h"
72
73 #include "BLI_math.h"
74 #include "BLI_string.h"
75 #include "BLI_listbase.h"
76
77 #include "RNA_access.h"
78
79 #include "COLLADASWAsset.h"
80 #include "COLLADASWLibraryVisualScenes.h"
81 #include "COLLADASWNode.h"
82 #include "COLLADASWSource.h"
83 #include "COLLADASWInstanceGeometry.h"
84 #include "COLLADASWInputList.h"
85 #include "COLLADASWPrimitves.h"
86 #include "COLLADASWVertices.h"
87 #include "COLLADASWLibraryAnimations.h"
88 #include "COLLADASWLibraryImages.h"
89 #include "COLLADASWLibraryEffects.h"
90 #include "COLLADASWImage.h"
91 #include "COLLADASWEffectProfile.h"
92 #include "COLLADASWColorOrTexture.h"
93 #include "COLLADASWParamTemplate.h"
94 #include "COLLADASWParamBase.h"
95 #include "COLLADASWSurfaceInitOption.h"
96 #include "COLLADASWSampler.h"
97 #include "COLLADASWScene.h"
98 #include "COLLADASWTechnique.h"
99 #include "COLLADASWTexture.h"
100 #include "COLLADASWLibraryMaterials.h"
101 #include "COLLADASWBindMaterial.h"
102 #include "COLLADASWInstanceCamera.h"
103 #include "COLLADASWInstanceLight.h"
104 #include "COLLADASWConstants.h"
105 #include "COLLADASWLibraryControllers.h"
106 #include "COLLADASWInstanceController.h"
107 #include "COLLADASWBaseInputElement.h"
108
109 #include "collada_internal.h"
110 #include "DocumentExporter.h"
111
112 // can probably go after refactor is complete
113 #include "InstanceWriter.h"
114 #include "TransformWriter.h"
115
116 #include "ArmatureExporter.h"
117 #include "CameraExporter.h"
118 #include "EffectExporter.h"
119 #include "GeometryExporter.h"
120 #include "ImageExporter.h"
121 #include "LightExporter.h"
122 #include "MaterialExporter.h"
123
124 #include <vector>
125 #include <algorithm> // std::find
126
127 char *bc_CustomData_get_layer_name(const struct CustomData *data, int type, int n)
128 {
129         int layer_index = CustomData_get_layer_index(data, type);
130         if(layer_index < 0) return NULL;
131
132         return data->layers[layer_index+n].name;
133 }
134
135 char *bc_CustomData_get_active_layer_name(const CustomData *data, int type)
136 {
137         /* get the layer index of the active layer of type */
138         int layer_index = CustomData_get_active_layer_index(data, type);
139         if(layer_index < 0) return NULL;
140
141         return data->layers[layer_index].name;
142 }
143
144
145 /*
146   Utilities to avoid code duplication.
147   Definition can take some time to understand, but they should be useful.
148 */
149
150
151 template<class Functor>
152 void forEachObjectInScene(Scene *sce, Functor &f)
153 {
154         Base *base= (Base*) sce->base.first;
155         while(base) {
156                 Object *ob = base->object;
157                         
158                 f(ob);
159
160                 base= base->next;
161         }
162 }
163
164
165
166 class SceneExporter: COLLADASW::LibraryVisualScenes, protected TransformWriter, protected InstanceWriter
167 {
168         ArmatureExporter *arm_exporter;
169 public:
170         SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm) : COLLADASW::LibraryVisualScenes(sw),
171                                                                                                                                                 arm_exporter(arm) {}
172         
173         void exportScene(Scene *sce) {
174                 // <library_visual_scenes> <visual_scene>
175                 std::string id_naming = id_name(sce);
176                 openVisualScene(translate_id(id_naming), id_naming);
177
178                 // write <node>s
179                 //forEachMeshObjectInScene(sce, *this);
180                 //forEachCameraObjectInScene(sce, *this);
181                 //forEachLampObjectInScene(sce, *this);
182                 exportHierarchy(sce);
183
184                 // </visual_scene> </library_visual_scenes>
185                 closeVisualScene();
186
187                 closeLibrary();
188         }
189
190         void exportHierarchy(Scene *sce)
191         {
192                 Base *base= (Base*) sce->base.first;
193                 while(base) {
194                         Object *ob = base->object;
195
196                         if (!ob->parent) {
197                                 switch(ob->type) {
198                                 case OB_MESH:
199                                 case OB_CAMERA:
200                                 case OB_LAMP:
201                                 case OB_EMPTY:
202                                 case OB_ARMATURE:
203                                         // write nodes....
204                                         writeNodes(ob, sce);
205                                         break;
206                                 }
207                         }
208
209                         base= base->next;
210                 }
211         }
212
213
214         // called for each object
215         //void operator()(Object *ob) {
216         void writeNodes(Object *ob, Scene *sce)
217         {
218                 COLLADASW::Node node(mSW);
219                 node.setNodeId(translate_id(id_name(ob)));
220                 node.setType(COLLADASW::Node::NODE);
221
222                 node.start();
223
224                 bool is_skinned_mesh = arm_exporter->is_skinned_mesh(ob);
225
226                 if (ob->type == OB_MESH && is_skinned_mesh)
227                         // for skinned mesh we write obmat in <bind_shape_matrix>
228                         TransformWriter::add_node_transform_identity(node);
229                 else
230                         TransformWriter::add_node_transform_ob(node, ob);
231                 
232                 // <instance_geometry>
233                 if (ob->type == OB_MESH) {
234                         if (is_skinned_mesh) {
235                                 arm_exporter->add_instance_controller(ob);
236                         }
237                         else {
238                                 COLLADASW::InstanceGeometry instGeom(mSW);
239                                 instGeom.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob)));
240
241                                 InstanceWriter::add_material_bindings(instGeom.getBindMaterial(), ob);
242                         
243                                 instGeom.add();
244                         }
245                 }
246
247                 // <instance_controller>
248                 else if (ob->type == OB_ARMATURE) {
249                         arm_exporter->add_armature_bones(ob, sce);
250
251                         // XXX this looks unstable...
252                         node.end();
253                 }
254                 
255                 // <instance_camera>
256                 else if (ob->type == OB_CAMERA) {
257                         COLLADASW::InstanceCamera instCam(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_camera_id(ob)));
258                         instCam.add();
259                 }
260                 
261                 // <instance_light>
262                 else if (ob->type == OB_LAMP) {
263                         COLLADASW::InstanceLight instLa(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_light_id(ob)));
264                         instLa.add();
265                 }
266
267                 // empty object
268                 else if (ob->type == OB_EMPTY) {
269                 }
270
271                 // write nodes for child objects
272                 Base *b = (Base*) sce->base.first;
273                 while(b) {
274                         // cob - child object
275                         Object *cob = b->object;
276
277                         if (cob->parent == ob) {
278                                 switch(cob->type) {
279                                 case OB_MESH:
280                                 case OB_CAMERA:
281                                 case OB_LAMP:
282                                 case OB_EMPTY:
283                                 case OB_ARMATURE:
284                                         // write node...
285                                         writeNodes(cob, sce);
286                                         break;
287                                 }
288                         }
289
290                         b = b->next;
291                 }
292
293                 if (ob->type != OB_ARMATURE)
294                         node.end();
295         }
296 };
297
298 // TODO: it would be better to instantiate animations rather than create a new one per object
299 // COLLADA allows this through multiple <channel>s in <animation>.
300 // For this to work, we need to know objects that use a certain action.
301 class AnimationExporter: COLLADASW::LibraryAnimations
302 {
303         Scene *scene;
304         COLLADASW::StreamWriter *sw;
305
306 public:
307
308         AnimationExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryAnimations(sw) { this->sw = sw; }
309
310         void exportAnimations(Scene *sce)
311         {
312                 this->scene = sce;
313
314                 openLibrary();
315                 
316                 forEachObjectInScene(sce, *this);
317                 
318                 closeLibrary();
319         }
320
321         // called for each exported object
322         void operator() (Object *ob) 
323         {
324                 if (!ob->adt || !ob->adt->action) return;
325                 
326                 FCurve *fcu = (FCurve*)ob->adt->action->curves.first;
327                 
328                 if (ob->type == OB_ARMATURE) {
329                         if (!ob->data) return;
330
331                         bArmature *arm = (bArmature*)ob->data;
332                         for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next)
333                                 write_bone_animation(ob, bone);
334                 }
335                 else {
336                         while (fcu) {
337                                 // TODO "rotation_quaternion" is also possible for objects (although euler is default)
338                                 if ((!strcmp(fcu->rna_path, "location") || !strcmp(fcu->rna_path, "scale")) ||
339                                         (!strcmp(fcu->rna_path, "rotation_euler") && ob->rotmode == ROT_MODE_EUL))
340                                         dae_animation(fcu, id_name(ob));
341
342                                 fcu = fcu->next;
343                         }
344                 }
345         }
346
347 protected:
348
349         void dae_animation(FCurve *fcu, std::string ob_name)
350         {
351                 const char *axis_names[] = {"X", "Y", "Z"};
352                 const char *axis_name = NULL;
353                 char anim_id[200];
354                 
355                 if (fcu->array_index < 3)
356                         axis_name = axis_names[fcu->array_index];
357
358                 BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
359                                          fcu->rna_path, axis_names[fcu->array_index]);
360
361                 // check rna_path is one of: rotation, scale, location
362
363                 openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
364
365                 // create input source
366                 std::string input_id = create_source_from_fcurve(COLLADASW::InputSemantic::INPUT, fcu, anim_id, axis_name);
367
368                 // create output source
369                 std::string output_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name);
370
371                 // create interpolations source
372                 std::string interpolation_id = create_interpolation_source(fcu->totvert, anim_id, axis_name);
373
374                 std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
375                 COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
376                 std::string empty;
377                 sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
378                 sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
379
380                 // this input is required
381                 sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
382
383                 addSampler(sampler);
384
385                 std::string target = translate_id(ob_name)
386                         + "/" + get_transform_sid(fcu->rna_path, -1, axis_name, true);
387                 addChannel(COLLADABU::URI(empty, sampler_id), target);
388
389                 closeAnimation();
390         }
391
392         void write_bone_animation(Object *ob_arm, Bone *bone)
393         {
394                 if (!ob_arm->adt)
395                         return;
396
397                 for (int i = 0; i < 3; i++)
398                         sample_and_write_bone_animation(ob_arm, bone, i);
399
400                 for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next)
401                         write_bone_animation(ob_arm, child);
402         }
403
404         void sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type)
405         {
406                 bArmature *arm = (bArmature*)ob_arm->data;
407                 int flag = arm->flag;
408                 std::vector<float> fra;
409                 char prefix[256];
410
411                 BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone->name);
412
413                 bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name);
414                 if (!pchan)
415                         return;
416
417                 switch (transform_type) {
418                 case 0:
419                         find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode);
420                         break;
421                 case 1:
422                         find_frames(ob_arm, fra, prefix, "scale");
423                         break;
424                 case 2:
425                         find_frames(ob_arm, fra, prefix, "location");
426                         break;
427                 default:
428                         return;
429                 }
430
431                 // exit rest position
432                 if (flag & ARM_RESTPOS) {
433                         arm->flag &= ~ARM_RESTPOS;
434                         where_is_pose(scene, ob_arm);
435                 }
436
437                 if (fra.size()) {
438                         float *v = (float*)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames");
439                         sample_animation(v, fra, transform_type, bone, ob_arm);
440
441                         if (transform_type == 0) {
442                                 // write x, y, z curves separately if it is rotation
443                                 float *c = (float*)MEM_callocN(sizeof(float) * fra.size(), "temp. anim frames");
444                                 for (int i = 0; i < 3; i++) {
445                                         for (unsigned int j = 0; j < fra.size(); j++)
446                                                 c[j] = v[j * 3 + i];
447
448                                         dae_bone_animation(fra, c, transform_type, i, id_name(ob_arm), bone->name);
449                                 }
450                                 MEM_freeN(c);
451                         }
452                         else {
453                                 // write xyz at once if it is location or scale
454                                 dae_bone_animation(fra, v, transform_type, -1, id_name(ob_arm), bone->name);
455                         }
456
457                         MEM_freeN(v);
458                 }
459
460                 // restore restpos
461                 if (flag & ARM_RESTPOS) 
462                         arm->flag = flag;
463                 where_is_pose(scene, ob_arm);
464         }
465
466         void sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm)
467         {
468                 bPoseChannel *pchan, *parchan = NULL;
469                 bPose *pose = ob_arm->pose;
470
471                 pchan = get_pose_channel(pose, bone->name);
472
473                 if (!pchan)
474                         return;
475
476                 parchan = pchan->parent;
477
478                 enable_fcurves(ob_arm->adt->action, bone->name);
479
480                 std::vector<float>::iterator it;
481                 for (it = frames.begin(); it != frames.end(); it++) {
482                         float mat[4][4], ipar[4][4];
483
484                         float ctime = bsystem_time(scene, ob_arm, *it, 0.0f);
485
486                         BKE_animsys_evaluate_animdata(&ob_arm->id, ob_arm->adt, *it, ADT_RECALC_ANIM);
487                         where_is_pose_bone(scene, ob_arm, pchan, ctime, 1);
488
489                         // compute bone local mat
490                         if (bone->parent) {
491                                 invert_m4_m4(ipar, parchan->pose_mat);
492                                 mul_m4_m4m4(mat, pchan->pose_mat, ipar);
493                         }
494                         else
495                                 copy_m4_m4(mat, pchan->pose_mat);
496
497                         switch (type) {
498                         case 0:
499                                 mat4_to_eul(v, mat);
500                                 break;
501                         case 1:
502                                 mat4_to_size(v, mat);
503                                 break;
504                         case 2:
505                                 copy_v3_v3(v, mat[3]);
506                                 break;
507                         }
508
509                         v += 3;
510                 }
511
512                 enable_fcurves(ob_arm->adt->action, NULL);
513         }
514
515         // dae_bone_animation -> add_bone_animation
516         // (blend this into dae_bone_animation)
517         void dae_bone_animation(std::vector<float> &fra, float *v, int tm_type, int axis, std::string ob_name, std::string bone_name)
518         {
519                 const char *axis_names[] = {"X", "Y", "Z"};
520                 const char *axis_name = NULL;
521                 char anim_id[200];
522                 bool is_rot = tm_type == 0;
523                 
524                 if (!fra.size())
525                         return;
526
527                 char rna_path[200];
528                 BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].%s", bone_name.c_str(),
529                                          tm_type == 0 ? "rotation_quaternion" : (tm_type == 1 ? "scale" : "location"));
530
531                 if (axis > -1)
532                         axis_name = axis_names[axis];
533                 
534                 std::string transform_sid = get_transform_sid(NULL, tm_type, axis_name, false);
535                 
536                 BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
537                                          (char*)translate_id(bone_name).c_str(), (char*)transform_sid.c_str());
538
539                 openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
540
541                 // create input source
542                 std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, is_rot, anim_id, axis_name);
543
544                 // create output source
545                 std::string output_id;
546                 if (axis == -1)
547                         output_id = create_xyz_source(v, fra.size(), anim_id);
548                 else
549                         output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, v, fra.size(), is_rot, anim_id, axis_name);
550
551                 // create interpolations source
552                 std::string interpolation_id = create_interpolation_source(fra.size(), anim_id, axis_name);
553
554                 std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
555                 COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
556                 std::string empty;
557                 sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
558                 sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
559
560                 // TODO create in/out tangents source
561
562                 // this input is required
563                 sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
564
565                 addSampler(sampler);
566
567                 std::string target = translate_id(ob_name + "_" + bone_name) + "/" + transform_sid;
568                 addChannel(COLLADABU::URI(empty, sampler_id), target);
569
570                 closeAnimation();
571         }
572
573         float convert_time(float frame)
574         {
575                 return FRA2TIME(frame);
576         }
577
578         float convert_angle(float angle)
579         {
580                 return COLLADABU::Math::Utils::radToDegF(angle);
581         }
582
583         std::string get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic)
584         {
585                 switch(semantic) {
586                 case COLLADASW::InputSemantic::INPUT:
587                         return INPUT_SOURCE_ID_SUFFIX;
588                 case COLLADASW::InputSemantic::OUTPUT:
589                         return OUTPUT_SOURCE_ID_SUFFIX;
590                 case COLLADASW::InputSemantic::INTERPOLATION:
591                         return INTERPOLATION_SOURCE_ID_SUFFIX;
592                 case COLLADASW::InputSemantic::IN_TANGENT:
593                         return INTANGENT_SOURCE_ID_SUFFIX;
594                 case COLLADASW::InputSemantic::OUT_TANGENT:
595                         return OUTTANGENT_SOURCE_ID_SUFFIX;
596                 default:
597                         break;
598                 }
599                 return "";
600         }
601
602         void add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
603                                                            COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis)
604         {
605                 switch(semantic) {
606                 case COLLADASW::InputSemantic::INPUT:
607                         param.push_back("TIME");
608                         break;
609                 case COLLADASW::InputSemantic::OUTPUT:
610                         if (is_rot) {
611                                 param.push_back("ANGLE");
612                         }
613                         else {
614                                 if (axis) {
615                                         param.push_back(axis);
616                                 }
617                                 else {
618                                         param.push_back("X");
619                                         param.push_back("Y");
620                                         param.push_back("Z");
621                                 }
622                         }
623                         break;
624                 case COLLADASW::InputSemantic::IN_TANGENT:
625                 case COLLADASW::InputSemantic::OUT_TANGENT:
626                         param.push_back("X");
627                         param.push_back("Y");
628                         break;
629                 default:
630                         break;
631                 }
632         }
633
634         void get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool rotation, float *values, int *length)
635         {
636                 switch (semantic) {
637                 case COLLADASW::InputSemantic::INPUT:
638                         *length = 1;
639                         values[0] = convert_time(bezt->vec[1][0]);
640                         break;
641                 case COLLADASW::InputSemantic::OUTPUT:
642                         *length = 1;
643                         if (rotation) {
644                                 values[0] = convert_angle(bezt->vec[1][1]);
645                         }
646                         else {
647                                 values[0] = bezt->vec[1][1];
648                         }
649                         break;
650                 case COLLADASW::InputSemantic::IN_TANGENT:
651                 case COLLADASW::InputSemantic::OUT_TANGENT:
652                         // XXX
653                         *length = 2;
654                         break;
655                 default:
656                         *length = 0;
657                         break;
658                 }
659         }
660
661         std::string create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name)
662         {
663                 std::string source_id = anim_id + get_semantic_suffix(semantic);
664
665                 //bool is_rotation = !strcmp(fcu->rna_path, "rotation");
666                 bool is_rotation = false;
667                 
668                 if (strstr(fcu->rna_path, "rotation")) is_rotation = true;
669                 
670                 COLLADASW::FloatSourceF source(mSW);
671                 source.setId(source_id);
672                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
673                 source.setAccessorCount(fcu->totvert);
674                 source.setAccessorStride(1);
675                 
676                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
677                 add_source_parameters(param, semantic, is_rotation, axis_name);
678
679                 source.prepareToAppendValues();
680
681                 for (unsigned int i = 0; i < fcu->totvert; i++) {
682                         float values[3]; // be careful!
683                         int length = 0;
684
685                         get_source_values(&fcu->bezt[i], semantic, is_rotation, values, &length);
686                         for (int j = 0; j < length; j++)
687                                 source.appendValues(values[j]);
688                 }
689
690                 source.finish();
691
692                 return source_id;
693         }
694
695         std::string create_source_from_array(COLLADASW::InputSemantic::Semantics semantic, float *v, int tot, bool is_rot, const std::string& anim_id, const char *axis_name)
696         {
697                 std::string source_id = anim_id + get_semantic_suffix(semantic);
698
699                 COLLADASW::FloatSourceF source(mSW);
700                 source.setId(source_id);
701                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
702                 source.setAccessorCount(tot);
703                 source.setAccessorStride(1);
704                 
705                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
706                 add_source_parameters(param, semantic, is_rot, axis_name);
707
708                 source.prepareToAppendValues();
709
710                 for (int i = 0; i < tot; i++) {
711                         float val = v[i];
712                         if (semantic == COLLADASW::InputSemantic::INPUT)
713                                 val = convert_time(val);
714                         else if (is_rot)
715                                 val = convert_angle(val);
716                         source.appendValues(val);
717                 }
718
719                 source.finish();
720
721                 return source_id;
722         }
723
724         std::string create_source_from_vector(COLLADASW::InputSemantic::Semantics semantic, std::vector<float> &fra, bool is_rot, const std::string& anim_id, const char *axis_name)
725         {
726                 std::string source_id = anim_id + get_semantic_suffix(semantic);
727
728                 COLLADASW::FloatSourceF source(mSW);
729                 source.setId(source_id);
730                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
731                 source.setAccessorCount(fra.size());
732                 source.setAccessorStride(1);
733                 
734                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
735                 add_source_parameters(param, semantic, is_rot, axis_name);
736
737                 source.prepareToAppendValues();
738
739                 std::vector<float>::iterator it;
740                 for (it = fra.begin(); it != fra.end(); it++) {
741                         float val = *it;
742                         if (semantic == COLLADASW::InputSemantic::INPUT)
743                                 val = convert_time(val);
744                         else if (is_rot)
745                                 val = convert_angle(val);
746                         source.appendValues(val);
747                 }
748
749                 source.finish();
750
751                 return source_id;
752         }
753
754         // only used for sources with OUTPUT semantic
755         std::string create_xyz_source(float *v, int tot, const std::string& anim_id)
756         {
757                 COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
758                 std::string source_id = anim_id + get_semantic_suffix(semantic);
759
760                 COLLADASW::FloatSourceF source(mSW);
761                 source.setId(source_id);
762                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
763                 source.setAccessorCount(tot);
764                 source.setAccessorStride(3);
765                 
766                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
767                 add_source_parameters(param, semantic, false, NULL);
768
769                 source.prepareToAppendValues();
770
771                 for (int i = 0; i < tot; i++) {
772                         source.appendValues(*v, *(v + 1), *(v + 2));
773                         v += 3;
774                 }
775
776                 source.finish();
777
778                 return source_id;
779         }
780
781         std::string create_interpolation_source(int tot, const std::string& anim_id, const char *axis_name)
782         {
783                 std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
784
785                 COLLADASW::NameSource source(mSW);
786                 source.setId(source_id);
787                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
788                 source.setAccessorCount(tot);
789                 source.setAccessorStride(1);
790                 
791                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
792                 param.push_back("INTERPOLATION");
793
794                 source.prepareToAppendValues();
795
796                 for (int i = 0; i < tot; i++) {
797                         source.appendValues(LINEAR_NAME);
798                 }
799
800                 source.finish();
801
802                 return source_id;
803         }
804
805         // for rotation, axis name is always appended and the value of append_axis is ignored
806         std::string get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
807         {
808                 std::string tm_name;
809
810                 // when given rna_path, determine tm_type from it
811                 if (rna_path) {
812                         char *name = extract_transform_name(rna_path);
813
814                         if (strstr(name, "rotation"))
815                                 tm_type = 0;
816                         else if (!strcmp(name, "scale"))
817                                 tm_type = 1;
818                         else if (!strcmp(name, "location"))
819                                 tm_type = 2;
820                         else
821                                 tm_type = -1;
822                 }
823
824                 switch (tm_type) {
825                 case 0:
826                         return std::string("rotation") + std::string(axis_name) + ".ANGLE";
827                 case 1:
828                         tm_name = "scale";
829                         break;
830                 case 2:
831                         tm_name = "location";
832                         break;
833                 default:
834                         tm_name = "";
835                         break;
836                 }
837
838                 if (tm_name.size()) {
839                         if (append_axis)
840                                 return tm_name + std::string(".") + std::string(axis_name);
841                         else
842                                 return tm_name;
843                 }
844
845                 return std::string("");
846         }
847
848         char *extract_transform_name(char *rna_path)
849         {
850                 char *dot = strrchr(rna_path, '.');
851                 return dot ? (dot + 1) : rna_path;
852         }
853
854         void find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name)
855         {
856                 FCurve *fcu= (FCurve*)ob->adt->action->curves.first;
857
858                 for (; fcu; fcu = fcu->next) {
859                         if (prefix && strncmp(prefix, fcu->rna_path, strlen(prefix)))
860                                 continue;
861
862                         char *name = extract_transform_name(fcu->rna_path);
863                         if (!strcmp(name, tm_name)) {
864                                 for (unsigned int i = 0; i < fcu->totvert; i++) {
865                                         float f = fcu->bezt[i].vec[1][0];
866                                         if (std::find(fra.begin(), fra.end(), f) == fra.end())
867                                                 fra.push_back(f);
868                                 }
869                         }
870                 }
871
872                 // keep the keys in ascending order
873                 std::sort(fra.begin(), fra.end());
874         }
875
876         void find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode)
877         {
878                 if (rotmode > 0)
879                         find_frames(ob, fra, prefix, "rotation_euler");
880                 else if (rotmode == ROT_MODE_QUAT)
881                         find_frames(ob, fra, prefix, "rotation_quaternion");
882                 /*else if (rotmode == ROT_MODE_AXISANGLE)
883                         ;*/
884         }
885
886         // enable fcurves driving a specific bone, disable all the rest
887         // if bone_name = NULL enable all fcurves
888         void enable_fcurves(bAction *act, char *bone_name)
889         {
890                 FCurve *fcu;
891                 char prefix[200];
892
893                 if (bone_name)
894                         BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name);
895
896                 for (fcu = (FCurve*)act->curves.first; fcu; fcu = fcu->next) {
897                         if (bone_name) {
898                                 if (!strncmp(fcu->rna_path, prefix, strlen(prefix)))
899                                         fcu->flag &= ~FCURVE_DISABLED;
900                                 else
901                                         fcu->flag |= FCURVE_DISABLED;
902                         }
903                         else {
904                                 fcu->flag &= ~FCURVE_DISABLED;
905                         }
906                 }
907         }
908 };
909
910 void DocumentExporter::exportCurrentScene(Scene *sce, const char* filename)
911 {
912         PointerRNA sceneptr, unit_settings;
913         PropertyRNA *system; /* unused , *scale; */
914
915         clear_global_id_map();
916         
917         COLLADABU::NativeString native_filename =
918                 COLLADABU::NativeString(std::string(filename));
919         COLLADASW::StreamWriter sw(native_filename);
920
921         // open <collada>
922         sw.startDocument();
923
924         // <asset>
925         COLLADASW::Asset asset(&sw);
926
927         RNA_id_pointer_create(&(sce->id), &sceneptr);
928         unit_settings = RNA_pointer_get(&sceneptr, "unit_settings");
929         system = RNA_struct_find_property(&unit_settings, "system");
930         //scale = RNA_struct_find_property(&unit_settings, "scale_length");
931
932         std::string unitname = "meter";
933         float linearmeasure = 1.0f;
934
935         linearmeasure = RNA_float_get(&unit_settings, "scale_length");
936
937         switch(RNA_property_enum_get(&unit_settings, system)) {
938                 case USER_UNIT_NONE:
939                 case USER_UNIT_METRIC:
940                         if(linearmeasure == 0.001f) {
941                                 unitname = "millimeter";
942                         }
943                         else if(linearmeasure == 0.01f) {
944                                 unitname = "centimeter";
945                         }
946                         else if(linearmeasure == 0.1f) {
947                                 unitname = "decimeter";
948                         }
949                         else if(linearmeasure == 1.0f) {
950                                 unitname = "meter";
951                         }
952                         else if(linearmeasure == 1000.0f) {
953                                 unitname = "kilometer";
954                         }
955                         break;
956                 case USER_UNIT_IMPERIAL:
957                         if(linearmeasure == 0.0254f) {
958                                 unitname = "inch";
959                         }
960                         else if(linearmeasure == 0.3048f) {
961                                 unitname = "foot";
962                         }
963                         else if(linearmeasure == 0.9144f) {
964                                 unitname = "yard";
965                         }
966                         break;
967                 default:
968                         break;
969         }
970
971         asset.setUnit(unitname, linearmeasure);
972         asset.setUpAxisType(COLLADASW::Asset::Z_UP);
973         // TODO: need an Author field in userpref
974         if(strlen(U.author) > 0) {
975                 asset.getContributor().mAuthor = U.author;
976         }
977         else {
978                 asset.getContributor().mAuthor = "Blender User";
979         }
980 #ifdef NAN_BUILDINFO
981         char version_buf[128];
982         sprintf(version_buf, "Blender %d.%02d.%d r%s", BLENDER_VERSION/100, BLENDER_VERSION%100, BLENDER_SUBVERSION, build_rev);
983         asset.getContributor().mAuthoringTool = version_buf;
984 #else
985         asset.getContributor().mAuthoringTool = "Blender 2.5x";
986 #endif
987         asset.add();
988         
989         // <library_cameras>
990         CamerasExporter ce(&sw);
991         ce.exportCameras(sce);
992         
993         // <library_lights>
994         LightsExporter le(&sw);
995         le.exportLights(sce);
996
997         // <library_images>
998         ImagesExporter ie(&sw, filename);
999         ie.exportImages(sce);
1000         
1001         // <library_effects>
1002         EffectsExporter ee(&sw);
1003         ee.exportEffects(sce);
1004         
1005         // <library_materials>
1006         MaterialsExporter me(&sw);
1007         me.exportMaterials(sce);
1008
1009         // <library_geometries>
1010         GeometryExporter ge(&sw);
1011         ge.exportGeom(sce);
1012
1013         // <library_animations>
1014         AnimationExporter ae(&sw);
1015         ae.exportAnimations(sce);
1016
1017         // <library_controllers>
1018         ArmatureExporter arm_exporter(&sw);
1019         arm_exporter.export_controllers(sce);
1020
1021         // <library_visual_scenes>
1022         SceneExporter se(&sw, &arm_exporter);
1023         se.exportScene(sce);
1024         
1025         // <scene>
1026         std::string scene_name(translate_id(id_name(sce)));
1027         COLLADASW::Scene scene(&sw, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING,
1028                                                                                            scene_name));
1029         scene.add();
1030         
1031         // close <Collada>
1032         sw.endDocument();
1033
1034 }
1035
1036 void DocumentExporter::exportScenes(const char* filename)
1037 {
1038 }
1039
1040 /*
1041
1042 NOTES:
1043
1044 * AnimationExporter::sample_animation enables all curves on armature, this is undesirable for a user
1045
1046  */