COLLADA branch: bone anim export works. Export-import roundtrip is possible.
[blender.git] / source / blender / collada / DocumentExporter.cpp
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <math.h>
4
5 #include "DNA_scene_types.h"
6 #include "DNA_object_types.h"
7 #include "DNA_meshdata_types.h"
8 #include "DNA_mesh_types.h"
9 #include "DNA_image_types.h"
10 #include "DNA_material_types.h"
11 #include "DNA_texture_types.h"
12 #include "DNA_camera_types.h"
13 #include "DNA_lamp_types.h"
14 #include "DNA_anim_types.h"
15 #include "DNA_action_types.h"
16 #include "DNA_curve_types.h"
17 #include "DNA_armature_types.h"
18 #include "DNA_modifier_types.h"
19
20 extern "C" 
21 {
22 #include "BKE_DerivedMesh.h"
23 #include "BKE_fcurve.h"
24 #include "BKE_animsys.h"
25 #include "BLI_util.h"
26 #include "BLI_fileops.h"
27 #include "ED_keyframing.h"
28 }
29
30 #include "MEM_guardedalloc.h"
31
32 #include "BKE_scene.h"
33 #include "BKE_global.h"
34 #include "BKE_main.h"
35 #include "BKE_material.h"
36 #include "BKE_action.h" // pose functions
37 #include "BKE_armature.h"
38 #include "BKE_image.h"
39 #include "BKE_utildefines.h"
40 #include "BKE_object.h"
41
42 #include "BLI_math.h"
43 #include "BLI_string.h"
44 #include "BLI_listbase.h"
45
46 #include "COLLADASWAsset.h"
47 #include "COLLADASWLibraryVisualScenes.h"
48 #include "COLLADASWNode.h"
49 #include "COLLADASWLibraryGeometries.h"
50 #include "COLLADASWSource.h"
51 #include "COLLADASWInstanceGeometry.h"
52 #include "COLLADASWInputList.h"
53 #include "COLLADASWPrimitves.h"
54 #include "COLLADASWVertices.h"
55 #include "COLLADASWLibraryAnimations.h"
56 #include "COLLADASWLibraryImages.h"
57 #include "COLLADASWLibraryEffects.h"
58 #include "COLLADASWImage.h"
59 #include "COLLADASWEffectProfile.h"
60 #include "COLLADASWColorOrTexture.h"
61 #include "COLLADASWParamTemplate.h"
62 #include "COLLADASWParamBase.h"
63 #include "COLLADASWSurfaceInitOption.h"
64 #include "COLLADASWSampler.h"
65 #include "COLLADASWScene.h"
66 //#include "COLLADASWSurface.h"
67 #include "COLLADASWTechnique.h"
68 #include "COLLADASWTexture.h"
69 #include "COLLADASWLibraryMaterials.h"
70 #include "COLLADASWBindMaterial.h"
71 #include "COLLADASWLibraryCameras.h"
72 #include "COLLADASWLibraryLights.h"
73 #include "COLLADASWInstanceCamera.h"
74 #include "COLLADASWInstanceLight.h"
75 #include "COLLADASWCameraOptic.h"
76 #include "COLLADASWConstants.h"
77 #include "COLLADASWLibraryControllers.h"
78 #include "COLLADASWInstanceController.h"
79 #include "COLLADASWBaseInputElement.h"
80
81 #include "collada_internal.h"
82 #include "DocumentExporter.h"
83
84 #include <vector>
85 #include <algorithm> // std::find
86
87 // arithb.c now has QuatToAxisAngle too
88 #if 0
89 // This function assumes that quat is normalized.
90 // The following document was used as reference:
91 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
92 void quat_to_axis_angle( float *axis, float *angle,float *q)
93 {
94         // quat to axis angle
95         *angle = 2 * acos(q[0]);
96         float divisor = sqrt(1 - q[0] * q[0]);
97
98         // test to avoid divide by zero, divisor is always positive
99         if (divisor < 0.001f ) {
100                 axis[0] = 1.0f;
101                 axis[1] = 0.0f;
102                 axis[2] = 0.0f;
103         }
104         else {
105                 axis[0] = q[1] / divisor;
106                 axis[1] = q[2] / divisor;
107                 axis[2] = q[3] / divisor;
108         }
109 }
110 #endif
111
112 char *CustomData_get_layer_name(const struct CustomData *data, int type, int n)
113 {
114         int layer_index = CustomData_get_layer_index(data, type);
115         if(layer_index < 0) return NULL;
116
117         return data->layers[layer_index+n].name;
118 }
119
120 char *CustomData_get_active_layer_name(const CustomData *data, int type)
121 {
122         /* get the layer index of the active layer of type */
123         int layer_index = CustomData_get_active_layer_index(data, type);
124         if(layer_index < 0) return NULL;
125
126         return data->layers[layer_index].name;
127 }
128
129 /**
130 Translation map.
131 Used to translate every COLLADA id to a valid id, no matter what "wrong" letters may be
132 included. Look at the IDREF XSD declaration for more.
133 Follows strictly the COLLADA XSD declaration which explicitly allows non-english chars,
134 like special chars (e.g. micro sign), umlauts and so on.
135 The COLLADA spec also allows additional chars for member access ('.'), these
136 must obviously be removed too, otherwise they would be heavily misinterpreted.
137 */
138 const unsigned char translate_map[256] = {
139         95, 95, 95, 95, 95, 95, 95, 95,
140         95, 95, 95, 95, 95, 95, 95, 95,
141         95, 95, 95, 95, 95, 95, 95, 95,
142         95, 95, 95, 95, 95, 95, 95, 95,
143         95, 95, 95, 95, 95, 95, 95, 95,
144         95, 95, 95, 95, 95, 45, 95, 95,
145         48, 49, 50, 51, 52, 53, 54, 55,
146         56, 57, 95, 95, 95, 95, 95, 95,
147         95, 65, 66, 67, 68, 69, 70, 71,
148         72, 73, 74, 75, 76, 77, 78, 79,
149         80, 81, 82, 83, 84, 85, 86, 87,
150         88, 89, 90, 95, 95, 95, 95, 95,
151         95, 97, 98, 99, 100, 101, 102, 103,
152         104, 105, 106, 107, 108, 109, 110, 111,
153         112, 113, 114, 115, 116, 117, 118, 119,
154         120, 121, 122, 95, 95, 95, 95, 95,
155         95, 95, 95, 95, 95, 95, 95, 95,
156         95, 95, 95, 95, 95, 95, 95, 95,
157         95, 95, 95, 95, 95, 95, 95, 95,
158         95, 95, 95, 95, 95, 95, 95, 95,
159         95, 95, 95, 95, 95, 95, 95, 95,
160         95, 95, 95, 95, 95, 95, 95, 95,
161         95, 95, 95, 95, 95, 95, 95, 183,
162         95, 95, 95, 95, 95, 95, 95, 95,
163         192, 193, 194, 195, 196, 197, 198, 199,
164         200, 201, 202, 203, 204, 205, 206, 207,
165         208, 209, 210, 211, 212, 213, 214, 95,
166         216, 217, 218, 219, 220, 221, 222, 223,
167         224, 225, 226, 227, 228, 229, 230, 231,
168         232, 233, 234, 235, 236, 237, 238, 239,
169         240, 241, 242, 243, 244, 245, 246, 95,
170         248, 249, 250, 251, 252, 253, 254, 255};
171
172 /** Look at documentation of translate_map */
173 static std::string translate_id(const std::string &id)
174 {
175         std::string id_translated = id;
176         for (int i=0; i < id_translated.size(); i++)
177         {
178                 id_translated[i] = translate_map[id_translated[i]];
179         }
180         return id_translated;
181 }
182
183 static std::string id_name(void *id)
184 {
185         return ((ID*)id)->name + 2;
186 }
187
188 static std::string get_geometry_id(Object *ob)
189 {
190         return translate_id(id_name(ob)) + "-mesh";
191 }
192
193 static std::string get_light_id(Object *ob)
194 {
195         return translate_id(id_name(ob)) + "-light";
196 }
197
198 static std::string get_camera_id(Object *ob)
199 {
200         return translate_id(id_name(ob)) + "-camera";
201 }
202
203 std::string get_joint_id(Bone *bone, Object *ob_arm)
204 {
205         return translate_id(id_name(ob_arm) + "_" + bone->name);
206 }
207
208
209 /*
210   Utilities to avoid code duplication.
211   Definition can take some time to understand, but they should be useful.
212 */
213
214 // f should have
215 // void operator()(Object* ob)
216 template<class Functor>
217 void forEachMeshObjectInScene(Scene *sce, Functor &f)
218 {
219         
220         Base *base= (Base*) sce->base.first;
221         while(base) {
222                 Object *ob = base->object;
223                 
224                 if (ob->type == OB_MESH && ob->data) {
225                         f(ob);
226                 }
227                 base= base->next;
228                 
229         }
230 }
231
232 template<class Functor>
233 void forEachObjectInScene(Scene *sce, Functor &f)
234 {
235         Base *base= (Base*) sce->base.first;
236         while(base) {
237                 Object *ob = base->object;
238                         
239                 f(ob);
240
241                 base= base->next;
242         }
243 }
244
245 template<class Functor>
246 void forEachCameraObjectInScene(Scene *sce, Functor &f)
247 {
248         Base *base= (Base*) sce->base.first;
249         while(base) {
250                 Object *ob = base->object;
251                         
252                 if (ob->type == OB_CAMERA && ob->data) {
253                         f(ob, sce);
254                 }
255                 base= base->next;
256         }
257 }
258
259 template<class Functor>
260 void forEachLampObjectInScene(Scene *sce, Functor &f)
261 {
262         Base *base= (Base*) sce->base.first;
263         while(base) {
264                 Object *ob = base->object;
265                         
266                 if (ob->type == OB_LAMP && ob->data) {
267                         f(ob);
268                 }
269                 base= base->next;
270         }
271 }
272
273 // used in forEachMaterialInScene
274 template <class MaterialFunctor>
275 class ForEachMaterialFunctor
276 {
277         std::vector<std::string> mMat; // contains list of material names, to avoid duplicate calling of f
278         MaterialFunctor *f;
279 public:
280         ForEachMaterialFunctor(MaterialFunctor *f) : f(f) { }
281         void operator ()(Object *ob)
282         {
283                 int a;
284                 for(a = 0; a < ob->totcol; a++) {
285
286                         Material *ma = give_current_material(ob, a+1);
287
288                         if (!ma) continue;
289
290                         std::string translated_id = translate_id(id_name(ma));
291                         if (find(mMat.begin(), mMat.end(), translated_id) == mMat.end()) {
292                                 (*this->f)(ma, ob);
293
294                                 mMat.push_back(translated_id);
295                         }
296                 }
297         }
298 };
299
300 // calls f for each unique material linked to each object in sce
301 // f should have
302 // void operator()(Material* ma)
303 template<class Functor>
304 void forEachMaterialInScene(Scene *sce, Functor &f)
305 {
306         ForEachMaterialFunctor<Functor> matfunc(&f);
307         forEachMeshObjectInScene(sce, matfunc);
308 }
309
310 // OB_MESH is assumed
311 std::string getActiveUVLayerName(Object *ob)
312 {
313         Mesh *me = (Mesh*)ob->data;
314
315         int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
316         if (num_layers)
317                 return std::string(CustomData_get_active_layer_name(&me->fdata, CD_MTFACE));
318                 
319         return "";
320 }
321
322 // TODO: optimize UV sets by making indexed list with duplicates removed
323 class GeometryExporter : COLLADASW::LibraryGeometries
324 {
325         Scene *mScene;
326 public:
327         GeometryExporter(COLLADASW::StreamWriter *sw) : COLLADASW::LibraryGeometries(sw) {}
328
329         void exportGeom(Scene *sce)
330         {
331                 openLibrary();
332
333                 mScene = sce;
334                 forEachMeshObjectInScene(sce, *this);
335
336                 closeLibrary();
337         }
338
339         void operator()(Object *ob)
340         {
341                 // XXX don't use DerivedMesh, Mesh instead?
342
343 #if 0           
344                 DerivedMesh *dm = mesh_get_derived_final(mScene, ob, CD_MASK_BAREMESH);
345 #endif
346                 Mesh *me = (Mesh*)ob->data;
347                 std::string geom_id = get_geometry_id(ob);
348                 
349                 // openMesh(geoId, geoName, meshId)
350                 openMesh(geom_id);
351                 
352                 // writes <source> for vertex coords
353                 createVertsSource(geom_id, me);
354                 
355                 // writes <source> for normal coords
356                 createNormalsSource(geom_id, me);
357
358                 int has_uvs = CustomData_has_layer(&me->fdata, CD_MTFACE);
359                 
360                 // writes <source> for uv coords if mesh has uv coords
361                 if (has_uvs) {
362                         createTexcoordsSource(geom_id, (Mesh*)ob->data);
363                 }
364                 // <vertices>
365                 COLLADASW::Vertices verts(mSW);
366                 verts.setId(getIdBySemantics(geom_id, COLLADASW::VERTEX));
367                 COLLADASW::InputList &input_list = verts.getInputList();
368                 COLLADASW::Input input(COLLADASW::POSITION, getUrlBySemantics(geom_id, COLLADASW::POSITION));
369                 input_list.push_back(input);
370                 verts.add();
371
372                 // XXX slow             
373                 if (ob->totcol) {
374                         for(int a = 0; a < ob->totcol; a++)     {
375                                 // account for NULL materials, this should not normally happen?
376                                 Material *ma = give_current_material(ob, a + 1);
377                                 createPolylist(ma != NULL, a, has_uvs, ob, geom_id);
378                         }
379                 }
380                 else {
381                         createPolylist(false, 0, has_uvs, ob, geom_id);
382                 }
383                 
384                 closeMesh();
385                 closeGeometry();
386                 
387 #if 0
388                 dm->release(dm);
389 #endif
390         }
391
392         // powerful because it handles both cases when there is material and when there's not
393         void createPolylist(bool has_material,
394                                                 int material_index,
395                                                 bool has_uvs,
396                                                 Object *ob,
397                                                 std::string& geom_id)
398         {
399 #if 0
400                 MFace *mfaces = dm->getFaceArray(dm);
401                 int totfaces = dm->getNumFaces(dm);
402 #endif
403                 Mesh *me = (Mesh*)ob->data;
404                 MFace *mfaces = me->mface;
405                 int totfaces = me->totface;
406
407                 // <vcount>
408                 int i;
409                 int faces_in_polylist = 0;
410                 std::vector<unsigned long> vcount_list;
411
412                 // count faces with this material
413                 for (i = 0; i < totfaces; i++) {
414                         MFace *f = &mfaces[i];
415                         
416                         if ((has_material && f->mat_nr == material_index) || !has_material) {
417                                 faces_in_polylist++;
418                                 if (f->v4 == 0) {
419                                         vcount_list.push_back(3);
420                                 }
421                                 else {
422                                         vcount_list.push_back(4);
423                                 }
424                         }
425                 }
426
427                 // no faces using this material
428                 if (faces_in_polylist == 0) {
429                         return;
430                 }
431                         
432                 Material *ma = has_material ? give_current_material(ob, material_index + 1) : NULL;
433                 COLLADASW::Polylist polylist(mSW);
434                         
435                 // sets count attribute in <polylist>
436                 polylist.setCount(faces_in_polylist);
437                         
438                 // sets material name
439                 if (has_material) {
440                         polylist.setMaterial(translate_id(id_name(ma)));
441                 }
442                                 
443                 COLLADASW::InputList &til = polylist.getInputList();
444                         
445                 // creates <input> in <polylist> for vertices 
446                 COLLADASW::Input input1(COLLADASW::VERTEX, getUrlBySemantics
447                                                                 (geom_id, COLLADASW::VERTEX), 0);
448                         
449                 // creates <input> in <polylist> for normals
450                 COLLADASW::Input input2(COLLADASW::NORMAL, getUrlBySemantics
451                                                                 (geom_id, COLLADASW::NORMAL), 0);
452                         
453                 til.push_back(input1);
454                 til.push_back(input2);
455                         
456                 // if mesh has uv coords writes <input> for TEXCOORD
457                 int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
458
459                 for (i = 0; i < num_layers; i++) {
460                         char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i);
461                         COLLADASW::Input input3(COLLADASW::TEXCOORD,
462                                                                         makeUrl(makeTexcoordSourceId(geom_id, i)),
463                                                                         1, // offset always 1, this is only until we have optimized UV sets
464                                                                         i  // set number equals UV layer index
465                                                                         );
466                         til.push_back(input3);
467                 }
468                         
469                 // sets <vcount>
470                 polylist.setVCountList(vcount_list);
471                         
472                 // performs the actual writing
473                 polylist.prepareToAppendValues();
474                         
475                 // <p>
476                 int texindex = 0;
477                 for (i = 0; i < totfaces; i++) {
478                         MFace *f = &mfaces[i];
479
480                         if ((has_material && f->mat_nr == material_index) || !has_material) {
481
482                                 unsigned int *v = &f->v1;
483                                 for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) {
484                                         polylist.appendValues(v[j]);
485
486                                         if (has_uvs)
487                                                 polylist.appendValues(texindex + j);
488                                 }
489                         }
490
491                         texindex += 3;
492                         if (f->v4 != 0)
493                                 texindex++;
494                 }
495                         
496                 polylist.finish();
497         }
498         
499         // creates <source> for positions
500         void createVertsSource(std::string geom_id, Mesh *me)
501         {
502 #if 0
503                 int totverts = dm->getNumVerts(dm);
504                 MVert *verts = dm->getVertArray(dm);
505 #endif
506                 int totverts = me->totvert;
507                 MVert *verts = me->mvert;
508                 
509                 COLLADASW::FloatSourceF source(mSW);
510                 source.setId(getIdBySemantics(geom_id, COLLADASW::POSITION));
511                 source.setArrayId(getIdBySemantics(geom_id, COLLADASW::POSITION) +
512                                                   ARRAY_ID_SUFFIX);
513                 source.setAccessorCount(totverts);
514                 source.setAccessorStride(3);
515                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
516                 param.push_back("X");
517                 param.push_back("Y");
518                 param.push_back("Z");
519                 /*main function, it creates <source id = "">, <float_array id = ""
520                   count = ""> */
521                 source.prepareToAppendValues();
522                 //appends data to <float_array>
523                 int i = 0;
524                 for (i = 0; i < totverts; i++) {
525                         source.appendValues(verts[i].co[0], verts[i].co[1], verts[i].co[2]);                    
526                 }
527                 
528                 source.finish();
529         
530         }
531
532         std::string makeTexcoordSourceId(std::string& geom_id, int layer_index)
533         {
534                 char suffix[20];
535                 sprintf(suffix, "-%d", layer_index);
536                 return getIdBySemantics(geom_id, COLLADASW::TEXCOORD) + suffix;
537         }
538
539         //creates <source> for texcoords
540         void createTexcoordsSource(std::string geom_id, Mesh *me)
541         {
542 #if 0
543                 int totfaces = dm->getNumFaces(dm);
544                 MFace *mfaces = dm->getFaceArray(dm);
545 #endif
546                 int totfaces = me->totface;
547                 MFace *mfaces = me->mface;
548
549                 int totuv = 0;
550                 int i;
551
552                 // count totuv
553                 for (i = 0; i < totfaces; i++) {
554                         MFace *f = &mfaces[i];
555                         if (f->v4 == 0) {
556                                 totuv+=3;
557                         }
558                         else {
559                                 totuv+=4;
560                         }
561                 }
562
563                 int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
564
565                 // write <source> for each layer
566                 // each <source> will get id like meshName + "map-channel-1"
567                 for (int a = 0; a < num_layers; a++) {
568                         MTFace *tface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, a);
569                         char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, a);
570                         
571                         COLLADASW::FloatSourceF source(mSW);
572                         std::string layer_id = makeTexcoordSourceId(geom_id, a);
573                         source.setId(layer_id);
574                         source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
575                         
576                         source.setAccessorCount(totuv);
577                         source.setAccessorStride(2);
578                         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
579                         param.push_back("X");
580                         param.push_back("Y");
581                         
582                         source.prepareToAppendValues();
583                         
584                         for (i = 0; i < totfaces; i++) {
585                                 MFace *f = &mfaces[i];
586                                 
587                                 for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) {
588                                         source.appendValues(tface[i].uv[j][0],
589                                                                                 tface[i].uv[j][1]);
590                                 }
591                         }
592                         
593                         source.finish();
594                 }
595         }
596
597
598         //creates <source> for normals
599         void createNormalsSource(std::string geom_id, Mesh *me)
600         {
601 #if 0
602                 int totverts = dm->getNumVerts(dm);
603                 MVert *verts = dm->getVertArray(dm);
604 #endif
605
606                 int totverts = me->totvert;
607                 MVert *verts = me->mvert;
608
609                 COLLADASW::FloatSourceF source(mSW);
610                 source.setId(getIdBySemantics(geom_id, COLLADASW::NORMAL));
611                 source.setArrayId(getIdBySemantics(geom_id, COLLADASW::NORMAL) +
612                                                   ARRAY_ID_SUFFIX);
613                 source.setAccessorCount(totverts);
614                 source.setAccessorStride(3);
615                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
616                 param.push_back("X");
617                 param.push_back("Y");
618                 param.push_back("Z");
619                 
620                 source.prepareToAppendValues();
621                 
622                 int i = 0;
623                 
624                 for( i = 0; i < totverts; ++i ){
625                         
626                         source.appendValues(float(verts[i].no[0]/32767.0),
627                                                                 float(verts[i].no[1]/32767.0),
628                                                                 float(verts[i].no[2]/32767.0));
629                                 
630                 }
631                 source.finish();
632         }
633         
634         std::string getIdBySemantics(std::string geom_id, COLLADASW::Semantics type, std::string other_suffix = "") {
635                 return geom_id + getSuffixBySemantic(type) + other_suffix;
636         }
637         
638         
639         COLLADASW::URI getUrlBySemantics(std::string geom_id, COLLADASW::Semantics type, std::string other_suffix = "") {
640                 
641                 std::string id(getIdBySemantics(geom_id, type, other_suffix));
642                 return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
643                 
644         }
645
646         COLLADASW::URI makeUrl(std::string id)
647         {
648                 return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
649         }
650         
651
652         /*      int getTriCount(MFace *faces, int totface) {
653                 int i;
654                 int tris = 0;
655                 for (i = 0; i < totface; i++) {
656                         // if quad
657                         if (faces[i].v4 != 0)
658                                 tris += 2;
659                         else
660                                 tris++;
661                 }
662
663                 return tris;
664                 }*/
665 };
666
667 class TransformWriter : protected TransformBase
668 {
669 protected:
670         void add_node_transform(COLLADASW::Node& node, float mat[][4], float parent_mat[][4])
671         {
672                 float loc[3], rot[3], size[3];
673                 float local[4][4];
674
675                 if (parent_mat) {
676                         float invpar[4][4];
677                         invert_m4_m4(invpar, parent_mat);
678                         mul_m4_m4m4(local, mat, invpar);
679                 }
680                 else {
681                         copy_m4_m4(local, mat);
682                 }
683
684                 TransformBase::decompose(local, loc, rot, NULL, size);
685                 
686                 /*
687                 // this code used to create a single <rotate> representing object rotation
688                 float quat[4];
689                 float axis[3];
690                 float angle;
691                 double angle_deg;
692                 eul_to_quat( quat,rot);
693                 normalize_qt(quat);
694                 quat_to_axis_angle( axis, &angle,quat);
695                 angle_deg = angle * 180.0f / M_PI;
696                 node.addRotate(axis[0], axis[1], axis[2], angle_deg);
697                 */
698                 node.addTranslate("location", loc[0], loc[1], loc[2]);
699
700                 node.addRotateZ("rotationZ", COLLADABU::Math::Utils::radToDegF(rot[2]));
701                 node.addRotateY("rotationY", COLLADABU::Math::Utils::radToDegF(rot[1]));
702                 node.addRotateX("rotationX", COLLADABU::Math::Utils::radToDegF(rot[0]));
703
704                 node.addScale("scale", size[0], size[1], size[2]);
705         }
706 };
707
708 class InstanceWriter
709 {
710 protected:
711         void add_material_bindings(COLLADASW::BindMaterial& bind_material, Object *ob)
712         {
713                 for(int a = 0; a < ob->totcol; a++)     {
714                         Material *ma = give_current_material(ob, a+1);
715                                 
716                         COLLADASW::InstanceMaterialList& iml = bind_material.getInstanceMaterialList();
717
718                         if (ma) {
719                                 std::string matid(id_name(ma));
720                                 matid = translate_id(matid);
721                                 COLLADASW::InstanceMaterial im(matid, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, matid));
722                                 
723                                 // create <bind_vertex_input> for each uv layer
724                                 Mesh *me = (Mesh*)ob->data;
725                                 int totlayer = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
726                                 
727                                 for (int b = 0; b < totlayer; b++) {
728                                         char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, b);
729                                         im.push_back(COLLADASW::BindVertexInput(name, "TEXCOORD", b));
730                                 }
731                                 
732                                 iml.push_back(im);
733                         }
734                 }
735         }
736 };
737
738 // XXX exporter writes wrong data for shared armatures.  A separate
739 // controller should be written for each armature-mesh binding how do
740 // we make controller ids then?
741 class ArmatureExporter: public COLLADASW::LibraryControllers, protected TransformWriter, protected InstanceWriter
742 {
743 private:
744         Scene *scene;
745
746 public:
747         ArmatureExporter(COLLADASW::StreamWriter *sw) : COLLADASW::LibraryControllers(sw) {}
748
749         // write bone nodes
750         void add_armature_bones(Object *ob_arm, Scene *sce)
751         {
752                 // write bone nodes
753                 bArmature *arm = (bArmature*)ob_arm->data;
754                 for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next) {
755                         // start from root bones
756                         if (!bone->parent)
757                                 add_bone_node(bone, ob_arm);
758                 }
759         }
760
761         bool is_skinned_mesh(Object *ob)
762         {
763                 return get_assigned_armature(ob) != NULL;
764         }
765
766         void add_instance_controller(Object *ob)
767         {
768                 Object *ob_arm = get_assigned_armature(ob);
769                 bArmature *arm = (bArmature*)ob_arm->data;
770
771                 const std::string& controller_id = get_controller_id(ob_arm);
772
773                 COLLADASW::InstanceController ins(mSW);
774                 ins.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, controller_id));
775
776                 // write root bone URLs
777                 Bone *bone;
778                 for (bone = (Bone*)arm->bonebase.first; bone; bone = bone->next) {
779                         if (!bone->parent)
780                                 ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(bone, ob_arm)));
781                 }
782
783                 InstanceWriter::add_material_bindings(ins.getBindMaterial(), ob);
784                         
785                 ins.add();
786         }
787
788         void export_controllers(Scene *sce)
789         {
790                 scene = sce;
791
792                 openLibrary();
793
794                 forEachMeshObjectInScene(sce, *this);
795
796                 closeLibrary();
797         }
798
799         void operator()(Object *ob)
800         {
801                 Object *ob_arm = get_assigned_armature(ob);
802
803                 if (ob_arm /*&& !already_written(ob_arm)*/)
804                         export_controller(ob, ob_arm);
805         }
806
807 private:
808
809         UnitConverter converter;
810
811 #if 0
812         std::vector<Object*> written_armatures;
813
814         bool already_written(Object *ob_arm)
815         {
816                 return std::find(written_armatures.begin(), written_armatures.end(), ob_arm) != written_armatures.end();
817         }
818
819         void wrote(Object *ob_arm)
820         {
821                 written_armatures.push_back(ob_arm);
822         }
823
824         void find_objects_using_armature(Object *ob_arm, std::vector<Object *>& objects, Scene *sce)
825         {
826                 objects.clear();
827
828                 Base *base= (Base*) sce->base.first;
829                 while(base) {
830                         Object *ob = base->object;
831                         
832                         if (ob->type == OB_MESH && get_assigned_armature(ob) == ob_arm) {
833                                 objects.push_back(ob);
834                         }
835
836                         base= base->next;
837                 }
838         }
839 #endif
840
841         Object *get_assigned_armature(Object *ob)
842         {
843                 Object *ob_arm = NULL;
844
845                 if (ob->parent && ob->partype == PARSKEL && ob->parent->type == OB_ARMATURE) {
846                         ob_arm = ob->parent;
847                 }
848                 else {
849                         ModifierData *mod = (ModifierData*)ob->modifiers.first;
850                         while (mod) {
851                                 if (mod->type == eModifierType_Armature) {
852                                         ob_arm = ((ArmatureModifierData*)mod)->object;
853                                 }
854
855                                 mod = mod->next;
856                         }
857                 }
858
859                 return ob_arm;
860         }
861
862         std::string get_joint_sid(Bone *bone)
863         {
864                 char name[100];
865                 BLI_strncpy(name, bone->name, sizeof(name));
866                 return translate_id(name);
867         }
868
869         // parent_mat is armature-space
870         void add_bone_node(Bone *bone, Object *ob_arm)
871         {
872                 std::string node_id = get_joint_id(bone, ob_arm);
873                 std::string node_name = std::string(bone->name);
874                 std::string node_sid = get_joint_sid(bone);
875
876                 COLLADASW::Node node(mSW);
877
878                 node.setType(COLLADASW::Node::JOINT);
879                 node.setNodeId(node_id);
880                 node.setNodeName(node_name);
881                 node.setNodeSid(node_sid);
882
883                 node.start();
884
885                 add_bone_transform(ob_arm, bone, node);
886
887                 for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next) {
888                         add_bone_node(child, ob_arm);
889                 }
890
891                 node.end();
892         }
893
894         void add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node)
895         {
896                 bPose *pose = ob_arm->pose;
897
898                 bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name);
899
900                 float mat[4][4];
901
902                 if (bone->parent) {
903                         // get bone-space matrix from armature-space
904                         bPoseChannel *parchan = get_pose_channel(ob_arm->pose, bone->parent->name);
905
906                         float invpar[4][4];
907                         invert_m4_m4(invpar, parchan->pose_mat);
908                         mul_m4_m4m4(mat, pchan->pose_mat, invpar);
909                 }
910                 else {
911                         // get world-space from armature-space
912                         mul_m4_m4m4(mat, pchan->pose_mat, ob_arm->obmat);
913                 }
914
915                 TransformWriter::add_node_transform(node, mat, NULL);
916         }
917
918         std::string get_controller_id(Object *ob_arm)
919         {
920                 return translate_id(id_name(ob_arm)) + SKIN_CONTROLLER_ID_SUFFIX;
921         }
922
923         // ob should be of type OB_MESH
924         // both args are required
925         void export_controller(Object* ob, Object *ob_arm)
926         {
927                 // joint names
928                 // joint inverse bind matrices
929                 // vertex weights
930
931                 // input:
932                 // joint names: ob -> vertex group names
933                 // vertex group weights: me->dvert -> groups -> index, weight
934
935                 /*
936                 me->dvert:
937
938                 typedef struct MDeformVert {
939                         struct MDeformWeight *dw;
940                         int totweight;
941                         int flag;       // flag only in use for weightpaint now
942                 } MDeformVert;
943
944                 typedef struct MDeformWeight {
945                         int                             def_nr;
946                         float                   weight;
947                 } MDeformWeight;
948                 */
949
950                 Mesh *me = (Mesh*)ob->data;
951                 if (!me->dvert) return;
952
953                 std::string controller_name = id_name(ob_arm);
954                 std::string controller_id = get_controller_id(ob_arm);
955
956                 openSkin(controller_id, controller_name,
957                                  COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob)));
958
959                 add_bind_shape_mat(ob);
960
961                 std::string joints_source_id = add_joints_source(ob_arm, &ob->defbase, controller_id);
962                 std::string inv_bind_mat_source_id = add_inv_bind_mats_source(ob_arm, &ob->defbase, controller_id);
963                 std::string weights_source_id = add_weights_source(me, controller_id);
964
965                 add_joints_element(&ob->defbase, joints_source_id, inv_bind_mat_source_id);
966                 add_vertex_weights_element(weights_source_id, joints_source_id, me, ob_arm, &ob->defbase);
967
968                 closeSkin();
969                 closeController();
970         }
971
972         void add_joints_element(ListBase *defbase,
973                                                         const std::string& joints_source_id, const std::string& inv_bind_mat_source_id)
974         {
975                 COLLADASW::JointsElement joints(mSW);
976                 COLLADASW::InputList &input = joints.getInputList();
977
978                 int offset = 0;
979                 input.push_back(COLLADASW::Input(COLLADASW::JOINT, // constant declared in COLLADASWInputList.h
980                                                                                  COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, joints_source_id)));
981         input.push_back(COLLADASW::Input(COLLADASW::BINDMATRIX,
982                                                                                  COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, inv_bind_mat_source_id)));
983                 joints.add();
984         }
985
986         void add_bind_shape_mat(Object *ob)
987         {
988                 double bind_mat[4][4];
989
990                 converter.mat4_to_dae_double(bind_mat, ob->obmat);
991
992                 addBindShapeTransform(bind_mat);
993         }
994
995         std::string add_joints_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id)
996         {
997                 std::string source_id = controller_id + JOINTS_SOURCE_ID_SUFFIX;
998
999                 int totjoint = 0;
1000                 bDeformGroup *def;
1001                 for (def = (bDeformGroup*)defbase->first; def; def = def->next) {
1002                         if (is_bone_defgroup(ob_arm, def))
1003                                 totjoint++;
1004                 }
1005
1006                 COLLADASW::NameSource source(mSW);
1007                 source.setId(source_id);
1008                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
1009                 source.setAccessorCount(totjoint);
1010                 source.setAccessorStride(1);
1011                 
1012                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
1013                 param.push_back("JOINT");
1014
1015                 source.prepareToAppendValues();
1016
1017                 for (def = (bDeformGroup*)defbase->first; def; def = def->next) {
1018                         Bone *bone = get_bone_from_defgroup(ob_arm, def);
1019                         if (bone)
1020                                 source.appendValues(get_joint_sid(bone));
1021                 }
1022
1023                 source.finish();
1024
1025                 return source_id;
1026         }
1027
1028         std::string add_inv_bind_mats_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id)
1029         {
1030                 std::string source_id = controller_id + BIND_POSES_SOURCE_ID_SUFFIX;
1031
1032                 COLLADASW::FloatSourceF source(mSW);
1033                 source.setId(source_id);
1034                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
1035                 source.setAccessorCount(BLI_countlist(defbase));
1036                 source.setAccessorStride(16);
1037                 
1038                 source.setParameterTypeName(&COLLADASW::CSWC::CSW_VALUE_TYPE_FLOAT4x4);
1039                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
1040                 param.push_back("TRANSFORM");
1041
1042                 source.prepareToAppendValues();
1043
1044                 bPose *pose = ob_arm->pose;
1045                 bArmature *arm = (bArmature*)ob_arm->data;
1046
1047                 int flag = arm->flag;
1048
1049                 // put armature in rest position
1050                 if (!(arm->flag & ARM_RESTPOS)) {
1051                         arm->flag |= ARM_RESTPOS;
1052                         where_is_pose(scene, ob_arm);
1053                 }
1054
1055                 for (bDeformGroup *def = (bDeformGroup*)defbase->first; def; def = def->next) {
1056                         if (is_bone_defgroup(ob_arm, def)) {
1057
1058                                 bPoseChannel *pchan = get_pose_channel(pose, def->name);
1059
1060                                 float mat[4][4];
1061                                 float world[4][4];
1062                                 float inv_bind_mat[4][4];
1063
1064                                 // make world-space matrix, pose_mat is armature-space
1065                                 mul_m4_m4m4(world, pchan->pose_mat, ob_arm->obmat);
1066                                 
1067                                 invert_m4_m4(mat, world);
1068                                 converter.mat4_to_dae(inv_bind_mat, mat);
1069
1070                                 source.appendValues(inv_bind_mat);
1071                         }
1072                 }
1073
1074                 // back from rest positon
1075                 if (!(flag & ARM_RESTPOS)) {
1076                         arm->flag = flag;
1077                         where_is_pose(scene, ob_arm);
1078                 }
1079
1080                 source.finish();
1081
1082                 return source_id;
1083         }
1084
1085         Bone *get_bone_from_defgroup(Object *ob_arm, bDeformGroup* def)
1086         {
1087                 bPoseChannel *pchan = get_pose_channel(ob_arm->pose, def->name);
1088                 return pchan ? pchan->bone : NULL;
1089         }
1090
1091         bool is_bone_defgroup(Object *ob_arm, bDeformGroup* def)
1092         {
1093                 return get_bone_from_defgroup(ob_arm, def) != NULL;
1094         }
1095
1096         std::string add_weights_source(Mesh *me, const std::string& controller_id)
1097         {
1098                 std::string source_id = controller_id + WEIGHTS_SOURCE_ID_SUFFIX;
1099
1100                 int i;
1101                 int totweight = 0;
1102
1103                 for (i = 0; i < me->totvert; i++) {
1104                         totweight += me->dvert[i].totweight;
1105                 }
1106
1107                 COLLADASW::FloatSourceF source(mSW);
1108                 source.setId(source_id);
1109                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
1110                 source.setAccessorCount(totweight);
1111                 source.setAccessorStride(1);
1112                 
1113                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
1114                 param.push_back("WEIGHT");
1115
1116                 source.prepareToAppendValues();
1117
1118                 // NOTE: COLLADA spec says weights should be normalized
1119
1120                 for (i = 0; i < me->totvert; i++) {
1121                         MDeformVert *vert = &me->dvert[i];
1122                         for (int j = 0; j < vert->totweight; j++) {
1123                                 source.appendValues(vert->dw[j].weight);
1124                         }
1125                 }
1126
1127                 source.finish();
1128
1129                 return source_id;
1130         }
1131
1132         void add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id, Mesh *me,
1133                                                                         Object *ob_arm, ListBase *defbase)
1134         {
1135                 COLLADASW::VertexWeightsElement weights(mSW);
1136                 COLLADASW::InputList &input = weights.getInputList();
1137
1138                 int offset = 0;
1139                 input.push_back(COLLADASW::Input(COLLADASW::JOINT, // constant declared in COLLADASWInputList.h
1140                                                                                  COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, joints_source_id), offset++));
1141         input.push_back(COLLADASW::Input(COLLADASW::WEIGHT,
1142                                                                                  COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, weights_source_id), offset++));
1143
1144                 weights.setCount(me->totvert);
1145
1146                 // write number of deformers per vertex
1147                 COLLADASW::PrimitivesBase::VCountList vcount;
1148                 int i;
1149                 for (i = 0; i < me->totvert; i++) {
1150                         vcount.push_back(me->dvert[i].totweight);
1151                 }
1152
1153                 weights.prepareToAppendVCountValues();
1154                 weights.appendVertexCount(vcount);
1155
1156                 // def group index -> joint index
1157                 std::map<int, int> joint_index_by_def_index;
1158                 bDeformGroup *def;
1159                 int j;
1160                 for (def = (bDeformGroup*)defbase->first, i = 0, j = 0; def; def = def->next, i++) {
1161                         if (is_bone_defgroup(ob_arm, def))
1162                                 joint_index_by_def_index[i] = j++;
1163                         else
1164                                 joint_index_by_def_index[i] = -1;
1165                 }
1166
1167                 weights.CloseVCountAndOpenVElement();
1168
1169                 // write deformer index - weight index pairs
1170                 int weight_index = 0;
1171                 for (i = 0; i < me->totvert; i++) {
1172                         MDeformVert *dvert = &me->dvert[i];
1173                         for (int j = 0; j < dvert->totweight; j++) {
1174                                 weights.appendValues(joint_index_by_def_index[dvert->dw[j].def_nr]);
1175                                 weights.appendValues(weight_index++);
1176                         }
1177                 }
1178
1179                 weights.finish();
1180         }
1181 };
1182
1183 class SceneExporter: COLLADASW::LibraryVisualScenes, protected TransformWriter, protected InstanceWriter
1184 {
1185         ArmatureExporter *arm_exporter;
1186 public:
1187         SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm) : COLLADASW::LibraryVisualScenes(sw),
1188                                                                                                                                                 arm_exporter(arm) {}
1189         
1190         void exportScene(Scene *sce) {
1191                 // <library_visual_scenes> <visual_scene>
1192                 std::string id_naming = id_name(sce);
1193                 openVisualScene(translate_id(id_naming), id_naming);
1194
1195                 // write <node>s
1196                 //forEachMeshObjectInScene(sce, *this);
1197                 //forEachCameraObjectInScene(sce, *this);
1198                 //forEachLampObjectInScene(sce, *this);
1199                 exportHierarchy(sce);
1200
1201                 // </visual_scene> </library_visual_scenes>
1202                 closeVisualScene();
1203
1204                 closeLibrary();
1205         }
1206
1207         void exportHierarchy(Scene *sce)
1208         {
1209                 Base *base= (Base*) sce->base.first;
1210                 while(base) {
1211                         Object *ob = base->object;
1212
1213                         if (!ob->parent) {
1214                                 switch(ob->type) {
1215                                 case OB_MESH:
1216                                 case OB_CAMERA:
1217                                 case OB_LAMP:
1218                                 case OB_EMPTY:
1219                                 case OB_ARMATURE:
1220                                         // write nodes....
1221                                         writeNodes(ob, sce);
1222                                         break;
1223                                 }
1224                         }
1225
1226                         base= base->next;
1227                 }
1228         }
1229
1230
1231         // called for each object
1232         //void operator()(Object *ob) {
1233         void writeNodes(Object *ob, Scene *sce)
1234         {
1235                 COLLADASW::Node node(mSW);
1236                 node.setNodeId(translate_id(id_name(ob)));
1237                 node.setType(COLLADASW::Node::NODE);
1238
1239                 node.start();
1240
1241                 bool is_skinned_mesh = arm_exporter->is_skinned_mesh(ob);
1242
1243                 float mat[4][4];
1244                 
1245                 if (ob->type == OB_MESH && is_skinned_mesh)
1246                         // for skinned mesh we write obmat in <bind_shape_matrix>
1247                         unit_m4(mat);
1248                 else
1249                         copy_m4_m4(mat, ob->obmat);
1250
1251                 TransformWriter::add_node_transform(node, mat, ob->parent ? ob->parent->obmat : NULL);
1252                 
1253                 // <instance_geometry>
1254                 if (ob->type == OB_MESH) {
1255                         if (is_skinned_mesh) {
1256                                 arm_exporter->add_instance_controller(ob);
1257                         }
1258                         else {
1259                                 COLLADASW::InstanceGeometry instGeom(mSW);
1260                                 instGeom.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob)));
1261
1262                                 InstanceWriter::add_material_bindings(instGeom.getBindMaterial(), ob);
1263                         
1264                                 instGeom.add();
1265                         }
1266                 }
1267
1268                 // <instance_controller>
1269                 else if (ob->type == OB_ARMATURE) {
1270                         arm_exporter->add_armature_bones(ob, sce);
1271
1272                         // XXX this looks unstable...
1273                         node.end();
1274                 }
1275                 
1276                 // <instance_camera>
1277                 else if (ob->type == OB_CAMERA) {
1278                         COLLADASW::InstanceCamera instCam(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_camera_id(ob)));
1279                         instCam.add();
1280                 }
1281                 
1282                 // <instance_light>
1283                 else if (ob->type == OB_LAMP) {
1284                         COLLADASW::InstanceLight instLa(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_light_id(ob)));
1285                         instLa.add();
1286                 }
1287
1288                 // empty object
1289                 else if (ob->type == OB_EMPTY) {
1290                 }
1291
1292                 // write nodes for child objects
1293                 Base *b = (Base*) sce->base.first;
1294                 while(b) {
1295                         // cob - child object
1296                         Object *cob = b->object;
1297
1298                         if (cob->parent == ob) {
1299                                 switch(cob->type) {
1300                                 case OB_MESH:
1301                                 case OB_CAMERA:
1302                                 case OB_LAMP:
1303                                 case OB_EMPTY:
1304                                 case OB_ARMATURE:
1305                                         // write node...
1306                                         writeNodes(cob, sce);
1307                                         break;
1308                                 }
1309                         }
1310
1311                         b = b->next;
1312                 }
1313
1314                 if (ob->type != OB_ARMATURE)
1315                         node.end();
1316         }
1317 };
1318
1319 class ImagesExporter: COLLADASW::LibraryImages
1320 {
1321         const char *mfilename;
1322         std::vector<std::string> mImages; // contains list of written images, to avoid duplicates
1323 public:
1324         ImagesExporter(COLLADASW::StreamWriter *sw, const char* filename) : COLLADASW::LibraryImages(sw), mfilename(filename)
1325         {}
1326         
1327         void exportImages(Scene *sce)
1328         {
1329                 openLibrary();
1330
1331                 forEachMaterialInScene(sce, *this);
1332
1333                 closeLibrary();
1334         }
1335
1336         void operator()(Material *ma, Object *ob)
1337         {
1338                 int a;
1339                 for (a = 0; a < MAX_MTEX; a++) {
1340                         MTex *mtex = ma->mtex[a];
1341                         if (mtex && mtex->tex && mtex->tex->ima) {
1342
1343                                 Image *image = mtex->tex->ima;
1344                                 std::string name(id_name(image));
1345                                 name = translate_id(name);
1346                                 char rel[FILE_MAX];
1347                                 char abs[FILE_MAX];
1348                                 char src[FILE_MAX];
1349                                 char dir[FILE_MAX];
1350                                 
1351                                 BLI_split_dirfile_basic(mfilename, dir, NULL);
1352
1353                                 BKE_get_image_export_path(image, dir, abs, sizeof(abs), rel, sizeof(rel));
1354
1355                                 if (strlen(abs)) {
1356
1357                                         // make absolute source path
1358                                         BLI_strncpy(src, image->name, sizeof(src));
1359                                         BLI_convertstringcode(src, G.sce);
1360
1361                                         // make dest directory if it doesn't exist
1362                                         BLI_make_existing_file(abs);
1363                                 
1364                                         if (BLI_copy_fileops(src, abs) != 0) {
1365                                                 fprintf(stderr, "Cannot copy image to file's directory. \n");
1366                                         }
1367                                 } 
1368                                 
1369                                 if (find(mImages.begin(), mImages.end(), name) == mImages.end()) {
1370                                         COLLADASW::Image img(COLLADABU::URI(COLLADABU::URI::nativePathToUri(rel)), name);
1371                                         img.add(mSW);
1372
1373                                         mImages.push_back(name);
1374                                 }
1375                         }
1376                 }
1377         }
1378 };
1379
1380
1381 class EffectsExporter: COLLADASW::LibraryEffects
1382 {
1383 public:
1384         EffectsExporter(COLLADASW::StreamWriter *sw) : COLLADASW::LibraryEffects(sw){}
1385         void exportEffects(Scene *sce)
1386         {
1387                 openLibrary();
1388
1389                 forEachMaterialInScene(sce, *this);
1390
1391                 closeLibrary();
1392         }
1393
1394         void operator()(Material *ma, Object *ob)
1395         {
1396                 // create a list of indices to textures of type TEX_IMAGE
1397                 std::vector<int> tex_indices;
1398                 createTextureIndices(ma, tex_indices);
1399
1400                 openEffect(translate_id(id_name(ma)) + "-effect");
1401                 
1402                 COLLADASW::EffectProfile ep(mSW);
1403                 ep.setProfileType(COLLADASW::EffectProfile::COMMON);
1404                 ep.openProfile();
1405                 // set shader type - one of three blinn, phong or lambert
1406                 if (ma->spec_shader == MA_SPEC_BLINN) {
1407                         ep.setShaderType(COLLADASW::EffectProfile::BLINN);
1408                         // shininess
1409                         ep.setShininess(ma->spec);
1410                 }
1411                 else if (ma->spec_shader == MA_SPEC_PHONG) {
1412                         ep.setShaderType(COLLADASW::EffectProfile::PHONG);
1413                         // shininess
1414                         // XXX not sure, stolen this from previous Collada plugin
1415                         ep.setShininess(ma->har / 4);
1416                 }
1417                 else {
1418                         // XXX write warning "Current shader type is not supported" 
1419                         ep.setShaderType(COLLADASW::EffectProfile::LAMBERT);
1420                 }
1421                 // index of refraction
1422                 if (ma->mode & MA_RAYTRANSP) {
1423                         ep.setIndexOfRefraction(ma->ang);
1424                 }
1425                 else {
1426                         ep.setIndexOfRefraction(1.0f);
1427                 }
1428                 // transparency
1429                 ep.setTransparency(ma->alpha);
1430                 // emission
1431                 COLLADASW::ColorOrTexture cot = getcol(0.0f, 0.0f, 0.0f, 1.0f);
1432                 ep.setEmission(cot);
1433                 ep.setTransparent(cot);
1434                 // diffuse 
1435                 cot = getcol(ma->r, ma->g, ma->b, 1.0f);
1436                 ep.setDiffuse(cot);
1437                 // ambient
1438                 cot = getcol(ma->ambr, ma->ambg, ma->ambb, 1.0f);
1439                 ep.setAmbient(cot);
1440                 // reflective, reflectivity
1441                 if (ma->mode & MA_RAYMIRROR) {
1442                         cot = getcol(ma->mirr, ma->mirg, ma->mirb, 1.0f);
1443                         ep.setReflective(cot);
1444                         ep.setReflectivity(ma->ray_mirror);
1445                 }
1446                 else {
1447                         cot = getcol(0.0f, 0.0f, 0.0f, 1.0f);
1448                         ep.setReflective(cot);
1449                         ep.setReflectivity(0.0f);
1450                 }
1451                 // specular
1452                 if (ep.getShaderType() != COLLADASW::EffectProfile::LAMBERT) {
1453                         cot = getcol(ma->specr, ma->specg, ma->specb, 1.0f);
1454                         ep.setSpecular(cot);
1455                 }
1456
1457                 // XXX make this more readable if possible
1458
1459                 // create <sampler> and <surface> for each image
1460                 COLLADASW::Sampler samplers[MAX_MTEX];
1461                 //COLLADASW::Surface surfaces[MAX_MTEX];
1462                 //void *samp_surf[MAX_MTEX][2];
1463                 void *samp_surf[MAX_MTEX][1];
1464                 
1465                 // image to index to samp_surf map
1466                 // samp_surf[index] stores 2 pointers, sampler and surface
1467                 std::map<std::string, int> im_samp_map;
1468
1469                 unsigned int a, b;
1470                 for (a = 0, b = 0; a < tex_indices.size(); a++) {
1471                         MTex *t = ma->mtex[tex_indices[a]];
1472                         Image *ima = t->tex->ima;
1473                         
1474                         std::string key(id_name(ima));
1475                         key = translate_id(key);
1476
1477                         // create only one <sampler>/<surface> pair for each unique image
1478                         if (im_samp_map.find(key) == im_samp_map.end()) {
1479                                 //<newparam> <surface> <init_from>
1480                         //      COLLADASW::Surface surface(COLLADASW::Surface::SURFACE_TYPE_2D,
1481 //                                                                                 key + COLLADASW::Surface::SURFACE_SID_SUFFIX);
1482 //                              COLLADASW::SurfaceInitOption sio(COLLADASW::SurfaceInitOption::INIT_FROM);
1483 //                              sio.setImageReference(key);
1484 //                              surface.setInitOption(sio);
1485                                 
1486                                 //<newparam> <sampler> <source>
1487                                 COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D,
1488                                                                                    key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
1489                                                                                    key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
1490                                 sampler.setImageId(key);
1491                                 // copy values to arrays since they will live longer
1492                                 samplers[a] = sampler;
1493                                 //surfaces[a] = surface;
1494                                 
1495                                 // store pointers so they can be used later when we create <texture>s
1496                                 samp_surf[b][0] = &samplers[a];
1497                                 //samp_surf[b][1] = &surfaces[a];
1498                                 
1499                                 im_samp_map[key] = b;
1500                                 b++;
1501                         }
1502                 }
1503
1504                 // used as fallback when MTex->uvname is "" (this is pretty common)
1505                 // it is indeed the correct value to use in that case
1506                 std::string active_uv(getActiveUVLayerName(ob));
1507
1508                 // write textures
1509                 // XXX very slow
1510                 for (a = 0; a < tex_indices.size(); a++) {
1511                         MTex *t = ma->mtex[tex_indices[a]];
1512                         Image *ima = t->tex->ima;
1513
1514                         // we assume map input is always TEXCO_UV
1515
1516                         std::string key(id_name(ima));
1517                         key = translate_id(key);
1518                         int i = im_samp_map[key];
1519                         COLLADASW::Sampler *sampler = (COLLADASW::Sampler*)samp_surf[i][0];
1520                         //COLLADASW::Surface *surface = (COLLADASW::Surface*)samp_surf[i][1];
1521
1522                         std::string uvname = strlen(t->uvname) ? t->uvname : active_uv;
1523
1524                         // color
1525                         if (t->mapto & MAP_COL) {
1526                                 ep.setDiffuse(createTexture(ima, uvname, sampler));
1527                         }
1528                         // ambient
1529                         if (t->mapto & MAP_AMB) {
1530                                 ep.setAmbient(createTexture(ima, uvname, sampler));
1531                         }
1532                         // specular
1533                         if (t->mapto & MAP_SPEC) {
1534                                 ep.setSpecular(createTexture(ima, uvname, sampler));
1535                         }
1536                         // emission
1537                         if (t->mapto & MAP_EMIT) {
1538                                 ep.setEmission(createTexture(ima, uvname, sampler));
1539                         }
1540                         // reflective
1541                         if (t->mapto & MAP_REF) {
1542                                 ep.setReflective(createTexture(ima, uvname, sampler));
1543                         }
1544                         // alpha
1545                         if (t->mapto & MAP_ALPHA) {
1546                                 ep.setTransparent(createTexture(ima, uvname, sampler));
1547                         }
1548                         // extension:
1549                         // Normal map --> Must be stored with <extra> tag as different technique, 
1550                         // since COLLADA doesn't support normal maps, even in current COLLADA 1.5.
1551                         if (t->mapto & MAP_NORM) {
1552                                 COLLADASW::Texture texture(key);
1553                                 texture.setTexcoord(uvname);
1554                                 texture.setSampler(*sampler);
1555                                 // technique FCOLLADA, with the <bump> tag, is most likely the best understood,
1556                                 // most widespread de-facto standard.
1557                                 texture.setProfileName("FCOLLADA");
1558                                 texture.setChildElementName("bump");                            
1559                                 ep.setExtraTechniqueColorOrTexture(COLLADASW::ColorOrTexture(texture));
1560                         }
1561                 }
1562                 // performs the actual writing
1563                 ep.addProfileElements();
1564                 ep.closeProfile();
1565                 closeEffect();  
1566         }
1567         
1568         COLLADASW::ColorOrTexture createTexture(Image *ima,
1569                                                                                         std::string& uv_layer_name,
1570                                                                                         COLLADASW::Sampler *sampler
1571                                                                                         /*COLLADASW::Surface *surface*/)
1572         {
1573                 
1574                 COLLADASW::Texture texture(translate_id(id_name(ima)));
1575                 texture.setTexcoord(uv_layer_name);
1576                 //texture.setSurface(*surface);
1577                 texture.setSampler(*sampler);
1578                 
1579                 COLLADASW::ColorOrTexture cot(texture);
1580                 return cot;
1581         }
1582         
1583         COLLADASW::ColorOrTexture getcol(float r, float g, float b, float a)
1584         {
1585                 COLLADASW::Color color(r,g,b,a);
1586                 COLLADASW::ColorOrTexture cot(color);
1587                 return cot;
1588         }
1589         
1590         //returns the array of mtex indices which have image 
1591         //need this for exporting textures
1592         void createTextureIndices(Material *ma, std::vector<int> &indices)
1593         {
1594                 indices.clear();
1595
1596                 for (int a = 0; a < MAX_MTEX; a++) {
1597                         if (ma->mtex[a] &&
1598                                 ma->mtex[a]->tex->type == TEX_IMAGE &&
1599                                 ma->mtex[a]->texco == TEXCO_UV){
1600                                 indices.push_back(a);
1601                         }
1602                 }
1603         }
1604 };
1605
1606 class MaterialsExporter: COLLADASW::LibraryMaterials
1607 {
1608 public:
1609         MaterialsExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryMaterials(sw){}
1610         void exportMaterials(Scene *sce)
1611         {
1612                 openLibrary();
1613
1614                 forEachMaterialInScene(sce, *this);
1615
1616                 closeLibrary();
1617         }
1618
1619         void operator()(Material *ma, Object *ob)
1620         {
1621                 std::string name(id_name(ma));
1622
1623                 openMaterial(translate_id(name), name);
1624
1625                 std::string efid = translate_id(name) + "-effect";
1626                 addInstanceEffect(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, efid));
1627
1628                 closeMaterial();
1629         }
1630 };
1631
1632 class CamerasExporter: COLLADASW::LibraryCameras
1633 {
1634 public:
1635         CamerasExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryCameras(sw){}
1636         void exportCameras(Scene *sce)
1637         {
1638                 openLibrary();
1639                 
1640                 forEachCameraObjectInScene(sce, *this);
1641                 
1642                 closeLibrary();
1643         }
1644         void operator()(Object *ob, Scene *sce)
1645         {
1646                 // XXX add other params later
1647                 Camera *cam = (Camera*)ob->data;
1648                 std::string cam_id(get_camera_id(ob));
1649                 std::string cam_name(id_name(cam));
1650                 
1651                 if (cam->type == CAM_PERSP) {
1652                         COLLADASW::PerspectiveOptic persp(mSW);
1653                         persp.setXFov(1.0);
1654                         persp.setAspectRatio(0.1);
1655                         persp.setZFar(cam->clipend);
1656                         persp.setZNear(cam->clipsta);
1657                         COLLADASW::Camera ccam(mSW, &persp, cam_id, cam_name);
1658                         addCamera(ccam);
1659                 }
1660                 else {
1661                         COLLADASW::OrthographicOptic ortho(mSW);
1662                         ortho.setXMag(1.0);
1663                         ortho.setAspectRatio(0.1);
1664                         ortho.setZFar(cam->clipend);
1665                         ortho.setZNear(cam->clipsta);
1666                         COLLADASW::Camera ccam(mSW, &ortho, cam_id, cam_name);
1667                         addCamera(ccam);
1668                 }
1669         }       
1670 };
1671
1672 class LightsExporter: COLLADASW::LibraryLights
1673 {
1674 public:
1675         LightsExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryLights(sw){}
1676         void exportLights(Scene *sce)
1677         {
1678                 openLibrary();
1679                 
1680                 forEachLampObjectInScene(sce, *this);
1681                 
1682                 closeLibrary();
1683         }
1684         void operator()(Object *ob)
1685         {
1686                 Lamp *la = (Lamp*)ob->data;
1687                 std::string la_id(get_light_id(ob));
1688                 std::string la_name(id_name(la));
1689                 COLLADASW::Color col(la->r, la->g, la->b);
1690                 float e = la->energy;
1691                 
1692                 // sun
1693                 if (la->type == LA_SUN) {
1694                         COLLADASW::DirectionalLight cla(mSW, la_id, la_name, e);
1695                         cla.setColor(col);
1696                         addLight(cla);
1697                 }
1698                 // hemi
1699                 else if (la->type == LA_HEMI) {
1700                         COLLADASW::AmbientLight cla(mSW, la_id, la_name, e);
1701                         cla.setColor(col);
1702                         addLight(cla);
1703                 }
1704                 // spot
1705                 else if (la->type == LA_SPOT) {
1706                         COLLADASW::SpotLight cla(mSW, la_id, la_name, e);
1707                         cla.setColor(col);
1708                         cla.setFallOffAngle(la->spotsize);
1709                         cla.setFallOffExponent(la->spotblend);
1710                         cla.setLinearAttenuation(la->att1);
1711                         cla.setQuadraticAttenuation(la->att2);
1712                         addLight(cla);
1713                 }
1714                 // lamp
1715                 else if (la->type == LA_LOCAL) {
1716                         COLLADASW::PointLight cla(mSW, la_id, la_name, e);
1717                         cla.setColor(col);
1718                         cla.setLinearAttenuation(la->att1);
1719                         cla.setQuadraticAttenuation(la->att2);
1720                         addLight(cla);
1721                 }
1722                 // area lamp is not supported
1723                 // it will be exported as a local lamp
1724                 else {
1725                         COLLADASW::PointLight cla(mSW, la_id, la_name, e);
1726                         cla.setColor(col);
1727                         cla.setLinearAttenuation(la->att1);
1728                         cla.setQuadraticAttenuation(la->att2);
1729                         addLight(cla);
1730                 }
1731         }
1732 };
1733
1734 // TODO: it would be better to instantiate animations rather than create a new one per object
1735 // COLLADA allows this through multiple <channel>s in <animation>.
1736 // For this to work, we need to know objects that use a certain action.
1737 class AnimationExporter: COLLADASW::LibraryAnimations
1738 {
1739         Scene *scene;
1740
1741 public:
1742
1743         AnimationExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryAnimations(sw) {}
1744
1745         void exportAnimations(Scene *sce)
1746         {
1747                 this->scene = sce;
1748
1749                 openLibrary();
1750                 
1751                 forEachObjectInScene(sce, *this);
1752                 
1753                 closeLibrary();
1754         }
1755
1756         // called for each exported object
1757         void operator() (Object *ob) 
1758         {
1759                 if (!ob->adt || !ob->adt->action) return;
1760                 
1761                 FCurve *fcu = (FCurve*)ob->adt->action->curves.first;
1762                 
1763                 if (ob->type == OB_ARMATURE) {
1764                         if (!ob->data) return;
1765
1766                         bArmature *arm = (bArmature*)ob->data;
1767                         for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next)
1768                                 write_bone_animation(ob, bone);
1769                 }
1770                 else {
1771                         while (fcu) {
1772                                 // TODO "rotation_quaternion" is also possible for objects (although euler is default)
1773                                 if ((!strcmp(fcu->rna_path, "location") || !strcmp(fcu->rna_path, "scale")) ||
1774                                         (!strcmp(fcu->rna_path, "rotation_euler") && ob->rotmode == ROT_MODE_EUL))
1775                                         dae_animation(fcu, id_name(ob));
1776
1777                                 fcu = fcu->next;
1778                         }
1779                 }
1780         }
1781
1782 protected:
1783
1784         void dae_animation(FCurve *fcu, std::string ob_name)
1785         {
1786                 const char *axis_names[] = {"X", "Y", "Z"};
1787                 const char *axis_name = NULL;
1788                 char anim_id[200];
1789                 char anim_name[200];
1790                 
1791                 if (fcu->array_index < 3)
1792                         axis_name = axis_names[fcu->array_index];
1793
1794                 BLI_snprintf(anim_id, sizeof(anim_id), "%s.%s.%s", (char*)translate_id(ob_name).c_str(),
1795                                          fcu->rna_path, axis_names[fcu->array_index]);
1796                 BLI_snprintf(anim_name, sizeof(anim_name), "%s.%s.%s", 
1797                                          (char*)ob_name.c_str(), fcu->rna_path, axis_names[fcu->array_index]);
1798
1799                 // check rna_path is one of: rotation, scale, location
1800
1801                 openAnimation(anim_id, anim_name);
1802
1803                 // create input source
1804                 std::string input_id = create_source_from_fcurve(Sampler::INPUT, fcu, anim_id, axis_name);
1805
1806                 // create output source
1807                 std::string output_id = create_source_from_fcurve(Sampler::OUTPUT, fcu, anim_id, axis_name);
1808
1809                 // create interpolations source
1810                 std::string interpolation_id = create_interpolation_source(fcu->totvert, anim_id, axis_name);
1811
1812                 std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
1813                 COLLADASW::LibraryAnimations::Sampler sampler(sampler_id);
1814                 std::string empty;
1815                 sampler.addInput(Sampler::INPUT, COLLADABU::URI(empty, input_id));
1816                 sampler.addInput(Sampler::OUTPUT, COLLADABU::URI(empty, output_id));
1817
1818                 // this input is required
1819                 sampler.addInput(Sampler::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
1820
1821                 addSampler(sampler);
1822
1823                 std::string target = translate_id(ob_name)
1824                         + "/" + get_transform_sid(fcu->rna_path, -1, axis_name);
1825                 addChannel(COLLADABU::URI(empty, sampler_id), target);
1826
1827                 closeAnimation();
1828         }
1829
1830         void write_bone_animation(Object *ob_arm, Bone *bone)
1831         {
1832                 if (!ob_arm->adt)
1833                         return;
1834
1835                 for (int i = 0; i < 3; i++)
1836                         sample_and_write_bone_animation(ob_arm, bone, i);
1837
1838                 for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next)
1839                         write_bone_animation(ob_arm, child);
1840         }
1841
1842         void sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type)
1843         {
1844                 bArmature *arm = (bArmature*)ob_arm->data;
1845                 int flag = arm->flag;
1846                 std::vector<float> fra;
1847                 char prefix[256];
1848
1849                 BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone->name);
1850
1851                 bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name);
1852                 if (!pchan)
1853                         return;
1854
1855                 switch (transform_type) {
1856                 case 0:
1857                         find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode);
1858                         break;
1859                 case 1:
1860                         find_frames(ob_arm, fra, prefix, "scale");
1861                         break;
1862                 case 2:
1863                         find_frames(ob_arm, fra, prefix, "location");
1864                         break;
1865                 default:
1866                         return;
1867                 }
1868
1869                 // exit rest position
1870                 if (flag & ARM_RESTPOS) {
1871                         arm->flag &= ~ARM_RESTPOS;
1872                         where_is_pose(scene, ob_arm);
1873                 }
1874
1875                 if (fra.size()) {
1876                         float *v = (float*)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames");
1877                         sample_animation(v, fra, transform_type, bone, ob_arm);
1878
1879                         if (transform_type == 0) {
1880                                 // write x, y, z curves separately if it is rotation
1881                                 float *c = (float*)MEM_callocN(sizeof(float) * fra.size(), "temp. anim frames");
1882                                 for (int i = 0; i < 3; i++) {
1883                                         for (int j = 0; j < fra.size(); j++)
1884                                                 c[j] = v[j * 3 + i];
1885
1886                                         dae_bone_animation(fra, c, transform_type, i, id_name(ob_arm), bone->name);
1887                                 }
1888                                 MEM_freeN(c);
1889                         }
1890                         else {
1891                                 // write xyz at once if it is location or scale
1892                                 dae_bone_animation(fra, v, transform_type, -1, id_name(ob_arm), bone->name);
1893                         }
1894
1895                         MEM_freeN(v);
1896                 }
1897
1898                 // restore restpos
1899                 if (flag & ARM_RESTPOS) 
1900                         arm->flag = flag;
1901                 where_is_pose(scene, ob_arm);
1902         }
1903
1904         void sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm)
1905         {
1906                 bPoseChannel *pchan, *parchan = NULL;
1907                 bPose *pose = ob_arm->pose;
1908
1909                 pchan = get_pose_channel(pose, bone->name);
1910
1911                 if (!pchan)
1912                         return;
1913
1914                 parchan = pchan->parent;
1915
1916                 enable_fcurves(ob_arm->adt->action, bone->name);
1917
1918                 std::vector<float>::iterator it;
1919                 for (it = frames.begin(); it != frames.end(); it++) {
1920                         float mat[4][4], ipar[4][4];
1921
1922                         float ctime = bsystem_time(scene, ob_arm, *it, 0.0f);
1923
1924                         BKE_animsys_evaluate_animdata(&ob_arm->id, ob_arm->adt, *it, ADT_RECALC_ANIM);
1925                         where_is_pose_bone(scene, ob_arm, pchan, ctime);
1926
1927                         // compute bone local mat
1928                         if (bone->parent) {
1929                                 invert_m4_m4(ipar, parchan->pose_mat);
1930                                 mul_m4_m4m4(mat, pchan->pose_mat, ipar);
1931                         }
1932                         else
1933                                 copy_m4_m4(mat, pchan->pose_mat);
1934
1935                         switch (type) {
1936                         case 0:
1937                                 mat4_to_eul(v, mat);
1938                                 break;
1939                         case 1:
1940                                 mat4_to_size(v, mat);
1941                                 break;
1942                         case 2:
1943                                 copy_v3_v3(v, mat[3]);
1944                                 break;
1945                         }
1946
1947                         v += 3;
1948                 }
1949
1950                 enable_fcurves(ob_arm->adt->action, NULL);
1951         }
1952
1953         // dae_bone_animation -> add_bone_animation
1954         // (blend this into dae_bone_animation)
1955         void dae_bone_animation(std::vector<float> &fra, float *v, int tm_type, int axis, std::string ob_name, std::string bone_name)
1956         {
1957                 const char *axis_names[] = {"X", "Y", "Z"};
1958                 const char *axis_name = NULL;
1959                 char anim_id[200];
1960                 char anim_name[200];
1961                 bool is_rot = tm_type == 0;
1962                 
1963                 if (!fra.size())
1964                         return;
1965
1966                 char rna_path[200];
1967                 BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].%s", bone_name.c_str(),
1968                                          tm_type == 0 ? "rotation_quaternion" : (tm_type == 1 ? "scale" : "location"));
1969
1970                 if (axis > -1)
1971                         axis_name = axis_names[axis];
1972                 
1973                 std::string transform_sid = get_transform_sid(NULL, tm_type, axis_name);
1974                 
1975                 BLI_snprintf(anim_id, sizeof(anim_id), "%s.%s.%s", (char*)translate_id(ob_name).c_str(),
1976                                          (char*)translate_id(bone_name).c_str(), (char*)transform_sid.c_str());
1977                 BLI_snprintf(anim_name, sizeof(anim_name), "%s.%s.%s",
1978                                          (char*)ob_name.c_str(), (char*)bone_name.c_str(), (char*)transform_sid.c_str());
1979
1980                 // TODO check rna_path is one of: rotation, scale, location
1981
1982                 openAnimation(anim_id, anim_name);
1983
1984                 // create input source
1985                 std::string input_id = create_source_from_vector(Sampler::INPUT, fra, is_rot, anim_id, axis_name);
1986
1987                 // create output source
1988                 std::string output_id;
1989                 if (axis == -1)
1990                         output_id = create_xyz_source(v, fra.size(), anim_id);
1991                 else
1992                         output_id = create_source_from_array(Sampler::OUTPUT, v, fra.size(), is_rot, anim_id, axis_name);
1993
1994                 // create interpolations source
1995                 std::string interpolation_id = create_interpolation_source(fra.size(), anim_id, axis_name);
1996
1997                 std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
1998                 COLLADASW::LibraryAnimations::Sampler sampler(sampler_id);
1999                 std::string empty;
2000                 sampler.addInput(Sampler::INPUT, COLLADABU::URI(empty, input_id));
2001                 sampler.addInput(Sampler::OUTPUT, COLLADABU::URI(empty, output_id));
2002
2003                 // TODO create in/out tangents source
2004
2005                 // this input is required
2006                 sampler.addInput(Sampler::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
2007
2008                 addSampler(sampler);
2009
2010                 std::string target = translate_id(ob_name + "_" + bone_name) + "/" + transform_sid;
2011                 addChannel(COLLADABU::URI(empty, sampler_id), target);
2012
2013                 closeAnimation();
2014         }
2015
2016         float convert_time(float frame)
2017         {
2018                 return FRA2TIME(frame);
2019         }
2020
2021         float convert_angle(float angle)
2022         {
2023                 return COLLADABU::Math::Utils::radToDegF(angle);
2024         }
2025
2026         std::string get_semantic_suffix(Sampler::Semantic semantic)
2027         {
2028                 switch(semantic) {
2029                 case Sampler::INPUT:
2030                         return INPUT_SOURCE_ID_SUFFIX;
2031                 case Sampler::OUTPUT:
2032                         return OUTPUT_SOURCE_ID_SUFFIX;
2033                 case Sampler::INTERPOLATION:
2034                         return INTERPOLATION_SOURCE_ID_SUFFIX;
2035                 case Sampler::IN_TANGENT:
2036                         return INTANGENT_SOURCE_ID_SUFFIX;
2037                 case Sampler::OUT_TANGENT:
2038                         return OUTTANGENT_SOURCE_ID_SUFFIX;
2039                 }
2040                 return "";
2041         }
2042
2043         void add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
2044                                                            Sampler::Semantic semantic, bool is_rot, const char *axis)
2045         {
2046                 switch(semantic) {
2047                 case Sampler::INPUT:
2048                         param.push_back("TIME");
2049                         break;
2050                 case Sampler::OUTPUT:
2051                         if (is_rot) {
2052                                 param.push_back("ANGLE");
2053                         }
2054                         else {
2055                                 if (axis) {
2056                                         param.push_back(axis);
2057                                 }
2058                                 else {
2059                                         param.push_back("X");
2060                                         param.push_back("Y");
2061                                         param.push_back("Z");
2062                                 }
2063                         }
2064                         break;
2065                 case Sampler::IN_TANGENT:
2066                 case Sampler::OUT_TANGENT:
2067                         param.push_back("X");
2068                         param.push_back("Y");
2069                         break;
2070                 }
2071         }
2072
2073         void get_source_values(BezTriple *bezt, Sampler::Semantic semantic, bool rotation, float *values, int *length)
2074         {
2075                 switch (semantic) {
2076                 case Sampler::INPUT:
2077                         *length = 1;
2078                         values[0] = convert_time(bezt->vec[1][0]);
2079                         break;
2080                 case Sampler::OUTPUT:
2081                         *length = 1;
2082                         if (rotation) {
2083                                 values[0] = convert_angle(bezt->vec[1][1]);
2084                         }
2085                         else {
2086                                 values[0] = bezt->vec[1][1];
2087                         }
2088                         break;
2089                 case Sampler::IN_TANGENT:
2090                 case Sampler::OUT_TANGENT:
2091                         // XXX
2092                         *length = 2;
2093                         break;
2094                 }
2095         }
2096
2097         std::string create_source_from_fcurve(Sampler::Semantic semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name)
2098         {
2099                 std::string source_id = anim_id + get_semantic_suffix(semantic);
2100
2101                 //bool is_rotation = !strcmp(fcu->rna_path, "rotation");
2102                 bool is_rotation = false;
2103                 
2104                 if (strstr(fcu->rna_path, "rotation")) is_rotation = true;
2105                 
2106                 COLLADASW::FloatSourceF source(mSW);
2107                 source.setId(source_id);
2108                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
2109                 source.setAccessorCount(fcu->totvert);
2110                 source.setAccessorStride(1);
2111                 
2112                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
2113                 add_source_parameters(param, semantic, is_rotation, axis_name);
2114
2115                 source.prepareToAppendValues();
2116
2117                 for (int i = 0; i < fcu->totvert; i++) {
2118                         float values[3]; // be careful!
2119                         int length;
2120
2121                         get_source_values(&fcu->bezt[i], semantic, is_rotation, values, &length);
2122                         for (int j = 0; j < length; j++)
2123                                 source.appendValues(values[j]);
2124                 }
2125
2126                 source.finish();
2127
2128                 return source_id;
2129         }
2130
2131         std::string create_source_from_array(Sampler::Semantic semantic, float *v, int tot, bool is_rot, const std::string& anim_id, const char *axis_name)
2132         {
2133                 std::string source_id = anim_id + get_semantic_suffix(semantic);
2134
2135                 COLLADASW::FloatSourceF source(mSW);
2136                 source.setId(source_id);
2137                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
2138                 source.setAccessorCount(tot);
2139                 source.setAccessorStride(1);
2140                 
2141                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
2142                 add_source_parameters(param, semantic, is_rot, axis_name);
2143
2144                 source.prepareToAppendValues();
2145
2146                 for (int i = 0; i < tot; i++) {
2147                         float val = v[i];
2148                         if (semantic == Sampler::INPUT)
2149                                 val = convert_time(val);
2150                         else if (is_rot)
2151                                 val = convert_angle(val);
2152                         source.appendValues(val);
2153                 }
2154
2155                 source.finish();
2156
2157                 return source_id;
2158         }
2159
2160         std::string create_source_from_vector(Sampler::Semantic semantic, std::vector<float> &fra, bool is_rot, const std::string& anim_id, const char *axis_name)
2161         {
2162                 std::string source_id = anim_id + get_semantic_suffix(semantic);
2163
2164                 COLLADASW::FloatSourceF source(mSW);
2165                 source.setId(source_id);
2166                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
2167                 source.setAccessorCount(fra.size());
2168                 source.setAccessorStride(1);
2169                 
2170                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
2171                 add_source_parameters(param, semantic, is_rot, axis_name);
2172
2173                 source.prepareToAppendValues();
2174
2175                 std::vector<float>::iterator it;
2176                 for (it = fra.begin(); it != fra.end(); it++) {
2177                         float val = *it;
2178                         if (semantic == Sampler::INPUT)
2179                                 val = convert_time(val);
2180                         else if (is_rot)
2181                                 val = convert_angle(val);
2182                         source.appendValues(val);
2183                 }
2184
2185                 source.finish();
2186
2187                 return source_id;
2188         }
2189
2190         // only used for sources with OUTPUT semantic
2191         std::string create_xyz_source(float *v, int tot, const std::string& anim_id)
2192         {
2193                 Sampler::Semantic semantic = Sampler::OUTPUT;
2194                 std::string source_id = anim_id + get_semantic_suffix(semantic);
2195
2196                 COLLADASW::FloatSourceF source(mSW);
2197                 source.setId(source_id);
2198                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
2199                 source.setAccessorCount(tot);
2200                 source.setAccessorStride(3);
2201                 
2202                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
2203                 add_source_parameters(param, semantic, false, NULL);
2204
2205                 source.prepareToAppendValues();
2206
2207                 for (int i = 0; i < tot; i++) {
2208                         source.appendValues(*v, *(v + 1), *(v + 2));
2209                         v += 3;
2210                 }
2211
2212                 source.finish();
2213
2214                 return source_id;
2215         }
2216
2217         std::string create_interpolation_source(int tot, const std::string& anim_id, const char *axis_name)
2218         {
2219                 std::string source_id = anim_id + get_semantic_suffix(Sampler::INTERPOLATION);
2220
2221                 COLLADASW::NameSource source(mSW);
2222                 source.setId(source_id);
2223                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
2224                 source.setAccessorCount(tot);
2225                 source.setAccessorStride(1);
2226                 
2227                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
2228                 param.push_back("INTERPOLATION");
2229
2230                 source.prepareToAppendValues();
2231
2232                 for (int i = 0; i < tot; i++) {
2233                         source.appendValues(LINEAR_NAME);
2234                 }
2235
2236                 source.finish();
2237
2238                 return source_id;
2239         }
2240
2241         std::string get_transform_sid(char *rna_path, int tm_type, const char *axis_name)
2242         {
2243                 if (rna_path) {
2244                         char *name = extract_transform_name(rna_path);
2245
2246                         if (strstr(name, "rotation"))
2247                                 return std::string("rotation") + axis_name;
2248                         else if (!strcmp(name, "location") || !strcmp(name, "scale"))
2249                                 return std::string(name);
2250                 }
2251                 else {
2252                         if (tm_type == 0)
2253                                 return std::string("rotation") + axis_name;
2254                         else
2255                                 return tm_type == 1 ? "scale" : "location";
2256                 }
2257
2258                 return NULL;
2259         }
2260
2261         char *extract_transform_name(char *rna_path)
2262         {
2263                 char *dot = strrchr(rna_path, '.');
2264                 return dot ? (dot + 1) : rna_path;
2265         }
2266
2267         void find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name)
2268         {
2269                 FCurve *fcu= (FCurve*)ob->adt->action->curves.first;
2270
2271                 for (; fcu; fcu = fcu->next) {
2272                         if (prefix && strncmp(prefix, fcu->rna_path, strlen(prefix)))
2273                                 continue;
2274
2275                         char *name = extract_transform_name(fcu->rna_path);
2276                         if (!strcmp(name, tm_name)) {
2277                                 for (int i = 0; i < fcu->totvert; i++) {
2278                                         float f = fcu->bezt[i].vec[1][0];
2279                                         if (std::find(fra.begin(), fra.end(), f) == fra.end())
2280                                                 fra.push_back(f);
2281                                 }
2282                         }
2283                 }
2284         }
2285
2286         void find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode)
2287         {
2288                 if (rotmode > 0)
2289                         find_frames(ob, fra, prefix, "rotation_euler");
2290                 else if (rotmode == ROT_MODE_QUAT)
2291                         find_frames(ob, fra, prefix, "rotation_quaternion");
2292                 else if (rotmode == ROT_MODE_AXISANGLE)
2293                         ;
2294         }
2295
2296         // enable fcurves driving a specific bone, disable all the rest
2297         // if bone_name = NULL enable all fcurves
2298         void enable_fcurves(bAction *act, char *bone_name)
2299         {
2300                 FCurve *fcu;
2301                 char prefix[200];
2302
2303                 if (bone_name)
2304                         BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name);
2305
2306                 for (fcu = (FCurve*)act->curves.first; fcu; fcu = fcu->next) {
2307                         if (bone_name) {
2308                                 if (!strncmp(fcu->rna_path, prefix, strlen(prefix)))
2309                                         fcu->flag &= ~FCURVE_DISABLED;
2310                                 else
2311                                         fcu->flag |= FCURVE_DISABLED;
2312                         }
2313                         else {
2314                                 fcu->flag &= ~FCURVE_DISABLED;
2315                         }
2316                 }
2317         }
2318 };
2319
2320 void DocumentExporter::exportCurrentScene(Scene *sce, const char* filename)
2321 {
2322         COLLADABU::NativeString native_filename =
2323                 COLLADABU::NativeString(std::string(filename));
2324         COLLADASW::StreamWriter sw(native_filename);
2325
2326         // open <Collada>
2327         sw.startDocument();
2328
2329         // <asset>
2330         COLLADASW::Asset asset(&sw);
2331         // XXX ask blender devs about this?
2332         asset.setUnit("decimetre", 0.1);
2333         asset.setUpAxisType(COLLADASW::Asset::Z_UP);
2334         asset.add();
2335         
2336         // <library_cameras>
2337         CamerasExporter ce(&sw);
2338         ce.exportCameras(sce);
2339         
2340         // <library_lights>
2341         LightsExporter le(&sw);
2342         le.exportLights(sce);
2343
2344         // <library_images>
2345         ImagesExporter ie(&sw, filename);
2346         ie.exportImages(sce);
2347         
2348         // <library_effects>
2349         EffectsExporter ee(&sw);
2350         ee.exportEffects(sce);
2351         
2352         // <library_materials>
2353         MaterialsExporter me(&sw);
2354         me.exportMaterials(sce);
2355
2356         // <library_geometries>
2357         GeometryExporter ge(&sw);
2358         ge.exportGeom(sce);
2359
2360         // <library_animations>
2361         AnimationExporter ae(&sw);
2362         ae.exportAnimations(sce);
2363
2364         // <library_controllers>
2365         ArmatureExporter arm_exporter(&sw);
2366         arm_exporter.export_controllers(sce);
2367
2368         // <library_visual_scenes>
2369         SceneExporter se(&sw, &arm_exporter);
2370         se.exportScene(sce);
2371         
2372         // <scene>
2373         std::string scene_name(translate_id(id_name(sce)));
2374         COLLADASW::Scene scene(&sw, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING,
2375                                                                                            scene_name));
2376         scene.add();
2377         
2378         // close <Collada>
2379         sw.endDocument();
2380
2381 }
2382
2383 void DocumentExporter::exportScenes(const char* filename)
2384 {
2385 }
2386
2387 /*
2388
2389 NOTES:
2390
2391 * AnimationExporter::sample_animation enables all curves on armature, this is undesirable for a user
2392
2393  */
2394