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