2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed,
21 * ***** END GPL LICENSE BLOCK *****
24 /** \file blender/collada/GeometryExporter.cpp
31 #include "COLLADASWPrimitves.h"
32 #include "COLLADASWSource.h"
33 #include "COLLADASWVertices.h"
34 #include "COLLADABUUtils.h"
36 #include "GeometryExporter.h"
38 #include "DNA_meshdata_types.h"
41 #include "BLI_utildefines.h"
43 #include "BKE_DerivedMesh.h"
45 #include "BKE_global.h"
46 #include "BKE_library.h"
47 #include "BKE_customdata.h"
48 #include "BKE_material.h"
52 #include "collada_internal.h"
53 #include "collada_utils.h"
55 // TODO: optimize UV sets by making indexed list with duplicates removed
56 GeometryExporter::GeometryExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryGeometries(sw), export_settings(export_settings) {
60 void GeometryExporter::exportGeom(Scene *sce)
66 gf.forEachMeshObjectInExportSet<GeometryExporter>(sce, *this, this->export_settings->export_set);
71 void GeometryExporter::operator()(Object *ob)
73 // XXX don't use DerivedMesh, Mesh instead?
75 DerivedMesh *dm = mesh_get_derived_final(mScene, ob, CD_MASK_BAREMESH);
78 bool use_instantiation = this->export_settings->use_object_instantiation;
80 if (this->export_settings->apply_modifiers) {
81 me = bc_to_mesh_apply_modifiers(mScene, ob, this->export_settings->export_mesh_type);
84 me = (Mesh *)ob->data;
86 BKE_mesh_tessface_ensure(me);
88 std::string geom_id = get_geometry_id(ob, use_instantiation);
89 std::vector<Normal> nor;
90 std::vector<Face> norind;
92 // Skip if linked geometry was already exported from another reference
93 if (use_instantiation &&
94 exportedGeometry.find(geom_id) != exportedGeometry.end())
99 std::string geom_name = (use_instantiation) ? id_name(ob->data) : id_name(ob);
101 exportedGeometry.insert(geom_id);
103 bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL);
105 create_normals(nor, norind, me);
107 // openMesh(geoId, geoName, meshId)
108 openMesh(geom_id, geom_name);
110 // writes <source> for vertex coords
111 createVertsSource(geom_id, me);
113 // writes <source> for normal coords
114 createNormalsSource(geom_id, me, nor);
116 bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
118 // writes <source> for uv coords if mesh has uv coords
120 createTexcoordsSource(geom_id, me);
123 createVertexColorSource(geom_id, me);
127 COLLADASW::Vertices verts(mSW);
128 verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
129 COLLADASW::InputList &input_list = verts.getInputList();
130 COLLADASW::Input input(COLLADASW::InputSemantic::POSITION, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
131 input_list.push_back(input);
134 createLooseEdgeList(ob, me, geom_id, norind);
136 // Only create Polylists if number of faces > 0
137 if (me->totface > 0) {
140 for (int a = 0; a < ob->totcol; a++) {
141 createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
145 createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind);
151 if (me->flag & ME_TWOSIDED) {
152 mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>");
157 if (this->export_settings->apply_modifiers) {
158 BKE_libblock_free_us(&(G.main->mesh), me);
161 if (this->export_settings->include_shapekeys) {
162 Key * key = BKE_key_from_object(ob);
164 KeyBlock * kb = (KeyBlock*)key->block.first;
167 for (; kb; kb = kb->next) {
168 BKE_key_convert_to_mesh(kb, me);
169 export_key_mesh(ob, me, kb);
178 void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb){
179 std::string geom_id = get_geometry_id(ob, false) + "_morph_" + translate_id(kb->name);
180 std::vector<Normal> nor;
181 std::vector<Face> norind;
183 if (exportedGeometry.find(geom_id) != exportedGeometry.end())
188 std::string geom_name = id_name(ob) + "_morph_" + kb->name;
190 exportedGeometry.insert(geom_id);
192 bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL);
194 create_normals(nor, norind, me);
196 // openMesh(geoId, geoName, meshId)
197 openMesh(geom_id, geom_name);
199 // writes <source> for vertex coords
200 createVertsSource(geom_id, me);
202 // writes <source> for normal coords
203 createNormalsSource(geom_id, me, nor);
205 bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
207 // writes <source> for uv coords if mesh has uv coords
209 createTexcoordsSource(geom_id, me);
212 createVertexColorSource(geom_id, me);
216 COLLADASW::Vertices verts(mSW);
217 verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
218 COLLADASW::InputList &input_list = verts.getInputList();
219 COLLADASW::Input input(COLLADASW::InputSemantic::POSITION, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
220 input_list.push_back(input);
223 //createLooseEdgeList(ob, me, geom_id, norind);
227 for (int a = 0; a < ob->totcol; a++) {
228 createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
232 createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind);
237 if (me->flag & ME_TWOSIDED) {
238 mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>");
244 void GeometryExporter::createLooseEdgeList(Object *ob,
246 std::string& geom_id,
247 std::vector<Face>& norind)
250 MEdge *medges = me->medge;
251 int totedges = me->totedge;
252 int edges_in_linelist = 0;
253 std::vector<unsigned int> edge_list;
256 // Find all loose edges in Mesh
257 // and save vertex indices in edge_list
258 for (index = 0; index < totedges; index++)
260 MEdge *edge = &medges[index];
262 if (edge->flag & ME_LOOSEEDGE)
264 edges_in_linelist += 1;
265 edge_list.push_back(edge->v1);
266 edge_list.push_back(edge->v2);
270 if (edges_in_linelist > 0)
272 // Create the list of loose edges
273 COLLADASW::Lines lines(mSW);
275 lines.setCount(edges_in_linelist);
278 COLLADASW::InputList &til = lines.getInputList();
280 // creates <input> in <lines> for vertices
281 COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
282 til.push_back(input1);
284 lines.prepareToAppendValues();
286 for (index = 0; index < edges_in_linelist; index++)
288 lines.appendValues(edge_list[2 * index + 1]);
289 lines.appendValues(edge_list[2 * index]);
296 // powerful because it handles both cases when there is material and when there's not
297 void GeometryExporter::createPolylist(short material_index,
302 std::string& geom_id,
303 std::vector<Face>& norind)
305 MFace *mfaces = me->mface;
306 int totfaces = me->totface;
310 int faces_in_polylist = 0;
311 std::vector<unsigned long> vcount_list;
313 // count faces with this material
314 for (i = 0; i < totfaces; i++) {
315 MFace *f = &mfaces[i];
317 if (f->mat_nr == material_index) {
320 vcount_list.push_back(3);
323 vcount_list.push_back(4);
328 // no faces using this material
329 if (faces_in_polylist == 0) {
330 fprintf(stderr, "%s: material with index %d is not used.\n", id_name(ob).c_str(), material_index);
334 Material *ma = ob->totcol ? give_current_material(ob, material_index + 1) : NULL;
335 COLLADASW::Polylist polylist(mSW);
337 // sets count attribute in <polylist>
338 polylist.setCount(faces_in_polylist);
340 // sets material name
342 std::string material_id = get_material_id(ma);
343 std::ostringstream ostr;
344 ostr << translate_id(material_id);
345 polylist.setMaterial(ostr.str());
348 COLLADASW::InputList &til = polylist.getInputList();
350 // creates <input> in <polylist> for vertices
351 COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
353 // creates <input> in <polylist> for normals
354 COLLADASW::Input input2(COLLADASW::InputSemantic::NORMAL, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL), 1);
356 til.push_back(input1);
357 til.push_back(input2);
359 // if mesh has uv coords writes <input> for TEXCOORD
360 int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
361 int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE)-1;
362 for (i = 0; i < num_layers; i++) {
363 if (!this->export_settings->active_uv_only || i == active_uv_index) {
365 // char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i);
366 COLLADASW::Input input3(COLLADASW::InputSemantic::TEXCOORD,
367 makeUrl(makeTexcoordSourceId(geom_id, i)),
368 2, // offset always 2, this is only until we have optimized UV sets
369 i // set number equals UV map index
371 til.push_back(input3);
376 COLLADASW::Input input4(COLLADASW::InputSemantic::COLOR, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::COLOR), has_uvs ? 3 : 2);
377 til.push_back(input4);
381 polylist.setVCountList(vcount_list);
383 // performs the actual writing
384 polylist.prepareToAppendValues();
390 for (i = 0; i < totfaces; i++) {
391 MFace *f = &mfaces[i];
393 if (f->mat_nr == material_index) {
395 unsigned int *v = &f->v1;
396 unsigned int *n = &norind[i].v1;
397 for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) {
398 polylist.appendValues(v[j]);
399 polylist.appendValues(n[j]);
402 polylist.appendValues(texindex + j);
405 polylist.appendValues(texindex + j);
417 // creates <source> for positions
418 void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me)
421 int totverts = dm->getNumVerts(dm);
422 MVert *verts = dm->getVertArray(dm);
424 int totverts = me->totvert;
425 MVert *verts = me->mvert;
427 COLLADASW::FloatSourceF source(mSW);
428 source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
429 source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION) +
431 source.setAccessorCount(totverts);
432 source.setAccessorStride(3);
433 COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
434 param.push_back("X");
435 param.push_back("Y");
436 param.push_back("Z");
437 /* main function, it creates <source id = "">, <float_array id = ""
439 source.prepareToAppendValues();
440 //appends data to <float_array>
442 for (i = 0; i < totverts; i++) {
443 source.appendValues(verts[i].co[0], verts[i].co[1], verts[i].co[2]);
450 void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me)
452 if (!CustomData_has_layer(&me->fdata, CD_MCOL))
456 int totcolor = 0, i, j;
458 for (i = 0, f = me->mface; i < me->totface; i++, f++)
459 totcolor += f->v4 ? 4 : 3;
461 COLLADASW::FloatSourceF source(mSW);
462 source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::COLOR));
463 source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::COLOR) + ARRAY_ID_SUFFIX);
464 source.setAccessorCount(totcolor);
465 source.setAccessorStride(3);
467 COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
468 param.push_back("R");
469 param.push_back("G");
470 param.push_back("B");
472 source.prepareToAppendValues();
474 int index = CustomData_get_active_layer_index(&me->fdata, CD_MCOL);
476 MCol *mcol = (MCol *)me->fdata.layers[index].data;
479 for (i = 0, f = me->mface; i < me->totface; i++, c += 4, f++)
480 for (j = 0; j < (f->v4 ? 4 : 3); j++)
481 source.appendValues(c[j].b / 255.0f, c[j].g / 255.0f, c[j].r / 255.0f);
486 std::string GeometryExporter::makeTexcoordSourceId(std::string& geom_id, int layer_index)
489 sprintf(suffix, "-%d", layer_index);
490 return getIdBySemantics(geom_id, COLLADASW::InputSemantic::TEXCOORD) + suffix;
493 //creates <source> for texcoords
494 void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
497 int totfaces = dm->getNumTessFaces(dm);
498 MFace *mfaces = dm->getTessFaceArray(dm);
500 int totfaces = me->totface;
501 MFace *mfaces = me->mface;
507 for (i = 0; i < totfaces; i++) {
508 MFace *f = &mfaces[i];
517 int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
519 // write <source> for each layer
520 // each <source> will get id like meshName + "map-channel-1"
522 int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE)-1;
523 for (int a = 0; a < num_layers; a++) {
525 if (!this->export_settings->active_uv_only || a == active_uv_index) {
526 MTFace *tface = (MTFace *)CustomData_get_layer_n(&me->fdata, CD_MTFACE, a);
527 // char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, a);
529 COLLADASW::FloatSourceF source(mSW);
530 std::string layer_id = makeTexcoordSourceId(geom_id, map_index++);
531 source.setId(layer_id);
532 source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
534 source.setAccessorCount(totuv);
535 source.setAccessorStride(2);
536 COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
537 param.push_back("S");
538 param.push_back("T");
540 source.prepareToAppendValues();
542 for (i = 0; i < totfaces; i++) {
543 MFace *f = &mfaces[i];
545 for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) {
546 source.appendValues(tface[i].uv[j][0],
557 //creates <source> for normals
558 void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal>& nor)
561 int totverts = dm->getNumVerts(dm);
562 MVert *verts = dm->getVertArray(dm);
565 COLLADASW::FloatSourceF source(mSW);
566 source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL));
567 source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL) +
569 source.setAccessorCount((unsigned long)nor.size());
570 source.setAccessorStride(3);
571 COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
572 param.push_back("X");
573 param.push_back("Y");
574 param.push_back("Z");
576 source.prepareToAppendValues();
578 std::vector<Normal>::iterator it;
579 for (it = nor.begin(); it != nor.end(); it++) {
581 source.appendValues(n.x, n.y, n.z);
587 void GeometryExporter::create_normals(std::vector<Normal> &nor, std::vector<Face> &ind, Mesh *me)
590 MVert *vert = me->mvert;
591 std::map<unsigned int, unsigned int> nshar;
593 for (i = 0; i < me->totface; i++) {
594 MFace *fa = &me->mface[i];
596 unsigned int *nn = &f.v1;
597 unsigned int *vv = &fa->v1;
599 memset(&f, 0, sizeof(f));
600 v = fa->v4 == 0 ? 3 : 4;
602 if (!(fa->flag & ME_SMOOTH)) {
605 normal_quad_v3(&n.x, vert[fa->v1].co, vert[fa->v2].co, vert[fa->v3].co, vert[fa->v4].co);
607 normal_tri_v3(&n.x, vert[fa->v1].co, vert[fa->v2].co, vert[fa->v3].co);
611 for (j = 0; j < v; j++) {
612 if (fa->flag & ME_SMOOTH) {
613 if (nshar.find(*vv) != nshar.end())
617 (float)vert[*vv].no[0] / 32767.0f,
618 (float)vert[*vv].no[1] / 32767.0f,
619 (float)vert[*vv].no[2] / 32767.0f
622 *nn = (unsigned int)nor.size() - 1;
628 *nn = (unsigned int)nor.size() - 1;
637 std::string GeometryExporter::getIdBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix)
639 return geom_id + getSuffixBySemantic(type) + other_suffix;
643 COLLADASW::URI GeometryExporter::getUrlBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix)
646 std::string id(getIdBySemantics(geom_id, type, other_suffix));
647 return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
651 COLLADASW::URI GeometryExporter::makeUrl(std::string id)
653 return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
657 int GeometryExporter::getTriCount(MFace *faces, int totface)
661 for (i = 0; i < totface; i++) {
663 if (faces[i].v4 != 0)