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