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