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