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