fix T60049: Collada Exporter: When exporting multiple UVs, the set index must start...
[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
40 extern "C" {
41         #include "BLI_utildefines.h"
42
43         #include "BKE_customdata.h"
44         #include "BKE_global.h"
45         #include "BKE_library.h"
46         #include "BKE_material.h"
47         #include "BKE_mesh.h"
48 }
49
50 #include "collada_internal.h"
51 #include "collada_utils.h"
52
53
54 void GeometryExporter::exportGeom()
55 {
56         Scene *sce = blender_context.get_scene();
57         openLibrary();
58
59         GeometryFunctor gf;
60         gf.forEachMeshObjectInExportSet<GeometryExporter>(sce, *this, this->export_settings->export_set);
61
62         closeLibrary();
63 }
64
65 void GeometryExporter::operator()(Object *ob)
66 {
67         bool use_instantiation = this->export_settings->use_object_instantiation;
68         Mesh *me = bc_get_mesh_copy(
69                                         blender_context,
70                                         ob,
71                                         this->export_settings->export_mesh_type,
72                                         this->export_settings->apply_modifiers,
73                                         this->export_settings->triangulate);
74
75         std::string geom_id = get_geometry_id(ob, use_instantiation);
76         std::vector<Normal> nor;
77         std::vector<BCPolygonNormalsIndices> norind;
78
79         // Skip if linked geometry was already exported from another reference
80         if (use_instantiation &&
81             exportedGeometry.find(geom_id) != exportedGeometry.end())
82         {
83                 return;
84         }
85
86         std::string geom_name = (use_instantiation) ? id_name(ob->data) : id_name(ob);
87         geom_name = encode_xml(geom_name);
88
89         exportedGeometry.insert(geom_id);
90
91         bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL);
92
93         create_normals(nor, norind, me);
94
95         // openMesh(geoId, geoName, meshId)
96         openMesh(geom_id, geom_name);
97
98         // writes <source> for vertex coords
99         createVertsSource(geom_id, me);
100
101         // writes <source> for normal coords
102         createNormalsSource(geom_id, me, nor);
103
104         bool has_uvs = (bool)CustomData_has_layer(&me->ldata, CD_MLOOPUV);
105
106         // writes <source> for uv coords if mesh has uv coords
107         if (has_uvs) {
108                 createTexcoordsSource(geom_id, me);
109         }
110
111         if (has_color) {
112                 createVertexColorSource(geom_id, me);
113         }
114         // <vertices>
115
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);
121         verts.add();
122
123         createLooseEdgeList(ob, me, geom_id);
124
125         // Only create Polylists if number of faces > 0
126         if (me->totface > 0) {
127                 // XXX slow
128                 if (ob->totcol) {
129                         for (int a = 0; a < ob->totcol; a++) {
130                                 createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
131                         }
132                 }
133                 else {
134                         createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind);
135                 }
136         }
137
138         closeMesh();
139
140         if (me->flag & ME_TWOSIDED) {
141                 mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>");
142         }
143
144         closeGeometry();
145
146         if (this->export_settings->include_shapekeys) {
147                 Key *key = BKE_key_from_object(ob);
148                 if (key) {
149                         KeyBlock *kb = (KeyBlock *)key->block.first;
150                         //skip the basis
151                         kb = kb->next;
152                         for (; kb; kb = kb->next) {
153                                 BKE_keyblock_convert_to_mesh(kb, me);
154                                 export_key_mesh(ob, me, kb);
155                         }
156                 }
157         }
158
159         BKE_id_free(NULL, me);
160 }
161
162 void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb)
163 {
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;
167
168         if (exportedGeometry.find(geom_id) != exportedGeometry.end())
169         {
170                 return;
171         }
172
173         std::string geom_name = kb->name;
174
175         exportedGeometry.insert(geom_id);
176
177         bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL);
178
179         create_normals(nor, norind, me);
180
181         // openMesh(geoId, geoName, meshId)
182         openMesh(geom_id, geom_name);
183
184         // writes <source> for vertex coords
185         createVertsSource(geom_id, me);
186
187         // writes <source> for normal coords
188         createNormalsSource(geom_id, me, nor);
189
190         bool has_uvs = (bool)CustomData_has_layer(&me->ldata, CD_MLOOPUV);
191
192         // writes <source> for uv coords if mesh has uv coords
193         if (has_uvs) {
194                 createTexcoordsSource(geom_id, me);
195         }
196
197         if (has_color) {
198                 createVertexColorSource(geom_id, me);
199         }
200
201         // <vertices>
202
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);
208         verts.add();
209
210         //createLooseEdgeList(ob, me, geom_id, norind);
211
212         // XXX slow
213         if (ob->totcol) {
214                 for (int a = 0; a < ob->totcol; a++) {
215                         createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
216                 }
217         }
218         else {
219                 createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind);
220         }
221
222         closeMesh();
223
224         if (me->flag & ME_TWOSIDED) {
225                 mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>");
226         }
227
228         closeGeometry();
229 }
230
231 void GeometryExporter::createLooseEdgeList(Object *ob,
232                                            Mesh   *me,
233                                            std::string& geom_id)
234 {
235
236         MEdge *medges = me->medge;
237         int totedges  = me->totedge;
238         int edges_in_linelist = 0;
239         std::vector<unsigned int> edge_list;
240         int index;
241
242         // Find all loose edges in Mesh
243         // and save vertex indices in edge_list
244         for (index = 0; index < totedges; index++)
245         {
246                 MEdge *edge = &medges[index];
247
248                 if (edge->flag & ME_LOOSEEDGE)
249                 {
250                         edges_in_linelist += 1;
251                         edge_list.push_back(edge->v1);
252                         edge_list.push_back(edge->v2);
253                 }
254         }
255
256         if (edges_in_linelist > 0)
257         {
258                 // Create the list of loose edges
259                 COLLADASW::Lines lines(mSW);
260
261                 lines.setCount(edges_in_linelist);
262
263
264                 COLLADASW::InputList &til = lines.getInputList();
265
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);
269
270                 lines.prepareToAppendValues();
271
272                 for (index = 0; index < edges_in_linelist; index++)
273                 {
274                         lines.appendValues(edge_list[2 * index + 1]);
275                         lines.appendValues(edge_list[2 * index]);
276                 }
277                 lines.finish();
278         }
279
280 }
281
282 std::string GeometryExporter::makeVertexColorSourceId(std::string& geom_id, char *layer_name)
283 {
284         std::string result = getIdBySemantics(geom_id, COLLADASW::InputSemantic::COLOR) + "-" + layer_name;
285         return result;
286 }
287
288 // powerful because it handles both cases when there is material and when there's not
289 void GeometryExporter::createPolylist(short material_index,
290                                       bool has_uvs,
291                                       bool has_color,
292                                       Object *ob,
293                                       Mesh *me,
294                                       std::string& geom_id,
295                                       std::vector<BCPolygonNormalsIndices>& norind)
296 {
297
298         MPoly *mpolys = me->mpoly;
299         MLoop *mloops = me->mloop;
300         int totpolys  = me->totpoly;
301
302         // <vcount>
303         int i;
304         int faces_in_polylist = 0;
305         std::vector<unsigned long> vcount_list;
306
307         // count faces with this material
308         for (i = 0; i < totpolys; i++) {
309                 MPoly *p = &mpolys[i];
310
311                 if (p->mat_nr == material_index) {
312                         faces_in_polylist++;
313                         vcount_list.push_back(p->totloop);
314                 }
315         }
316
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);
320                 return;
321         }
322
323         Material *ma = ob->totcol ? give_current_material(ob, material_index + 1) : NULL;
324         COLLADASW::Polylist polylist(mSW);
325
326         // sets count attribute in <polylist>
327         polylist.setCount(faces_in_polylist);
328
329         // sets material name
330         if (ma) {
331                 std::string material_id = get_material_id(ma);
332                 std::ostringstream ostr;
333                 ostr << translate_id(material_id);
334                 polylist.setMaterial(ostr.str());
335         }
336
337         COLLADASW::InputList &til = polylist.getInputList();
338
339         // creates <input> in <polylist> for vertices
340         COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
341
342         // creates <input> in <polylist> for normals
343         COLLADASW::Input input2(COLLADASW::InputSemantic::NORMAL, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL), 1);
344
345         til.push_back(input1);
346         til.push_back(input2);
347
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) {
354
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,...)
360                                                                         );
361                         til.push_back(input3);
362                 }
363         }
364
365         int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
366         if (totlayer_mcol > 0) {
367                 int map_index = 0;
368
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
375                                                 );
376                         til.push_back(input4);
377                         map_index++;
378                 }
379         }
380
381         // sets <vcount>
382         polylist.setVCountList(vcount_list);
383
384         // performs the actual writing
385         polylist.prepareToAppendValues();
386
387         // <p>
388         int texindex = 0;
389         for (i = 0; i < totpolys; i++) {
390                 MPoly *p = &mpolys[i];
391                 int loop_count = p->totloop;
392
393                 if (p->mat_nr == material_index) {
394                         MLoop *l = &mloops[p->loopstart];
395                         BCPolygonNormalsIndices normal_indices = norind[i];
396
397                         for (int j = 0; j < loop_count; j++) {
398                                 polylist.appendValues(l[j].v);
399                                 polylist.appendValues(normal_indices[j]);
400                                 if (has_uvs)
401                                         polylist.appendValues(texindex + j);
402
403                                 if (has_color)
404                                         polylist.appendValues(texindex + j);
405                         }
406                 }
407
408                 texindex += loop_count;
409         }
410
411         polylist.finish();
412 }
413
414 // creates <source> for positions
415 void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me)
416 {
417 #if 0
418         int totverts = dm->getNumVerts(dm);
419         MVert *verts = dm->getVertArray(dm);
420 #endif
421         int totverts = me->totvert;
422         MVert *verts = me->mvert;
423
424         COLLADASW::FloatSourceF source(mSW);
425         source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
426         source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION) +
427                           ARRAY_ID_SUFFIX);
428         source.setAccessorCount(totverts);
429         source.setAccessorStride(3);
430
431         COLLADASW::SourceBase::ParameterNameList &param = 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 = ""
436          * count = ""> */
437         source.prepareToAppendValues();
438         //appends data to <float_array>
439         int i = 0;
440         for (i = 0; i < totverts; i++) {
441                 source.appendValues(verts[i].co[0], verts[i].co[1], verts[i].co[2]);
442         }
443
444         source.finish();
445
446 }
447
448
449 void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me)
450 {
451         /* Find number of vertex color layers */
452         int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
453         if (totlayer_mcol == 0)
454                 return;
455
456         int map_index = 0;
457         for (int a = 0; a < totlayer_mcol; a++) {
458
459                 map_index++;
460                 MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(&me->ldata, CD_MLOOPCOL, a);
461
462                 COLLADASW::FloatSourceF source(mSW);
463
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);
467
468                 source.setNodeName(layer_name);
469
470                 source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
471                 source.setAccessorCount(me->totloop);
472                 source.setAccessorStride(4);
473
474                 COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
475                 param.push_back("R");
476                 param.push_back("G");
477                 param.push_back("B");
478                 param.push_back("A");
479
480                 source.prepareToAppendValues();
481
482                 MPoly *mpoly;
483                 int i;
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++) {
487                                 source.appendValues(
488                                                 mlc->r / 255.0f,
489                                                 mlc->g / 255.0f,
490                                                 mlc->b / 255.0f,
491                                                 mlc->a / 255.0f
492                                 );
493                         }
494                 }
495
496                 source.finish();
497         }
498 }
499
500
501 std::string GeometryExporter::makeTexcoordSourceId(std::string& geom_id, int layer_index, bool is_single_layer)
502 {
503         char suffix[20];
504         if (is_single_layer) {
505                 suffix[0] = '\0';
506         }
507         else {
508                 sprintf(suffix, "-%d", layer_index);
509         }
510         return getIdBySemantics(geom_id, COLLADASW::InputSemantic::TEXCOORD) + suffix;
511 }
512
513 //creates <source> for texcoords
514 void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
515 {
516
517         int totpoly   = me->totpoly;
518         int totuv     = me->totloop;
519         MPoly *mpolys = me->mpoly;
520
521         int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
522
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);
530
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);
535
536                         source.setAccessorCount(totuv);
537                         source.setAccessorStride(2);
538                         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
539                         param.push_back("S");
540                         param.push_back("T");
541
542                         source.prepareToAppendValues();
543
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],
549                                                                                 mloop[j].uv[1]);
550                                 }
551                         }
552
553                         source.finish();
554                 }
555         }
556 }
557
558 bool operator<(const Normal &a, const Normal &b)
559 {
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)));
562 }
563
564 //creates <source> for normals
565 void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal>& nor)
566 {
567 #if 0
568         int totverts = dm->getNumVerts(dm);
569         MVert *verts = dm->getVertArray(dm);
570 #endif
571
572         COLLADASW::FloatSourceF source(mSW);
573         source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL));
574         source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL) +
575                           ARRAY_ID_SUFFIX);
576         source.setAccessorCount((unsigned long)nor.size());
577         source.setAccessorStride(3);
578         COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
579         param.push_back("X");
580         param.push_back("Y");
581         param.push_back("Z");
582
583         source.prepareToAppendValues();
584
585         std::vector<Normal>::iterator it;
586         for (it = nor.begin(); it != nor.end(); it++) {
587                 Normal& n = *it;
588                 source.appendValues(n.x, n.y, n.z);
589         }
590
591         source.finish();
592 }
593
594 void GeometryExporter::create_normals(std::vector<Normal> &normals, std::vector<BCPolygonNormalsIndices> &polygons_normals, Mesh *me)
595 {
596         std::map<Normal, unsigned int> shared_normal_indices;
597         int last_normal_index = -1;
598
599         MVert *verts  = me->mvert;
600         MLoop *mloops = me->mloop;
601         float(*lnors)[3] = NULL;
602         bool use_custom_normals = false;
603
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;
608         }
609
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;
613
614                 if (!use_vertex_normals) {
615                         // For flat faces use face normal as vertex normal:
616
617                         float vector[3];
618                         BKE_mesh_calc_poly_normal(mpoly, mloops+mpoly->loopstart, verts, vector);
619
620                         Normal n = { vector[0], vector[1], vector[2] };
621                         normals.push_back(n);
622                         last_normal_index++;
623                 }
624
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) {
629                                 float normalized[3];
630
631                                 if (use_custom_normals) {
632                                         normalize_v3_v3(normalized, lnors[loop_idx]);
633                                 }
634                                 else {
635                                         normal_short_to_float_v3(normalized, verts[mloops[loop_index].v].no);
636                                         normalize_v3(normalized);
637                                 }
638                                 Normal n = { normalized[0], normalized[1], normalized[2] };
639
640                                 if (shared_normal_indices.find(n) != shared_normal_indices.end()) {
641                                         poly_indices.add_index(shared_normal_indices[n]);
642                                 }
643                                 else {
644                                         last_normal_index++;
645                                         poly_indices.add_index(last_normal_index);
646                                         shared_normal_indices[n] = last_normal_index;
647                                         normals.push_back(n);
648                                 }
649                         }
650                         else {
651                                 poly_indices.add_index(last_normal_index);
652                         }
653                 }
654
655                 polygons_normals.push_back(poly_indices);
656         }
657 }
658
659 std::string GeometryExporter::getIdBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix)
660 {
661         return geom_id + getSuffixBySemantic(type) + other_suffix;
662 }
663
664
665 COLLADASW::URI GeometryExporter::getUrlBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix)
666 {
667
668         std::string id(getIdBySemantics(geom_id, type, other_suffix));
669         return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
670
671 }
672
673 COLLADASW::URI GeometryExporter::makeUrl(std::string id)
674 {
675         return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
676 }