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