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 freestyle
19  */
20 
21 #include "BlenderFileLoader.h"
22 
23 #include "BLI_utildefines.h"
24 
25 #include "BKE_global.h"
26 #include "BKE_object.h"
27 
28 #include <sstream>
29 
30 namespace Freestyle {
31 
BlenderFileLoader(Render * re,ViewLayer * view_layer,Depsgraph * depsgraph)32 BlenderFileLoader::BlenderFileLoader(Render *re, ViewLayer *view_layer, Depsgraph *depsgraph)
33 {
34   _re = re;
35   _depsgraph = depsgraph;
36   _Scene = NULL;
37   _numFacesRead = 0;
38 #if 0
39   _minEdgeSize = DBL_MAX;
40 #endif
41   _smooth = (view_layer->freestyle_config.flags & FREESTYLE_FACE_SMOOTHNESS_FLAG) != 0;
42   _pRenderMonitor = NULL;
43 }
44 
~BlenderFileLoader()45 BlenderFileLoader::~BlenderFileLoader()
46 {
47   _Scene = NULL;
48 }
49 
Load()50 NodeGroup *BlenderFileLoader::Load()
51 {
52   if (G.debug & G_DEBUG_FREESTYLE) {
53     cout << "\n===  Importing triangular meshes into Blender  ===" << endl;
54   }
55 
56   // creation of the scene root node
57   _Scene = new NodeGroup;
58 
59   _viewplane_left = _re->viewplane.xmin;
60   _viewplane_right = _re->viewplane.xmax;
61   _viewplane_bottom = _re->viewplane.ymin;
62   _viewplane_top = _re->viewplane.ymax;
63 
64   if (_re->clip_start < 0.f) {
65     // Adjust clipping start/end and set up a Z offset when the viewport preview
66     // is used with the orthographic view.  In this case, _re->clip_start is negative,
67     // while Freestyle assumes that imported mesh data are in the camera coordinate
68     // system with the view point located at origin [bug T36009].
69     _z_near = -0.001f;
70     _z_offset = _re->clip_start + _z_near;
71     _z_far = -_re->clip_end + _z_offset;
72   }
73   else {
74     _z_near = -_re->clip_start;
75     _z_far = -_re->clip_end;
76     _z_offset = 0.f;
77   }
78 
79 #if 0
80   if (G.debug & G_DEBUG_FREESTYLE) {
81     cout << "Frustum: l " << _viewplane_left << " r " << _viewplane_right << " b "
82          << _viewplane_bottom << " t " << _viewplane_top << " n " << _z_near << " f " << _z_far
83          << endl;
84   }
85 #endif
86 
87   int id = 0;
88   const eEvaluationMode eval_mode = DEG_get_mode(_depsgraph);
89 
90   DEG_OBJECT_ITER_BEGIN (_depsgraph,
91                          ob,
92                          DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
93                              DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | DEG_ITER_OBJECT_FLAG_VISIBLE |
94                              DEG_ITER_OBJECT_FLAG_DUPLI) {
95     if (_pRenderMonitor && _pRenderMonitor->testBreak()) {
96       break;
97     }
98 
99     if (ob->base_flag & (BASE_HOLDOUT | BASE_INDIRECT_ONLY)) {
100       continue;
101     }
102 
103     if (!(BKE_object_visibility(ob, eval_mode) & OB_VISIBLE_SELF)) {
104       continue;
105     }
106 
107     Mesh *mesh = BKE_object_to_mesh(NULL, ob, false);
108 
109     if (mesh) {
110       insertShapeNode(ob, mesh, ++id);
111       BKE_object_to_mesh_clear(ob);
112     }
113   }
114   DEG_OBJECT_ITER_END;
115 
116   // Return the built scene.
117   return _Scene;
118 }
119 
120 #define CLIPPED_BY_NEAR -1
121 #define NOT_CLIPPED 0
122 #define CLIPPED_BY_FAR 1
123 
124 // check if each vertex of a triangle (V1, V2, V3) is clipped by the near/far plane
125 // and calculate the number of triangles to be generated by clipping
countClippedFaces(float v1[3],float v2[3],float v3[3],int clip[3])126 int BlenderFileLoader::countClippedFaces(float v1[3], float v2[3], float v3[3], int clip[3])
127 {
128   float *v[3];
129   int numClipped, sum, numTris = 0;
130 
131   v[0] = v1;
132   v[1] = v2;
133   v[2] = v3;
134   numClipped = sum = 0;
135   for (int i = 0; i < 3; i++) {
136     if (v[i][2] > _z_near) {
137       clip[i] = CLIPPED_BY_NEAR;
138       numClipped++;
139     }
140     else if (v[i][2] < _z_far) {
141       clip[i] = CLIPPED_BY_FAR;
142       numClipped++;
143     }
144     else {
145       clip[i] = NOT_CLIPPED;
146     }
147 #if 0
148     if (G.debug & G_DEBUG_FREESTYLE) {
149       printf("%d %s\n",
150              i,
151              (clip[i] == NOT_CLIPPED) ? "not" : (clip[i] == CLIPPED_BY_NEAR) ? "near" : "far");
152     }
153 #endif
154     sum += clip[i];
155   }
156   switch (numClipped) {
157     case 0:
158       numTris = 1;  // triangle
159       break;
160     case 1:
161       numTris = 2;  // tetragon
162       break;
163     case 2:
164       if (sum == 0) {
165         numTris = 3;  // pentagon
166       }
167       else {
168         numTris = 1;  // triangle
169       }
170       break;
171     case 3:
172       if (sum == 3 || sum == -3) {
173         numTris = 0;
174       }
175       else {
176         numTris = 2;  // tetragon
177       }
178       break;
179   }
180   return numTris;
181 }
182 
183 // find the intersection point C between the line segment from V1 to V2 and
184 // a clipping plane at depth Z (i.e., the Z component of C is known, while
185 // the X and Y components are unknown).
clipLine(float v1[3],float v2[3],float c[3],float z)186 void BlenderFileLoader::clipLine(float v1[3], float v2[3], float c[3], float z)
187 {
188   // Order v1 and v2 by Z values to make sure that clipLine(P, Q, c, z)
189   // and clipLine(Q, P, c, z) gives exactly the same numerical result.
190   float *p, *q;
191   if (v1[2] < v2[2]) {
192     p = v1;
193     q = v2;
194   }
195   else {
196     p = v2;
197     q = v1;
198   }
199   double d[3];
200   for (int i = 0; i < 3; i++) {
201     d[i] = q[i] - p[i];
202   }
203   double t = (z - p[2]) / d[2];
204   c[0] = p[0] + t * d[0];
205   c[1] = p[1] + t * d[1];
206   c[2] = z;
207 }
208 
209 // clip the triangle (V1, V2, V3) by the near and far clipping plane and
210 // obtain a set of vertices after the clipping.  The number of vertices
211 // is at most 5.
clipTriangle(int numTris,float triCoords[][3],float v1[3],float v2[3],float v3[3],float triNormals[][3],float n1[3],float n2[3],float n3[3],bool edgeMarks[],bool em1,bool em2,bool em3,const int clip[3])212 void BlenderFileLoader::clipTriangle(int numTris,
213                                      float triCoords[][3],
214                                      float v1[3],
215                                      float v2[3],
216                                      float v3[3],
217                                      float triNormals[][3],
218                                      float n1[3],
219                                      float n2[3],
220                                      float n3[3],
221                                      bool edgeMarks[],
222                                      bool em1,
223                                      bool em2,
224                                      bool em3,
225                                      const int clip[3])
226 {
227   float *v[3], *n[3];
228   bool em[3];
229   int i, j, k;
230 
231   v[0] = v1;
232   n[0] = n1;
233   v[1] = v2;
234   n[1] = n2;
235   v[2] = v3;
236   n[2] = n3;
237   em[0] = em1; /* edge mark of the edge between v1 and v2 */
238   em[1] = em2; /* edge mark of the edge between v2 and v3 */
239   em[2] = em3; /* edge mark of the edge between v3 and v1 */
240   k = 0;
241   for (i = 0; i < 3; i++) {
242     j = (i + 1) % 3;
243     if (clip[i] == NOT_CLIPPED) {
244       copy_v3_v3(triCoords[k], v[i]);
245       copy_v3_v3(triNormals[k], n[i]);
246       edgeMarks[k] = em[i];
247       k++;
248       if (clip[j] != NOT_CLIPPED) {
249         clipLine(v[i], v[j], triCoords[k], (clip[j] == CLIPPED_BY_NEAR) ? _z_near : _z_far);
250         copy_v3_v3(triNormals[k], n[j]);
251         edgeMarks[k] = false;
252         k++;
253       }
254     }
255     else if (clip[i] != clip[j]) {
256       if (clip[j] == NOT_CLIPPED) {
257         clipLine(v[i], v[j], triCoords[k], (clip[i] == CLIPPED_BY_NEAR) ? _z_near : _z_far);
258         copy_v3_v3(triNormals[k], n[i]);
259         edgeMarks[k] = em[i];
260         k++;
261       }
262       else {
263         clipLine(v[i], v[j], triCoords[k], (clip[i] == CLIPPED_BY_NEAR) ? _z_near : _z_far);
264         copy_v3_v3(triNormals[k], n[i]);
265         edgeMarks[k] = em[i];
266         k++;
267         clipLine(v[i], v[j], triCoords[k], (clip[j] == CLIPPED_BY_NEAR) ? _z_near : _z_far);
268         copy_v3_v3(triNormals[k], n[j]);
269         edgeMarks[k] = false;
270         k++;
271       }
272     }
273   }
274   BLI_assert(k == 2 + numTris);
275   (void)numTris; /* Ignored in release builds. */
276 }
277 
addTriangle(struct LoaderState * ls,float v1[3],float v2[3],float v3[3],float n1[3],float n2[3],float n3[3],bool fm,bool em1,bool em2,bool em3)278 void BlenderFileLoader::addTriangle(struct LoaderState *ls,
279                                     float v1[3],
280                                     float v2[3],
281                                     float v3[3],
282                                     float n1[3],
283                                     float n2[3],
284                                     float n3[3],
285                                     bool fm,
286                                     bool em1,
287                                     bool em2,
288                                     bool em3)
289 {
290   float *fv[3], *fn[3];
291 #if 0
292   float len;
293 #endif
294   unsigned int i, j;
295   IndexedFaceSet::FaceEdgeMark marks = 0;
296 
297   // initialize the bounding box by the first vertex
298   if (ls->currentIndex == 0) {
299     copy_v3_v3(ls->minBBox, v1);
300     copy_v3_v3(ls->maxBBox, v1);
301   }
302 
303   fv[0] = v1;
304   fn[0] = n1;
305   fv[1] = v2;
306   fn[1] = n2;
307   fv[2] = v3;
308   fn[2] = n3;
309   for (i = 0; i < 3; i++) {
310 
311     copy_v3_v3(ls->pv, fv[i]);
312     copy_v3_v3(ls->pn, fn[i]);
313 
314     // update the bounding box
315     for (j = 0; j < 3; j++) {
316       if (ls->minBBox[j] > ls->pv[j]) {
317         ls->minBBox[j] = ls->pv[j];
318       }
319 
320       if (ls->maxBBox[j] < ls->pv[j]) {
321         ls->maxBBox[j] = ls->pv[j];
322       }
323     }
324 
325 #if 0
326     len = len_v3v3(fv[i], fv[(i + 1) % 3]);
327     if (_minEdgeSize > len) {
328       _minEdgeSize = len;
329     }
330 #endif
331 
332     *ls->pvi = ls->currentIndex;
333     *ls->pni = ls->currentIndex;
334     *ls->pmi = ls->currentMIndex;
335 
336     ls->currentIndex += 3;
337     ls->pv += 3;
338     ls->pn += 3;
339 
340     ls->pvi++;
341     ls->pni++;
342     ls->pmi++;
343   }
344 
345   if (fm) {
346     marks |= IndexedFaceSet::FACE_MARK;
347   }
348   if (em1) {
349     marks |= IndexedFaceSet::EDGE_MARK_V1V2;
350   }
351   if (em2) {
352     marks |= IndexedFaceSet::EDGE_MARK_V2V3;
353   }
354   if (em3) {
355     marks |= IndexedFaceSet::EDGE_MARK_V3V1;
356   }
357   *(ls->pm++) = marks;
358 }
359 
360 // With A, B and P indicating the three vertices of a given triangle, returns:
361 // 1 if points A and B are in the same position in the 3D space;
362 // 2 if the distance between point P and line segment AB is zero; and
363 // zero otherwise.
testDegenerateTriangle(float v1[3],float v2[3],float v3[3])364 int BlenderFileLoader::testDegenerateTriangle(float v1[3], float v2[3], float v3[3])
365 {
366   const float eps = 1.0e-6;
367   const float eps_sq = eps * eps;
368 
369 #if 0
370   float area = area_tri_v3(v1, v2, v3);
371   bool verbose = (area < 1.0e-6);
372 #endif
373 
374   if (equals_v3v3(v1, v2) || equals_v3v3(v2, v3) || equals_v3v3(v1, v3)) {
375 #if 0
376     if (verbose && G.debug & G_DEBUG_FREESTYLE) {
377       printf("BlenderFileLoader::testDegenerateTriangle = 1\n");
378     }
379 #endif
380     return 1;
381   }
382   if (dist_squared_to_line_segment_v3(v1, v2, v3) < eps_sq ||
383       dist_squared_to_line_segment_v3(v2, v1, v3) < eps_sq ||
384       dist_squared_to_line_segment_v3(v3, v1, v2) < eps_sq) {
385 #if 0
386     if (verbose && G.debug & G_DEBUG_FREESTYLE) {
387       printf("BlenderFileLoader::testDegenerateTriangle = 2\n");
388     }
389 #endif
390     return 2;
391   }
392 #if 0
393   if (verbose && G.debug & G_DEBUG_FREESTYLE) {
394     printf("BlenderFileLoader::testDegenerateTriangle = 0\n");
395   }
396 #endif
397   return 0;
398 }
399 
testEdgeMark(Mesh * me,FreestyleEdge * fed,const MLoopTri * lt,int i)400 static bool testEdgeMark(Mesh *me, FreestyleEdge *fed, const MLoopTri *lt, int i)
401 {
402   MLoop *mloop = &me->mloop[lt->tri[i]];
403   MLoop *mloop_next = &me->mloop[lt->tri[(i + 1) % 3]];
404   MEdge *medge = &me->medge[mloop->e];
405 
406   if (!ELEM(mloop_next->v, medge->v1, medge->v2)) {
407     /* Not an edge in the original mesh before triangulation. */
408     return false;
409   }
410 
411   return (fed[mloop->e].flag & FREESTYLE_EDGE_MARK) != 0;
412 }
413 
insertShapeNode(Object * ob,Mesh * me,int id)414 void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id)
415 {
416   char *name = ob->id.name + 2;
417 
418   // Compute loop triangles
419   int tottri = poly_to_tri_count(me->totpoly, me->totloop);
420   MLoopTri *mlooptri = (MLoopTri *)MEM_malloc_arrayN(tottri, sizeof(*mlooptri), __func__);
421   BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, mlooptri);
422 
423   // Compute loop normals
424   BKE_mesh_calc_normals_split(me);
425   float(*lnors)[3] = NULL;
426 
427   if (CustomData_has_layer(&me->ldata, CD_NORMAL)) {
428     lnors = (float(*)[3])CustomData_get_layer(&me->ldata, CD_NORMAL);
429   }
430 
431   // Get other mesh data
432   MVert *mvert = me->mvert;
433   MLoop *mloop = me->mloop;
434   MPoly *mpoly = me->mpoly;
435   FreestyleEdge *fed = (FreestyleEdge *)CustomData_get_layer(&me->edata, CD_FREESTYLE_EDGE);
436   FreestyleFace *ffa = (FreestyleFace *)CustomData_get_layer(&me->pdata, CD_FREESTYLE_FACE);
437 
438   // Compute view matrix
439   Object *ob_camera_eval = DEG_get_evaluated_object(_depsgraph, RE_GetCamera(_re));
440   float viewinv[4][4], viewmat[4][4];
441   RE_GetCameraModelMatrix(_re, ob_camera_eval, viewinv);
442   invert_m4_m4(viewmat, viewinv);
443 
444   // Compute matrix including camera transform
445   float obmat[4][4], nmat[4][4];
446   mul_m4_m4m4(obmat, viewmat, ob->obmat);
447   invert_m4_m4(nmat, obmat);
448   transpose_m4(nmat);
449 
450   // We count the number of triangles after the clipping by the near and far view
451   // planes is applied (Note: mesh vertices are in the camera coordinate system).
452   unsigned numFaces = 0;
453   float v1[3], v2[3], v3[3];
454   float n1[3], n2[3], n3[3], facenormal[3];
455   int clip[3];
456   for (int a = 0; a < tottri; a++) {
457     const MLoopTri *lt = &mlooptri[a];
458 
459     copy_v3_v3(v1, mvert[mloop[lt->tri[0]].v].co);
460     copy_v3_v3(v2, mvert[mloop[lt->tri[1]].v].co);
461     copy_v3_v3(v3, mvert[mloop[lt->tri[2]].v].co);
462 
463     mul_m4_v3(obmat, v1);
464     mul_m4_v3(obmat, v2);
465     mul_m4_v3(obmat, v3);
466 
467     v1[2] += _z_offset;
468     v2[2] += _z_offset;
469     v3[2] += _z_offset;
470 
471     numFaces += countClippedFaces(v1, v2, v3, clip);
472   }
473 #if 0
474   if (G.debug & G_DEBUG_FREESTYLE) {
475     cout << "numFaces " << numFaces << endl;
476   }
477 #endif
478   if (numFaces == 0) {
479     MEM_freeN(mlooptri);
480     return;
481   }
482 
483   // We allocate memory for the meshes to be imported
484   NodeGroup *currentMesh = new NodeGroup;
485   NodeShape *shape = new NodeShape;
486 
487   unsigned vSize = 3 * 3 * numFaces;
488   float *vertices = new float[vSize];
489   unsigned nSize = vSize;
490   float *normals = new float[nSize];
491   unsigned *numVertexPerFaces = new unsigned[numFaces];
492   vector<Material *> meshMaterials;
493   vector<FrsMaterial> meshFrsMaterials;
494 
495   IndexedFaceSet::TRIANGLES_STYLE *faceStyle = new IndexedFaceSet::TRIANGLES_STYLE[numFaces];
496   unsigned i;
497   for (i = 0; i < numFaces; i++) {
498     faceStyle[i] = IndexedFaceSet::TRIANGLES;
499     numVertexPerFaces[i] = 3;
500   }
501 
502   IndexedFaceSet::FaceEdgeMark *faceEdgeMarks = new IndexedFaceSet::FaceEdgeMark[numFaces];
503 
504   unsigned viSize = 3 * numFaces;
505   unsigned *VIndices = new unsigned[viSize];
506   unsigned niSize = viSize;
507   unsigned *NIndices = new unsigned[niSize];
508   unsigned *MIndices = new unsigned[viSize];  // Material Indices
509 
510   struct LoaderState ls;
511   ls.pv = vertices;
512   ls.pn = normals;
513   ls.pm = faceEdgeMarks;
514   ls.pvi = VIndices;
515   ls.pni = NIndices;
516   ls.pmi = MIndices;
517   ls.currentIndex = 0;
518   ls.currentMIndex = 0;
519 
520   FrsMaterial tmpMat;
521 
522   // We parse the vlak nodes again and import meshes while applying the clipping
523   // by the near and far view planes.
524   for (int a = 0; a < tottri; a++) {
525     const MLoopTri *lt = &mlooptri[a];
526     const MPoly *mp = &mpoly[lt->poly];
527     Material *mat = BKE_object_material_get(ob, mp->mat_nr + 1);
528 
529     copy_v3_v3(v1, mvert[mloop[lt->tri[0]].v].co);
530     copy_v3_v3(v2, mvert[mloop[lt->tri[1]].v].co);
531     copy_v3_v3(v3, mvert[mloop[lt->tri[2]].v].co);
532 
533     mul_m4_v3(obmat, v1);
534     mul_m4_v3(obmat, v2);
535     mul_m4_v3(obmat, v3);
536 
537     v1[2] += _z_offset;
538     v2[2] += _z_offset;
539     v3[2] += _z_offset;
540 
541     if (_smooth && (mp->flag & ME_SMOOTH) && lnors) {
542       copy_v3_v3(n1, lnors[lt->tri[0]]);
543       copy_v3_v3(n2, lnors[lt->tri[1]]);
544       copy_v3_v3(n3, lnors[lt->tri[2]]);
545 
546       mul_mat3_m4_v3(nmat, n1);
547       mul_mat3_m4_v3(nmat, n2);
548       mul_mat3_m4_v3(nmat, n3);
549 
550       normalize_v3(n1);
551       normalize_v3(n2);
552       normalize_v3(n3);
553     }
554     else {
555       normal_tri_v3(facenormal, v3, v2, v1);
556 
557       copy_v3_v3(n1, facenormal);
558       copy_v3_v3(n2, facenormal);
559       copy_v3_v3(n3, facenormal);
560     }
561 
562     unsigned int numTris = countClippedFaces(v1, v2, v3, clip);
563     if (numTris == 0) {
564       continue;
565     }
566 
567     bool fm = (ffa) ? (ffa[lt->poly].flag & FREESTYLE_FACE_MARK) != 0 : false;
568     bool em1 = false, em2 = false, em3 = false;
569 
570     if (fed) {
571       em1 = testEdgeMark(me, fed, lt, 0);
572       em2 = testEdgeMark(me, fed, lt, 1);
573       em3 = testEdgeMark(me, fed, lt, 2);
574     }
575 
576     if (mat) {
577       tmpMat.setLine(mat->line_col[0], mat->line_col[1], mat->line_col[2], mat->line_col[3]);
578       tmpMat.setDiffuse(mat->r, mat->g, mat->b, 1.0f);
579       tmpMat.setSpecular(mat->specr, mat->specg, mat->specb, 1.0f);
580       tmpMat.setShininess(128.f);
581       tmpMat.setPriority(mat->line_priority);
582     }
583 
584     if (meshMaterials.empty()) {
585       meshMaterials.push_back(mat);
586       meshFrsMaterials.push_back(tmpMat);
587       shape->setFrsMaterial(tmpMat);
588     }
589     else {
590       // find if the Blender material is already in the list
591       unsigned int i = 0;
592       bool found = false;
593 
594       for (vector<Material *>::iterator it = meshMaterials.begin(), itend = meshMaterials.end();
595            it != itend;
596            it++, i++) {
597         if (*it == mat) {
598           ls.currentMIndex = i;
599           found = true;
600           break;
601         }
602       }
603 
604       if (!found) {
605         meshMaterials.push_back(mat);
606         meshFrsMaterials.push_back(tmpMat);
607         ls.currentMIndex = meshFrsMaterials.size() - 1;
608       }
609     }
610 
611     float triCoords[5][3], triNormals[5][3];
612     bool edgeMarks[5];  // edgeMarks[i] is for the edge between i-th and (i+1)-th vertices
613 
614     clipTriangle(
615         numTris, triCoords, v1, v2, v3, triNormals, n1, n2, n3, edgeMarks, em1, em2, em3, clip);
616     for (i = 0; i < numTris; i++) {
617       addTriangle(&ls,
618                   triCoords[0],
619                   triCoords[i + 1],
620                   triCoords[i + 2],
621                   triNormals[0],
622                   triNormals[i + 1],
623                   triNormals[i + 2],
624                   fm,
625                   (i == 0) ? edgeMarks[0] : false,
626                   edgeMarks[i + 1],
627                   (i == numTris - 1) ? edgeMarks[i + 2] : false);
628       _numFacesRead++;
629     }
630   }
631 
632   MEM_freeN(mlooptri);
633 
634   // We might have several times the same vertex. We want a clean
635   // shape with no real-vertex. Here, we are making a cleaning pass.
636   float *cleanVertices = NULL;
637   unsigned int cvSize;
638   unsigned int *cleanVIndices = NULL;
639 
640   GeomCleaner::CleanIndexedVertexArray(
641       vertices, vSize, VIndices, viSize, &cleanVertices, &cvSize, &cleanVIndices);
642 
643   float *cleanNormals = NULL;
644   unsigned int cnSize;
645   unsigned int *cleanNIndices = NULL;
646 
647   GeomCleaner::CleanIndexedVertexArray(
648       normals, nSize, NIndices, niSize, &cleanNormals, &cnSize, &cleanNIndices);
649 
650   // format materials array
651   FrsMaterial **marray = new FrsMaterial *[meshFrsMaterials.size()];
652   unsigned int mindex = 0;
653   for (vector<FrsMaterial>::iterator m = meshFrsMaterials.begin(), mend = meshFrsMaterials.end();
654        m != mend;
655        ++m) {
656     marray[mindex] = new FrsMaterial(*m);
657     ++mindex;
658   }
659 
660   // deallocates memory:
661   delete[] vertices;
662   delete[] normals;
663   delete[] VIndices;
664   delete[] NIndices;
665 
666   // Fix for degenerated triangles
667   // A degenerate triangle is a triangle such that
668   // 1) A and B are in the same position in the 3D space; or
669   // 2) the distance between point P and line segment AB is zero.
670   // Only those degenerate triangles in the second form are resolved here
671   // by adding a small offset to P, whereas those in the first form are
672   // addressed later in WShape::MakeFace().
673   vector<detri_t> detriList;
674   Vec3r zero(0.0, 0.0, 0.0);
675   unsigned vi0, vi1, vi2;
676   for (i = 0; i < viSize; i += 3) {
677     detri_t detri;
678     vi0 = cleanVIndices[i];
679     vi1 = cleanVIndices[i + 1];
680     vi2 = cleanVIndices[i + 2];
681     Vec3r v0(cleanVertices[vi0], cleanVertices[vi0 + 1], cleanVertices[vi0 + 2]);
682     Vec3r v1(cleanVertices[vi1], cleanVertices[vi1 + 1], cleanVertices[vi1 + 2]);
683     Vec3r v2(cleanVertices[vi2], cleanVertices[vi2 + 1], cleanVertices[vi2 + 2]);
684     if (v0 == v1 || v0 == v2 || v1 == v2) {
685       continue;  // do nothing for now
686     }
687     if (GeomUtils::distPointSegment<Vec3r>(v0, v1, v2) < 1.0e-6) {
688       detri.viP = vi0;
689       detri.viA = vi1;
690       detri.viB = vi2;
691     }
692     else if (GeomUtils::distPointSegment<Vec3r>(v1, v0, v2) < 1.0e-6) {
693       detri.viP = vi1;
694       detri.viA = vi0;
695       detri.viB = vi2;
696     }
697     else if (GeomUtils::distPointSegment<Vec3r>(v2, v0, v1) < 1.0e-6) {
698       detri.viP = vi2;
699       detri.viA = vi0;
700       detri.viB = vi1;
701     }
702     else {
703       continue;
704     }
705 
706     detri.v = zero;
707     detri.n = 0;
708     for (unsigned int j = 0; j < viSize; j += 3) {
709       if (i == j) {
710         continue;
711       }
712       vi0 = cleanVIndices[j];
713       vi1 = cleanVIndices[j + 1];
714       vi2 = cleanVIndices[j + 2];
715       Vec3r v0(cleanVertices[vi0], cleanVertices[vi0 + 1], cleanVertices[vi0 + 2]);
716       Vec3r v1(cleanVertices[vi1], cleanVertices[vi1 + 1], cleanVertices[vi1 + 2]);
717       Vec3r v2(cleanVertices[vi2], cleanVertices[vi2 + 1], cleanVertices[vi2 + 2]);
718       if (detri.viP == vi0 && (detri.viA == vi1 || detri.viB == vi1)) {
719         detri.v += (v2 - v0);
720         detri.n++;
721       }
722       else if (detri.viP == vi0 && (detri.viA == vi2 || detri.viB == vi2)) {
723         detri.v += (v1 - v0);
724         detri.n++;
725       }
726       else if (detri.viP == vi1 && (detri.viA == vi0 || detri.viB == vi0)) {
727         detri.v += (v2 - v1);
728         detri.n++;
729       }
730       else if (detri.viP == vi1 && (detri.viA == vi2 || detri.viB == vi2)) {
731         detri.v += (v0 - v1);
732         detri.n++;
733       }
734       else if (detri.viP == vi2 && (detri.viA == vi0 || detri.viB == vi0)) {
735         detri.v += (v1 - v2);
736         detri.n++;
737       }
738       else if (detri.viP == vi2 && (detri.viA == vi1 || detri.viB == vi1)) {
739         detri.v += (v0 - v2);
740         detri.n++;
741       }
742     }
743     if (detri.n > 0) {
744       detri.v.normalizeSafe();
745     }
746     detriList.push_back(detri);
747   }
748 
749   if (!detriList.empty()) {
750     vector<detri_t>::iterator v;
751     for (v = detriList.begin(); v != detriList.end(); v++) {
752       detri_t detri = (*v);
753       if (detri.n == 0) {
754         cleanVertices[detri.viP] = cleanVertices[detri.viA];
755         cleanVertices[detri.viP + 1] = cleanVertices[detri.viA + 1];
756         cleanVertices[detri.viP + 2] = cleanVertices[detri.viA + 2];
757       }
758       else if (detri.v.norm() > 0.0) {
759         cleanVertices[detri.viP] += 1.0e-5 * detri.v.x();
760         cleanVertices[detri.viP + 1] += 1.0e-5 * detri.v.y();
761         cleanVertices[detri.viP + 2] += 1.0e-5 * detri.v.z();
762       }
763     }
764     if (G.debug & G_DEBUG_FREESTYLE) {
765       printf("Warning: Object %s contains %lu degenerated triangle%s (strokes may be incorrect)\n",
766              name,
767              (long unsigned int)detriList.size(),
768              (detriList.size() > 1) ? "s" : "");
769     }
770   }
771 
772   // Create the IndexedFaceSet with the retrieved attributes
773   IndexedFaceSet *rep;
774   rep = new IndexedFaceSet(cleanVertices,
775                            cvSize,
776                            cleanNormals,
777                            cnSize,
778                            marray,
779                            meshFrsMaterials.size(),
780                            0,
781                            0,
782                            numFaces,
783                            numVertexPerFaces,
784                            faceStyle,
785                            faceEdgeMarks,
786                            cleanVIndices,
787                            viSize,
788                            cleanNIndices,
789                            niSize,
790                            MIndices,
791                            viSize,
792                            0,
793                            0,
794                            0);
795   // sets the id of the rep
796   rep->setId(Id(id, 0));
797   rep->setName(ob->id.name + 2);
798   rep->setLibraryPath(ob->id.lib ? ob->id.lib->filepath : "");
799 
800   const BBox<Vec3r> bbox = BBox<Vec3r>(Vec3r(ls.minBBox[0], ls.minBBox[1], ls.minBBox[2]),
801                                        Vec3r(ls.maxBBox[0], ls.maxBBox[1], ls.maxBBox[2]));
802   rep->setBBox(bbox);
803   shape->AddRep(rep);
804 
805   currentMesh->AddChild(shape);
806   _Scene->AddChild(currentMesh);
807 }
808 
809 } /* namespace Freestyle */
810