1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 /** \file
18  * \ingroup collada
19  */
20 
21 #include <sstream>
22 
23 #include "COLLADABUUtils.h"
24 #include "COLLADASWPrimitves.h"
25 #include "COLLADASWSource.h"
26 #include "COLLADASWVertices.h"
27 
28 #include "GeometryExporter.h"
29 
30 #include "DNA_meshdata_types.h"
31 
32 #include "BLI_utildefines.h"
33 
34 #include "BKE_customdata.h"
35 #include "BKE_global.h"
36 #include "BKE_lib_id.h"
37 #include "BKE_material.h"
38 #include "BKE_mesh.h"
39 
40 #include "collada_internal.h"
41 #include "collada_utils.h"
42 
exportGeom()43 void GeometryExporter::exportGeom()
44 {
45   Scene *sce = blender_context.get_scene();
46   openLibrary();
47 
48   GeometryFunctor gf;
49   gf.forEachMeshObjectInExportSet<GeometryExporter>(
50       sce, *this, this->export_settings.get_export_set());
51 
52   closeLibrary();
53 }
54 
operator ()(Object * ob)55 void GeometryExporter::operator()(Object *ob)
56 {
57   bool use_instantiation = this->export_settings.get_use_object_instantiation();
58   Mesh *me = bc_get_mesh_copy(blender_context,
59                               ob,
60                               this->export_settings.get_export_mesh_type(),
61                               this->export_settings.get_apply_modifiers(),
62                               this->export_settings.get_triangulate());
63 
64   std::string geom_id = get_geometry_id(ob, use_instantiation);
65   std::vector<Normal> nor;
66   std::vector<BCPolygonNormalsIndices> norind;
67 
68   /* Skip if linked geometry was already exported from another reference */
69   if (use_instantiation && exportedGeometry.find(geom_id) != exportedGeometry.end()) {
70     return;
71   }
72 
73   std::string geom_name = (use_instantiation) ? id_name(ob->data) : id_name(ob);
74   geom_name = encode_xml(geom_name);
75 
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, geom_name);
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->ldata, CD_MLOOPUV);
92 
93   /* writes <source> for uv coords if mesh has uv coords */
94   if (has_uvs) {
95     createTexcoordsSource(geom_id, me);
96   }
97 
98   if (has_color) {
99     createVertexColorSource(geom_id, me);
100   }
101   /* <vertices> */
102 
103   COLLADASW::Vertices verts(mSW);
104   verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
105   COLLADASW::InputList &input_list = verts.getInputList();
106   COLLADASW::Input input(COLLADASW::InputSemantic::POSITION,
107                          getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
108   input_list.push_back(input);
109   verts.add();
110 
111   createLooseEdgeList(ob, me, geom_id);
112 
113   /* Only create Polylists if number of faces > 0 */
114   if (me->totface > 0) {
115     /* XXX slow */
116     if (ob->totcol) {
117       for (int a = 0; a < ob->totcol; a++) {
118         create_mesh_primitive_list(a, has_uvs, has_color, ob, me, geom_id, norind);
119       }
120     }
121     else {
122       create_mesh_primitive_list(0, has_uvs, has_color, ob, me, geom_id, norind);
123     }
124   }
125 
126   closeMesh();
127 
128   closeGeometry();
129 
130   if (this->export_settings.get_include_shapekeys()) {
131     Key *key = BKE_key_from_object(ob);
132     if (key) {
133       KeyBlock *kb = (KeyBlock *)key->block.first;
134       /* skip the basis */
135       kb = kb->next;
136       for (; kb; kb = kb->next) {
137         BKE_keyblock_convert_to_mesh(kb, me);
138         export_key_mesh(ob, me, kb);
139       }
140     }
141   }
142 
143   BKE_id_free(NULL, me);
144 }
145 
export_key_mesh(Object * ob,Mesh * me,KeyBlock * kb)146 void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb)
147 {
148   std::string geom_id = get_geometry_id(ob, false) + "_morph_" + translate_id(kb->name);
149   std::vector<Normal> nor;
150   std::vector<BCPolygonNormalsIndices> norind;
151 
152   if (exportedGeometry.find(geom_id) != exportedGeometry.end()) {
153     return;
154   }
155 
156   std::string geom_name = kb->name;
157 
158   exportedGeometry.insert(geom_id);
159 
160   bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL);
161 
162   create_normals(nor, norind, me);
163 
164   // openMesh(geoId, geoName, meshId)
165   openMesh(geom_id, geom_name);
166 
167   /* writes <source> for vertex coords */
168   createVertsSource(geom_id, me);
169 
170   /* writes <source> for normal coords */
171   createNormalsSource(geom_id, me, nor);
172 
173   bool has_uvs = (bool)CustomData_has_layer(&me->ldata, CD_MLOOPUV);
174 
175   /* writes <source> for uv coords if mesh has uv coords */
176   if (has_uvs) {
177     createTexcoordsSource(geom_id, me);
178   }
179 
180   if (has_color) {
181     createVertexColorSource(geom_id, me);
182   }
183 
184   /* <vertices> */
185 
186   COLLADASW::Vertices verts(mSW);
187   verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
188   COLLADASW::InputList &input_list = verts.getInputList();
189   COLLADASW::Input input(COLLADASW::InputSemantic::POSITION,
190                          getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
191   input_list.push_back(input);
192   verts.add();
193 
194   // createLooseEdgeList(ob, me, geom_id, norind);
195 
196   /* XXX slow */
197   if (ob->totcol) {
198     for (int a = 0; a < ob->totcol; a++) {
199       create_mesh_primitive_list(a, has_uvs, has_color, ob, me, geom_id, norind);
200     }
201   }
202   else {
203     create_mesh_primitive_list(0, has_uvs, has_color, ob, me, geom_id, norind);
204   }
205 
206   closeMesh();
207 
208   closeGeometry();
209 }
210 
createLooseEdgeList(Object * ob,Mesh * me,std::string & geom_id)211 void GeometryExporter::createLooseEdgeList(Object *ob, Mesh *me, std::string &geom_id)
212 {
213 
214   MEdge *medges = me->medge;
215   int totedges = me->totedge;
216   int edges_in_linelist = 0;
217   std::vector<unsigned int> edge_list;
218   int index;
219 
220   /* Find all loose edges in Mesh
221    * and save vertex indices in edge_list */
222   for (index = 0; index < totedges; index++) {
223     MEdge *edge = &medges[index];
224 
225     if (edge->flag & ME_LOOSEEDGE) {
226       edges_in_linelist += 1;
227       edge_list.push_back(edge->v1);
228       edge_list.push_back(edge->v2);
229     }
230   }
231 
232   if (edges_in_linelist > 0) {
233     /* Create the list of loose edges */
234     COLLADASW::Lines lines(mSW);
235 
236     lines.setCount(edges_in_linelist);
237 
238     COLLADASW::InputList &til = lines.getInputList();
239 
240     /* creates <input> in <lines> for vertices */
241     COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX,
242                             getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX),
243                             0);
244     til.push_back(input1);
245 
246     lines.prepareToAppendValues();
247 
248     for (index = 0; index < edges_in_linelist; index++) {
249       lines.appendValues(edge_list[2 * index + 1]);
250       lines.appendValues(edge_list[2 * index]);
251     }
252     lines.finish();
253   }
254 }
255 
prepareToAppendValues(bool is_triangulated,COLLADASW::PrimitivesBase & primitive_list,std::vector<unsigned long> & vcount_list)256 static void prepareToAppendValues(bool is_triangulated,
257                                   COLLADASW::PrimitivesBase &primitive_list,
258                                   std::vector<unsigned long> &vcount_list)
259 {
260   /* performs the actual writing */
261   if (is_triangulated) {
262     ((COLLADASW::Triangles &)primitive_list).prepareToAppendValues();
263   }
264   else {
265     /* sets <vcount> */
266     primitive_list.setVCountList(vcount_list);
267     ((COLLADASW::Polylist &)primitive_list).prepareToAppendValues();
268   }
269 }
270 
finish_and_delete_primitive_List(bool is_triangulated,COLLADASW::PrimitivesBase * primitive_list)271 static void finish_and_delete_primitive_List(bool is_triangulated,
272                                              COLLADASW::PrimitivesBase *primitive_list)
273 {
274   if (is_triangulated) {
275     ((COLLADASW::Triangles *)primitive_list)->finish();
276   }
277   else {
278     ((COLLADASW::Polylist *)primitive_list)->finish();
279   }
280   delete primitive_list;
281 }
282 
create_primitive_list(bool is_triangulated,COLLADASW::StreamWriter * mSW)283 static COLLADASW::PrimitivesBase *create_primitive_list(bool is_triangulated,
284                                                         COLLADASW::StreamWriter *mSW)
285 {
286   COLLADASW::PrimitivesBase *primitive_list;
287 
288   if (is_triangulated) {
289     primitive_list = new COLLADASW::Triangles(mSW);
290   }
291   else {
292     primitive_list = new COLLADASW::Polylist(mSW);
293   }
294   return primitive_list;
295 }
296 
collect_vertex_counts_per_poly(Mesh * me,int material_index,std::vector<unsigned long> & vcount_list)297 static bool collect_vertex_counts_per_poly(Mesh *me,
298                                            int material_index,
299                                            std::vector<unsigned long> &vcount_list)
300 {
301   MPoly *mpolys = me->mpoly;
302   int totpolys = me->totpoly;
303   bool is_triangulated = true;
304 
305   int i;
306   /* Expecting that p->mat_nr is always 0 if the mesh has no materials assigned */
307   for (i = 0; i < totpolys; i++) {
308     MPoly *p = &mpolys[i];
309     if (p->mat_nr == material_index) {
310       int vertex_count = p->totloop;
311       vcount_list.push_back(vertex_count);
312       if (vertex_count != 3) {
313         is_triangulated = false;
314       }
315     }
316   }
317   return is_triangulated;
318 }
319 
makeVertexColorSourceId(std::string & geom_id,char * layer_name)320 std::string GeometryExporter::makeVertexColorSourceId(std::string &geom_id, char *layer_name)
321 {
322   std::string result = getIdBySemantics(geom_id, COLLADASW::InputSemantic::COLOR) + "-" +
323                        layer_name;
324   return result;
325 }
326 
327 /* powerful because it handles both cases when there is material and when there's not */
create_mesh_primitive_list(short material_index,bool has_uvs,bool has_color,Object * ob,Mesh * me,std::string & geom_id,std::vector<BCPolygonNormalsIndices> & norind)328 void GeometryExporter::create_mesh_primitive_list(short material_index,
329                                                   bool has_uvs,
330                                                   bool has_color,
331                                                   Object *ob,
332                                                   Mesh *me,
333                                                   std::string &geom_id,
334                                                   std::vector<BCPolygonNormalsIndices> &norind)
335 {
336 
337   MPoly *mpolys = me->mpoly;
338   MLoop *mloops = me->mloop;
339   int totpolys = me->totpoly;
340 
341   std::vector<unsigned long> vcount_list;
342 
343   bool is_triangulated = collect_vertex_counts_per_poly(me, material_index, vcount_list);
344   int polygon_count = vcount_list.size();
345 
346   /* no faces using this material */
347   if (polygon_count == 0) {
348     fprintf(
349         stderr, "%s: material with index %d is not used.\n", id_name(ob).c_str(), material_index);
350     return;
351   }
352 
353   Material *ma = ob->totcol ? BKE_object_material_get(ob, material_index + 1) : NULL;
354   COLLADASW::PrimitivesBase *primitive_list = create_primitive_list(is_triangulated, mSW);
355 
356   /* sets count attribute in <polylist> */
357   primitive_list->setCount(polygon_count);
358 
359   /* sets material name */
360   if (ma) {
361     std::string material_id = get_material_id(ma);
362     std::ostringstream ostr;
363     ostr << translate_id(material_id);
364     primitive_list->setMaterial(ostr.str());
365   }
366 
367   COLLADASW::Input vertex_input(COLLADASW::InputSemantic::VERTEX,
368                                 getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX),
369                                 0);
370   COLLADASW::Input normals_input(COLLADASW::InputSemantic::NORMAL,
371                                  getUrlBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL),
372                                  1);
373 
374   COLLADASW::InputList &til = primitive_list->getInputList();
375   til.push_back(vertex_input);
376   til.push_back(normals_input);
377 
378   /* if mesh has uv coords writes <input> for TEXCOORD */
379   int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
380   int active_uv_index = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV);
381   for (int i = 0; i < num_layers; i++) {
382     int layer_index = CustomData_get_layer_index_n(&me->ldata, CD_MLOOPUV, i);
383     if (!this->export_settings.get_active_uv_only() || layer_index == active_uv_index) {
384 
385       // char *name = CustomData_get_layer_name(&me->ldata, CD_MLOOPUV, i);
386       COLLADASW::Input texcoord_input(
387           COLLADASW::InputSemantic::TEXCOORD,
388           makeUrl(makeTexcoordSourceId(geom_id, i, this->export_settings.get_active_uv_only())),
389           2, /* this is only until we have optimized UV sets */
390           (this->export_settings.get_active_uv_only()) ? 0 : layer_index - 1 /* set (0,1,2,...) */
391       );
392       til.push_back(texcoord_input);
393     }
394   }
395 
396   int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
397   if (totlayer_mcol > 0) {
398     int map_index = 0;
399 
400     for (int a = 0; a < totlayer_mcol; a++) {
401       char *layer_name = bc_CustomData_get_layer_name(&me->ldata, CD_MLOOPCOL, a);
402       COLLADASW::Input input4(COLLADASW::InputSemantic::COLOR,
403                               makeUrl(makeVertexColorSourceId(geom_id, layer_name)),
404                               (has_uvs) ? 3 : 2, /* all color layers have same index order */
405                               map_index          /* set number equals color map index */
406       );
407       til.push_back(input4);
408       map_index++;
409     }
410   }
411 
412   /* performs the actual writing */
413   prepareToAppendValues(is_triangulated, *primitive_list, vcount_list);
414 
415   /* <p> */
416   int texindex = 0;
417   for (int i = 0; i < totpolys; i++) {
418     MPoly *p = &mpolys[i];
419     int loop_count = p->totloop;
420 
421     if (p->mat_nr == material_index) {
422       MLoop *l = &mloops[p->loopstart];
423       BCPolygonNormalsIndices normal_indices = norind[i];
424 
425       for (int j = 0; j < loop_count; j++) {
426         primitive_list->appendValues(l[j].v);
427         primitive_list->appendValues(normal_indices[j]);
428         if (has_uvs) {
429           primitive_list->appendValues(texindex + j);
430         }
431 
432         if (has_color) {
433           primitive_list->appendValues(texindex + j);
434         }
435       }
436     }
437 
438     texindex += loop_count;
439   }
440 
441   finish_and_delete_primitive_List(is_triangulated, primitive_list);
442 }
443 
444 /* creates <source> for positions */
createVertsSource(std::string geom_id,Mesh * me)445 void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me)
446 {
447 #if 0
448   int totverts = dm->getNumVerts(dm);
449   MVert *verts = dm->getVertArray(dm);
450 #endif
451   int totverts = me->totvert;
452   MVert *verts = me->mvert;
453 
454   COLLADASW::FloatSourceF source(mSW);
455   source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
456   source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION) +
457                     ARRAY_ID_SUFFIX);
458   source.setAccessorCount(totverts);
459   source.setAccessorStride(3);
460 
461   COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
462   param.push_back("X");
463   param.push_back("Y");
464   param.push_back("Z");
465   /* main function, it creates <source id = "">, <float_array id = ""
466    * count = ""> */
467   source.prepareToAppendValues();
468   /* appends data to <float_array> */
469   int i = 0;
470   for (i = 0; i < totverts; i++) {
471     Vector co;
472     if (export_settings.get_apply_global_orientation()) {
473       bc_add_global_transform(co, verts[i].co, export_settings.get_global_transform());
474     }
475     else {
476       copy_v3_v3(co, verts[i].co);
477     }
478     source.appendValues(co[0], co[1], co[2]);
479   }
480 
481   source.finish();
482 }
483 
createVertexColorSource(std::string geom_id,Mesh * me)484 void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me)
485 {
486   /* Find number of vertex color layers */
487   int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
488   if (totlayer_mcol == 0) {
489     return;
490   }
491 
492   int map_index = 0;
493   for (int a = 0; a < totlayer_mcol; a++) {
494 
495     map_index++;
496     MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(&me->ldata, CD_MLOOPCOL, a);
497 
498     COLLADASW::FloatSourceF source(mSW);
499 
500     char *layer_name = bc_CustomData_get_layer_name(&me->ldata, CD_MLOOPCOL, a);
501     std::string layer_id = makeVertexColorSourceId(geom_id, layer_name);
502     source.setId(layer_id);
503 
504     source.setNodeName(layer_name);
505 
506     source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
507     source.setAccessorCount(me->totloop);
508     source.setAccessorStride(4);
509 
510     COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
511     param.push_back("R");
512     param.push_back("G");
513     param.push_back("B");
514     param.push_back("A");
515 
516     source.prepareToAppendValues();
517 
518     MPoly *mpoly;
519     int i;
520     for (i = 0, mpoly = me->mpoly; i < me->totpoly; i++, mpoly++) {
521       MLoopCol *mlc = mloopcol + mpoly->loopstart;
522       for (int j = 0; j < mpoly->totloop; j++, mlc++) {
523         source.appendValues(mlc->r / 255.0f, mlc->g / 255.0f, mlc->b / 255.0f, mlc->a / 255.0f);
524       }
525     }
526 
527     source.finish();
528   }
529 }
530 
makeTexcoordSourceId(std::string & geom_id,int layer_index,bool is_single_layer)531 std::string GeometryExporter::makeTexcoordSourceId(std::string &geom_id,
532                                                    int layer_index,
533                                                    bool is_single_layer)
534 {
535   char suffix[20];
536   if (is_single_layer) {
537     suffix[0] = '\0';
538   }
539   else {
540     sprintf(suffix, "-%d", layer_index);
541   }
542   return getIdBySemantics(geom_id, COLLADASW::InputSemantic::TEXCOORD) + suffix;
543 }
544 
545 /* creates <source> for texcoords */
createTexcoordsSource(std::string geom_id,Mesh * me)546 void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
547 {
548 
549   int totpoly = me->totpoly;
550   int totuv = me->totloop;
551   MPoly *mpolys = me->mpoly;
552 
553   int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
554 
555   /* write <source> for each layer
556    * each <source> will get id like meshName + "map-channel-1" */
557   int active_uv_index = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV);
558   for (int a = 0; a < num_layers; a++) {
559     int layer_index = CustomData_get_layer_index_n(&me->ldata, CD_MLOOPUV, a);
560     if (!this->export_settings.get_active_uv_only() || layer_index == active_uv_index) {
561       MLoopUV *mloops = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, a);
562 
563       COLLADASW::FloatSourceF source(mSW);
564       std::string layer_id = makeTexcoordSourceId(
565           geom_id, a, this->export_settings.get_active_uv_only());
566       source.setId(layer_id);
567       source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
568 
569       source.setAccessorCount(totuv);
570       source.setAccessorStride(2);
571       COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
572       param.push_back("S");
573       param.push_back("T");
574 
575       source.prepareToAppendValues();
576 
577       for (int index = 0; index < totpoly; index++) {
578         MPoly *mpoly = mpolys + index;
579         MLoopUV *mloop = mloops + mpoly->loopstart;
580         for (int j = 0; j < mpoly->totloop; j++) {
581           source.appendValues(mloop[j].uv[0], mloop[j].uv[1]);
582         }
583       }
584 
585       source.finish();
586     }
587   }
588 }
589 
operator <(const Normal & a,const Normal & b)590 bool operator<(const Normal &a, const Normal &b)
591 {
592   /* only needed to sort normal vectors and find() them later in a map.*/
593   return a.x < b.x || (a.x == b.x && (a.y < b.y || (a.y == b.y && a.z < b.z)));
594 }
595 
596 /* creates <source> for normals */
createNormalsSource(std::string geom_id,Mesh * me,std::vector<Normal> & nor)597 void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal> &nor)
598 {
599 #if 0
600   int totverts = dm->getNumVerts(dm);
601   MVert *verts = dm->getVertArray(dm);
602 #endif
603 
604   COLLADASW::FloatSourceF source(mSW);
605   source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL));
606   source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL) + ARRAY_ID_SUFFIX);
607   source.setAccessorCount((unsigned long)nor.size());
608   source.setAccessorStride(3);
609   COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
610   param.push_back("X");
611   param.push_back("Y");
612   param.push_back("Z");
613 
614   source.prepareToAppendValues();
615 
616   std::vector<Normal>::iterator it;
617   for (it = nor.begin(); it != nor.end(); it++) {
618     Normal &n = *it;
619 
620     Vector no{n.x, n.y, n.z};
621     if (export_settings.get_apply_global_orientation()) {
622       bc_add_global_transform(no, export_settings.get_global_transform());
623     }
624     source.appendValues(no[0], no[1], no[2]);
625   }
626 
627   source.finish();
628 }
629 
create_normals(std::vector<Normal> & normals,std::vector<BCPolygonNormalsIndices> & polygons_normals,Mesh * me)630 void GeometryExporter::create_normals(std::vector<Normal> &normals,
631                                       std::vector<BCPolygonNormalsIndices> &polygons_normals,
632                                       Mesh *me)
633 {
634   std::map<Normal, unsigned int> shared_normal_indices;
635   int last_normal_index = -1;
636 
637   MVert *verts = me->mvert;
638   MLoop *mloops = me->mloop;
639   float(*lnors)[3] = NULL;
640   bool use_custom_normals = false;
641 
642   BKE_mesh_calc_normals_split(me);
643   if (CustomData_has_layer(&me->ldata, CD_NORMAL)) {
644     lnors = (float(*)[3])CustomData_get_layer(&me->ldata, CD_NORMAL);
645     use_custom_normals = true;
646   }
647 
648   for (int poly_index = 0; poly_index < me->totpoly; poly_index++) {
649     MPoly *mpoly = &me->mpoly[poly_index];
650     bool use_vertex_normals = use_custom_normals || mpoly->flag & ME_SMOOTH;
651 
652     if (!use_vertex_normals) {
653       /* For flat faces use face normal as vertex normal: */
654 
655       float vector[3];
656       BKE_mesh_calc_poly_normal(mpoly, mloops + mpoly->loopstart, verts, vector);
657 
658       Normal n = {vector[0], vector[1], vector[2]};
659       normals.push_back(n);
660       last_normal_index++;
661     }
662 
663     BCPolygonNormalsIndices poly_indices;
664     for (int loop_index = 0; loop_index < mpoly->totloop; loop_index++) {
665       unsigned int loop_idx = mpoly->loopstart + loop_index;
666       if (use_vertex_normals) {
667         float normalized[3];
668 
669         if (use_custom_normals) {
670           normalize_v3_v3(normalized, lnors[loop_idx]);
671         }
672         else {
673           normal_short_to_float_v3(normalized, verts[mloops[loop_index].v].no);
674           normalize_v3(normalized);
675         }
676         Normal n = {normalized[0], normalized[1], normalized[2]};
677 
678         if (shared_normal_indices.find(n) != shared_normal_indices.end()) {
679           poly_indices.add_index(shared_normal_indices[n]);
680         }
681         else {
682           last_normal_index++;
683           poly_indices.add_index(last_normal_index);
684           shared_normal_indices[n] = last_normal_index;
685           normals.push_back(n);
686         }
687       }
688       else {
689         poly_indices.add_index(last_normal_index);
690       }
691     }
692 
693     polygons_normals.push_back(poly_indices);
694   }
695 }
696 
getIdBySemantics(std::string geom_id,COLLADASW::InputSemantic::Semantics type,std::string other_suffix)697 std::string GeometryExporter::getIdBySemantics(std::string geom_id,
698                                                COLLADASW::InputSemantic::Semantics type,
699                                                std::string other_suffix)
700 {
701   return geom_id + getSuffixBySemantic(type) + other_suffix;
702 }
703 
getUrlBySemantics(std::string geom_id,COLLADASW::InputSemantic::Semantics type,std::string other_suffix)704 COLLADASW::URI GeometryExporter::getUrlBySemantics(std::string geom_id,
705                                                    COLLADASW::InputSemantic::Semantics type,
706                                                    std::string other_suffix)
707 {
708 
709   std::string id(getIdBySemantics(geom_id, type, other_suffix));
710   return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
711 }
712 
makeUrl(std::string id)713 COLLADASW::URI GeometryExporter::makeUrl(std::string id)
714 {
715   return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
716 }
717