Bugfix #20574: New 3D View regions were all had their 'type' set to 'RGN_TYPE_UI...
[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 (unsigned int i=0; i < id_translated.size(); i++)
177         {
178                 id_translated[i] = translate_map[(unsigned int)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                         unsigned int *nn = &f.v1;
654                         unsigned int *vv = &fa->v1;
655
656                         memset(&f, 0, sizeof(f));
657                         v = fa->v4 == 0 ? 3 : 4;
658
659                         if (!(fa->flag & ME_SMOOTH)) {
660                                 Normal n;
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                                 nor.push_back(n);
666                         }
667
668                         for (j = 0; j < v; j++) {
669                                 if (fa->flag & ME_SMOOTH) {
670                                         if (nshar.find(*vv) != nshar.end())
671                                                 *nn = nshar[*vv];
672                                         else {
673                                                 Normal n = {
674                                                         vert[*vv].no[0]/32767.0,
675                                                         vert[*vv].no[1]/32767.0,
676                                                         vert[*vv].no[2]/32767.0
677                                                 };
678                                                 nor.push_back(n);
679                                                 *nn = nor.size() - 1;
680                                                 nshar[*vv] = *nn;
681                                         }
682                                         vv++;
683                                 }
684                                 else {
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], 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                 bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name);
989
990                 float mat[4][4];
991
992                 if (bone->parent) {
993                         // get bone-space matrix from armature-space
994                         bPoseChannel *parchan = get_pose_channel(ob_arm->pose, bone->parent->name);
995
996                         float invpar[4][4];
997                         invert_m4_m4(invpar, parchan->pose_mat);
998                         mul_m4_m4m4(mat, pchan->pose_mat, invpar);
999                 }
1000                 else {
1001                         // get world-space from armature-space
1002                         mul_m4_m4m4(mat, pchan->pose_mat, ob_arm->obmat);
1003                 }
1004
1005                 TransformWriter::add_node_transform(node, mat, NULL);
1006         }
1007
1008         std::string get_controller_id(Object *ob_arm)
1009         {
1010                 return translate_id(id_name(ob_arm)) + SKIN_CONTROLLER_ID_SUFFIX;
1011         }
1012
1013         // ob should be of type OB_MESH
1014         // both args are required
1015         void export_controller(Object* ob, Object *ob_arm)
1016         {
1017                 // joint names
1018                 // joint inverse bind matrices
1019                 // vertex weights
1020
1021                 // input:
1022                 // joint names: ob -> vertex group names
1023                 // vertex group weights: me->dvert -> groups -> index, weight
1024
1025                 /*
1026                 me->dvert:
1027
1028                 typedef struct MDeformVert {
1029                         struct MDeformWeight *dw;
1030                         int totweight;
1031                         int flag;       // flag only in use for weightpaint now
1032                 } MDeformVert;
1033
1034                 typedef struct MDeformWeight {
1035                         int                             def_nr;
1036                         float                   weight;
1037                 } MDeformWeight;
1038                 */
1039
1040                 Mesh *me = (Mesh*)ob->data;
1041                 if (!me->dvert) return;
1042
1043                 std::string controller_name = id_name(ob_arm);
1044                 std::string controller_id = get_controller_id(ob_arm);
1045
1046                 openSkin(controller_id, controller_name,
1047                                  COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob)));
1048
1049                 add_bind_shape_mat(ob);
1050
1051                 std::string joints_source_id = add_joints_source(ob_arm, &ob->defbase, controller_id);
1052                 std::string inv_bind_mat_source_id = add_inv_bind_mats_source(ob_arm, &ob->defbase, controller_id);
1053                 std::string weights_source_id = add_weights_source(me, controller_id);
1054
1055                 add_joints_element(&ob->defbase, joints_source_id, inv_bind_mat_source_id);
1056                 add_vertex_weights_element(weights_source_id, joints_source_id, me, ob_arm, &ob->defbase);
1057
1058                 closeSkin();
1059                 closeController();
1060         }
1061
1062         void add_joints_element(ListBase *defbase,
1063                                                         const std::string& joints_source_id, const std::string& inv_bind_mat_source_id)
1064         {
1065                 COLLADASW::JointsElement joints(mSW);
1066                 COLLADASW::InputList &input = joints.getInputList();
1067
1068                 input.push_back(COLLADASW::Input(COLLADASW::JOINT, // constant declared in COLLADASWInputList.h
1069                                                                    COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, joints_source_id)));
1070                 input.push_back(COLLADASW::Input(COLLADASW::BINDMATRIX,
1071                                                                    COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, inv_bind_mat_source_id)));
1072                 joints.add();
1073         }
1074
1075         void add_bind_shape_mat(Object *ob)
1076         {
1077                 double bind_mat[4][4];
1078
1079                 converter.mat4_to_dae_double(bind_mat, ob->obmat);
1080
1081                 addBindShapeTransform(bind_mat);
1082         }
1083
1084         std::string add_joints_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id)
1085         {
1086                 std::string source_id = controller_id + JOINTS_SOURCE_ID_SUFFIX;
1087
1088                 int totjoint = 0;
1089                 bDeformGroup *def;
1090                 for (def = (bDeformGroup*)defbase->first; def; def = def->next) {
1091                         if (is_bone_defgroup(ob_arm, def))
1092                                 totjoint++;
1093                 }
1094
1095                 COLLADASW::NameSource source(mSW);
1096                 source.setId(source_id);
1097                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
1098                 source.setAccessorCount(totjoint);
1099                 source.setAccessorStride(1);
1100                 
1101                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
1102                 param.push_back("JOINT");
1103
1104                 source.prepareToAppendValues();
1105
1106                 for (def = (bDeformGroup*)defbase->first; def; def = def->next) {
1107                         Bone *bone = get_bone_from_defgroup(ob_arm, def);
1108                         if (bone)
1109                                 source.appendValues(get_joint_sid(bone, ob_arm));
1110                 }
1111
1112                 source.finish();
1113
1114                 return source_id;
1115         }
1116
1117         std::string add_inv_bind_mats_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id)
1118         {
1119                 std::string source_id = controller_id + BIND_POSES_SOURCE_ID_SUFFIX;
1120
1121                 COLLADASW::FloatSourceF source(mSW);
1122                 source.setId(source_id);
1123                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
1124                 source.setAccessorCount(BLI_countlist(defbase));
1125                 source.setAccessorStride(16);
1126                 
1127                 source.setParameterTypeName(&COLLADASW::CSWC::CSW_VALUE_TYPE_FLOAT4x4);
1128                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
1129                 param.push_back("TRANSFORM");
1130
1131                 source.prepareToAppendValues();
1132
1133                 bPose *pose = ob_arm->pose;
1134                 bArmature *arm = (bArmature*)ob_arm->data;
1135
1136                 int flag = arm->flag;
1137
1138                 // put armature in rest position
1139                 if (!(arm->flag & ARM_RESTPOS)) {
1140                         arm->flag |= ARM_RESTPOS;
1141                         where_is_pose(scene, ob_arm);
1142                 }
1143
1144                 for (bDeformGroup *def = (bDeformGroup*)defbase->first; def; def = def->next) {
1145                         if (is_bone_defgroup(ob_arm, def)) {
1146
1147                                 bPoseChannel *pchan = get_pose_channel(pose, def->name);
1148
1149                                 float mat[4][4];
1150                                 float world[4][4];
1151                                 float inv_bind_mat[4][4];
1152
1153                                 // make world-space matrix, pose_mat is armature-space
1154                                 mul_m4_m4m4(world, pchan->pose_mat, ob_arm->obmat);
1155                                 
1156                                 invert_m4_m4(mat, world);
1157                                 converter.mat4_to_dae(inv_bind_mat, mat);
1158
1159                                 source.appendValues(inv_bind_mat);
1160                         }
1161                 }
1162
1163                 // back from rest positon
1164                 if (!(flag & ARM_RESTPOS)) {
1165                         arm->flag = flag;
1166                         where_is_pose(scene, ob_arm);
1167                 }
1168
1169                 source.finish();
1170
1171                 return source_id;
1172         }
1173
1174         Bone *get_bone_from_defgroup(Object *ob_arm, bDeformGroup* def)
1175         {
1176                 bPoseChannel *pchan = get_pose_channel(ob_arm->pose, def->name);
1177                 return pchan ? pchan->bone : NULL;
1178         }
1179
1180         bool is_bone_defgroup(Object *ob_arm, bDeformGroup* def)
1181         {
1182                 return get_bone_from_defgroup(ob_arm, def) != NULL;
1183         }
1184
1185         std::string add_weights_source(Mesh *me, const std::string& controller_id)
1186         {
1187                 std::string source_id = controller_id + WEIGHTS_SOURCE_ID_SUFFIX;
1188
1189                 int i;
1190                 int totweight = 0;
1191
1192                 for (i = 0; i < me->totvert; i++) {
1193                         totweight += me->dvert[i].totweight;
1194                 }
1195
1196                 COLLADASW::FloatSourceF source(mSW);
1197                 source.setId(source_id);
1198                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
1199                 source.setAccessorCount(totweight);
1200                 source.setAccessorStride(1);
1201                 
1202                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
1203                 param.push_back("WEIGHT");
1204
1205                 source.prepareToAppendValues();
1206
1207                 // NOTE: COLLADA spec says weights should be normalized
1208
1209                 for (i = 0; i < me->totvert; i++) {
1210                         MDeformVert *vert = &me->dvert[i];
1211                         for (int j = 0; j < vert->totweight; j++) {
1212                                 source.appendValues(vert->dw[j].weight);
1213                         }
1214                 }
1215
1216                 source.finish();
1217
1218                 return source_id;
1219         }
1220
1221         void add_vertex_weights_element(const std::string& weights_source_id, const std::string& joints_source_id, Mesh *me,
1222                                                                         Object *ob_arm, ListBase *defbase)
1223         {
1224                 COLLADASW::VertexWeightsElement weights(mSW);
1225                 COLLADASW::InputList &input = weights.getInputList();
1226
1227                 int offset = 0;
1228                 input.push_back(COLLADASW::Input(COLLADASW::JOINT, // constant declared in COLLADASWInputList.h
1229                                                                                  COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, joints_source_id), offset++));
1230         input.push_back(COLLADASW::Input(COLLADASW::WEIGHT,
1231                                                                                  COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, weights_source_id), offset++));
1232
1233                 weights.setCount(me->totvert);
1234
1235                 // write number of deformers per vertex
1236                 COLLADASW::PrimitivesBase::VCountList vcount;
1237                 int i;
1238                 for (i = 0; i < me->totvert; i++) {
1239                         vcount.push_back(me->dvert[i].totweight);
1240                 }
1241
1242                 weights.prepareToAppendVCountValues();
1243                 weights.appendVertexCount(vcount);
1244
1245                 // def group index -> joint index
1246                 std::map<int, int> joint_index_by_def_index;
1247                 bDeformGroup *def;
1248                 int j;
1249                 for (def = (bDeformGroup*)defbase->first, i = 0, j = 0; def; def = def->next, i++) {
1250                         if (is_bone_defgroup(ob_arm, def))
1251                                 joint_index_by_def_index[i] = j++;
1252                         else
1253                                 joint_index_by_def_index[i] = -1;
1254                 }
1255
1256                 weights.CloseVCountAndOpenVElement();
1257
1258                 // write deformer index - weight index pairs
1259                 int weight_index = 0;
1260                 for (i = 0; i < me->totvert; i++) {
1261                         MDeformVert *dvert = &me->dvert[i];
1262                         for (int j = 0; j < dvert->totweight; j++) {
1263                                 weights.appendValues(joint_index_by_def_index[dvert->dw[j].def_nr]);
1264                                 weights.appendValues(weight_index++);
1265                         }
1266                 }
1267
1268                 weights.finish();
1269         }
1270 };
1271
1272 class SceneExporter: COLLADASW::LibraryVisualScenes, protected TransformWriter, protected InstanceWriter
1273 {
1274         ArmatureExporter *arm_exporter;
1275 public:
1276         SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm) : COLLADASW::LibraryVisualScenes(sw),
1277                                                                                                                                                 arm_exporter(arm) {}
1278         
1279         void exportScene(Scene *sce) {
1280                 // <library_visual_scenes> <visual_scene>
1281                 std::string id_naming = id_name(sce);
1282                 openVisualScene(translate_id(id_naming), id_naming);
1283
1284                 // write <node>s
1285                 //forEachMeshObjectInScene(sce, *this);
1286                 //forEachCameraObjectInScene(sce, *this);
1287                 //forEachLampObjectInScene(sce, *this);
1288                 exportHierarchy(sce);
1289
1290                 // </visual_scene> </library_visual_scenes>
1291                 closeVisualScene();
1292
1293                 closeLibrary();
1294         }
1295
1296         void exportHierarchy(Scene *sce)
1297         {
1298                 Base *base= (Base*) sce->base.first;
1299                 while(base) {
1300                         Object *ob = base->object;
1301
1302                         if (!ob->parent) {
1303                                 switch(ob->type) {
1304                                 case OB_MESH:
1305                                 case OB_CAMERA:
1306                                 case OB_LAMP:
1307                                 case OB_EMPTY:
1308                                 case OB_ARMATURE:
1309                                         // write nodes....
1310                                         writeNodes(ob, sce);
1311                                         break;
1312                                 }
1313                         }
1314
1315                         base= base->next;
1316                 }
1317         }
1318
1319
1320         // called for each object
1321         //void operator()(Object *ob) {
1322         void writeNodes(Object *ob, Scene *sce)
1323         {
1324                 COLLADASW::Node node(mSW);
1325                 node.setNodeId(translate_id(id_name(ob)));
1326                 node.setType(COLLADASW::Node::NODE);
1327
1328                 node.start();
1329
1330                 bool is_skinned_mesh = arm_exporter->is_skinned_mesh(ob);
1331
1332                 if (ob->type == OB_MESH && is_skinned_mesh)
1333                         // for skinned mesh we write obmat in <bind_shape_matrix>
1334                         TransformWriter::add_node_transform_identity(node);
1335                 else
1336                         TransformWriter::add_node_transform_ob(node, ob);
1337                 
1338                 // <instance_geometry>
1339                 if (ob->type == OB_MESH) {
1340                         if (is_skinned_mesh) {
1341                                 arm_exporter->add_instance_controller(ob);
1342                         }
1343                         else {
1344                                 COLLADASW::InstanceGeometry instGeom(mSW);
1345                                 instGeom.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob)));
1346
1347                                 InstanceWriter::add_material_bindings(instGeom.getBindMaterial(), ob);
1348                         
1349                                 instGeom.add();
1350                         }
1351                 }
1352
1353                 // <instance_controller>
1354                 else if (ob->type == OB_ARMATURE) {
1355                         arm_exporter->add_armature_bones(ob, sce);
1356
1357                         // XXX this looks unstable...
1358                         node.end();
1359                 }
1360                 
1361                 // <instance_camera>
1362                 else if (ob->type == OB_CAMERA) {
1363                         COLLADASW::InstanceCamera instCam(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_camera_id(ob)));
1364                         instCam.add();
1365                 }
1366                 
1367                 // <instance_light>
1368                 else if (ob->type == OB_LAMP) {
1369                         COLLADASW::InstanceLight instLa(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_light_id(ob)));
1370                         instLa.add();
1371                 }
1372
1373                 // empty object
1374                 else if (ob->type == OB_EMPTY) {
1375                 }
1376
1377                 // write nodes for child objects
1378                 Base *b = (Base*) sce->base.first;
1379                 while(b) {
1380                         // cob - child object
1381                         Object *cob = b->object;
1382
1383                         if (cob->parent == ob) {
1384                                 switch(cob->type) {
1385                                 case OB_MESH:
1386                                 case OB_CAMERA:
1387                                 case OB_LAMP:
1388                                 case OB_EMPTY:
1389                                 case OB_ARMATURE:
1390                                         // write node...
1391                                         writeNodes(cob, sce);
1392                                         break;
1393                                 }
1394                         }
1395
1396                         b = b->next;
1397                 }
1398
1399                 if (ob->type != OB_ARMATURE)
1400                         node.end();
1401         }
1402 };
1403
1404 class ImagesExporter: COLLADASW::LibraryImages
1405 {
1406         const char *mfilename;
1407         std::vector<std::string> mImages; // contains list of written images, to avoid duplicates
1408 public:
1409         ImagesExporter(COLLADASW::StreamWriter *sw, const char* filename) : COLLADASW::LibraryImages(sw), mfilename(filename)
1410         {}
1411         
1412         void exportImages(Scene *sce)
1413         {
1414                 openLibrary();
1415
1416                 forEachMaterialInScene(sce, *this);
1417
1418                 closeLibrary();
1419         }
1420
1421         void operator()(Material *ma, Object *ob)
1422         {
1423                 int a;
1424                 for (a = 0; a < MAX_MTEX; a++) {
1425                         MTex *mtex = ma->mtex[a];
1426                         if (mtex && mtex->tex && mtex->tex->ima) {
1427
1428                                 Image *image = mtex->tex->ima;
1429                                 std::string name(id_name(image));
1430                                 name = translate_id(name);
1431                                 char rel[FILE_MAX];
1432                                 char abs[FILE_MAX];
1433                                 char src[FILE_MAX];
1434                                 char dir[FILE_MAX];
1435                                 
1436                                 BLI_split_dirfile_basic(mfilename, dir, NULL);
1437
1438                                 BKE_rebase_path(abs, sizeof(abs), rel, sizeof(rel), G.sce, image->name, dir);
1439
1440                                 if (abs[0] != '\0') {
1441
1442                                         // make absolute source path
1443                                         BLI_strncpy(src, image->name, sizeof(src));
1444                                         BLI_convertstringcode(src, G.sce);
1445
1446                                         // make dest directory if it doesn't exist
1447                                         BLI_make_existing_file(abs);
1448                                 
1449                                         if (BLI_copy_fileops(src, abs) != 0) {
1450                                                 fprintf(stderr, "Cannot copy image to file's directory. \n");
1451                                         }
1452                                 } 
1453                                 
1454                                 if (find(mImages.begin(), mImages.end(), name) == mImages.end()) {
1455                                         COLLADASW::Image img(COLLADABU::URI(COLLADABU::URI::nativePathToUri(rel)), name);
1456                                         img.add(mSW);
1457
1458                                         mImages.push_back(name);
1459                                 }
1460                         }
1461                 }
1462         }
1463 };
1464
1465 class EffectsExporter: COLLADASW::LibraryEffects
1466 {
1467 public:
1468         EffectsExporter(COLLADASW::StreamWriter *sw) : COLLADASW::LibraryEffects(sw){}
1469         void exportEffects(Scene *sce)
1470         {
1471                 openLibrary();
1472
1473                 forEachMaterialInScene(sce, *this);
1474
1475                 closeLibrary();
1476         }
1477
1478         void operator()(Material *ma, Object *ob)
1479         {
1480                 // create a list of indices to textures of type TEX_IMAGE
1481                 std::vector<int> tex_indices;
1482                 createTextureIndices(ma, tex_indices);
1483
1484                 openEffect(translate_id(id_name(ma)) + "-effect");
1485                 
1486                 COLLADASW::EffectProfile ep(mSW);
1487                 ep.setProfileType(COLLADASW::EffectProfile::COMMON);
1488                 ep.openProfile();
1489                 // set shader type - one of three blinn, phong or lambert
1490                 if (ma->spec_shader == MA_SPEC_BLINN) {
1491                         ep.setShaderType(COLLADASW::EffectProfile::BLINN);
1492                         // shininess
1493                         ep.setShininess(ma->spec);
1494                 }
1495                 else if (ma->spec_shader == MA_SPEC_PHONG) {
1496                         ep.setShaderType(COLLADASW::EffectProfile::PHONG);
1497                         // shininess
1498                         // XXX not sure, stolen this from previous Collada plugin
1499                         ep.setShininess(ma->har / 4);
1500                 }
1501                 else {
1502                         // XXX write warning "Current shader type is not supported" 
1503                         ep.setShaderType(COLLADASW::EffectProfile::LAMBERT);
1504                 }
1505                 // index of refraction
1506                 if (ma->mode & MA_RAYTRANSP) {
1507                         ep.setIndexOfRefraction(ma->ang);
1508                 }
1509                 else {
1510                         ep.setIndexOfRefraction(1.0f);
1511                 }
1512                 // transparency
1513                 ep.setTransparency(ma->alpha);
1514                 // emission
1515                 COLLADASW::ColorOrTexture cot = getcol(0.0f, 0.0f, 0.0f, 1.0f);
1516                 ep.setEmission(cot);
1517                 ep.setTransparent(cot);
1518                 // diffuse 
1519                 cot = getcol(ma->r, ma->g, ma->b, 1.0f);
1520                 ep.setDiffuse(cot);
1521                 // ambient
1522                 cot = getcol(ma->ambr, ma->ambg, ma->ambb, 1.0f);
1523                 ep.setAmbient(cot);
1524                 // reflective, reflectivity
1525                 if (ma->mode & MA_RAYMIRROR) {
1526                         cot = getcol(ma->mirr, ma->mirg, ma->mirb, 1.0f);
1527                         ep.setReflective(cot);
1528                         ep.setReflectivity(ma->ray_mirror);
1529                 }
1530                 else {
1531                         cot = getcol(0.0f, 0.0f, 0.0f, 1.0f);
1532                         ep.setReflective(cot);
1533                         ep.setReflectivity(0.0f);
1534                 }
1535                 // specular
1536                 if (ep.getShaderType() != COLLADASW::EffectProfile::LAMBERT) {
1537                         cot = getcol(ma->specr, ma->specg, ma->specb, 1.0f);
1538                         ep.setSpecular(cot);
1539                 }
1540
1541                 // XXX make this more readable if possible
1542
1543                 // create <sampler> and <surface> for each image
1544                 COLLADASW::Sampler samplers[MAX_MTEX];
1545                 //COLLADASW::Surface surfaces[MAX_MTEX];
1546                 //void *samp_surf[MAX_MTEX][2];
1547                 void *samp_surf[MAX_MTEX][1];
1548                 
1549                 // image to index to samp_surf map
1550                 // samp_surf[index] stores 2 pointers, sampler and surface
1551                 std::map<std::string, int> im_samp_map;
1552
1553                 unsigned int a, b;
1554                 for (a = 0, b = 0; a < tex_indices.size(); a++) {
1555                         MTex *t = ma->mtex[tex_indices[a]];
1556                         Image *ima = t->tex->ima;
1557                         
1558                         std::string key(id_name(ima));
1559                         key = translate_id(key);
1560
1561                         // create only one <sampler>/<surface> pair for each unique image
1562                         if (im_samp_map.find(key) == im_samp_map.end()) {
1563                                 //<newparam> <surface> <init_from>
1564                         //      COLLADASW::Surface surface(COLLADASW::Surface::SURFACE_TYPE_2D,
1565 //                                                                                 key + COLLADASW::Surface::SURFACE_SID_SUFFIX);
1566 //                              COLLADASW::SurfaceInitOption sio(COLLADASW::SurfaceInitOption::INIT_FROM);
1567 //                              sio.setImageReference(key);
1568 //                              surface.setInitOption(sio);
1569                                 
1570                                 //<newparam> <sampler> <source>
1571                                 COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D,
1572                                                                                    key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
1573                                                                                    key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
1574                                 sampler.setImageId(key);
1575                                 // copy values to arrays since they will live longer
1576                                 samplers[a] = sampler;
1577                                 //surfaces[a] = surface;
1578                                 
1579                                 // store pointers so they can be used later when we create <texture>s
1580                                 samp_surf[b][0] = &samplers[a];
1581                                 //samp_surf[b][1] = &surfaces[a];
1582                                 
1583                                 im_samp_map[key] = b;
1584                                 b++;
1585                         }
1586                 }
1587
1588                 // used as fallback when MTex->uvname is "" (this is pretty common)
1589                 // it is indeed the correct value to use in that case
1590                 std::string active_uv(getActiveUVLayerName(ob));
1591
1592                 // write textures
1593                 // XXX very slow
1594                 for (a = 0; a < tex_indices.size(); a++) {
1595                         MTex *t = ma->mtex[tex_indices[a]];
1596                         Image *ima = t->tex->ima;
1597
1598                         // we assume map input is always TEXCO_UV
1599
1600                         std::string key(id_name(ima));
1601                         key = translate_id(key);
1602                         int i = im_samp_map[key];
1603                         COLLADASW::Sampler *sampler = (COLLADASW::Sampler*)samp_surf[i][0];
1604                         //COLLADASW::Surface *surface = (COLLADASW::Surface*)samp_surf[i][1];
1605
1606                         std::string uvname = strlen(t->uvname) ? t->uvname : active_uv;
1607
1608                         // color
1609                         if (t->mapto & MAP_COL) {
1610                                 ep.setDiffuse(createTexture(ima, uvname, sampler));
1611                         }
1612                         // ambient
1613                         if (t->mapto & MAP_AMB) {
1614                                 ep.setAmbient(createTexture(ima, uvname, sampler));
1615                         }
1616                         // specular
1617                         if (t->mapto & MAP_SPEC) {
1618                                 ep.setSpecular(createTexture(ima, uvname, sampler));
1619                         }
1620                         // emission
1621                         if (t->mapto & MAP_EMIT) {
1622                                 ep.setEmission(createTexture(ima, uvname, sampler));
1623                         }
1624                         // reflective
1625                         if (t->mapto & MAP_REF) {
1626                                 ep.setReflective(createTexture(ima, uvname, sampler));
1627                         }
1628                         // alpha
1629                         if (t->mapto & MAP_ALPHA) {
1630                                 ep.setTransparent(createTexture(ima, uvname, sampler));
1631                         }
1632                         // extension:
1633                         // Normal map --> Must be stored with <extra> tag as different technique, 
1634                         // since COLLADA doesn't support normal maps, even in current COLLADA 1.5.
1635                         if (t->mapto & MAP_NORM) {
1636                                 COLLADASW::Texture texture(key);
1637                                 texture.setTexcoord(uvname);
1638                                 texture.setSampler(*sampler);
1639                                 // technique FCOLLADA, with the <bump> tag, is most likely the best understood,
1640                                 // most widespread de-facto standard.
1641                                 texture.setProfileName("FCOLLADA");
1642                                 texture.setChildElementName("bump");                            
1643                                 ep.setExtraTechniqueColorOrTexture(COLLADASW::ColorOrTexture(texture));
1644                         }
1645                 }
1646                 // performs the actual writing
1647                 ep.addProfileElements();
1648                 ep.closeProfile();
1649                 closeEffect();  
1650         }
1651         
1652         COLLADASW::ColorOrTexture createTexture(Image *ima,
1653                                                                                         std::string& uv_layer_name,
1654                                                                                         COLLADASW::Sampler *sampler
1655                                                                                         /*COLLADASW::Surface *surface*/)
1656         {
1657                 
1658                 COLLADASW::Texture texture(translate_id(id_name(ima)));
1659                 texture.setTexcoord(uv_layer_name);
1660                 //texture.setSurface(*surface);
1661                 texture.setSampler(*sampler);
1662                 
1663                 COLLADASW::ColorOrTexture cot(texture);
1664                 return cot;
1665         }
1666         
1667         COLLADASW::ColorOrTexture getcol(float r, float g, float b, float a)
1668         {
1669                 COLLADASW::Color color(r,g,b,a);
1670                 COLLADASW::ColorOrTexture cot(color);
1671                 return cot;
1672         }
1673         
1674         //returns the array of mtex indices which have image 
1675         //need this for exporting textures
1676         void createTextureIndices(Material *ma, std::vector<int> &indices)
1677         {
1678                 indices.clear();
1679
1680                 for (int a = 0; a < MAX_MTEX; a++) {
1681                         if (ma->mtex[a] &&
1682                                 ma->mtex[a]->tex->type == TEX_IMAGE &&
1683                                 ma->mtex[a]->texco == TEXCO_UV){
1684                                 indices.push_back(a);
1685                         }
1686                 }
1687         }
1688 };
1689
1690 class MaterialsExporter: COLLADASW::LibraryMaterials
1691 {
1692 public:
1693         MaterialsExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryMaterials(sw){}
1694         void exportMaterials(Scene *sce)
1695         {
1696                 openLibrary();
1697
1698                 forEachMaterialInScene(sce, *this);
1699
1700                 closeLibrary();
1701         }
1702
1703         void operator()(Material *ma, Object *ob)
1704         {
1705                 std::string name(id_name(ma));
1706
1707                 openMaterial(translate_id(name), name);
1708
1709                 std::string efid = translate_id(name) + "-effect";
1710                 addInstanceEffect(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, efid));
1711
1712                 closeMaterial();
1713         }
1714 };
1715
1716 class CamerasExporter: COLLADASW::LibraryCameras
1717 {
1718 public:
1719         CamerasExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryCameras(sw){}
1720         void exportCameras(Scene *sce)
1721         {
1722                 openLibrary();
1723                 
1724                 forEachCameraObjectInScene(sce, *this);
1725                 
1726                 closeLibrary();
1727         }
1728         void operator()(Object *ob, Scene *sce)
1729         {
1730                 // XXX add other params later
1731                 Camera *cam = (Camera*)ob->data;
1732                 std::string cam_id(get_camera_id(ob));
1733                 std::string cam_name(id_name(cam));
1734                 
1735                 if (cam->type == CAM_PERSP) {
1736                         COLLADASW::PerspectiveOptic persp(mSW);
1737                         persp.setXFov(1.0);
1738                         persp.setAspectRatio(0.1);
1739                         persp.setZFar(cam->clipend);
1740                         persp.setZNear(cam->clipsta);
1741                         COLLADASW::Camera ccam(mSW, &persp, cam_id, cam_name);
1742                         addCamera(ccam);
1743                 }
1744                 else {
1745                         COLLADASW::OrthographicOptic ortho(mSW);
1746                         ortho.setXMag(1.0);
1747                         ortho.setAspectRatio(0.1);
1748                         ortho.setZFar(cam->clipend);
1749                         ortho.setZNear(cam->clipsta);
1750                         COLLADASW::Camera ccam(mSW, &ortho, cam_id, cam_name);
1751                         addCamera(ccam);
1752                 }
1753         }       
1754 };
1755
1756 class LightsExporter: COLLADASW::LibraryLights
1757 {
1758 public:
1759         LightsExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryLights(sw){}
1760         void exportLights(Scene *sce)
1761         {
1762                 openLibrary();
1763                 
1764                 forEachLampObjectInScene(sce, *this);
1765                 
1766                 closeLibrary();
1767         }
1768         void operator()(Object *ob)
1769         {
1770                 Lamp *la = (Lamp*)ob->data;
1771                 std::string la_id(get_light_id(ob));
1772                 std::string la_name(id_name(la));
1773                 COLLADASW::Color col(la->r, la->g, la->b);
1774                 float e = la->energy;
1775                 
1776                 // sun
1777                 if (la->type == LA_SUN) {
1778                         COLLADASW::DirectionalLight cla(mSW, la_id, la_name, e);
1779                         cla.setColor(col);
1780                         addLight(cla);
1781                 }
1782                 // hemi
1783                 else if (la->type == LA_HEMI) {
1784                         COLLADASW::AmbientLight cla(mSW, la_id, la_name, e);
1785                         cla.setColor(col);
1786                         addLight(cla);
1787                 }
1788                 // spot
1789                 else if (la->type == LA_SPOT) {
1790                         COLLADASW::SpotLight cla(mSW, la_id, la_name, e);
1791                         cla.setColor(col);
1792                         cla.setFallOffAngle(la->spotsize);
1793                         cla.setFallOffExponent(la->spotblend);
1794                         cla.setLinearAttenuation(la->att1);
1795                         cla.setQuadraticAttenuation(la->att2);
1796                         addLight(cla);
1797                 }
1798                 // lamp
1799                 else if (la->type == LA_LOCAL) {
1800                         COLLADASW::PointLight cla(mSW, la_id, la_name, e);
1801                         cla.setColor(col);
1802                         cla.setLinearAttenuation(la->att1);
1803                         cla.setQuadraticAttenuation(la->att2);
1804                         addLight(cla);
1805                 }
1806                 // area lamp is not supported
1807                 // it will be exported as a local lamp
1808                 else {
1809                         COLLADASW::PointLight cla(mSW, la_id, la_name, e);
1810                         cla.setColor(col);
1811                         cla.setLinearAttenuation(la->att1);
1812                         cla.setQuadraticAttenuation(la->att2);
1813                         addLight(cla);
1814                 }
1815         }
1816 };
1817
1818 // TODO: it would be better to instantiate animations rather than create a new one per object
1819 // COLLADA allows this through multiple <channel>s in <animation>.
1820 // For this to work, we need to know objects that use a certain action.
1821 class AnimationExporter: COLLADASW::LibraryAnimations
1822 {
1823         Scene *scene;
1824
1825 public:
1826
1827         AnimationExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryAnimations(sw) {}
1828
1829         void exportAnimations(Scene *sce)
1830         {
1831                 this->scene = sce;
1832
1833                 openLibrary();
1834                 
1835                 forEachObjectInScene(sce, *this);
1836                 
1837                 closeLibrary();
1838         }
1839
1840         // called for each exported object
1841         void operator() (Object *ob) 
1842         {
1843                 if (!ob->adt || !ob->adt->action) return;
1844                 
1845                 FCurve *fcu = (FCurve*)ob->adt->action->curves.first;
1846                 
1847                 if (ob->type == OB_ARMATURE) {
1848                         if (!ob->data) return;
1849
1850                         bArmature *arm = (bArmature*)ob->data;
1851                         for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next)
1852                                 write_bone_animation(ob, bone);
1853                 }
1854                 else {
1855                         while (fcu) {
1856                                 // TODO "rotation_quaternion" is also possible for objects (although euler is default)
1857                                 if ((!strcmp(fcu->rna_path, "location") || !strcmp(fcu->rna_path, "scale")) ||
1858                                         (!strcmp(fcu->rna_path, "rotation_euler") && ob->rotmode == ROT_MODE_EUL))
1859                                         dae_animation(fcu, id_name(ob));
1860
1861                                 fcu = fcu->next;
1862                         }
1863                 }
1864         }
1865
1866 protected:
1867
1868         void dae_animation(FCurve *fcu, std::string ob_name)
1869         {
1870                 const char *axis_names[] = {"X", "Y", "Z"};
1871                 const char *axis_name = NULL;
1872                 char anim_id[200];
1873                 
1874                 if (fcu->array_index < 3)
1875                         axis_name = axis_names[fcu->array_index];
1876
1877                 BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
1878                                          fcu->rna_path, axis_names[fcu->array_index]);
1879
1880                 // check rna_path is one of: rotation, scale, location
1881
1882                 openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
1883
1884                 // create input source
1885                 std::string input_id = create_source_from_fcurve(Sampler::INPUT, fcu, anim_id, axis_name);
1886
1887                 // create output source
1888                 std::string output_id = create_source_from_fcurve(Sampler::OUTPUT, fcu, anim_id, axis_name);
1889
1890                 // create interpolations source
1891                 std::string interpolation_id = create_interpolation_source(fcu->totvert, anim_id, axis_name);
1892
1893                 std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
1894                 COLLADASW::LibraryAnimations::Sampler sampler(sampler_id);
1895                 std::string empty;
1896                 sampler.addInput(Sampler::INPUT, COLLADABU::URI(empty, input_id));
1897                 sampler.addInput(Sampler::OUTPUT, COLLADABU::URI(empty, output_id));
1898
1899                 // this input is required
1900                 sampler.addInput(Sampler::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
1901
1902                 addSampler(sampler);
1903
1904                 std::string target = translate_id(ob_name)
1905                         + "/" + get_transform_sid(fcu->rna_path, -1, axis_name);
1906                 addChannel(COLLADABU::URI(empty, sampler_id), target);
1907
1908                 closeAnimation();
1909         }
1910
1911         void write_bone_animation(Object *ob_arm, Bone *bone)
1912         {
1913                 if (!ob_arm->adt)
1914                         return;
1915
1916                 for (int i = 0; i < 3; i++)
1917                         sample_and_write_bone_animation(ob_arm, bone, i);
1918
1919                 for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next)
1920                         write_bone_animation(ob_arm, child);
1921         }
1922
1923         void sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type)
1924         {
1925                 bArmature *arm = (bArmature*)ob_arm->data;
1926                 int flag = arm->flag;
1927                 std::vector<float> fra;
1928                 char prefix[256];
1929
1930                 BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone->name);
1931
1932                 bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name);
1933                 if (!pchan)
1934                         return;
1935
1936                 switch (transform_type) {
1937                 case 0:
1938                         find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode);
1939                         break;
1940                 case 1:
1941                         find_frames(ob_arm, fra, prefix, "scale");
1942                         break;
1943                 case 2:
1944                         find_frames(ob_arm, fra, prefix, "location");
1945                         break;
1946                 default:
1947                         return;
1948                 }
1949
1950                 // exit rest position
1951                 if (flag & ARM_RESTPOS) {
1952                         arm->flag &= ~ARM_RESTPOS;
1953                         where_is_pose(scene, ob_arm);
1954                 }
1955
1956                 if (fra.size()) {
1957                         float *v = (float*)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames");
1958                         sample_animation(v, fra, transform_type, bone, ob_arm);
1959
1960                         if (transform_type == 0) {
1961                                 // write x, y, z curves separately if it is rotation
1962                                 float *c = (float*)MEM_callocN(sizeof(float) * fra.size(), "temp. anim frames");
1963                                 for (int i = 0; i < 3; i++) {
1964                                         for (unsigned int j = 0; j < fra.size(); j++)
1965                                                 c[j] = v[j * 3 + i];
1966
1967                                         dae_bone_animation(fra, c, transform_type, i, id_name(ob_arm), bone->name);
1968                                 }
1969                                 MEM_freeN(c);
1970                         }
1971                         else {
1972                                 // write xyz at once if it is location or scale
1973                                 dae_bone_animation(fra, v, transform_type, -1, id_name(ob_arm), bone->name);
1974                         }
1975
1976                         MEM_freeN(v);
1977                 }
1978
1979                 // restore restpos
1980                 if (flag & ARM_RESTPOS) 
1981                         arm->flag = flag;
1982                 where_is_pose(scene, ob_arm);
1983         }
1984
1985         void sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm)
1986         {
1987                 bPoseChannel *pchan, *parchan = NULL;
1988                 bPose *pose = ob_arm->pose;
1989
1990                 pchan = get_pose_channel(pose, bone->name);
1991
1992                 if (!pchan)
1993                         return;
1994
1995                 parchan = pchan->parent;
1996
1997                 enable_fcurves(ob_arm->adt->action, bone->name);
1998
1999                 std::vector<float>::iterator it;
2000                 for (it = frames.begin(); it != frames.end(); it++) {
2001                         float mat[4][4], ipar[4][4];
2002
2003                         float ctime = bsystem_time(scene, ob_arm, *it, 0.0f);
2004
2005                         BKE_animsys_evaluate_animdata(&ob_arm->id, ob_arm->adt, *it, ADT_RECALC_ANIM);
2006                         where_is_pose_bone(scene, ob_arm, pchan, ctime, 1);
2007
2008                         // compute bone local mat
2009                         if (bone->parent) {
2010                                 invert_m4_m4(ipar, parchan->pose_mat);
2011                                 mul_m4_m4m4(mat, pchan->pose_mat, ipar);
2012                         }
2013                         else
2014                                 copy_m4_m4(mat, pchan->pose_mat);
2015
2016                         switch (type) {
2017                         case 0:
2018                                 mat4_to_eul(v, mat);
2019                                 break;
2020                         case 1:
2021                                 mat4_to_size(v, mat);
2022                                 break;
2023                         case 2:
2024                                 copy_v3_v3(v, mat[3]);
2025                                 break;
2026                         }
2027
2028                         v += 3;
2029                 }
2030
2031                 enable_fcurves(ob_arm->adt->action, NULL);
2032         }
2033
2034         // dae_bone_animation -> add_bone_animation
2035         // (blend this into dae_bone_animation)
2036         void dae_bone_animation(std::vector<float> &fra, float *v, int tm_type, int axis, std::string ob_name, std::string bone_name)
2037         {
2038                 const char *axis_names[] = {"X", "Y", "Z"};
2039                 const char *axis_name = NULL;
2040                 char anim_id[200];
2041                 bool is_rot = tm_type == 0;
2042                 
2043                 if (!fra.size())
2044                         return;
2045
2046                 char rna_path[200];
2047                 BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].%s", bone_name.c_str(),
2048                                          tm_type == 0 ? "rotation_quaternion" : (tm_type == 1 ? "scale" : "location"));
2049
2050                 if (axis > -1)
2051                         axis_name = axis_names[axis];
2052                 
2053                 std::string transform_sid = get_transform_sid(NULL, tm_type, axis_name);
2054                 
2055                 BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char*)translate_id(ob_name).c_str(),
2056                                          (char*)translate_id(bone_name).c_str(), (char*)transform_sid.c_str());
2057
2058                 openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
2059
2060                 // create input source
2061                 std::string input_id = create_source_from_vector(Sampler::INPUT, fra, is_rot, anim_id, axis_name);
2062
2063                 // create output source
2064                 std::string output_id;
2065                 if (axis == -1)
2066                         output_id = create_xyz_source(v, fra.size(), anim_id);
2067                 else
2068                         output_id = create_source_from_array(Sampler::OUTPUT, v, fra.size(), is_rot, anim_id, axis_name);
2069
2070                 // create interpolations source
2071                 std::string interpolation_id = create_interpolation_source(fra.size(), anim_id, axis_name);
2072
2073                 std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
2074                 COLLADASW::LibraryAnimations::Sampler sampler(sampler_id);
2075                 std::string empty;
2076                 sampler.addInput(Sampler::INPUT, COLLADABU::URI(empty, input_id));
2077                 sampler.addInput(Sampler::OUTPUT, COLLADABU::URI(empty, output_id));
2078
2079                 // TODO create in/out tangents source
2080
2081                 // this input is required
2082                 sampler.addInput(Sampler::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
2083
2084                 addSampler(sampler);
2085
2086                 std::string target = translate_id(ob_name + "_" + bone_name) + "/" + transform_sid;
2087                 addChannel(COLLADABU::URI(empty, sampler_id), target);
2088
2089                 closeAnimation();
2090         }
2091
2092         float convert_time(float frame)
2093         {
2094                 return FRA2TIME(frame);
2095         }
2096
2097         float convert_angle(float angle)
2098         {
2099                 return COLLADABU::Math::Utils::radToDegF(angle);
2100         }
2101
2102         std::string get_semantic_suffix(Sampler::Semantic semantic)
2103         {
2104                 switch(semantic) {
2105                 case Sampler::INPUT:
2106                         return INPUT_SOURCE_ID_SUFFIX;
2107                 case Sampler::OUTPUT:
2108                         return OUTPUT_SOURCE_ID_SUFFIX;
2109                 case Sampler::INTERPOLATION:
2110                         return INTERPOLATION_SOURCE_ID_SUFFIX;
2111                 case Sampler::IN_TANGENT:
2112                         return INTANGENT_SOURCE_ID_SUFFIX;
2113                 case Sampler::OUT_TANGENT:
2114                         return OUTTANGENT_SOURCE_ID_SUFFIX;
2115                 default:
2116                         break;
2117                 }
2118                 return "";
2119         }
2120
2121         void add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
2122                                                            Sampler::Semantic semantic, bool is_rot, const char *axis)
2123         {
2124                 switch(semantic) {
2125                 case Sampler::INPUT:
2126                         param.push_back("TIME");
2127                         break;
2128                 case Sampler::OUTPUT:
2129                         if (is_rot) {
2130                                 param.push_back("ANGLE");
2131                         }
2132                         else {
2133                                 if (axis) {
2134                                         param.push_back(axis);
2135                                 }
2136                                 else {
2137                                         param.push_back("X");
2138                                         param.push_back("Y");
2139                                         param.push_back("Z");
2140                                 }
2141                         }
2142                         break;
2143                 case Sampler::IN_TANGENT:
2144                 case Sampler::OUT_TANGENT:
2145                         param.push_back("X");
2146                         param.push_back("Y");
2147                         break;
2148                 default:
2149                         break;
2150                 }
2151         }
2152
2153         void get_source_values(BezTriple *bezt, Sampler::Semantic semantic, bool rotation, float *values, int *length)
2154         {
2155                 switch (semantic) {
2156                 case Sampler::INPUT:
2157                         *length = 1;
2158                         values[0] = convert_time(bezt->vec[1][0]);
2159                         break;
2160                 case Sampler::OUTPUT:
2161                         *length = 1;
2162                         if (rotation) {
2163                                 values[0] = convert_angle(bezt->vec[1][1]);
2164                         }
2165                         else {
2166                                 values[0] = bezt->vec[1][1];
2167                         }
2168                         break;
2169                 case Sampler::IN_TANGENT:
2170                 case Sampler::OUT_TANGENT:
2171                         // XXX
2172                         *length = 2;
2173                         break;
2174                 default:
2175                         *length = 0;
2176                         break;
2177                 }
2178         }
2179
2180         std::string create_source_from_fcurve(Sampler::Semantic semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name)
2181         {
2182                 std::string source_id = anim_id + get_semantic_suffix(semantic);
2183
2184                 //bool is_rotation = !strcmp(fcu->rna_path, "rotation");
2185                 bool is_rotation = false;
2186                 
2187                 if (strstr(fcu->rna_path, "rotation")) is_rotation = true;
2188                 
2189                 COLLADASW::FloatSourceF source(mSW);
2190                 source.setId(source_id);
2191                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
2192                 source.setAccessorCount(fcu->totvert);
2193                 source.setAccessorStride(1);
2194                 
2195                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
2196                 add_source_parameters(param, semantic, is_rotation, axis_name);
2197
2198                 source.prepareToAppendValues();
2199
2200                 for (unsigned int i = 0; i < fcu->totvert; i++) {
2201                         float values[3]; // be careful!
2202                         int length = 0;
2203
2204                         get_source_values(&fcu->bezt[i], semantic, is_rotation, values, &length);
2205                         for (int j = 0; j < length; j++)
2206                                 source.appendValues(values[j]);
2207                 }
2208
2209                 source.finish();
2210
2211                 return source_id;
2212         }
2213
2214         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)
2215         {
2216                 std::string source_id = anim_id + get_semantic_suffix(semantic);
2217
2218                 COLLADASW::FloatSourceF source(mSW);
2219                 source.setId(source_id);
2220                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
2221                 source.setAccessorCount(tot);
2222                 source.setAccessorStride(1);
2223                 
2224                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
2225                 add_source_parameters(param, semantic, is_rot, axis_name);
2226
2227                 source.prepareToAppendValues();
2228
2229                 for (int i = 0; i < tot; i++) {
2230                         float val = v[i];
2231                         if (semantic == Sampler::INPUT)
2232                                 val = convert_time(val);
2233                         else if (is_rot)
2234                                 val = convert_angle(val);
2235                         source.appendValues(val);
2236                 }
2237
2238                 source.finish();
2239
2240                 return source_id;
2241         }
2242
2243         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)
2244         {
2245                 std::string source_id = anim_id + get_semantic_suffix(semantic);
2246
2247                 COLLADASW::FloatSourceF source(mSW);
2248                 source.setId(source_id);
2249                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
2250                 source.setAccessorCount(fra.size());
2251                 source.setAccessorStride(1);
2252                 
2253                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
2254                 add_source_parameters(param, semantic, is_rot, axis_name);
2255
2256                 source.prepareToAppendValues();
2257
2258                 std::vector<float>::iterator it;
2259                 for (it = fra.begin(); it != fra.end(); it++) {
2260                         float val = *it;
2261                         if (semantic == Sampler::INPUT)
2262                                 val = convert_time(val);
2263                         else if (is_rot)
2264                                 val = convert_angle(val);
2265                         source.appendValues(val);
2266                 }
2267
2268                 source.finish();
2269
2270                 return source_id;
2271         }
2272
2273         // only used for sources with OUTPUT semantic
2274         std::string create_xyz_source(float *v, int tot, const std::string& anim_id)
2275         {
2276                 Sampler::Semantic semantic = Sampler::OUTPUT;
2277                 std::string source_id = anim_id + get_semantic_suffix(semantic);
2278
2279                 COLLADASW::FloatSourceF source(mSW);
2280                 source.setId(source_id);
2281                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
2282                 source.setAccessorCount(tot);
2283                 source.setAccessorStride(3);
2284                 
2285                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
2286                 add_source_parameters(param, semantic, false, NULL);
2287
2288                 source.prepareToAppendValues();
2289
2290                 for (int i = 0; i < tot; i++) {
2291                         source.appendValues(*v, *(v + 1), *(v + 2));
2292                         v += 3;
2293                 }
2294
2295                 source.finish();
2296
2297                 return source_id;
2298         }
2299
2300         std::string create_interpolation_source(int tot, const std::string& anim_id, const char *axis_name)
2301         {
2302                 std::string source_id = anim_id + get_semantic_suffix(Sampler::INTERPOLATION);
2303
2304                 COLLADASW::NameSource source(mSW);
2305                 source.setId(source_id);
2306                 source.setArrayId(source_id + ARRAY_ID_SUFFIX);
2307                 source.setAccessorCount(tot);
2308                 source.setAccessorStride(1);
2309                 
2310                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
2311                 param.push_back("INTERPOLATION");
2312
2313                 source.prepareToAppendValues();
2314
2315                 for (int i = 0; i < tot; i++) {
2316                         source.appendValues(LINEAR_NAME);
2317                 }
2318
2319                 source.finish();
2320
2321                 return source_id;
2322         }
2323
2324         std::string get_transform_sid(char *rna_path, int tm_type, const char *axis_name)
2325         {
2326                 if (rna_path) {
2327                         char *name = extract_transform_name(rna_path);
2328
2329                         if (strstr(name, "rotation"))
2330                                 return std::string("rotation") + std::string(axis_name) + ".ANGLE";
2331                         else if (!strcmp(name, "location") || !strcmp(name, "scale"))
2332                                 return std::string(name);
2333                 }
2334                 else {
2335                         if (tm_type == 0)
2336                                 return std::string("rotation") + std::string(axis_name) + ".ANGLE";
2337                         else
2338                                 return tm_type == 1 ? "scale" : "location";
2339                 }
2340
2341                 return NULL;
2342         }
2343
2344         char *extract_transform_name(char *rna_path)
2345         {
2346                 char *dot = strrchr(rna_path, '.');
2347                 return dot ? (dot + 1) : rna_path;
2348         }
2349
2350         void find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name)
2351         {
2352                 FCurve *fcu= (FCurve*)ob->adt->action->curves.first;
2353
2354                 for (; fcu; fcu = fcu->next) {
2355                         if (prefix && strncmp(prefix, fcu->rna_path, strlen(prefix)))
2356                                 continue;
2357
2358                         char *name = extract_transform_name(fcu->rna_path);
2359                         if (!strcmp(name, tm_name)) {
2360                                 for (unsigned int i = 0; i < fcu->totvert; i++) {
2361                                         float f = fcu->bezt[i].vec[1][0];
2362                                         if (std::find(fra.begin(), fra.end(), f) == fra.end())
2363                                                 fra.push_back(f);
2364                                 }
2365                         }
2366                 }
2367         }
2368
2369         void find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode)
2370         {
2371                 if (rotmode > 0)
2372                         find_frames(ob, fra, prefix, "rotation_euler");
2373                 else if (rotmode == ROT_MODE_QUAT)
2374                         find_frames(ob, fra, prefix, "rotation_quaternion");
2375                 else if (rotmode == ROT_MODE_AXISANGLE)
2376                         ;
2377         }
2378
2379         // enable fcurves driving a specific bone, disable all the rest
2380         // if bone_name = NULL enable all fcurves
2381         void enable_fcurves(bAction *act, char *bone_name)
2382         {
2383                 FCurve *fcu;
2384                 char prefix[200];
2385
2386                 if (bone_name)
2387                         BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name);
2388
2389                 for (fcu = (FCurve*)act->curves.first; fcu; fcu = fcu->next) {
2390                         if (bone_name) {
2391                                 if (!strncmp(fcu->rna_path, prefix, strlen(prefix)))
2392                                         fcu->flag &= ~FCURVE_DISABLED;
2393                                 else
2394                                         fcu->flag |= FCURVE_DISABLED;
2395                         }
2396                         else {
2397                                 fcu->flag &= ~FCURVE_DISABLED;
2398                         }
2399                 }
2400         }
2401 };
2402
2403 void DocumentExporter::exportCurrentScene(Scene *sce, const char* filename)
2404 {
2405         COLLADABU::NativeString native_filename =
2406                 COLLADABU::NativeString(std::string(filename));
2407         COLLADASW::StreamWriter sw(native_filename);
2408
2409         // open <Collada>
2410         sw.startDocument();
2411
2412         // <asset>
2413         COLLADASW::Asset asset(&sw);
2414         // XXX ask blender devs about this?
2415         asset.setUnit("decimetre", 0.1);
2416         asset.setUpAxisType(COLLADASW::Asset::Z_UP);
2417         asset.add();
2418         
2419         // <library_cameras>
2420         CamerasExporter ce(&sw);
2421         ce.exportCameras(sce);
2422         
2423         // <library_lights>
2424         LightsExporter le(&sw);
2425         le.exportLights(sce);
2426
2427         // <library_images>
2428         ImagesExporter ie(&sw, filename);
2429         ie.exportImages(sce);
2430         
2431         // <library_effects>
2432         EffectsExporter ee(&sw);
2433         ee.exportEffects(sce);
2434         
2435         // <library_materials>
2436         MaterialsExporter me(&sw);
2437         me.exportMaterials(sce);
2438
2439         // <library_geometries>
2440         GeometryExporter ge(&sw);
2441         ge.exportGeom(sce);
2442
2443         // <library_animations>
2444         AnimationExporter ae(&sw);
2445         ae.exportAnimations(sce);
2446
2447         // <library_controllers>
2448         ArmatureExporter arm_exporter(&sw);
2449         arm_exporter.export_controllers(sce);
2450
2451         // <library_visual_scenes>
2452         SceneExporter se(&sw, &arm_exporter);
2453         se.exportScene(sce);
2454         
2455         // <scene>
2456         std::string scene_name(translate_id(id_name(sce)));
2457         COLLADASW::Scene scene(&sw, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING,
2458                                                                                            scene_name));
2459         scene.add();
2460         
2461         // close <Collada>
2462         sw.endDocument();
2463
2464 }
2465
2466 void DocumentExporter::exportScenes(const char* filename)
2467 {
2468 }
2469
2470 /*
2471
2472 NOTES:
2473
2474 * AnimationExporter::sample_animation enables all curves on armature, this is undesirable for a user
2475
2476  */
2477