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