Cleanup: remove redundant doxygen \file argument
[blender.git] / source / blender / collada / GeometryExporter.cpp
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16
17 /** \file \ingroup collada
18  */
19
20
21 #include <sstream>
22
23 #include "COLLADASWPrimitves.h"
24 #include "COLLADASWSource.h"
25 #include "COLLADASWVertices.h"
26 #include "COLLADABUUtils.h"
27
28 #include "GeometryExporter.h"
29
30 #include "DNA_meshdata_types.h"
31
32 extern "C" {
33         #include "BLI_utildefines.h"
34
35         #include "BKE_customdata.h"
36         #include "BKE_global.h"
37         #include "BKE_library.h"
38         #include "BKE_material.h"
39         #include "BKE_mesh.h"
40 }
41
42 #include "collada_internal.h"
43 #include "collada_utils.h"
44
45
46 void GeometryExporter::exportGeom()
47 {
48         Scene *sce = blender_context.get_scene();
49         openLibrary();
50
51         GeometryFunctor gf;
52         gf.forEachMeshObjectInExportSet<GeometryExporter>(sce, *this, this->export_settings->export_set);
53
54         closeLibrary();
55 }
56
57 void GeometryExporter::operator()(Object *ob)
58 {
59         bool use_instantiation = this->export_settings->use_object_instantiation;
60         Mesh *me = bc_get_mesh_copy(
61                                         blender_context,
62                                         ob,
63                                         this->export_settings->export_mesh_type,
64                                         this->export_settings->apply_modifiers,
65                                         this->export_settings->triangulate);
66
67         std::string geom_id = get_geometry_id(ob, use_instantiation);
68         std::vector<Normal> nor;
69         std::vector<BCPolygonNormalsIndices> norind;
70
71         // Skip if linked geometry was already exported from another reference
72         if (use_instantiation &&
73             exportedGeometry.find(geom_id) != exportedGeometry.end())
74         {
75                 return;
76         }
77
78         std::string geom_name = (use_instantiation) ? id_name(ob->data) : id_name(ob);
79         geom_name = encode_xml(geom_name);
80
81         exportedGeometry.insert(geom_id);
82
83         bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL);
84
85         create_normals(nor, norind, me);
86
87         // openMesh(geoId, geoName, meshId)
88         openMesh(geom_id, geom_name);
89
90         // writes <source> for vertex coords
91         createVertsSource(geom_id, me);
92
93         // writes <source> for normal coords
94         createNormalsSource(geom_id, me, nor);
95
96         bool has_uvs = (bool)CustomData_has_layer(&me->ldata, CD_MLOOPUV);
97
98         // writes <source> for uv coords if mesh has uv coords
99         if (has_uvs) {
100                 createTexcoordsSource(geom_id, me);
101         }
102
103         if (has_color) {
104                 createVertexColorSource(geom_id, me);
105         }
106         // <vertices>
107
108         COLLADASW::Vertices verts(mSW);
109         verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
110         COLLADASW::InputList &input_list = verts.getInputList();
111         COLLADASW::Input input(COLLADASW::InputSemantic::POSITION, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
112         input_list.push_back(input);
113         verts.add();
114
115         createLooseEdgeList(ob, me, geom_id);
116
117         // Only create Polylists if number of faces > 0
118         if (me->totface > 0) {
119                 // XXX slow
120                 if (ob->totcol) {
121                         for (int a = 0; a < ob->totcol; a++) {
122                                 createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
123                         }
124                 }
125                 else {
126                         createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind);
127                 }
128         }
129
130         closeMesh();
131
132         if (me->flag & ME_TWOSIDED) {
133                 mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>");
134         }
135
136         closeGeometry();
137
138         if (this->export_settings->include_shapekeys) {
139                 Key *key = BKE_key_from_object(ob);
140                 if (key) {
141                         KeyBlock *kb = (KeyBlock *)key->block.first;
142                         //skip the basis
143                         kb = kb->next;
144                         for (; kb; kb = kb->next) {
145                                 BKE_keyblock_convert_to_mesh(kb, me);
146                                 export_key_mesh(ob, me, kb);
147                         }
148                 }
149         }
150
151         BKE_id_free(NULL, me);
152 }
153
154 void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb)
155 {
156         std::string geom_id = get_geometry_id(ob, false) + "_morph_" + translate_id(kb->name);
157         std::vector<Normal> nor;
158         std::vector<BCPolygonNormalsIndices> norind;
159
160         if (exportedGeometry.find(geom_id) != exportedGeometry.end())
161         {
162                 return;
163         }
164
165         std::string geom_name = kb->name;
166
167         exportedGeometry.insert(geom_id);
168
169         bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL);
170
171         create_normals(nor, norind, me);
172
173         // openMesh(geoId, geoName, meshId)
174         openMesh(geom_id, geom_name);
175
176         // writes <source> for vertex coords
177         createVertsSource(geom_id, me);
178
179         // writes <source> for normal coords
180         createNormalsSource(geom_id, me, nor);
181
182         bool has_uvs = (bool)CustomData_has_layer(&me->ldata, CD_MLOOPUV);
183
184         // writes <source> for uv coords if mesh has uv coords
185         if (has_uvs) {
186                 createTexcoordsSource(geom_id, me);
187         }
188
189         if (has_color) {
190                 createVertexColorSource(geom_id, me);
191         }
192
193         // <vertices>
194
195         COLLADASW::Vertices verts(mSW);
196         verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
197         COLLADASW::InputList &input_list = verts.getInputList();
198         COLLADASW::Input input(COLLADASW::InputSemantic::POSITION, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
199         input_list.push_back(input);
200         verts.add();
201
202         //createLooseEdgeList(ob, me, geom_id, norind);
203
204         // XXX slow
205         if (ob->totcol) {
206                 for (int a = 0; a < ob->totcol; a++) {
207                         createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
208                 }
209         }
210         else {
211                 createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind);
212         }
213
214         closeMesh();
215
216         if (me->flag & ME_TWOSIDED) {
217                 mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>");
218         }
219
220         closeGeometry();
221 }
222
223 void GeometryExporter::createLooseEdgeList(Object *ob,
224                                            Mesh   *me,
225                                            std::string& geom_id)
226 {
227
228         MEdge *medges = me->medge;
229         int totedges  = me->totedge;
230         int edges_in_linelist = 0;
231         std::vector<unsigned int> edge_list;
232         int index;
233
234         // Find all loose edges in Mesh
235         // and save vertex indices in edge_list
236         for (index = 0; index < totedges; index++)
237         {
238                 MEdge *edge = &medges[index];
239
240                 if (edge->flag & ME_LOOSEEDGE)
241                 {
242                         edges_in_linelist += 1;
243                         edge_list.push_back(edge->v1);
244                         edge_list.push_back(edge->v2);
245                 }
246         }
247
248         if (edges_in_linelist > 0)
249         {
250                 // Create the list of loose edges
251                 COLLADASW::Lines lines(mSW);
252
253                 lines.setCount(edges_in_linelist);
254
255
256                 COLLADASW::InputList &til = lines.getInputList();
257
258                 // creates <input> in <lines> for vertices
259                 COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
260                 til.push_back(input1);
261
262                 lines.prepareToAppendValues();
263
264                 for (index = 0; index < edges_in_linelist; index++)
265                 {
266                         lines.appendValues(edge_list[2 * index + 1]);
267                         lines.appendValues(edge_list[2 * index]);
268                 }
269                 lines.finish();
270         }
271
272 }
273
274 std::string GeometryExporter::makeVertexColorSourceId(std::string& geom_id, char *layer_name)
275 {
276         std::string result = getIdBySemantics(geom_id, COLLADASW::InputSemantic::COLOR) + "-" + layer_name;
277         return result;
278 }
279
280 // powerful because it handles both cases when there is material and when there's not
281 void GeometryExporter::createPolylist(short material_index,
282                                       bool has_uvs,
283                                       bool has_color,
284                                       Object *ob,
285                                       Mesh *me,
286                                       std::string& geom_id,
287                                       std::vector<BCPolygonNormalsIndices>& norind)
288 {
289
290         MPoly *mpolys = me->mpoly;
291         MLoop *mloops = me->mloop;
292         int totpolys  = me->totpoly;
293
294         // <vcount>
295         int i;
296         int faces_in_polylist = 0;
297         std::vector<unsigned long> vcount_list;
298
299         // count faces with this material
300         for (i = 0; i < totpolys; i++) {
301                 MPoly *p = &mpolys[i];
302
303                 if (p->mat_nr == material_index) {
304                         faces_in_polylist++;
305                         vcount_list.push_back(p->totloop);
306                 }
307         }
308
309         // no faces using this material
310         if (faces_in_polylist == 0) {
311                 fprintf(stderr, "%s: material with index %d is not used.\n", id_name(ob).c_str(), material_index);
312                 return;
313         }
314
315         Material *ma = ob->totcol ? give_current_material(ob, material_index + 1) : NULL;
316         COLLADASW::Polylist polylist(mSW);
317
318         // sets count attribute in <polylist>
319         polylist.setCount(faces_in_polylist);
320
321         // sets material name
322         if (ma) {
323                 std::string material_id = get_material_id(ma);
324                 std::ostringstream ostr;
325                 ostr << translate_id(material_id);
326                 polylist.setMaterial(ostr.str());
327         }
328
329         COLLADASW::InputList &til = polylist.getInputList();
330
331         // creates <input> in <polylist> for vertices
332         COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
333
334         // creates <input> in <polylist> for normals
335         COLLADASW::Input input2(COLLADASW::InputSemantic::NORMAL, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL), 1);
336
337         til.push_back(input1);
338         til.push_back(input2);
339
340         // if mesh has uv coords writes <input> for TEXCOORD
341         int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
342         int active_uv_index = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV);
343         for (i = 0; i < num_layers; i++) {
344                 int layer_index = CustomData_get_layer_index_n(&me->ldata, CD_MLOOPUV, i);
345                 if (!this->export_settings->active_uv_only || layer_index == active_uv_index) {
346
347                         // char *name = CustomData_get_layer_name(&me->ldata, CD_MLOOPUV, i);
348                         COLLADASW::Input input3(COLLADASW::InputSemantic::TEXCOORD,
349                                                                         makeUrl(makeTexcoordSourceId(geom_id, i, this->export_settings->active_uv_only)),
350                                                                         2, // this is only until we have optimized UV sets
351                                                                         (this->export_settings->active_uv_only) ? 0 : layer_index-1  //set (0,1,2,...)
352                                                                         );
353                         til.push_back(input3);
354                 }
355         }
356
357         int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
358         if (totlayer_mcol > 0) {
359                 int map_index = 0;
360
361                 for (int a = 0; a < totlayer_mcol; a++) {
362                         char *layer_name = bc_CustomData_get_layer_name(&me->ldata, CD_MLOOPCOL, a);
363                         COLLADASW::Input input4(COLLADASW::InputSemantic::COLOR,
364                                                 makeUrl(makeVertexColorSourceId(geom_id, layer_name)),
365                                                 (has_uvs) ? 3 : 2,  // all color layers have same index order
366                                                 map_index           // set number equals color map index
367                                                 );
368                         til.push_back(input4);
369                         map_index++;
370                 }
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 // creates <source> for positions
407 void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me)
408 {
409 #if 0
410         int totverts = dm->getNumVerts(dm);
411         MVert *verts = dm->getVertArray(dm);
412 #endif
413         int totverts = me->totvert;
414         MVert *verts = me->mvert;
415
416         COLLADASW::FloatSourceF source(mSW);
417         source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
418         source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION) +
419                           ARRAY_ID_SUFFIX);
420         source.setAccessorCount(totverts);
421         source.setAccessorStride(3);
422
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
441 void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me)
442 {
443         /* Find number of vertex color layers */
444         int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
445         if (totlayer_mcol == 0)
446                 return;
447
448         int map_index = 0;
449         for (int a = 0; a < totlayer_mcol; a++) {
450
451                 map_index++;
452                 MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(&me->ldata, CD_MLOOPCOL, a);
453
454                 COLLADASW::FloatSourceF source(mSW);
455
456                 char *layer_name = bc_CustomData_get_layer_name(&me->ldata, CD_MLOOPCOL, a);
457                 std::string layer_id = makeVertexColorSourceId(geom_id, layer_name);
458                 source.setId(layer_id);
459
460                 source.setNodeName(layer_name);
461
462                 source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
463                 source.setAccessorCount(me->totloop);
464                 source.setAccessorStride(4);
465
466                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
467                 param.push_back("R");
468                 param.push_back("G");
469                 param.push_back("B");
470                 param.push_back("A");
471
472                 source.prepareToAppendValues();
473
474                 MPoly *mpoly;
475                 int i;
476                 for (i = 0, mpoly = me->mpoly; i < me->totpoly; i++, mpoly++) {
477                         MLoopCol *mlc = mloopcol + mpoly->loopstart;
478                         for (int j = 0; j < mpoly->totloop; j++, mlc++) {
479                                 source.appendValues(
480                                                 mlc->r / 255.0f,
481                                                 mlc->g / 255.0f,
482                                                 mlc->b / 255.0f,
483                                                 mlc->a / 255.0f
484                                 );
485                         }
486                 }
487
488                 source.finish();
489         }
490 }
491
492
493 std::string GeometryExporter::makeTexcoordSourceId(std::string& geom_id, int layer_index, bool is_single_layer)
494 {
495         char suffix[20];
496         if (is_single_layer) {
497                 suffix[0] = '\0';
498         }
499         else {
500                 sprintf(suffix, "-%d", layer_index);
501         }
502         return getIdBySemantics(geom_id, COLLADASW::InputSemantic::TEXCOORD) + suffix;
503 }
504
505 //creates <source> for texcoords
506 void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
507 {
508
509         int totpoly   = me->totpoly;
510         int totuv     = me->totloop;
511         MPoly *mpolys = me->mpoly;
512
513         int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
514
515         // write <source> for each layer
516         // each <source> will get id like meshName + "map-channel-1"
517         int active_uv_index = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV);
518         for (int a = 0; a < num_layers; a++) {
519                 int layer_index = CustomData_get_layer_index_n(&me->ldata, CD_MLOOPUV, a);
520                 if (!this->export_settings->active_uv_only || layer_index == active_uv_index) {
521                         MLoopUV *mloops = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, a);
522
523                         COLLADASW::FloatSourceF source(mSW);
524                         std::string layer_id = makeTexcoordSourceId(geom_id, a, this->export_settings->active_uv_only);
525                         source.setId(layer_id);
526                         source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
527
528                         source.setAccessorCount(totuv);
529                         source.setAccessorStride(2);
530                         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
531                         param.push_back("S");
532                         param.push_back("T");
533
534                         source.prepareToAppendValues();
535
536                         for (int index = 0; index < totpoly; index++) {
537                                 MPoly   *mpoly = mpolys+index;
538                                 MLoopUV *mloop = mloops+mpoly->loopstart;
539                                 for (int j = 0; j < mpoly->totloop; j++) {
540                                         source.appendValues(mloop[j].uv[0],
541                                                                                 mloop[j].uv[1]);
542                                 }
543                         }
544
545                         source.finish();
546                 }
547         }
548 }
549
550 bool operator<(const Normal &a, const Normal &b)
551 {
552         /* only needed to sort normal vectors and find() them later in a map.*/
553         return a.x < b.x || (a.x == b.x && (a.y < b.y || (a.y == b.y && a.z < b.z)));
554 }
555
556 //creates <source> for normals
557 void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal>& nor)
558 {
559 #if 0
560         int totverts = dm->getNumVerts(dm);
561         MVert *verts = dm->getVertArray(dm);
562 #endif
563
564         COLLADASW::FloatSourceF source(mSW);
565         source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL));
566         source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL) +
567                           ARRAY_ID_SUFFIX);
568         source.setAccessorCount((unsigned long)nor.size());
569         source.setAccessorStride(3);
570         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
571         param.push_back("X");
572         param.push_back("Y");
573         param.push_back("Z");
574
575         source.prepareToAppendValues();
576
577         std::vector<Normal>::iterator it;
578         for (it = nor.begin(); it != nor.end(); it++) {
579                 Normal& n = *it;
580                 source.appendValues(n.x, n.y, n.z);
581         }
582
583         source.finish();
584 }
585
586 void GeometryExporter::create_normals(std::vector<Normal> &normals, std::vector<BCPolygonNormalsIndices> &polygons_normals, Mesh *me)
587 {
588         std::map<Normal, unsigned int> shared_normal_indices;
589         int last_normal_index = -1;
590
591         MVert *verts  = me->mvert;
592         MLoop *mloops = me->mloop;
593         float(*lnors)[3] = NULL;
594         bool use_custom_normals = false;
595
596         BKE_mesh_calc_normals_split(me);
597         if (CustomData_has_layer(&me->ldata, CD_NORMAL)) {
598                 lnors = (float(*)[3])CustomData_get_layer(&me->ldata, CD_NORMAL);
599                 use_custom_normals = true;
600         }
601
602         for (int poly_index = 0; poly_index < me->totpoly; poly_index++) {
603                 MPoly *mpoly  = &me->mpoly[poly_index];
604                 bool use_vertex_normals = use_custom_normals || mpoly->flag & ME_SMOOTH;
605
606                 if (!use_vertex_normals) {
607                         // For flat faces use face normal as vertex normal:
608
609                         float vector[3];
610                         BKE_mesh_calc_poly_normal(mpoly, mloops+mpoly->loopstart, verts, vector);
611
612                         Normal n = { vector[0], vector[1], vector[2] };
613                         normals.push_back(n);
614                         last_normal_index++;
615                 }
616
617                 BCPolygonNormalsIndices poly_indices;
618                 for (int loop_index = 0; loop_index < mpoly->totloop; loop_index++) {
619                         unsigned int loop_idx = mpoly->loopstart + loop_index;
620                         if (use_vertex_normals) {
621                                 float normalized[3];
622
623                                 if (use_custom_normals) {
624                                         normalize_v3_v3(normalized, lnors[loop_idx]);
625                                 }
626                                 else {
627                                         normal_short_to_float_v3(normalized, verts[mloops[loop_index].v].no);
628                                         normalize_v3(normalized);
629                                 }
630                                 Normal n = { normalized[0], normalized[1], normalized[2] };
631
632                                 if (shared_normal_indices.find(n) != shared_normal_indices.end()) {
633                                         poly_indices.add_index(shared_normal_indices[n]);
634                                 }
635                                 else {
636                                         last_normal_index++;
637                                         poly_indices.add_index(last_normal_index);
638                                         shared_normal_indices[n] = last_normal_index;
639                                         normals.push_back(n);
640                                 }
641                         }
642                         else {
643                                 poly_indices.add_index(last_normal_index);
644                         }
645                 }
646
647                 polygons_normals.push_back(poly_indices);
648         }
649 }
650
651 std::string GeometryExporter::getIdBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix)
652 {
653         return geom_id + getSuffixBySemantic(type) + other_suffix;
654 }
655
656
657 COLLADASW::URI GeometryExporter::getUrlBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix)
658 {
659
660         std::string id(getIdBySemantics(geom_id, type, other_suffix));
661         return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
662
663 }
664
665 COLLADASW::URI GeometryExporter::makeUrl(std::string id)
666 {
667         return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
668 }