style cleanup
[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 // TODO: optimize UV sets by making indexed list with duplicates removed
56 GeometryExporter::GeometryExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryGeometries(sw), export_settings(export_settings)
57 {
58 }
59
60 void GeometryExporter::exportGeom(Scene *sce)
61 {
62         openLibrary();
63
64         mScene = sce;
65         GeometryFunctor gf;
66         gf.forEachMeshObjectInExportSet<GeometryExporter>(sce, *this, this->export_settings->export_set);
67
68         closeLibrary();
69 }
70
71 void GeometryExporter::operator()(Object *ob)
72
73         // XXX don't use DerivedMesh, Mesh instead?
74 #if 0           
75         DerivedMesh *dm = mesh_get_derived_final(mScene, ob, CD_MASK_BAREMESH);
76 #endif
77
78         bool use_instantiation = this->export_settings->use_object_instantiation;
79         Mesh *me = bc_get_mesh_copy( mScene, 
80                                         ob,
81                                         this->export_settings->export_mesh_type,
82                                         this->export_settings->apply_modifiers,
83                                         this->export_settings->triangulate);
84
85         std::string geom_id = get_geometry_id(ob, use_instantiation);
86         std::vector<Normal> nor;
87         std::vector<BCPolygonNormalsIndices> norind;
88
89         // Skip if linked geometry was already exported from another reference
90         if (use_instantiation && 
91             exportedGeometry.find(geom_id) != exportedGeometry.end())
92         {
93                 return;
94         }
95
96         std::string geom_name = (use_instantiation) ? id_name(ob->data) : id_name(ob);
97
98         exportedGeometry.insert(geom_id);
99
100         bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL);
101
102         create_normals(nor, norind, me);
103
104         // openMesh(geoId, geoName, meshId)
105         openMesh(geom_id, geom_name);
106         
107         // writes <source> for vertex coords
108         createVertsSource(geom_id, me);
109         
110         // writes <source> for normal coords
111         createNormalsSource(geom_id, me, nor);
112
113         bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
114         
115         // writes <source> for uv coords if mesh has uv coords
116         if (has_uvs) {
117                 createTexcoordsSource(geom_id, me);
118         }
119
120         if (has_color) {
121                 createVertexColorSource(geom_id, me);
122         }
123         // <vertices>
124
125         COLLADASW::Vertices verts(mSW);
126         verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
127         COLLADASW::InputList &input_list = verts.getInputList();
128         COLLADASW::Input input(COLLADASW::InputSemantic::POSITION, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
129         input_list.push_back(input);
130         verts.add();
131
132         createLooseEdgeList(ob, me, geom_id);
133
134         // Only create Polylists if number of faces > 0
135         if (me->totface > 0) {
136                 // XXX slow
137                 if (ob->totcol) {
138                         for (int a = 0; a < ob->totcol; a++) {
139                                 createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
140                         }
141                 }
142                 else {
143                         createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind);
144                 }
145         }
146         
147         closeMesh();
148         
149         if (me->flag & ME_TWOSIDED) {
150                 mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>");
151         }
152
153         closeGeometry();
154
155         if (this->export_settings->include_shapekeys) {
156                 Key * key = BKE_key_from_object(ob);
157                 if (key) {
158                         KeyBlock * kb = (KeyBlock *)key->block.first;
159                         //skip the basis
160                         kb = kb->next;
161                         for (; kb; kb = kb->next) {
162                                 BKE_key_convert_to_mesh(kb, me);
163                                 export_key_mesh(ob, me, kb);
164                         }
165                 }
166         }
167
168         BKE_libblock_free_us(&(G.main->mesh), me);
169
170 }
171
172 void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb)
173 {
174         std::string geom_id = get_geometry_id(ob, false) + "_morph_" + translate_id(kb->name);
175         std::vector<Normal> nor;
176         std::vector<BCPolygonNormalsIndices> norind;
177         
178         if (exportedGeometry.find(geom_id) != exportedGeometry.end())
179         {
180                 return;
181         }
182
183         std::string geom_name = kb->name;
184
185         exportedGeometry.insert(geom_id);
186
187         bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL);
188
189         create_normals(nor, norind, me);
190
191         // openMesh(geoId, geoName, meshId)
192         openMesh(geom_id, geom_name);
193         
194         // writes <source> for vertex coords
195         createVertsSource(geom_id, me);
196         
197         // writes <source> for normal coords
198         createNormalsSource(geom_id, me, nor);
199
200         bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
201         
202         // writes <source> for uv coords if mesh has uv coords
203         if (has_uvs) {
204                 createTexcoordsSource(geom_id, me);
205         }
206
207         if (has_color) {
208                 createVertexColorSource(geom_id, me);
209         }
210
211         // <vertices>
212
213         COLLADASW::Vertices verts(mSW);
214         verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
215         COLLADASW::InputList &input_list = verts.getInputList();
216         COLLADASW::Input input(COLLADASW::InputSemantic::POSITION, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
217         input_list.push_back(input);
218         verts.add();
219
220         //createLooseEdgeList(ob, me, geom_id, norind);
221
222         // XXX slow             
223         if (ob->totcol) {
224                 for (int a = 0; a < ob->totcol; a++) {
225                         createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
226                 }
227         }
228         else {
229                 createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind);
230         }
231         
232         closeMesh();
233         
234         if (me->flag & ME_TWOSIDED) {
235                 mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>");
236         }
237
238         closeGeometry();
239 }
240
241 void GeometryExporter::createLooseEdgeList(Object *ob,
242                                            Mesh   *me,
243                                            std::string& geom_id)
244 {
245
246         MEdge *medges = me->medge;
247         int totedges  = me->totedge;
248         int edges_in_linelist = 0;
249         std::vector<unsigned int> edge_list;
250         int index;
251
252         // Find all loose edges in Mesh 
253         // and save vertex indices in edge_list
254         for (index = 0; index < totedges; index++) 
255         {
256                 MEdge *edge = &medges[index];
257
258                 if (edge->flag & ME_LOOSEEDGE)
259                 {
260                         edges_in_linelist += 1;
261                         edge_list.push_back(edge->v1);
262                         edge_list.push_back(edge->v2);
263                 }
264         }
265
266         if (edges_in_linelist > 0)
267         {
268                 // Create the list of loose edges
269                 COLLADASW::Lines lines(mSW);
270
271                 lines.setCount(edges_in_linelist);
272
273
274                 COLLADASW::InputList &til = lines.getInputList();
275                         
276                 // creates <input> in <lines> for vertices 
277                 COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
278                 til.push_back(input1);
279
280                 lines.prepareToAppendValues();
281
282                 for (index = 0; index < edges_in_linelist; index++) 
283                 {
284                         lines.appendValues(edge_list[2 * index + 1]);
285                         lines.appendValues(edge_list[2 * index]);
286                 }
287                 lines.finish();
288         }
289
290 }
291
292 // powerful because it handles both cases when there is material and when there's not
293 void GeometryExporter::createPolylist(short material_index,
294                                       bool has_uvs,
295                                       bool has_color,
296                                       Object *ob,
297                                       Mesh *me,
298                                       std::string& geom_id,
299                                       std::vector<BCPolygonNormalsIndices>& norind)
300 {
301
302         MPoly *mpolys = me->mpoly;
303         MLoop *mloops = me->mloop;
304         int totpolys  = me->totpoly;
305
306         // <vcount>
307         int i;
308         int faces_in_polylist = 0;
309         std::vector<unsigned long> vcount_list;
310
311         // count faces with this material
312         for (i = 0; i < totpolys; i++) {
313                 MPoly *p = &mpolys[i];
314                 
315                 if (p->mat_nr == material_index) {
316                         faces_in_polylist++;
317                         vcount_list.push_back(p->totloop);
318                 }
319         }
320
321         // no faces using this material
322         if (faces_in_polylist == 0) {
323                 fprintf(stderr, "%s: material with index %d is not used.\n", id_name(ob).c_str(), material_index);
324                 return;
325         }
326                 
327         Material *ma = ob->totcol ? give_current_material(ob, material_index + 1) : NULL;
328         COLLADASW::Polylist polylist(mSW);
329                 
330         // sets count attribute in <polylist>
331         polylist.setCount(faces_in_polylist);
332                 
333         // sets material name
334         if (ma) {
335                 std::string material_id = get_material_id(ma);
336                 std::ostringstream ostr;
337                 ostr << translate_id(material_id);
338                 polylist.setMaterial(ostr.str());
339         }
340                         
341         COLLADASW::InputList &til = polylist.getInputList();
342                 
343         // creates <input> in <polylist> for vertices 
344         COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
345                 
346         // creates <input> in <polylist> for normals
347         COLLADASW::Input input2(COLLADASW::InputSemantic::NORMAL, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL), 1);
348                 
349         til.push_back(input1);
350         til.push_back(input2);
351                 
352         // if mesh has uv coords writes <input> for TEXCOORD
353         int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
354         int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE)-1;
355         for (i = 0; i < num_layers; i++) {
356                 if (!this->export_settings->active_uv_only || i == active_uv_index) {
357
358                         // char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i);
359                         COLLADASW::Input input3(COLLADASW::InputSemantic::TEXCOORD,
360                                                                         makeUrl(makeTexcoordSourceId(geom_id, i)),
361                                                                         2, // offset always 2, this is only until we have optimized UV sets
362                                                                         i  // set number equals UV map index
363                                                                         );
364                         til.push_back(input3);
365                 }
366         }
367
368         if (has_color) {
369                 COLLADASW::Input input4(COLLADASW::InputSemantic::COLOR, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::COLOR), has_uvs ? 3 : 2);
370                 til.push_back(input4);
371         }
372                 
373         // sets <vcount>
374         polylist.setVCountList(vcount_list);
375                 
376         // performs the actual writing
377         polylist.prepareToAppendValues();
378         
379         // <p>
380         int texindex = 0;
381         for (i = 0; i < totpolys; i++) {
382                 MPoly *p = &mpolys[i];
383                 int loop_count = p->totloop;
384
385                 if (p->mat_nr == material_index) {
386                         MLoop *l = &mloops[p->loopstart];
387                         BCPolygonNormalsIndices normal_indices = norind[i];
388
389                         for (int j = 0; j < loop_count; j++) {
390                                 polylist.appendValues(l[j].v);
391                                 polylist.appendValues(normal_indices[j]);
392                                 if (has_uvs)
393                                         polylist.appendValues(texindex + j);
394
395                                 if (has_color)
396                                         polylist.appendValues(texindex + j);
397                         }
398                 }
399
400                 texindex += loop_count;
401         }
402                 
403         polylist.finish();
404 }
405
406
407 // creates <source> for positions
408 void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me)
409 {
410 #if 0
411         int totverts = dm->getNumVerts(dm);
412         MVert *verts = dm->getVertArray(dm);
413 #endif
414         int totverts = me->totvert;
415         MVert *verts = me->mvert;
416         
417         COLLADASW::FloatSourceF source(mSW);
418         source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
419         source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION) +
420                           ARRAY_ID_SUFFIX);
421         source.setAccessorCount(totverts);
422         source.setAccessorStride(3);
423         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
424         param.push_back("X");
425         param.push_back("Y");
426         param.push_back("Z");
427         /* main function, it creates <source id = "">, <float_array id = ""
428          * count = ""> */
429         source.prepareToAppendValues();
430         //appends data to <float_array>
431         int i = 0;
432         for (i = 0; i < totverts; i++) {
433                 source.appendValues(verts[i].co[0], verts[i].co[1], verts[i].co[2]);
434         }
435         
436         source.finish();
437
438 }
439
440 void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me)
441 {
442         if (!CustomData_has_layer(&me->ldata, CD_MLOOPCOL))
443                 return;
444
445
446         COLLADASW::FloatSourceF source(mSW);
447         source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::COLOR));
448         source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::COLOR) + ARRAY_ID_SUFFIX);
449         source.setAccessorCount(me->totloop);
450         source.setAccessorStride(3);
451
452         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
453         param.push_back("R");
454         param.push_back("G");
455         param.push_back("B");
456
457         source.prepareToAppendValues();
458
459         int index = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPCOL);
460         MCol *mcol = (MCol *)me->ldata.layers[index].data;
461
462         MPoly *mpoly;
463         int i;
464         for (i = 0, mpoly = me->mpoly; i < me->totpoly; i++, mpoly++) {
465                 MCol *color = mcol + mpoly->loopstart;
466                 for (int j = 0; j < mpoly->totloop; j++, color++) {
467                         source.appendValues(
468                                         color->b / 255.0f,
469                                         color->g / 255.0f,
470                                         color->r / 255.0f 
471                         );
472                 }
473         }
474         
475         source.finish();
476 }
477
478
479 std::string GeometryExporter::makeTexcoordSourceId(std::string& geom_id, int layer_index)
480 {
481         char suffix[20];
482         sprintf(suffix, "-%d", layer_index);
483         return getIdBySemantics(geom_id, COLLADASW::InputSemantic::TEXCOORD) + suffix;
484 }
485
486 //creates <source> for texcoords
487 void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
488 {
489
490         int totpoly   = me->totpoly;
491         int totuv     = me->totloop;
492         MPoly *mpolys = me->mpoly;
493
494         int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
495
496         // write <source> for each layer
497         // each <source> will get id like meshName + "map-channel-1"
498         int map_index = 0;
499         int active_uv_index = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV);
500         for (int a = 0; a < num_layers; a++) {
501
502                 if (!this->export_settings->active_uv_only || a == active_uv_index) {
503                         MLoopUV *mloops = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, a);
504                         
505                         COLLADASW::FloatSourceF source(mSW);
506                         std::string layer_id = makeTexcoordSourceId(geom_id, map_index++);
507                         source.setId(layer_id);
508                         source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
509                         
510                         source.setAccessorCount(totuv);
511                         source.setAccessorStride(2);
512                         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
513                         param.push_back("S");
514                         param.push_back("T");
515                         
516                         source.prepareToAppendValues();
517                         
518                         for (int index = 0; index < totpoly; index++) {
519                                 MPoly   *mpoly = mpolys+index;
520                                 MLoopUV *mloop = mloops+mpoly->loopstart;
521                                 for (int j = 0; j < mpoly->totloop; j++) {
522                                         source.appendValues(mloop[j].uv[0],
523                                                                                 mloop[j].uv[1]);
524                                 }
525                         }
526                         
527                         source.finish();
528                 }
529         }
530 }
531
532
533 //creates <source> for normals
534 void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal>& nor)
535 {
536 #if 0
537         int totverts = dm->getNumVerts(dm);
538         MVert *verts = dm->getVertArray(dm);
539 #endif
540
541         COLLADASW::FloatSourceF source(mSW);
542         source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL));
543         source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL) +
544                           ARRAY_ID_SUFFIX);
545         source.setAccessorCount((unsigned long)nor.size());
546         source.setAccessorStride(3);
547         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
548         param.push_back("X");
549         param.push_back("Y");
550         param.push_back("Z");
551         
552         source.prepareToAppendValues();
553
554         std::vector<Normal>::iterator it;
555         for (it = nor.begin(); it != nor.end(); it++) {
556                 Normal& n = *it;
557                 source.appendValues(n.x, n.y, n.z);
558         }
559
560         source.finish();
561 }
562
563 void GeometryExporter::create_normals(std::vector<Normal> &normals, std::vector<BCPolygonNormalsIndices> &polygons_normals, Mesh *me)
564 {
565         std::map<unsigned int, unsigned int> shared_normal_indices;
566         int last_normal_index = -1;
567
568         MVert *verts  = me->mvert;
569         MLoop *mloops = me->mloop;
570         for (int poly_index = 0; poly_index < me->totpoly; poly_index++) {
571                 MPoly *mpoly  = &me->mpoly[poly_index];
572
573                 if (!(mpoly->flag & ME_SMOOTH)) {
574                         // For flat faces use face normal as vertex normal:
575
576                         float vector[3];
577                         BKE_mesh_calc_poly_normal(mpoly, mloops, verts, vector);
578
579                         Normal n = { vector[0], vector[1], vector[2] };
580                         normals.push_back(n);
581                         last_normal_index++;
582                 }
583
584
585                 MLoop *mloop = mloops + mpoly->loopstart;
586                 BCPolygonNormalsIndices poly_indices;
587                 for (int loop_index = 0; loop_index < mpoly->totloop; loop_index++) {
588                         unsigned int vertex_index = mloop[loop_index].v;
589                         if (mpoly->flag & ME_SMOOTH) {
590                                 if (shared_normal_indices.find(vertex_index) != shared_normal_indices.end())
591                                         poly_indices.add_index (shared_normal_indices[vertex_index]);
592                                 else {
593
594                                         float vector[3];
595                                         normal_short_to_float_v3(vector, verts[vertex_index].no);
596
597                                         Normal n = { vector[0], vector[1], vector[2] };
598                                         normals.push_back(n);
599                                         last_normal_index++;
600
601                                         poly_indices.add_index(last_normal_index);
602                                         shared_normal_indices[vertex_index] = last_normal_index;
603                                 }
604                         }
605                         else {
606                                 poly_indices.add_index(last_normal_index);
607                         }
608                 }
609
610                 polygons_normals.push_back(poly_indices);
611         }
612 }
613
614 std::string GeometryExporter::getIdBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix)
615 {
616         return geom_id + getSuffixBySemantic(type) + other_suffix;
617 }
618
619
620 COLLADASW::URI GeometryExporter::getUrlBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix)
621 {
622         
623         std::string id(getIdBySemantics(geom_id, type, other_suffix));
624         return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
625         
626 }
627
628 COLLADASW::URI GeometryExporter::makeUrl(std::string id)
629 {
630         return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
631 }
632
633