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