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