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_customdata.h"
44 #include "BKE_global.h"
45 #include "BKE_library.h"
46 #include "BKE_material.h"
50 #include "collada_internal.h"
51 #include "collada_utils.h"
54 void GeometryExporter::exportGeom()
56 Scene *sce = blender_context.get_scene();
60 gf.forEachMeshObjectInExportSet<GeometryExporter>(sce, *this, this->export_settings->export_set);
65 void GeometryExporter::operator()(Object *ob)
67 bool use_instantiation = this->export_settings->use_object_instantiation;
68 Mesh *me = bc_get_mesh_copy(
71 this->export_settings->export_mesh_type,
72 this->export_settings->apply_modifiers,
73 this->export_settings->triangulate);
75 std::string geom_id = get_geometry_id(ob, use_instantiation);
76 std::vector<Normal> nor;
77 std::vector<BCPolygonNormalsIndices> norind;
79 // Skip if linked geometry was already exported from another reference
80 if (use_instantiation &&
81 exportedGeometry.find(geom_id) != exportedGeometry.end())
86 std::string geom_name = (use_instantiation) ? id_name(ob->data) : id_name(ob);
87 geom_name = encode_xml(geom_name);
89 exportedGeometry.insert(geom_id);
91 bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL);
93 create_normals(nor, norind, me);
95 // openMesh(geoId, geoName, meshId)
96 openMesh(geom_id, geom_name);
98 // writes <source> for vertex coords
99 createVertsSource(geom_id, me);
101 // writes <source> for normal coords
102 createNormalsSource(geom_id, me, nor);
104 bool has_uvs = (bool)CustomData_has_layer(&me->ldata, CD_MLOOPUV);
106 // writes <source> for uv coords if mesh has uv coords
108 createTexcoordsSource(geom_id, me);
112 createVertexColorSource(geom_id, me);
116 COLLADASW::Vertices verts(mSW);
117 verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
118 COLLADASW::InputList &input_list = verts.getInputList();
119 COLLADASW::Input input(COLLADASW::InputSemantic::POSITION, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
120 input_list.push_back(input);
123 createLooseEdgeList(ob, me, geom_id);
125 // Only create Polylists if number of faces > 0
126 if (me->totface > 0) {
129 for (int a = 0; a < ob->totcol; a++) {
130 createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
134 createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind);
140 if (me->flag & ME_TWOSIDED) {
141 mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>");
146 if (this->export_settings->include_shapekeys) {
147 Key *key = BKE_key_from_object(ob);
149 KeyBlock *kb = (KeyBlock *)key->block.first;
152 for (; kb; kb = kb->next) {
153 BKE_keyblock_convert_to_mesh(kb, me);
154 export_key_mesh(ob, me, kb);
159 BKE_id_free(NULL, me);
162 void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb)
164 std::string geom_id = get_geometry_id(ob, false) + "_morph_" + translate_id(kb->name);
165 std::vector<Normal> nor;
166 std::vector<BCPolygonNormalsIndices> norind;
168 if (exportedGeometry.find(geom_id) != exportedGeometry.end())
173 std::string geom_name = kb->name;
175 exportedGeometry.insert(geom_id);
177 bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL);
179 create_normals(nor, norind, me);
181 // openMesh(geoId, geoName, meshId)
182 openMesh(geom_id, geom_name);
184 // writes <source> for vertex coords
185 createVertsSource(geom_id, me);
187 // writes <source> for normal coords
188 createNormalsSource(geom_id, me, nor);
190 bool has_uvs = (bool)CustomData_has_layer(&me->ldata, CD_MLOOPUV);
192 // writes <source> for uv coords if mesh has uv coords
194 createTexcoordsSource(geom_id, me);
198 createVertexColorSource(geom_id, me);
203 COLLADASW::Vertices verts(mSW);
204 verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
205 COLLADASW::InputList &input_list = verts.getInputList();
206 COLLADASW::Input input(COLLADASW::InputSemantic::POSITION, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
207 input_list.push_back(input);
210 //createLooseEdgeList(ob, me, geom_id, norind);
214 for (int a = 0; a < ob->totcol; a++) {
215 createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
219 createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind);
224 if (me->flag & ME_TWOSIDED) {
225 mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>");
231 void GeometryExporter::createLooseEdgeList(Object *ob,
233 std::string& geom_id)
236 MEdge *medges = me->medge;
237 int totedges = me->totedge;
238 int edges_in_linelist = 0;
239 std::vector<unsigned int> edge_list;
242 // Find all loose edges in Mesh
243 // and save vertex indices in edge_list
244 for (index = 0; index < totedges; index++)
246 MEdge *edge = &medges[index];
248 if (edge->flag & ME_LOOSEEDGE)
250 edges_in_linelist += 1;
251 edge_list.push_back(edge->v1);
252 edge_list.push_back(edge->v2);
256 if (edges_in_linelist > 0)
258 // Create the list of loose edges
259 COLLADASW::Lines lines(mSW);
261 lines.setCount(edges_in_linelist);
264 COLLADASW::InputList &til = lines.getInputList();
266 // creates <input> in <lines> for vertices
267 COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
268 til.push_back(input1);
270 lines.prepareToAppendValues();
272 for (index = 0; index < edges_in_linelist; index++)
274 lines.appendValues(edge_list[2 * index + 1]);
275 lines.appendValues(edge_list[2 * index]);
282 std::string GeometryExporter::makeVertexColorSourceId(std::string& geom_id, char *layer_name)
284 std::string result = getIdBySemantics(geom_id, COLLADASW::InputSemantic::COLOR) + "-" + layer_name;
288 // powerful because it handles both cases when there is material and when there's not
289 void GeometryExporter::createPolylist(short material_index,
294 std::string& geom_id,
295 std::vector<BCPolygonNormalsIndices>& norind)
298 MPoly *mpolys = me->mpoly;
299 MLoop *mloops = me->mloop;
300 int totpolys = me->totpoly;
304 int faces_in_polylist = 0;
305 std::vector<unsigned long> vcount_list;
307 // count faces with this material
308 for (i = 0; i < totpolys; i++) {
309 MPoly *p = &mpolys[i];
311 if (p->mat_nr == material_index) {
313 vcount_list.push_back(p->totloop);
317 // no faces using this material
318 if (faces_in_polylist == 0) {
319 fprintf(stderr, "%s: material with index %d is not used.\n", id_name(ob).c_str(), material_index);
323 Material *ma = ob->totcol ? give_current_material(ob, material_index + 1) : NULL;
324 COLLADASW::Polylist polylist(mSW);
326 // sets count attribute in <polylist>
327 polylist.setCount(faces_in_polylist);
329 // sets material name
331 std::string material_id = get_material_id(ma);
332 std::ostringstream ostr;
333 ostr << translate_id(material_id);
334 polylist.setMaterial(ostr.str());
337 COLLADASW::InputList &til = polylist.getInputList();
339 // creates <input> in <polylist> for vertices
340 COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
342 // creates <input> in <polylist> for normals
343 COLLADASW::Input input2(COLLADASW::InputSemantic::NORMAL, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL), 1);
345 til.push_back(input1);
346 til.push_back(input2);
348 // if mesh has uv coords writes <input> for TEXCOORD
349 int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
350 int active_uv_index = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV);
351 for (i = 0; i < num_layers; i++) {
352 int layer_index = CustomData_get_layer_index_n(&me->ldata, CD_MLOOPUV, i);
353 if (!this->export_settings->active_uv_only || layer_index == active_uv_index) {
355 // char *name = CustomData_get_layer_name(&me->ldata, CD_MLOOPUV, i);
356 COLLADASW::Input input3(COLLADASW::InputSemantic::TEXCOORD,
357 makeUrl(makeTexcoordSourceId(geom_id, i, this->export_settings->active_uv_only)),
358 2, // this is only until we have optimized UV sets
359 (this->export_settings->active_uv_only) ? 0 : layer_index-1 //set (0,1,2,...)
361 til.push_back(input3);
365 int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
366 if (totlayer_mcol > 0) {
369 for (int a = 0; a < totlayer_mcol; a++) {
370 char *layer_name = bc_CustomData_get_layer_name(&me->ldata, CD_MLOOPCOL, a);
371 COLLADASW::Input input4(COLLADASW::InputSemantic::COLOR,
372 makeUrl(makeVertexColorSourceId(geom_id, layer_name)),
373 (has_uvs) ? 3 : 2, // all color layers have same index order
374 map_index // set number equals color map index
376 til.push_back(input4);
382 polylist.setVCountList(vcount_list);
384 // performs the actual writing
385 polylist.prepareToAppendValues();
389 for (i = 0; i < totpolys; i++) {
390 MPoly *p = &mpolys[i];
391 int loop_count = p->totloop;
393 if (p->mat_nr == material_index) {
394 MLoop *l = &mloops[p->loopstart];
395 BCPolygonNormalsIndices normal_indices = norind[i];
397 for (int j = 0; j < loop_count; j++) {
398 polylist.appendValues(l[j].v);
399 polylist.appendValues(normal_indices[j]);
401 polylist.appendValues(texindex + j);
404 polylist.appendValues(texindex + j);
408 texindex += loop_count;
414 // creates <source> for positions
415 void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me)
418 int totverts = dm->getNumVerts(dm);
419 MVert *verts = dm->getVertArray(dm);
421 int totverts = me->totvert;
422 MVert *verts = me->mvert;
424 COLLADASW::FloatSourceF source(mSW);
425 source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
426 source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION) +
428 source.setAccessorCount(totverts);
429 source.setAccessorStride(3);
431 COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
432 param.push_back("X");
433 param.push_back("Y");
434 param.push_back("Z");
435 /* main function, it creates <source id = "">, <float_array id = ""
437 source.prepareToAppendValues();
438 //appends data to <float_array>
440 for (i = 0; i < totverts; i++) {
441 source.appendValues(verts[i].co[0], verts[i].co[1], verts[i].co[2]);
449 void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me)
451 /* Find number of vertex color layers */
452 int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
453 if (totlayer_mcol == 0)
457 for (int a = 0; a < totlayer_mcol; a++) {
460 MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(&me->ldata, CD_MLOOPCOL, a);
462 COLLADASW::FloatSourceF source(mSW);
464 char *layer_name = bc_CustomData_get_layer_name(&me->ldata, CD_MLOOPCOL, a);
465 std::string layer_id = makeVertexColorSourceId(geom_id, layer_name);
466 source.setId(layer_id);
468 source.setNodeName(layer_name);
470 source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
471 source.setAccessorCount(me->totloop);
472 source.setAccessorStride(4);
474 COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
475 param.push_back("R");
476 param.push_back("G");
477 param.push_back("B");
478 param.push_back("A");
480 source.prepareToAppendValues();
484 for (i = 0, mpoly = me->mpoly; i < me->totpoly; i++, mpoly++) {
485 MLoopCol *mlc = mloopcol + mpoly->loopstart;
486 for (int j = 0; j < mpoly->totloop; j++, mlc++) {
501 std::string GeometryExporter::makeTexcoordSourceId(std::string& geom_id, int layer_index, bool is_single_layer)
504 if (is_single_layer) {
508 sprintf(suffix, "-%d", layer_index);
510 return getIdBySemantics(geom_id, COLLADASW::InputSemantic::TEXCOORD) + suffix;
513 //creates <source> for texcoords
514 void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
517 int totpoly = me->totpoly;
518 int totuv = me->totloop;
519 MPoly *mpolys = me->mpoly;
521 int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
523 // write <source> for each layer
524 // each <source> will get id like meshName + "map-channel-1"
525 int active_uv_index = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV);
526 for (int a = 0; a < num_layers; a++) {
527 int layer_index = CustomData_get_layer_index_n(&me->ldata, CD_MLOOPUV, a);
528 if (!this->export_settings->active_uv_only || layer_index == active_uv_index) {
529 MLoopUV *mloops = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, a);
531 COLLADASW::FloatSourceF source(mSW);
532 std::string layer_id = makeTexcoordSourceId(geom_id, a, this->export_settings->active_uv_only);
533 source.setId(layer_id);
534 source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
536 source.setAccessorCount(totuv);
537 source.setAccessorStride(2);
538 COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
539 param.push_back("S");
540 param.push_back("T");
542 source.prepareToAppendValues();
544 for (int index = 0; index < totpoly; index++) {
545 MPoly *mpoly = mpolys+index;
546 MLoopUV *mloop = mloops+mpoly->loopstart;
547 for (int j = 0; j < mpoly->totloop; j++) {
548 source.appendValues(mloop[j].uv[0],
558 bool operator<(const Normal &a, const Normal &b)
560 /* only needed to sort normal vectors and find() them later in a map.*/
561 return a.x < b.x || (a.x == b.x && (a.y < b.y || (a.y == b.y && a.z < b.z)));
564 //creates <source> for normals
565 void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal>& nor)
568 int totverts = dm->getNumVerts(dm);
569 MVert *verts = dm->getVertArray(dm);
572 COLLADASW::FloatSourceF source(mSW);
573 source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL));
574 source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL) +
576 source.setAccessorCount((unsigned long)nor.size());
577 source.setAccessorStride(3);
578 COLLADASW::SourceBase::ParameterNameList ¶m = source.getParameterNameList();
579 param.push_back("X");
580 param.push_back("Y");
581 param.push_back("Z");
583 source.prepareToAppendValues();
585 std::vector<Normal>::iterator it;
586 for (it = nor.begin(); it != nor.end(); it++) {
588 source.appendValues(n.x, n.y, n.z);
594 void GeometryExporter::create_normals(std::vector<Normal> &normals, std::vector<BCPolygonNormalsIndices> &polygons_normals, Mesh *me)
596 std::map<Normal, unsigned int> shared_normal_indices;
597 int last_normal_index = -1;
599 MVert *verts = me->mvert;
600 MLoop *mloops = me->mloop;
601 float(*lnors)[3] = NULL;
602 bool use_custom_normals = false;
604 BKE_mesh_calc_normals_split(me);
605 if (CustomData_has_layer(&me->ldata, CD_NORMAL)) {
606 lnors = (float(*)[3])CustomData_get_layer(&me->ldata, CD_NORMAL);
607 use_custom_normals = true;
610 for (int poly_index = 0; poly_index < me->totpoly; poly_index++) {
611 MPoly *mpoly = &me->mpoly[poly_index];
612 bool use_vertex_normals = use_custom_normals || mpoly->flag & ME_SMOOTH;
614 if (!use_vertex_normals) {
615 // For flat faces use face normal as vertex normal:
618 BKE_mesh_calc_poly_normal(mpoly, mloops+mpoly->loopstart, verts, vector);
620 Normal n = { vector[0], vector[1], vector[2] };
621 normals.push_back(n);
625 BCPolygonNormalsIndices poly_indices;
626 for (int loop_index = 0; loop_index < mpoly->totloop; loop_index++) {
627 unsigned int loop_idx = mpoly->loopstart + loop_index;
628 if (use_vertex_normals) {
631 if (use_custom_normals) {
632 normalize_v3_v3(normalized, lnors[loop_idx]);
635 normal_short_to_float_v3(normalized, verts[mloops[loop_index].v].no);
636 normalize_v3(normalized);
638 Normal n = { normalized[0], normalized[1], normalized[2] };
640 if (shared_normal_indices.find(n) != shared_normal_indices.end()) {
641 poly_indices.add_index(shared_normal_indices[n]);
645 poly_indices.add_index(last_normal_index);
646 shared_normal_indices[n] = last_normal_index;
647 normals.push_back(n);
651 poly_indices.add_index(last_normal_index);
655 polygons_normals.push_back(poly_indices);
659 std::string GeometryExporter::getIdBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix)
661 return geom_id + getSuffixBySemantic(type) + other_suffix;
665 COLLADASW::URI GeometryExporter::getUrlBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix)
668 std::string id(getIdBySemantics(geom_id, type, other_suffix));
669 return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
673 COLLADASW::URI GeometryExporter::makeUrl(std::string id)
675 return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);