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