Cleanup: trailing space
[blender.git] / source / blender / collada / GeometryExporter.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed,
19  *                 Nathan Letwory
20  *
21  * ***** END GPL LICENSE BLOCK *****
22  */
23
24 /** \file blender/collada/GeometryExporter.cpp
25  *  \ingroup collada
26  */
27
28
29 #include <sstream>
30
31 #include "COLLADASWPrimitves.h"
32 #include "COLLADASWSource.h"
33 #include "COLLADASWVertices.h"
34 #include "COLLADABUUtils.h"
35
36 #include "GeometryExporter.h"
37
38 #include "DNA_meshdata_types.h"
39
40 extern "C" {
41         #include "BLI_utildefines.h"
42
43         #include "BKE_DerivedMesh.h"
44         #include "BKE_main.h"
45         #include "BKE_global.h"
46         #include "BKE_library.h"
47         #include "BKE_customdata.h"
48         #include "BKE_material.h"
49         #include "BKE_mesh.h"
50 }
51
52 #include "collada_internal.h"
53 #include "collada_utils.h"
54
55
56 // TODO: optimize UV sets by making indexed list with duplicates removed
57 GeometryExporter::GeometryExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryGeometries(sw), export_settings(export_settings)
58 {
59 }
60
61 void GeometryExporter::exportGeom(Scene *sce)
62 {
63         openLibrary();
64
65         mScene = sce;
66         GeometryFunctor gf;
67         gf.forEachMeshObjectInExportSet<GeometryExporter>(sce, *this, this->export_settings->export_set);
68
69         closeLibrary();
70 }
71
72 void GeometryExporter::operator()(Object *ob)
73 {
74         // XXX don't use DerivedMesh, Mesh instead?
75 #if 0
76         DerivedMesh *dm = mesh_get_derived_final(mScene, ob, CD_MASK_BAREMESH);
77 #endif
78
79         bool use_instantiation = this->export_settings->use_object_instantiation;
80         Mesh *me = bc_get_mesh_copy( mScene,
81                                         ob,
82                                         this->export_settings->export_mesh_type,
83                                         this->export_settings->apply_modifiers,
84                                         this->export_settings->triangulate);
85
86         std::string geom_id = get_geometry_id(ob, use_instantiation);
87         std::vector<Normal> nor;
88         std::vector<BCPolygonNormalsIndices> norind;
89
90         // Skip if linked geometry was already exported from another reference
91         if (use_instantiation &&
92             exportedGeometry.find(geom_id) != exportedGeometry.end())
93         {
94                 return;
95         }
96
97         std::string geom_name = (use_instantiation) ? id_name(ob->data) : id_name(ob);
98
99         exportedGeometry.insert(geom_id);
100
101         bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL);
102
103         create_normals(nor, norind, me);
104
105         // openMesh(geoId, geoName, meshId)
106         openMesh(geom_id, geom_name);
107
108         // writes <source> for vertex coords
109         createVertsSource(geom_id, me);
110
111         // writes <source> for normal coords
112         createNormalsSource(geom_id, me, nor);
113
114         bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
115
116         // writes <source> for uv coords if mesh has uv coords
117         if (has_uvs) {
118                 createTexcoordsSource(geom_id, me);
119         }
120
121         if (has_color) {
122                 createVertexColorSource(geom_id, me);
123         }
124         // <vertices>
125
126         COLLADASW::Vertices verts(mSW);
127         verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
128         COLLADASW::InputList &input_list = verts.getInputList();
129         COLLADASW::Input input(COLLADASW::InputSemantic::POSITION, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
130         input_list.push_back(input);
131         verts.add();
132
133         createLooseEdgeList(ob, me, geom_id);
134
135         // Only create Polylists if number of faces > 0
136         if (me->totface > 0) {
137                 // XXX slow
138                 std::set<Image *> uv_images = bc_getUVImages(ob, !this->export_settings->active_uv_only);
139                 if (this->export_settings->export_texture_type == BC_TEXTURE_TYPE_MAT || uv_images.size() == 0) {
140                         if (ob->totcol) {
141                                 for (int a = 0; a < ob->totcol; a++) {
142                                         createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
143                                 }
144                         }
145                         else {
146                                 int i = 0;
147                                 createPolylist(i, has_uvs, has_color, ob, me, geom_id, norind);
148                         }
149                 }
150                 else {
151                         bool all_uv_layers = !this->export_settings->active_uv_only;
152                         std::set<Image *> uv_image_set = bc_getUVImages(ob, all_uv_layers);
153                         createPolylists(uv_image_set, has_uvs, has_color, ob, me, geom_id, norind);
154                 }
155         }
156
157         closeMesh();
158
159         if (me->flag & ME_TWOSIDED) {
160                 mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>");
161         }
162
163         closeGeometry();
164
165         if (this->export_settings->include_shapekeys) {
166                 Key * key = BKE_key_from_object(ob);
167                 if (key) {
168                         KeyBlock * kb = (KeyBlock *)key->block.first;
169                         //skip the basis
170                         kb = kb->next;
171                         for (; kb; kb = kb->next) {
172                                 BKE_keyblock_convert_to_mesh(kb, me);
173                                 export_key_mesh(ob, me, kb);
174                         }
175                 }
176         }
177
178         BKE_libblock_free_us(G.main, me);
179
180 }
181
182 void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb)
183 {
184         std::string geom_id = get_geometry_id(ob, false) + "_morph_" + translate_id(kb->name);
185         std::vector<Normal> nor;
186         std::vector<BCPolygonNormalsIndices> norind;
187
188         if (exportedGeometry.find(geom_id) != exportedGeometry.end())
189         {
190                 return;
191         }
192
193         std::string geom_name = kb->name;
194
195         exportedGeometry.insert(geom_id);
196
197         bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL);
198
199         create_normals(nor, norind, me);
200
201         // openMesh(geoId, geoName, meshId)
202         openMesh(geom_id, geom_name);
203
204         // writes <source> for vertex coords
205         createVertsSource(geom_id, me);
206
207         // writes <source> for normal coords
208         createNormalsSource(geom_id, me, nor);
209
210         bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
211
212         // writes <source> for uv coords if mesh has uv coords
213         if (has_uvs) {
214                 createTexcoordsSource(geom_id, me);
215         }
216
217         if (has_color) {
218                 createVertexColorSource(geom_id, me);
219         }
220
221         // <vertices>
222
223         COLLADASW::Vertices verts(mSW);
224         verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
225         COLLADASW::InputList &input_list = verts.getInputList();
226         COLLADASW::Input input(COLLADASW::InputSemantic::POSITION, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
227         input_list.push_back(input);
228         verts.add();
229
230         //createLooseEdgeList(ob, me, geom_id, norind);
231
232         // XXX slow
233         if (ob->totcol && this->export_settings->export_texture_type == BC_TEXTURE_TYPE_MAT) {
234                 for (int a = 0; a < ob->totcol; a++) {
235                         createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
236                 }
237         }
238         else {
239                 bool all_uv_layers = !this->export_settings->active_uv_only;
240                 std::set<Image *> uv_images = bc_getUVImages(ob, all_uv_layers);
241                 createPolylists(uv_images, has_uvs, has_color, ob, me, geom_id, norind);
242         }
243
244         closeMesh();
245
246         if (me->flag & ME_TWOSIDED) {
247                 mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>");
248         }
249
250         closeGeometry();
251 }
252
253 void GeometryExporter::createLooseEdgeList(Object *ob,
254                                            Mesh   *me,
255                                            std::string& geom_id)
256 {
257
258         MEdge *medges = me->medge;
259         int totedges  = me->totedge;
260         int edges_in_linelist = 0;
261         std::vector<unsigned int> edge_list;
262         int index;
263
264         // Find all loose edges in Mesh
265         // and save vertex indices in edge_list
266         for (index = 0; index < totedges; index++)
267         {
268                 MEdge *edge = &medges[index];
269
270                 if (edge->flag & ME_LOOSEEDGE)
271                 {
272                         edges_in_linelist += 1;
273                         edge_list.push_back(edge->v1);
274                         edge_list.push_back(edge->v2);
275                 }
276         }
277
278         if (edges_in_linelist > 0)
279         {
280                 // Create the list of loose edges
281                 COLLADASW::Lines lines(mSW);
282
283                 lines.setCount(edges_in_linelist);
284
285
286                 COLLADASW::InputList &til = lines.getInputList();
287
288                 // creates <input> in <lines> for vertices
289                 COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
290                 til.push_back(input1);
291
292                 lines.prepareToAppendValues();
293
294                 for (index = 0; index < edges_in_linelist; index++)
295                 {
296                         lines.appendValues(edge_list[2 * index + 1]);
297                         lines.appendValues(edge_list[2 * index]);
298                 }
299                 lines.finish();
300         }
301
302 }
303
304 std::string GeometryExporter::makeVertexColorSourceId(std::string& geom_id, char *layer_name)
305 {
306         std::string result = getIdBySemantics(geom_id, COLLADASW::InputSemantic::COLOR) + "-" + layer_name;
307         return result;
308 }
309
310 static void prepareToAppendValues(bool is_triangulated, COLLADASW::PrimitivesBase *facelist, std::vector<unsigned long> &vcount_list)
311 {
312         // performs the actual writing
313         if (is_triangulated) {
314                 ((COLLADASW::Triangles *)facelist)->prepareToAppendValues();
315         }
316         else {
317                 // sets <vcount>
318                 facelist->setVCountList(vcount_list);
319                 ((COLLADASW::Polylist *)facelist)-> prepareToAppendValues();
320         }
321 }
322
323 static void finishList(bool is_triangulated, COLLADASW::PrimitivesBase *facelist)
324 {
325         if (is_triangulated) {
326                 ((COLLADASW::Triangles *)facelist)->finish();
327         }
328         else {
329                 ((COLLADASW::Polylist *)facelist)->finish();
330         }
331 }
332
333 COLLADASW::PrimitivesBase *getFacelist(bool is_triangulated, COLLADASW::StreamWriter *mSW)
334 {
335         COLLADASW::PrimitivesBase *facelist;
336
337         if (is_triangulated)
338         {
339                 facelist = new COLLADASW::Triangles(mSW);
340         }
341         else {
342                 facelist = new COLLADASW::Polylist(mSW);
343         }
344         return facelist;
345 }
346
347 // Export meshes with Materials
348 void GeometryExporter::createPolylist(short material_index,
349                                       bool has_uvs,
350                                       bool has_color,
351                                       Object *ob,
352                                       Mesh *me,
353                                       std::string& geom_id,
354                                       std::vector<BCPolygonNormalsIndices>& norind)
355 {
356
357         MPoly *mpolys = me->mpoly;
358         MLoop *mloops = me->mloop;
359         int totpolys  = me->totpoly;
360
361         // <vcount>
362         int i;
363         int faces_in_polylist = 0;
364         std::vector<unsigned long> vcount_list;
365         bool is_triangulated = true;
366         // count faces with this material
367         for (i = 0; i < totpolys; i++) {
368                 MPoly *p = &mpolys[i];
369
370                 if (p->mat_nr == material_index) {
371                         faces_in_polylist++;
372                         vcount_list.push_back(p->totloop);
373                         if (p->totloop != 3) {
374                                 is_triangulated = false;
375                         }
376                 }
377         }
378
379         // no faces using this material
380         if (faces_in_polylist == 0) {
381                 fprintf(stderr, "%s: material with index %d is not used.\n", id_name(ob).c_str(), material_index);
382                 return;
383         }
384
385         Material *ma = ob->totcol ? give_current_material(ob, material_index + 1) : NULL;
386         COLLADASW::PrimitivesBase *facelist = getFacelist(is_triangulated, mSW);
387
388
389         // sets count attribute in <polylist>
390         facelist->setCount(faces_in_polylist);
391
392         // sets material name
393         if (ma) {
394                 std::string material_id = get_material_id(ma);
395                 std::ostringstream ostr;
396                 ostr << translate_id(material_id);
397                 facelist->setMaterial(ostr.str());
398         }
399
400         COLLADASW::InputList &til = facelist->getInputList();
401
402         // creates <input> in <polylist> for vertices
403         COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
404
405         // creates <input> in <polylist> for normals
406         COLLADASW::Input input2(COLLADASW::InputSemantic::NORMAL, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL), 1);
407
408         til.push_back(input1);
409         til.push_back(input2);
410
411         // if mesh has uv coords writes <input> for TEXCOORD
412         int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
413         int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE)-1;
414         for (i = 0; i < num_layers; i++) {
415                 if (!this->export_settings->active_uv_only || i == active_uv_index) {
416
417                         std::string uv_name(bc_get_uvlayer_name(me, i));
418                         std::string effective_id = geom_id; // (uv_name == "") ? geom_id : uv_name;
419                         std::string layer_id = makeTexcoordSourceId(
420                                 effective_id,
421                                 i, this->export_settings->active_uv_only);
422
423                         /* Note: the third parameter denotes the offset of TEXCOORD in polylist elements
424                            For now this is always 2 (This may change sometime/maybe)
425                         */
426                         COLLADASW::Input input3(COLLADASW::InputSemantic::TEXCOORD,
427                                 makeUrl(layer_id),
428                                 2, // this is only until we have optimized UV sets
429                                 (this->export_settings->active_uv_only) ? 0 : i  // only_active_uv exported -> we have only one set
430                                 );
431                         til.push_back(input3);
432                 }
433         }
434
435         int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
436         if (totlayer_mcol > 0) {
437                 int map_index = 0;
438
439                 for (int a = 0; a < totlayer_mcol; a++) {
440                         char *layer_name = bc_CustomData_get_layer_name(&me->ldata, CD_MLOOPCOL, a);
441                         COLLADASW::Input input4(COLLADASW::InputSemantic::COLOR,
442                                                 makeUrl(makeVertexColorSourceId(geom_id, layer_name)),
443                                                 (has_uvs) ? 3 : 2,  // all color layers have same index order
444                                                 map_index           // set number equals color map index
445                                                 );
446                         til.push_back(input4);
447                         map_index++;
448                 }
449         }
450
451
452         // performs the actual writing
453         prepareToAppendValues(is_triangulated, facelist, vcount_list);
454
455         // <p>
456         int texindex = 0;
457         for (i = 0; i < totpolys; i++) {
458                 MPoly *p = &mpolys[i];
459                 int loop_count = p->totloop;
460
461                 if (p->mat_nr == material_index) {
462                         MLoop *l = &mloops[p->loopstart];
463                         BCPolygonNormalsIndices normal_indices = norind[i];
464
465                         for (int j = 0; j < loop_count; j++) {
466                                 facelist->appendValues(l[j].v);
467                                 facelist->appendValues(normal_indices[j]);
468                                 if (has_uvs)
469                                         facelist->appendValues(texindex + j);
470
471                                 if (has_color)
472                                         facelist->appendValues(texindex + j);
473                         }
474                 }
475
476                 texindex += loop_count;
477         }
478
479         finishList(is_triangulated, facelist);
480         delete facelist;
481 }
482
483 void GeometryExporter::createPolylists(std::set<Image *> uv_images,
484         bool has_uvs,
485         bool has_color,
486         Object *ob,
487         Mesh *me,
488         std::string& geom_id,
489         std::vector<BCPolygonNormalsIndices>& norind)
490 {
491         std::set<Image *>::iterator uv_images_iter;
492         for (uv_images_iter = uv_images.begin();
493              uv_images_iter != uv_images.end();
494              uv_images_iter++)
495         {
496
497                 Image *ima = *uv_images_iter;
498                 std::string imageid(id_name(ima));
499                 createPolylist(imageid, has_uvs,
500                         has_color,
501                         ob,
502                         me,
503                         geom_id,
504                         norind);
505         }
506
507         /* We msut add an additional collector for the case when
508          * some parts of the object are not textured at all.
509          * The next call creates a polylist for all untextured polygons
510          */
511
512         createPolylist("", has_uvs,
513                 has_color,
514                 ob,
515                 me,
516                 geom_id,
517                 norind);
518
519 }
520
521 /* ===========================================================================
522  * Export Meshes with UV Textures (export as materials, see also in
523  * effectExporter and MaterialExporter)
524  *
525  * If imageid is the empty string, then collect only untextured polygons
526  * =========================================================================== */
527 void GeometryExporter::createPolylist(std::string imageid,
528         bool has_uvs,
529         bool has_color,
530         Object *ob,
531         Mesh *me,
532         std::string& geom_id,
533         std::vector<BCPolygonNormalsIndices>& norind)
534 {
535
536         MPoly *mpolys = me->mpoly;
537         MLoop *mloops = me->mloop;
538         MTexPoly *mtpolys = me->mtpoly;
539
540         int totpolys = me->totpoly;
541
542         // <vcount>
543         int i;
544         int faces_in_polylist = 0;
545         std::vector<unsigned long> vcount_list;
546         bool is_triangulated = true;
547         // count faces with this material
548         for (i = 0; i < totpolys; i++) {
549                 MTexPoly *tp = &mtpolys[i];
550                 MPoly *p = &mpolys[i];
551
552                 std::string tpageid = (mtpolys && tp->tpage) ? id_name(tp->tpage) : "";
553                 if (tpageid == imageid) {
554                         faces_in_polylist++;
555                         vcount_list.push_back(p->totloop);
556                         if (p->totloop != 3) {
557                                 is_triangulated = false;
558                         }
559                 }
560         }
561
562         // no faces using this imageid
563         if (faces_in_polylist == 0) {
564                 if (imageid != "")
565                         fprintf(stderr, "%s: Image %s is not used.\n", id_name(ob).c_str(), imageid.c_str());
566                 return;
567         }
568
569         COLLADASW::PrimitivesBase *facelist = getFacelist(is_triangulated, mSW);
570
571         // sets count attribute in <polylist>
572         facelist->setCount(faces_in_polylist);
573
574         if (imageid != "") {
575                 // sets material name
576                 std::string material_id = get_material_id_from_id(imageid);
577                 std::ostringstream ostr;
578                 ostr << translate_id(material_id);
579                 facelist->setMaterial(ostr.str());
580         }
581         COLLADASW::InputList &til = facelist->getInputList();
582
583         // creates <input> in <polylist> for vertices
584         COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
585
586         // creates <input> in <polylist> for normals
587         COLLADASW::Input input2(COLLADASW::InputSemantic::NORMAL, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL), 1);
588
589         til.push_back(input1);
590         til.push_back(input2);
591
592         // if mesh has uv coords writes <input> for TEXCOORD
593         int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
594         int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE) - 1;
595         for (i = 0; i < num_layers; i++) {
596                 if (!this->export_settings->active_uv_only || i == active_uv_index) {
597
598                         std::string uv_name(bc_get_uvlayer_name(me, i));
599                         std::string effective_id = geom_id; // (uv_name == "") ? geom_id : uv_name;
600                         std::string layer_id = makeTexcoordSourceId(
601                                 effective_id,
602                                 i, this->export_settings->active_uv_only);
603
604                         /* Note: the third parameter denotes the offset of TEXCOORD in polylist elements
605                         For now this is always 2 (This may change sometime/maybe)
606                         */
607                         COLLADASW::Input input3(COLLADASW::InputSemantic::TEXCOORD,
608                                 makeUrl(layer_id),
609                                 2, // this is only until we have optimized UV sets
610                                 (this->export_settings->active_uv_only) ? 0 : i  // only_active_uv exported -> we have only one set
611                                 );
612                         til.push_back(input3);
613                 }
614         }
615
616         int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
617         if (totlayer_mcol > 0) {
618                 int map_index = 0;
619
620                 for (int a = 0; a < totlayer_mcol; a++) {
621                         char *layer_name = bc_CustomData_get_layer_name(&me->ldata, CD_MLOOPCOL, a);
622                         COLLADASW::Input input4(COLLADASW::InputSemantic::COLOR,
623                                 makeUrl(makeVertexColorSourceId(geom_id, layer_name)),
624                                 (has_uvs) ? 3 : 2,  // all color layers have same index order
625                                 map_index           // set number equals color map index
626                                 );
627                         til.push_back(input4);
628                         map_index++;
629                 }
630         }
631
632         // performs the actual writing
633         prepareToAppendValues(is_triangulated, facelist, vcount_list);
634
635         // <p>
636         int texindex = 0;
637         for (i = 0; i < totpolys; i++) {
638                 MTexPoly *tp = &mtpolys[i];
639                 MPoly *p = &mpolys[i];
640                 int loop_count = p->totloop;
641                 std::string tpageid = (mtpolys && tp->tpage) ? id_name(tp->tpage) : "";
642                 if (tpageid == imageid) {
643                         MLoop *l = &mloops[p->loopstart];
644                         BCPolygonNormalsIndices normal_indices = norind[i];
645
646                         for (int j = 0; j < loop_count; j++) {
647                                 facelist->appendValues(l[j].v);
648                                 facelist->appendValues(normal_indices[j]);
649                                 if (has_uvs)
650                                         facelist->appendValues(texindex + j);
651
652                                 if (has_color)
653                                         facelist->appendValues(texindex + j);
654                         }
655                 }
656
657                 texindex += loop_count;
658         }
659
660         finishList(is_triangulated, facelist);
661         delete facelist;
662 }
663
664 // creates <source> for positions
665 void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me)
666 {
667 #if 0
668         int totverts = dm->getNumVerts(dm);
669         MVert *verts = dm->getVertArray(dm);
670 #endif
671         int totverts = me->totvert;
672         MVert *verts = me->mvert;
673
674         COLLADASW::FloatSourceF source(mSW);
675         source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
676         source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION) +
677                           ARRAY_ID_SUFFIX);
678         source.setAccessorCount(totverts);
679         source.setAccessorStride(3);
680
681         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
682         param.push_back("X");
683         param.push_back("Y");
684         param.push_back("Z");
685         /* main function, it creates <source id = "">, <float_array id = ""
686          * count = ""> */
687         source.prepareToAppendValues();
688         //appends data to <float_array>
689         int i = 0;
690         for (i = 0; i < totverts; i++) {
691                 source.appendValues(verts[i].co[0], verts[i].co[1], verts[i].co[2]);
692         }
693
694         source.finish();
695
696 }
697
698
699 void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me)
700 {
701         /* Find number of vertex color layers */
702         int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
703         if (totlayer_mcol == 0)
704                 return;
705
706         int map_index = 0;
707         for (int a = 0; a < totlayer_mcol; a++) {
708
709                 map_index++;
710                 MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(&me->ldata, CD_MLOOPCOL, a);
711
712                 COLLADASW::FloatSourceF source(mSW);
713
714                 char *layer_name = bc_CustomData_get_layer_name(&me->ldata, CD_MLOOPCOL, a);
715                 std::string layer_id = makeVertexColorSourceId(geom_id, layer_name);
716                 source.setId(layer_id);
717
718                 source.setNodeName(layer_name);
719
720                 source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
721                 source.setAccessorCount(me->totloop);
722                 source.setAccessorStride(4);
723
724                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
725                 param.push_back("R");
726                 param.push_back("G");
727                 param.push_back("B");
728                 param.push_back("A");
729
730                 source.prepareToAppendValues();
731
732                 MPoly *mpoly;
733                 int i;
734                 for (i = 0, mpoly = me->mpoly; i < me->totpoly; i++, mpoly++) {
735                         MLoopCol *mlc = mloopcol + mpoly->loopstart;
736                         for (int j = 0; j < mpoly->totloop; j++, mlc++) {
737                                 source.appendValues(
738                                                 mlc->r / 255.0f,
739                                                 mlc->g / 255.0f,
740                                                 mlc->b / 255.0f,
741                                                 mlc->a / 255.0f
742                                 );
743                         }
744                 }
745
746                 source.finish();
747         }
748 }
749
750
751 std::string GeometryExporter::makeTexcoordSourceId(std::string& geom_id, int layer_index, bool is_single_layer)
752 {
753         char suffix[20];
754         if (is_single_layer) {
755                 suffix[0] = '\0';
756         }
757         else {
758                 sprintf(suffix, "-%d", layer_index);
759         }
760         return getIdBySemantics(geom_id, COLLADASW::InputSemantic::TEXCOORD) + suffix;
761 }
762
763 //creates <source> for texcoords
764 void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
765 {
766
767         int totpoly   = me->totpoly;
768         int totuv     = me->totloop;
769         MPoly *mpolys = me->mpoly;
770
771         int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
772
773         // write <source> for each layer
774         // each <source> will get id like meshName + "map-channel-1"
775         int active_uv_index = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV);
776         for (int a = 0; a < num_layers; a++) {
777                 int layer_index = CustomData_get_layer_index_n(&me->ldata, CD_MLOOPUV, a);
778                 if (!this->export_settings->active_uv_only || layer_index == active_uv_index) {
779                         MLoopUV *mloops = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, a);
780
781                         COLLADASW::FloatSourceF source(mSW);
782                         std::string active_uv_name(bc_get_active_uvlayer_name(me));
783                         std::string effective_id = geom_id; // (active_uv_name == "") ? geom_id : active_uv_name;
784                         std::string layer_id = makeTexcoordSourceId(
785                                 effective_id,
786                                 a,
787                                 this->export_settings->active_uv_only );
788
789                         source.setId(layer_id);
790                         source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
791
792                         source.setAccessorCount(totuv);
793                         source.setAccessorStride(2);
794                         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
795                         param.push_back("S");
796                         param.push_back("T");
797
798                         source.prepareToAppendValues();
799
800                         for (int index = 0; index < totpoly; index++) {
801                                 MPoly   *mpoly = mpolys+index;
802                                 MLoopUV *mloop = mloops+mpoly->loopstart;
803                                 for (int j = 0; j < mpoly->totloop; j++) {
804                                         source.appendValues(mloop[j].uv[0],
805                                                                                 mloop[j].uv[1]);
806                                 }
807                         }
808
809                         source.finish();
810                 }
811         }
812 }
813
814 bool operator<(const Normal &a, const Normal &b)
815 {
816         /* only needed to sort normal vectors and find() them later in a map.*/
817         return a.x < b.x || (a.x == b.x && (a.y < b.y || (a.y == b.y && a.z < b.z)));
818 }
819
820 //creates <source> for normals
821 void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal>& nor)
822 {
823 #if 0
824         int totverts = dm->getNumVerts(dm);
825         MVert *verts = dm->getVertArray(dm);
826 #endif
827
828         COLLADASW::FloatSourceF source(mSW);
829         source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL));
830         source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL) +
831                           ARRAY_ID_SUFFIX);
832         source.setAccessorCount((unsigned long)nor.size());
833         source.setAccessorStride(3);
834         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
835         param.push_back("X");
836         param.push_back("Y");
837         param.push_back("Z");
838
839         source.prepareToAppendValues();
840
841         std::vector<Normal>::iterator it;
842         for (it = nor.begin(); it != nor.end(); it++) {
843                 Normal& n = *it;
844                 source.appendValues(n.x, n.y, n.z);
845         }
846
847         source.finish();
848 }
849
850 void GeometryExporter::create_normals(std::vector<Normal> &normals, std::vector<BCPolygonNormalsIndices> &polygons_normals, Mesh *me)
851 {
852         std::map<Normal, unsigned int> shared_normal_indices;
853         int last_normal_index = -1;
854
855         MVert *verts  = me->mvert;
856         MLoop *mloops = me->mloop;
857         float(*lnors)[3] = NULL;
858         bool use_custom_normals = false;
859
860         BKE_mesh_calc_normals_split(me);
861         if (CustomData_has_layer(&me->ldata, CD_NORMAL)) {
862                 lnors = (float(*)[3])CustomData_get_layer(&me->ldata, CD_NORMAL);
863                 use_custom_normals = true;
864         }
865
866         for (int poly_index = 0; poly_index < me->totpoly; poly_index++) {
867                 MPoly *mpoly  = &me->mpoly[poly_index];
868                 bool use_vertex_normals = use_custom_normals || mpoly->flag & ME_SMOOTH;
869
870                 if (!use_vertex_normals) {
871                         // For flat faces use face normal as vertex normal:
872
873                         float vector[3];
874                         BKE_mesh_calc_poly_normal(mpoly, mloops+mpoly->loopstart, verts, vector);
875
876                         Normal n = { vector[0], vector[1], vector[2] };
877                         normals.push_back(n);
878                         last_normal_index++;
879                 }
880
881                 BCPolygonNormalsIndices poly_indices;
882                 for (int loop_index = 0; loop_index < mpoly->totloop; loop_index++) {
883                         unsigned int loop_idx = mpoly->loopstart + loop_index;
884                         if (use_vertex_normals) {
885                                 float normalized[3];
886
887                                 if (use_custom_normals) {
888                                         normalize_v3_v3(normalized, lnors[loop_idx]);
889                                 }
890                                 else {
891                                         normal_short_to_float_v3(normalized, verts[mloops[loop_index].v].no);
892                                         normalize_v3(normalized);
893                                 }
894                                 Normal n = { normalized[0], normalized[1], normalized[2] };
895
896                                 if (shared_normal_indices.find(n) != shared_normal_indices.end()) {
897                                         poly_indices.add_index(shared_normal_indices[n]);
898                                 }
899                                 else {
900                                         last_normal_index++;
901                                         poly_indices.add_index(last_normal_index);
902                                         shared_normal_indices[n] = last_normal_index;
903                                         normals.push_back(n);
904                                 }
905                         }
906                         else {
907                                 poly_indices.add_index(last_normal_index);
908                         }
909                 }
910
911                 polygons_normals.push_back(poly_indices);
912         }
913 }
914
915 std::string GeometryExporter::getIdBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix)
916 {
917         return geom_id + getSuffixBySemantic(type) + other_suffix;
918 }
919
920
921 COLLADASW::URI GeometryExporter::getUrlBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix)
922 {
923
924         std::string id(getIdBySemantics(geom_id, type, other_suffix));
925         return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
926
927 }
928
929 COLLADASW::URI GeometryExporter::makeUrl(std::string id)
930 {
931         return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
932 }
933
934