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