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