Fix #27855: crash on enabling high resolution smoke.
[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, bool export_selected) {
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, export_selected);
183
184                 // </visual_scene> </library_visual_scenes>
185                 closeVisualScene();
186
187                 closeLibrary();
188         }
189
190         void exportHierarchy(Scene *sce, bool export_selected)
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_ARMATURE:
202                                 case OB_EMPTY:
203                                         if (export_selected && !(ob->flag & SELECT)) {
204                                                 break;
205                                         }
206                                         // write nodes....
207                                         writeNodes(ob, sce);
208                                         break;
209                                 }
210                         }
211
212                         base= base->next;
213                 }
214         }
215
216
217         // called for each object
218         //void operator()(Object *ob) {
219         void writeNodes(Object *ob, Scene *sce)
220         {
221                 COLLADASW::Node node(mSW);
222                 node.setNodeId(translate_id(id_name(ob)));
223                 node.setType(COLLADASW::Node::NODE);
224
225                 node.start();
226
227                 bool is_skinned_mesh = arm_exporter->is_skinned_mesh(ob);
228
229                 if (ob->type == OB_MESH && is_skinned_mesh)
230                         // for skinned mesh we write obmat in <bind_shape_matrix>
231                         TransformWriter::add_node_transform_identity(node);
232                 else
233                         TransformWriter::add_node_transform_ob(node, ob);
234                 
235                 // <instance_geometry>
236                 if (ob->type == OB_MESH) {
237                         if (is_skinned_mesh) {
238                                 arm_exporter->add_instance_controller(ob);
239                         }
240                         else {
241                                 COLLADASW::InstanceGeometry instGeom(mSW);
242                                 instGeom.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob)));
243
244                                 InstanceWriter::add_material_bindings(instGeom.getBindMaterial(), ob);
245                         
246                                 instGeom.add();
247                         }
248                 }
249
250                 // <instance_controller>
251                 else if (ob->type == OB_ARMATURE) {
252                         arm_exporter->add_armature_bones(ob, sce);
253
254                         // XXX this looks unstable...
255                         node.end();
256                 }
257                 
258                 // <instance_camera>
259                 else if (ob->type == OB_CAMERA) {
260                         COLLADASW::InstanceCamera instCam(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_camera_id(ob)));
261                         instCam.add();
262                 }
263                 
264                 // <instance_light>
265                 else if (ob->type == OB_LAMP) {
266                         COLLADASW::InstanceLight instLa(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_light_id(ob)));
267                         instLa.add();
268                 }
269
270                 // empty object
271                 else if (ob->type == OB_EMPTY) {
272                 }
273
274                 // write nodes for child objects
275                 Base *b = (Base*) sce->base.first;
276                 while(b) {
277                         // cob - child object
278                         Object *cob = b->object;
279
280                         if (cob->parent == ob) {
281                                 switch(cob->type) {
282                                 case OB_MESH:
283                                 case OB_CAMERA:
284                                 case OB_LAMP:
285                                 case OB_EMPTY:
286                                 case OB_ARMATURE:
287                                         // write node...
288                                         writeNodes(cob, sce);
289                                         break;
290                                 }
291                         }
292
293                         b = b->next;
294                 }
295
296                 if (ob->type != OB_ARMATURE)
297                         node.end();
298         }
299 };
300
301 // TODO: it would be better to instantiate animations rather than create a new one per object
302 // COLLADA allows this through multiple <channel>s in <animation>.
303 // For this to work, we need to know objects that use a certain action.
304 class AnimationExporter: COLLADASW::LibraryAnimations
305 {
306         Scene *scene;
307         COLLADASW::StreamWriter *sw;
308
309 public:
310
311         AnimationExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryAnimations(sw) { this->sw = sw; }
312
313
314
315         void exportAnimations(Scene *sce)
316         {
317                 if(hasAnimations(sce)) {
318                         this->scene = sce;
319
320                         openLibrary();
321
322                         forEachObjectInScene(sce, *this);
323
324                         closeLibrary();
325                 }
326         }
327
328         // called for each exported object
329         void operator() (Object *ob) 
330         {
331                 if (!ob->adt || !ob->adt->action) return;
332                 
333                 FCurve *fcu = (FCurve*)ob->adt->action->curves.first;
334                 
335                 if (ob->type == OB_ARMATURE) {
336                         if (!ob->data) return;
337
338                         bArmature *arm = (bArmature*)ob->data;
339                         for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next)
340                                 write_bone_animation(ob, bone);
341                 }
342                 else {
343                         while (fcu) {
344                                 // TODO "rotation_quaternion" is also possible for objects (although euler is default)
345                                 if ((!strcmp(fcu->rna_path, "location") || !strcmp(fcu->rna_path, "scale")) ||
346                                         (!strcmp(fcu->rna_path, "rotation_euler") && ob->rotmode == ROT_MODE_EUL))
347                                         dae_animation(fcu, id_name(ob));
348
349                                 fcu = fcu->next;
350                         }
351                 }
352         }
353
354 protected:
355
356         void dae_animation(FCurve *fcu, std::string ob_name)
357         {
358                 const char *axis_names[] = {"X", "Y", "Z"};
359                 const char *axis_name = NULL;
360                 char anim_id[200];
361                 
362                 if (fcu->array_index < 3)
363                         axis_name = axis_names[fcu->array_index];
364
365                 BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
366                                          fcu->rna_path, axis_names[fcu->array_index]);
367
368                 // check rna_path is one of: rotation, scale, location
369
370                 openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
371
372                 // create input source
373                 std::string input_id = create_source_from_fcurve(COLLADASW::InputSemantic::INPUT, fcu, anim_id, axis_name);
374
375                 // create output source
376                 std::string output_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name);
377
378                 // create interpolations source
379                 std::string interpolation_id = create_interpolation_source(fcu->totvert, anim_id, axis_name);
380
381                 std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
382                 COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
383                 std::string empty;
384                 sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
385                 sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
386
387                 // this input is required
388                 sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
389
390                 addSampler(sampler);
391
392                 std::string target = translate_id(ob_name)
393                         + "/" + get_transform_sid(fcu->rna_path, -1, axis_name, true);
394                 addChannel(COLLADABU::URI(empty, sampler_id), target);
395
396                 closeAnimation();
397         }
398
399         void write_bone_animation(Object *ob_arm, Bone *bone)
400         {
401                 if (!ob_arm->adt)
402                         return;
403
404                 for (int i = 0; i < 3; i++)
405                         sample_and_write_bone_animation(ob_arm, bone, i);
406
407                 for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next)
408                         write_bone_animation(ob_arm, child);
409         }
410
411         void sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type)
412         {
413                 bArmature *arm = (bArmature*)ob_arm->data;
414                 int flag = arm->flag;
415                 std::vector<float> fra;
416                 char prefix[256];
417
418                 BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone->name);
419
420                 bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name);
421                 if (!pchan)
422                         return;
423
424                 switch (transform_type) {
425                 case 0:
426                         find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode);
427                         break;
428                 case 1:
429                         find_frames(ob_arm, fra, prefix, "scale");
430                         break;
431                 case 2:
432                         find_frames(ob_arm, fra, prefix, "location");
433                         break;
434                 default:
435                         return;
436                 }
437
438                 // exit rest position
439                 if (flag & ARM_RESTPOS) {
440                         arm->flag &= ~ARM_RESTPOS;
441                         where_is_pose(scene, ob_arm);
442                 }
443
444                 if (fra.size()) {
445                         float *v = (float*)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames");
446                         sample_animation(v, fra, transform_type, bone, ob_arm);
447
448                         if (transform_type == 0) {
449                                 // write x, y, z curves separately if it is rotation
450                                 float *c = (float*)MEM_callocN(sizeof(float) * fra.size(), "temp. anim frames");
451                                 for (int i = 0; i < 3; i++) {
452                                         for (unsigned int j = 0; j < fra.size(); j++)
453                                                 c[j] = v[j * 3 + i];
454
455                                         dae_bone_animation(fra, c, transform_type, i, id_name(ob_arm), bone->name);
456                                 }
457                                 MEM_freeN(c);
458                         }
459                         else {
460                                 // write xyz at once if it is location or scale
461                                 dae_bone_animation(fra, v, transform_type, -1, id_name(ob_arm), bone->name);
462                         }
463
464                         MEM_freeN(v);
465                 }
466
467                 // restore restpos
468                 if (flag & ARM_RESTPOS) 
469                         arm->flag = flag;
470                 where_is_pose(scene, ob_arm);
471         }
472
473         void sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm)
474         {
475                 bPoseChannel *pchan, *parchan = NULL;
476                 bPose *pose = ob_arm->pose;
477
478                 pchan = get_pose_channel(pose, bone->name);
479
480                 if (!pchan)
481                         return;
482
483                 parchan = pchan->parent;
484
485                 enable_fcurves(ob_arm->adt->action, bone->name);
486
487                 std::vector<float>::iterator it;
488                 for (it = frames.begin(); it != frames.end(); it++) {
489                         float mat[4][4], ipar[4][4];
490
491                         float ctime = bsystem_time(scene, ob_arm, *it, 0.0f);
492
493                         BKE_animsys_evaluate_animdata(&ob_arm->id, ob_arm->adt, *it, ADT_RECALC_ANIM);
494                         where_is_pose_bone(scene, ob_arm, pchan, ctime, 1);
495
496                         // compute bone local mat
497                         if (bone->parent) {
498                                 invert_m4_m4(ipar, parchan->pose_mat);
499                                 mul_m4_m4m4(mat, pchan->pose_mat, ipar);
500                         }
501                         else
502                                 copy_m4_m4(mat, pchan->pose_mat);
503
504                         switch (type) {
505                         case 0:
506                                 mat4_to_eul(v, mat);
507                                 break;
508                         case 1:
509                                 mat4_to_size(v, mat);
510                                 break;
511                         case 2:
512                                 copy_v3_v3(v, mat[3]);
513                                 break;
514                         }
515
516                         v += 3;
517                 }
518
519                 enable_fcurves(ob_arm->adt->action, NULL);
520         }
521
522         // dae_bone_animation -> add_bone_animation
523         // (blend this into dae_bone_animation)
524         void dae_bone_animation(std::vector<float> &fra, float *v, int tm_type, int axis, std::string ob_name, std::string bone_name)
525         {
526                 const char *axis_names[] = {"X", "Y", "Z"};
527                 const char *axis_name = NULL;
528                 char anim_id[200];
529                 bool is_rot = tm_type == 0;
530                 
531                 if (!fra.size())
532                         return;
533
534                 char rna_path[200];
535                 BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].%s", bone_name.c_str(),
536                                          tm_type == 0 ? "rotation_quaternion" : (tm_type == 1 ? "scale" : "location"));
537
538                 if (axis > -1)
539                         axis_name = axis_names[axis];
540                 
541                 std::string transform_sid = get_transform_sid(NULL, tm_type, axis_name, false);
542                 
543                 BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
544                                          (char*)translate_id(bone_name).c_str(), (char*)transform_sid.c_str());
545
546                 openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
547
548                 // create input source
549                 std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, is_rot, anim_id, axis_name);
550
551                 // create output source
552                 std::string output_id;
553                 if (axis == -1)
554                         output_id = create_xyz_source(v, fra.size(), anim_id);
555                 else
556                         output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, v, fra.size(), is_rot, anim_id, axis_name);
557
558                 // create interpolations source
559                 std::string interpolation_id = create_interpolation_source(fra.size(), anim_id, axis_name);
560
561                 std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
562                 COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
563                 std::string empty;
564                 sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
565                 sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
566
567                 // TODO create in/out tangents source
568
569                 // this input is required
570                 sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
571
572                 addSampler(sampler);
573
574                 std::string target = translate_id(ob_name + "_" + bone_name) + "/" + transform_sid;
575                 addChannel(COLLADABU::URI(empty, sampler_id), target);
576
577                 closeAnimation();
578         }
579
580         float convert_time(float frame)
581         {
582                 return FRA2TIME(frame);
583         }
584
585         float convert_angle(float angle)
586         {
587                 return COLLADABU::Math::Utils::radToDegF(angle);
588         }
589
590         std::string get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic)
591         {
592                 switch(semantic) {
593                 case COLLADASW::InputSemantic::INPUT:
594                         return INPUT_SOURCE_ID_SUFFIX;
595                 case COLLADASW::InputSemantic::OUTPUT:
596                         return OUTPUT_SOURCE_ID_SUFFIX;
597                 case COLLADASW::InputSemantic::INTERPOLATION:
598                         return INTERPOLATION_SOURCE_ID_SUFFIX;
599                 case COLLADASW::InputSemantic::IN_TANGENT:
600                         return INTANGENT_SOURCE_ID_SUFFIX;
601                 case COLLADASW::InputSemantic::OUT_TANGENT:
602                         return OUTTANGENT_SOURCE_ID_SUFFIX;
603                 default:
604                         break;
605                 }
606                 return "";
607         }
608
609         void add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
610                                                            COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis)
611         {
612                 switch(semantic) {
613                 case COLLADASW::InputSemantic::INPUT:
614                         param.push_back("TIME");
615                         break;
616                 case COLLADASW::InputSemantic::OUTPUT:
617                         if (is_rot) {
618                                 param.push_back("ANGLE");
619                         }
620                         else {
621                                 if (axis) {
622                                         param.push_back(axis);
623                                 }
624                                 else {
625                                         param.push_back("X");
626                                         param.push_back("Y");
627                                         param.push_back("Z");
628                                 }
629                         }
630                         break;
631                 case COLLADASW::InputSemantic::IN_TANGENT:
632                 case COLLADASW::InputSemantic::OUT_TANGENT:
633                         param.push_back("X");
634                         param.push_back("Y");
635                         break;
636                 default:
637                         break;
638                 }
639         }
640
641         void get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool rotation, float *values, int *length)
642         {
643                 switch (semantic) {
644                 case COLLADASW::InputSemantic::INPUT:
645                         *length = 1;
646                         values[0] = convert_time(bezt->vec[1][0]);
647                         break;
648                 case COLLADASW::InputSemantic::OUTPUT:
649                         *length = 1;
650                         if (rotation) {
651                                 values[0] = convert_angle(bezt->vec[1][1]);
652                         }
653                         else {
654                                 values[0] = bezt->vec[1][1];
655                         }
656                         break;
657                 case COLLADASW::InputSemantic::IN_TANGENT:
658                 case COLLADASW::InputSemantic::OUT_TANGENT:
659                         // XXX
660                         *length = 2;
661                         break;
662                 default:
663                         *length = 0;
664                         break;
665                 }
666         }
667
668         std::string create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name)
669         {
670                 std::string source_id = anim_id + get_semantic_suffix(semantic);
671
672                 //bool is_rotation = !strcmp(fcu->rna_path, "rotation");
673                 bool is_rotation = false;
674                 
675                 if (strstr(fcu->rna_path, "rotation")) is_rotation = true;
676                 
677                 COLLADASW::FloatSourceF source(mSW);
678                 source.setId(source_id);
679                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
680                 source.setAccessorCount(fcu->totvert);
681                 source.setAccessorStride(1);
682                 
683                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
684                 add_source_parameters(param, semantic, is_rotation, axis_name);
685
686                 source.prepareToAppendValues();
687
688                 for (unsigned int i = 0; i < fcu->totvert; i++) {
689                         float values[3]; // be careful!
690                         int length = 0;
691
692                         get_source_values(&fcu->bezt[i], semantic, is_rotation, values, &length);
693                         for (int j = 0; j < length; j++)
694                                 source.appendValues(values[j]);
695                 }
696
697                 source.finish();
698
699                 return source_id;
700         }
701
702         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)
703         {
704                 std::string source_id = anim_id + get_semantic_suffix(semantic);
705
706                 COLLADASW::FloatSourceF source(mSW);
707                 source.setId(source_id);
708                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
709                 source.setAccessorCount(tot);
710                 source.setAccessorStride(1);
711                 
712                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
713                 add_source_parameters(param, semantic, is_rot, axis_name);
714
715                 source.prepareToAppendValues();
716
717                 for (int i = 0; i < tot; i++) {
718                         float val = v[i];
719                         if (semantic == COLLADASW::InputSemantic::INPUT)
720                                 val = convert_time(val);
721                         else if (is_rot)
722                                 val = convert_angle(val);
723                         source.appendValues(val);
724                 }
725
726                 source.finish();
727
728                 return source_id;
729         }
730
731         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)
732         {
733                 std::string source_id = anim_id + get_semantic_suffix(semantic);
734
735                 COLLADASW::FloatSourceF source(mSW);
736                 source.setId(source_id);
737                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
738                 source.setAccessorCount(fra.size());
739                 source.setAccessorStride(1);
740                 
741                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
742                 add_source_parameters(param, semantic, is_rot, axis_name);
743
744                 source.prepareToAppendValues();
745
746                 std::vector<float>::iterator it;
747                 for (it = fra.begin(); it != fra.end(); it++) {
748                         float val = *it;
749                         if (semantic == COLLADASW::InputSemantic::INPUT)
750                                 val = convert_time(val);
751                         else if (is_rot)
752                                 val = convert_angle(val);
753                         source.appendValues(val);
754                 }
755
756                 source.finish();
757
758                 return source_id;
759         }
760
761         // only used for sources with OUTPUT semantic
762         std::string create_xyz_source(float *v, int tot, const std::string& anim_id)
763         {
764                 COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
765                 std::string source_id = anim_id + get_semantic_suffix(semantic);
766
767                 COLLADASW::FloatSourceF source(mSW);
768                 source.setId(source_id);
769                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
770                 source.setAccessorCount(tot);
771                 source.setAccessorStride(3);
772                 
773                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
774                 add_source_parameters(param, semantic, false, NULL);
775
776                 source.prepareToAppendValues();
777
778                 for (int i = 0; i < tot; i++) {
779                         source.appendValues(*v, *(v + 1), *(v + 2));
780                         v += 3;
781                 }
782
783                 source.finish();
784
785                 return source_id;
786         }
787
788         std::string create_interpolation_source(int tot, const std::string& anim_id, const char *axis_name)
789         {
790                 std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
791
792                 COLLADASW::NameSource source(mSW);
793                 source.setId(source_id);
794                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
795                 source.setAccessorCount(tot);
796                 source.setAccessorStride(1);
797                 
798                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
799                 param.push_back("INTERPOLATION");
800
801                 source.prepareToAppendValues();
802
803                 for (int i = 0; i < tot; i++) {
804                         source.appendValues(LINEAR_NAME);
805                 }
806
807                 source.finish();
808
809                 return source_id;
810         }
811
812         // for rotation, axis name is always appended and the value of append_axis is ignored
813         std::string get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
814         {
815                 std::string tm_name;
816
817                 // when given rna_path, determine tm_type from it
818                 if (rna_path) {
819                         char *name = extract_transform_name(rna_path);
820
821                         if (strstr(name, "rotation"))
822                                 tm_type = 0;
823                         else if (!strcmp(name, "scale"))
824                                 tm_type = 1;
825                         else if (!strcmp(name, "location"))
826                                 tm_type = 2;
827                         else
828                                 tm_type = -1;
829                 }
830
831                 switch (tm_type) {
832                 case 0:
833                         return std::string("rotation") + std::string(axis_name) + ".ANGLE";
834                 case 1:
835                         tm_name = "scale";
836                         break;
837                 case 2:
838                         tm_name = "location";
839                         break;
840                 default:
841                         tm_name = "";
842                         break;
843                 }
844
845                 if (tm_name.size()) {
846                         if (append_axis)
847                                 return tm_name + std::string(".") + std::string(axis_name);
848                         else
849                                 return tm_name;
850                 }
851
852                 return std::string("");
853         }
854
855         char *extract_transform_name(char *rna_path)
856         {
857                 char *dot = strrchr(rna_path, '.');
858                 return dot ? (dot + 1) : rna_path;
859         }
860
861         void find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name)
862         {
863                 FCurve *fcu= (FCurve*)ob->adt->action->curves.first;
864
865                 for (; fcu; fcu = fcu->next) {
866                         if (prefix && strncmp(prefix, fcu->rna_path, strlen(prefix)))
867                                 continue;
868
869                         char *name = extract_transform_name(fcu->rna_path);
870                         if (!strcmp(name, tm_name)) {
871                                 for (unsigned int i = 0; i < fcu->totvert; i++) {
872                                         float f = fcu->bezt[i].vec[1][0];
873                                         if (std::find(fra.begin(), fra.end(), f) == fra.end())
874                                                 fra.push_back(f);
875                                 }
876                         }
877                 }
878
879                 // keep the keys in ascending order
880                 std::sort(fra.begin(), fra.end());
881         }
882
883         void find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode)
884         {
885                 if (rotmode > 0)
886                         find_frames(ob, fra, prefix, "rotation_euler");
887                 else if (rotmode == ROT_MODE_QUAT)
888                         find_frames(ob, fra, prefix, "rotation_quaternion");
889                 /*else if (rotmode == ROT_MODE_AXISANGLE)
890                         ;*/
891         }
892
893         // enable fcurves driving a specific bone, disable all the rest
894         // if bone_name = NULL enable all fcurves
895         void enable_fcurves(bAction *act, char *bone_name)
896         {
897                 FCurve *fcu;
898                 char prefix[200];
899
900                 if (bone_name)
901                         BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name);
902
903                 for (fcu = (FCurve*)act->curves.first; fcu; fcu = fcu->next) {
904                         if (bone_name) {
905                                 if (!strncmp(fcu->rna_path, prefix, strlen(prefix)))
906                                         fcu->flag &= ~FCURVE_DISABLED;
907                                 else
908                                         fcu->flag |= FCURVE_DISABLED;
909                         }
910                         else {
911                                 fcu->flag &= ~FCURVE_DISABLED;
912                         }
913                 }
914         }
915         
916         bool hasAnimations(Scene *sce)
917         {
918                 Base *base= (Base*) sce->base.first;
919                 while(base) {
920                         Object *ob = base->object;
921                         
922                         FCurve *fcu = 0;
923                         if(ob->adt && ob->adt->action)
924                                 fcu = (FCurve*)ob->adt->action->curves.first;
925                                 
926                         if ((ob->type == OB_ARMATURE && ob->data) || fcu) {
927                                 return true;
928                         }
929                         base= base->next;
930                 }
931                 return false;
932         }
933 };
934
935 void DocumentExporter::exportCurrentScene(Scene *sce, const char* filename, bool selected)
936 {
937         PointerRNA sceneptr, unit_settings;
938         PropertyRNA *system; /* unused , *scale; */
939
940         clear_global_id_map();
941         
942         COLLADABU::NativeString native_filename =
943                 COLLADABU::NativeString(std::string(filename));
944         COLLADASW::StreamWriter sw(native_filename);
945
946         // open <collada>
947         sw.startDocument();
948
949         // <asset>
950         COLLADASW::Asset asset(&sw);
951
952         RNA_id_pointer_create(&(sce->id), &sceneptr);
953         unit_settings = RNA_pointer_get(&sceneptr, "unit_settings");
954         system = RNA_struct_find_property(&unit_settings, "system");
955         //scale = RNA_struct_find_property(&unit_settings, "scale_length");
956
957         std::string unitname = "meter";
958         float linearmeasure = 1.0f;
959
960         linearmeasure = RNA_float_get(&unit_settings, "scale_length");
961
962         switch(RNA_property_enum_get(&unit_settings, system)) {
963                 case USER_UNIT_NONE:
964                 case USER_UNIT_METRIC:
965                         if(linearmeasure == 0.001f) {
966                                 unitname = "millimeter";
967                         }
968                         else if(linearmeasure == 0.01f) {
969                                 unitname = "centimeter";
970                         }
971                         else if(linearmeasure == 0.1f) {
972                                 unitname = "decimeter";
973                         }
974                         else if(linearmeasure == 1.0f) {
975                                 unitname = "meter";
976                         }
977                         else if(linearmeasure == 1000.0f) {
978                                 unitname = "kilometer";
979                         }
980                         break;
981                 case USER_UNIT_IMPERIAL:
982                         if(linearmeasure == 0.0254f) {
983                                 unitname = "inch";
984                         }
985                         else if(linearmeasure == 0.3048f) {
986                                 unitname = "foot";
987                         }
988                         else if(linearmeasure == 0.9144f) {
989                                 unitname = "yard";
990                         }
991                         break;
992                 default:
993                         break;
994         }
995
996         asset.setUnit(unitname, linearmeasure);
997         asset.setUpAxisType(COLLADASW::Asset::Z_UP);
998         // TODO: need an Author field in userpref
999         if(strlen(U.author) > 0) {
1000                 asset.getContributor().mAuthor = U.author;
1001         }
1002         else {
1003                 asset.getContributor().mAuthor = "Blender User";
1004         }
1005 #ifdef NAN_BUILDINFO
1006         char version_buf[128];
1007         sprintf(version_buf, "Blender %d.%02d.%d r%s", BLENDER_VERSION/100, BLENDER_VERSION%100, BLENDER_SUBVERSION, build_rev);
1008         asset.getContributor().mAuthoringTool = version_buf;
1009 #else
1010         asset.getContributor().mAuthoringTool = "Blender 2.5x";
1011 #endif
1012         asset.add();
1013         
1014         // <library_cameras>
1015         if(has_object_type(sce, OB_CAMERA)) {
1016                 CamerasExporter ce(&sw);
1017                 ce.exportCameras(sce, selected);
1018         }
1019         
1020         // <library_lights>
1021         if(has_object_type(sce, OB_LAMP)) {
1022                 LightsExporter le(&sw);
1023                 le.exportLights(sce, selected);
1024         }
1025
1026         // <library_images>
1027         ImagesExporter ie(&sw, filename);
1028         ie.exportImages(sce, selected);
1029         
1030         // <library_effects>
1031         EffectsExporter ee(&sw);
1032         ee.exportEffects(sce, selected);
1033         
1034         // <library_materials>
1035         MaterialsExporter me(&sw);
1036         me.exportMaterials(sce, selected);
1037
1038         // <library_geometries>
1039         if(has_object_type(sce, OB_MESH)) {
1040                 GeometryExporter ge(&sw);
1041                 ge.exportGeom(sce, selected);
1042         }
1043
1044         // <library_animations>
1045         AnimationExporter ae(&sw);
1046         ae.exportAnimations(sce);
1047
1048         // <library_controllers>
1049         ArmatureExporter arm_exporter(&sw);
1050         if(has_object_type(sce, OB_ARMATURE)) {
1051                 arm_exporter.export_controllers(sce, selected);
1052         }
1053
1054         // <library_visual_scenes>
1055         SceneExporter se(&sw, &arm_exporter);
1056         se.exportScene(sce, selected);
1057         
1058         // <scene>
1059         std::string scene_name(translate_id(id_name(sce)));
1060         COLLADASW::Scene scene(&sw, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING,
1061                                                                                            scene_name));
1062         scene.add();
1063         
1064         // close <Collada>
1065         sw.endDocument();
1066
1067 }
1068
1069 void DocumentExporter::exportScenes(const char* filename)
1070 {
1071 }
1072
1073 /*
1074
1075 NOTES:
1076
1077 * AnimationExporter::sample_animation enables all curves on armature, this is undesirable for a user
1078
1079  */