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