1 
2 /*
3      PLIB - A Suite of Portable Game Libraries
4      Copyright (C) 1998,2002  Steve Baker
5 
6      This library is free software; you can redistribute it and/or
7      modify it under the terms of the GNU Library General Public
8      License as published by the Free Software Foundation; either
9      version 2 of the License, or (at your option) any later version.
10 
11      This library is distributed in the hope that it will be useful,
12      but WITHOUT ANY WARRANTY; without even the implied warranty of
13      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14      Library General Public License for more details.
15 
16      You should have received a copy of the GNU Library General Public
17      License along with this library; if not, write to the Free Software
18      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 
20      For further information visit http://plib.sourceforge.net
21 
22      $Id: ssgLoaderWriterStuff.cxx 2060 2006-01-05 20:54:15Z fayjf $
23 */
24 
25 // ssgLoaderWriterStuff.cxx
26 // Here you will find classes and functions you can use to
27 // implement loaders and writers for ssg
28 // Also, there is the parser for loading ASCII files, which
29 // has its own file ssgParser.cxx and there are functions like
30 // the stripifier that are usefull not only for loaders/writers.
31 //
32 // 1. Version written by Wolfram Kuss (Wolfram.Kuss@t-online.de)
33 // in Nov of 2000
34 // Distributed with Steve Bakers plib under the LGPL licence
35 
36 #include "ssgLocal.h"
37 #include "ssgLoaderWriterStuff.h"
38 
39 
40 #undef ABS
41 #undef MIN
42 #undef MAX
43 #define ABS(x) ((x) >= 0 ? (x) : -(x))
44 #define MIN(a,b) ((a) <= (b) ? (a) : (b))
45 #define MAX(a,b) ((a) >= (b) ? (a) : (b))
46 #define MIN3(a,b,c) ((a) <= (b) ? MIN(a,c) : MIN(b,c))
47 #define MAX3(a,b,c) ((a) >= (b) ? MAX(a,c) : MAX(b,c))
48 
49 // texture coord epsilon
50 #define TC_EPSILON 0.01
51 
52 
53 sgVec4 currentDiffuse;
54 
55 // ***********************************************************************
56 // ********************  small utility functions  ************************
57 // ***********************************************************************
58 
ssgAccumVerticesAndFaces(ssgEntity * node,sgMat4 transform,ssgVertexArray * vertices,ssgIndexArray * indices,SGfloat epsilon,ssgSimpleStateArray * ssa,ssgIndexArray * materialIndices,ssgTexCoordArray * texCoordArray)59 void ssgAccumVerticesAndFaces( ssgEntity* node, sgMat4 transform, ssgVertexArray* vertices,
60 			       ssgIndexArray*  indices, SGfloat epsilon, ssgSimpleStateArray* ssa,
61 			       ssgIndexArray*  materialIndices, ssgTexCoordArray *texCoordArray)
62 // Accumulates all vertices and Faces (indexes of vertices making up faces)
63 // from node and any node below.
64 // Calls itself recursively.
65 // If indices is NULL, no face info is accumulated
66 // if epsilon is < 0.0, it is ignored. Else vertices are only accumulated if
67 // there is no vertex inside epsilon yet
68 {
69 
70    assert( vertices != NULL );
71    assert( (epsilon < 0.0) || (indices == NULL) ); // sorry: using epsilon AND using indices not implemented
72    if ( ssa != NULL ) { assert( indices != NULL ); }
73    assert ( ((ssa==NULL) && (materialIndices==NULL)) || ((ssa!=NULL) && (materialIndices!=NULL)));
74    if ( node->isAKindOf( ssgTypeTransform() ) ) {
75       sgMat4 local_transform;
76       ssgTransform *t_node = (ssgTransform*)node;
77 
78       t_node->getTransform(local_transform);
79       sgPostMultMat4( local_transform, transform );
80 
81       for (ssgEntity* kid = t_node->getKid(0); kid != NULL;
82 	   kid = t_node->getNextKid()) {
83 	 ssgAccumVerticesAndFaces( kid, local_transform, vertices, indices, epsilon, ssa, materialIndices, texCoordArray);
84       }
85    }
86    else if ( node->isAKindOf( ssgTypeBranch() ) ) {
87       ssgBranch *b_node = (ssgBranch*)node;
88       for (ssgEntity* kid = b_node->getKid(0); kid != NULL;
89 	   kid = b_node->getNextKid()) {
90 	 ssgAccumVerticesAndFaces( kid, transform, vertices, indices, epsilon, ssa, materialIndices, texCoordArray);
91       }
92    }
93    else if ( node->isAKindOf( ssgTypeLeaf() ) ) {
94       ssgLeaf* l_node = (ssgLeaf*)node;
95       int i, vert_low = vertices->getNum();
96 
97       int useTexture = FALSE;
98       if ( texCoordArray )
99 	if ( l_node->getState() )
100 	  if (l_node->getState()->isAKindOf(ssgTypeSimpleState()))
101 	    {
102 	       ssgSimpleState * ss = (ssgSimpleState *) l_node->getState();
103 	       if ( ss->isEnabled ( GL_TEXTURE_2D ) )
104 // wk kludge!!!						if ( l_node -> getNumTexCoords () == l_node -> getNumVertices() )
105 		 useTexture = TRUE;
106 	    }
107 
108       for (i = 0; i < l_node->getNumVertices(); i++) {
109 	 sgVec3 new_vertex;
110 	 sgXformVec3(new_vertex, l_node->getVertex(i), transform);
111 
112 	 if ( epsilon < 0.0 )
113 	   {
114 	      vertices->add(new_vertex);
115 	      if ( useTexture )
116 		texCoordArray ->add ( l_node->getTexCoord(i) );
117 	      else if ( texCoordArray )
118 		texCoordArray ->add ( _ssgTexCoord00 );
119 	   }
120 	 else
121 	   {
122 	      int j, bFound = FALSE, nv1 = vertices -> getNum ();
123 	      for ( j = 0; j < nv1; j++)
124 		{
125 		   float *oldvertex = vertices -> get(j);
126 		   if (( new_vertex[0] - oldvertex[0] > -epsilon) &&
127 		       ( new_vertex[0] - oldvertex[0] < epsilon) &&
128 		       ( new_vertex[1] - oldvertex[1] > -epsilon) &&
129 		       ( new_vertex[1] - oldvertex[1] < epsilon) &&
130 		       ( new_vertex[2] - oldvertex[2] > -epsilon) &&
131 		       ( new_vertex[2] - oldvertex[2] < epsilon))
132 		     {
133 			float *f = 0;
134 			if ( useTexture )
135 			  {
136 			     assert( texCoordArray ); // if texCoordArray would be NULL, useTexture would not be set.
137 			     f = texCoordArray -> get(j);
138 			  }
139 			if ( !useTexture || ((l_node->getTexCoord(i)[0] == f[0]) &&
140 					     (l_node->getTexCoord(i)[1] == f[1])))
141 			  {
142 			     bFound = TRUE;
143 			     break;
144 			  }
145 		     }
146 		}
147 	      if ( ! bFound )
148 		{
149 		   vertices -> add ( new_vertex );
150 		   if ( useTexture )
151 		     texCoordArray ->add ( l_node->getTexCoord(i) );
152 		   else if ( texCoordArray )
153 		     texCoordArray ->add ( _ssgTexCoord00 );
154 		}
155 	   }
156       }
157 
158       if ( indices != NULL )
159 	{
160 	   int index=-1;
161 	   if ( ssa != NULL )
162 	     {
163 		ssgState *s = l_node->getState();
164 		if ( s != NULL )
165 		  { index = ssa->findIndex (reinterpret_cast <class ssgSimpleState *> (s) );
166 		     if ( index < 0 )
167 		       { ssa -> add(reinterpret_cast <class ssgSimpleState *> (s) );
168 			  index = ssa->getNum()-1;
169 		       }
170 		  }
171 	     }
172 	   for (i = 0; i < l_node->getNumTriangles(); i++) {
173 	      short v1, v2, v3;
174 	      l_node->getTriangle(i, &v1, &v2, &v3);
175 	      indices->add( vert_low + v1 );
176 	      indices->add( vert_low + v2 );
177 	      indices->add( vert_low + v3 );
178 	      if ( materialIndices != NULL )
179 		materialIndices->add(index); // index is -1 for leafs without state
180 	   }
181 	}
182    }
183    if ( texCoordArray )
184      {
185 	assert( vertices->getNum() == texCoordArray->getNum() );
186      }
187 } ;
188 
189 
190 /*
191   ssgTriangulate - triangulate a simple polygon.
192 */
193 
triangulateConcave(sgVec3 * coords,int * w,int n,int x,int y,int * tris)194 static int triangulateConcave(sgVec3 *coords, int *w, int n, int x, int y, int *tris)
195 {
196    struct Vtx {
197       int index;
198       float x, y;
199       Vtx *next;
200    };
201 
202    Vtx buf[16], *arr, *p0, *p1, *p2, *m0, *m1, *m2, *t;
203    int i, chk, num_tris;
204    float a0, a1, a2, b0, b1, b2, c0, c1, c2;
205 
206    /* construct a circular linked list of the vertices */
207    arr = (n > 16) ? new Vtx [ n ] : buf;
208    p0 = &arr[0];
209    p0->index = w ? w[0] : 0;
210    p0->x = coords[p0->index][x];
211    p0->y = coords[p0->index][y];
212    p1 = p0;
213    p2 = 0;
214    for (i = 1; i < n; i++) {
215       p2 = &arr[i];
216       p2->index = w ? w[i] : i;
217       p2->x = coords[p2->index][x];
218       p2->y = coords[p2->index][y];
219       p1->next = p2;
220       p1 = p2;
221    }
222    p2->next = p0;
223 
224    m0 = p0;
225    m1 = p1 = p0->next;
226    m2 = p2 = p1->next;
227    chk = 0;
228    num_tris = 0;
229 
230    while (p0 != p2->next) {
231       if (chk && m0 == p0 && m1 == p1 && m2 == p2) {
232 	 /* no suitable vertex found.. */
233          ulSetError(UL_WARNING, "ssgTriangulate: Self-intersecting polygon.");
234 	 if (arr != buf)
235 	   delete [] arr;
236          return 0;
237       }
238       chk = 1;
239 
240       a0 = p1->y - p2->y;
241       a1 = p2->y - p0->y;
242       a2 = p0->y - p1->y;
243       b0 = p2->x - p1->x;
244       b1 = p0->x - p2->x;
245       b2 = p1->x - p0->x;
246 
247       if (b0 * a2 - b2 * a0 < 0) {
248 	 /* current angle is concave */
249          p0 = p1;
250          p1 = p2;
251          p2 = p2->next;
252       }
253       else {
254 	 /* current angle is convex */
255          float xmin = MIN3(p0->x, p1->x, p2->x);
256          float xmax = MAX3(p0->x, p1->x, p2->x);
257          float ymin = MIN3(p0->y, p1->y, p2->y);
258          float ymax = MAX3(p0->y, p1->y, p2->y);
259 
260 	 c0 = p1->x * p2->y - p2->x * p1->y;
261 	 c1 = p2->x * p0->y - p0->x * p2->y;
262 	 c2 = p0->x * p1->y - p1->x * p0->y;
263 
264          for (t = p2->next; t != p0; t = t->next) {
265 	    /* see if the triangle contains this vertex */
266             if (xmin <= t->x && t->x <= xmax &&
267                 ymin <= t->y && t->y <= ymax &&
268 		a0 * t->x + b0 * t->y + c0 > 0 &&
269 		a1 * t->x + b1 * t->y + c1 > 0 &&
270 		a2 * t->x + b2 * t->y + c2 > 0)
271 	       break;
272 	 }
273 
274          if (t != p0) {
275             p0 = p1;
276             p1 = p2;
277             p2 = p2->next;
278          }
279          else {
280 	    /* extract this triangle */
281 	    tris[3 * num_tris + 0] = p0->index;
282 	    tris[3 * num_tris + 1] = p1->index;
283 	    tris[3 * num_tris + 2] = p2->index;
284 	    num_tris++;
285 
286 	    p0->next = p1 = p2;
287 	    p2 = p2->next;
288 
289             m0 = p0;
290             m1 = p1;
291             m2 = p2;
292             chk = 0;
293          }
294       }
295    }
296 
297    tris[3 * num_tris + 0] = p0->index;
298    tris[3 * num_tris + 1] = p1->index;
299    tris[3 * num_tris + 2] = p2->index;
300    num_tris++;
301 
302    if (arr != buf)
303      delete [] arr;
304 
305    return num_tris;
306 }
307 
_ssgTriangulate(sgVec3 * coords,int * w,int n,int * tris)308 int _ssgTriangulate( sgVec3 *coords, int *w, int n, int *tris )
309 {
310    float *a, *b;
311    int i, x, y;
312 
313    /* trivial case */
314    if (n <= 3) {
315       if (n == 3) {
316 	 tris[0] = w ? w[0] : 0;
317 	 tris[1] = w ? w[1] : 1;
318 	 tris[2] = w ? w[2] : 2;
319 	 return 1;
320       }
321       ulSetError(UL_WARNING, "ssgTriangulate: Invalid number of vertices (%d).", n);
322       return 0;
323    }
324 
325    /* compute areas */
326    {
327       float s[3], t[3];
328       int swap;
329 
330       s[0] = s[1] = s[2] = 0;
331       b = coords[w ? w[n - 1] : n - 1];
332 
333       for (i = 0; i < n; i++) {
334 	 a = b;
335 	 b = coords[w ? w[i] : i];
336 	 s[0] += a[1] * b[2] - a[2] * b[1];
337 	 s[1] += a[2] * b[0] - a[0] * b[2];
338 	 s[2] += a[0] * b[1] - a[1] * b[0];
339       }
340 
341       /* select largest area */
342       t[0] = ABS(s[0]);
343       t[1] = ABS(s[1]);
344       t[2] = ABS(s[2]);
345       i = t[0] > t[1] ? t[0] > t[2] ? 0 : 2 : t[1] > t[2] ? 1 : 2;
346       swap = (s[i] < 0); /* swap coordinates if clockwise */
347       x = (i + 1 + swap) % 3;
348       y = (i + 2 - swap) % 3;
349    }
350 
351    /* concave check */
352    {
353       float x0, y0, x1, y1;
354 
355       a = coords[w ? w[n - 2] : n - 2];
356       b = coords[w ? w[n - 1] : n - 1];
357       x1 = b[x] - a[x];
358       y1 = b[y] - a[y];
359 
360       for (i = 0; i < n; i++) {
361 	 a = b;
362 	 b = coords[w ? w[i] : i];
363 	 x0 = x1;
364 	 y0 = y1;
365 	 x1 = b[x] - a[x];
366 	 y1 = b[y] - a[y];
367 	 if (x0 * y1 - x1 * y0 < 0)
368 	    return triangulateConcave(coords, w, n, x, y, tris);
369       }
370    }
371 
372    /* convert to triangles */
373    {
374       int v0 = 0, v1 = 1, v = n - 1;
375       int even = 1;
376       for (i = 0; i < n - 2; i++) {
377 	 if (even) {
378 	    tris[3 * i + 0] = w ? w[v0] : v0;
379 	    tris[3 * i + 1] = w ? w[v1] : v1;
380 	    tris[3 * i + 2] = w ? w[v] : v;
381 	    v0 = v1;
382 	    v1 = v;
383 	    v = v0 + 1;
384 	 }
385 	 else {
386 	    tris[3 * i + 0] = w ? w[v1] : v1;
387 	    tris[3 * i + 1] = w ? w[v0] : v0;
388 	    tris[3 * i + 2] = w ? w[v] : v;
389 	    v0 = v1;
390 	    v1 = v;
391 	    v = v0 - 1;
392 	 }
393 	 even = !even;
394       }
395    }
396    return n - 2;
397 }
398 
399 
400 
401 // ***********************************************************************
402 // ******************** class ssgLoaderWriterMesh ************************
403 // ***********************************************************************
404 
reInit(void)405 void ssgLoaderWriterMesh::reInit(void) // was: ReInit
406 {
407    theVertices = NULL ;
408    materialIndices = NULL ;
409    theFaces = NULL ;
410    perFaceAndVertexTextureCoordinate2Lists = NULL ;
411    theMaterials	= NULL ;
412    perVertexTextureCoordinates2 = NULL ;
413 	 name = NULL ;
414    textureCoordinatesArePerVertex = TRUE ;
415 }
416 
ssgLoaderWriterMesh()417 ssgLoaderWriterMesh::ssgLoaderWriterMesh()
418 {
419    reInit();
420 }
421 
~ssgLoaderWriterMesh()422 ssgLoaderWriterMesh::~ssgLoaderWriterMesh()
423 {}
424 
deletePerFaceAndVertexTextureCoordinates2()425 void ssgLoaderWriterMesh::deletePerFaceAndVertexTextureCoordinates2() // was: deleteTCPFAV
426 {}
427 
428 // creation stuff:
429 
createVertices(int numReservedVertices)430 void ssgLoaderWriterMesh::createVertices( int numReservedVertices ) // was: ThereAreNVertices
431 {
432    assert( theVertices == NULL );
433    theVertices = new ssgVertexArray ( numReservedVertices );
434 }
435 
addVertex(sgVec3 v)436 void ssgLoaderWriterMesh::addVertex( sgVec3 v )
437 {
438 	assert( theVertices!=NULL );
439 	theVertices->add ( v );
440 }
441 
setVertices(class ssgVertexArray * vertexArray)442 void ssgLoaderWriterMesh::setVertices( class ssgVertexArray *vertexArray )
443 {
444    assert( theVertices == NULL );
445    theVertices = vertexArray;
446 }
447 
setPerVertexTextureCoordinates2(class ssgTexCoordArray * texCoordArray)448 void ssgLoaderWriterMesh::setPerVertexTextureCoordinates2( class ssgTexCoordArray *texCoordArray )
449 {
450    assert( perVertexTextureCoordinates2 == NULL );
451    perVertexTextureCoordinates2 = texCoordArray;
452 }
453 
createFaces(int numReservedFaces)454 void ssgLoaderWriterMesh::createFaces( int numReservedFaces ) // was: ThereAreNFaces
455 {
456 	assert( theFaces == NULL );
457 	theFaces = new ssgListOfLists ( numReservedFaces );
458 }
459 
addFace(ssgIndexArray ** indexArray)460 void ssgLoaderWriterMesh::addFace( ssgIndexArray **indexArray )
461 {
462 	assert( theFaces!=NULL );
463 	theFaces->add ( (ssgSimpleList **)indexArray );
464 }
465 
addFaceFromIntegerArray(int numVertices,int * vertices)466 void ssgLoaderWriterMesh::addFaceFromIntegerArray( int numVertices, int *vertices )
467 {
468    int j;
469    class ssgIndexArray *oneFace = new ssgIndexArray( numVertices );
470    oneFace->ref();
471    for( j=0; j<numVertices; j++ )
472      oneFace->add( vertices[j] );
473 
474    addFace( (ssgIndexArray **) &oneFace );
475 }
476 
createPerFaceAndVertexTextureCoordinates2(int numReservedTextureCoordinateLists)477 void ssgLoaderWriterMesh::createPerFaceAndVertexTextureCoordinates2( int numReservedTextureCoordinateLists ) // was: ThereAreNTCPFAV
478 {
479    assert( perFaceAndVertexTextureCoordinate2Lists == NULL );
480    perFaceAndVertexTextureCoordinate2Lists = new ssgListOfLists( numReservedTextureCoordinateLists );
481 }
482 
addPerFaceAndVertexTextureCoordinate2(ssgTexCoordArray ** textureCoordinates2)483 void ssgLoaderWriterMesh::addPerFaceAndVertexTextureCoordinate2( ssgTexCoordArray **textureCoordinates2 ) // was: addTCPFAV
484 {
485    assert( perFaceAndVertexTextureCoordinate2Lists != NULL );
486    perFaceAndVertexTextureCoordinate2Lists->add( (ssgSimpleList **)textureCoordinates2 );
487 }
488 
createPerVertexTextureCoordinates2(int numReservedTextureCoordinates)489 void ssgLoaderWriterMesh::createPerVertexTextureCoordinates2( int numReservedTextureCoordinates )
490 {
491    assert( perVertexTextureCoordinates2 == NULL );
492    perVertexTextureCoordinates2 = new ssgTexCoordArray ( numReservedTextureCoordinates );
493 }
494 
addPerVertexTextureCoordinate2(sgVec2 textureCoordinate)495 void ssgLoaderWriterMesh::addPerVertexTextureCoordinate2( sgVec2 textureCoordinate )
496 {
497    assert( perVertexTextureCoordinates2 != NULL );
498    perVertexTextureCoordinates2->add ( textureCoordinate );
499 }
500 
createMaterialIndices(int numReservedMaterialIndices)501 void ssgLoaderWriterMesh::createMaterialIndices( int numReservedMaterialIndices ) // ThereAreNMaterialIndexes
502 {
503    assert( materialIndices == NULL );
504    materialIndices = new ssgIndexArray ( numReservedMaterialIndices );
505 }
506 
addMaterialIndex(short materialIndex)507 void ssgLoaderWriterMesh::addMaterialIndex( short materialIndex )
508 {
509    assert( materialIndices != NULL );
510    materialIndices->add ( materialIndex );
511 }
512 
createMaterials(int numReservedMaterials)513 void ssgLoaderWriterMesh::createMaterials( int numReservedMaterials ) // ThereAreNMaterials( int n )
514 {
515    assert( theMaterials == NULL );
516    theMaterials = new ssgSimpleStateList( numReservedMaterials );
517 }
518 
addMaterial(class ssgSimpleState ** simpleState)519 void ssgLoaderWriterMesh::addMaterial ( class ssgSimpleState **simpleState )
520 {
521    assert( theMaterials != NULL );
522    theMaterials->add( simpleState );
523 }
524 
recalcNormals(ssgIndexArray * indexList,ssgVertexArray * vertexList,ssgNormalArray * normalList)525 static void recalcNormals( ssgIndexArray* indexList, ssgVertexArray* vertexList, ssgNormalArray *normalList )
526 // wl: modified to use more code from sg
527 {
528    sgVec3 v1, v2, n;
529 
530    for (int i = 0; i < indexList->getNum() / 3; i++) {
531       short indices[3] = { *indexList->get( i*3 ), *indexList->get( i*3 + 1), *indexList->get( i*3 + 2) };
532 
533       sgSubVec3(v1, vertexList->get(indices[1]), vertexList->get(indices[0]));
534       sgSubVec3(v2, vertexList->get(indices[2]), vertexList->get(indices[0]));
535 
536       sgVectorProductVec3( n, v1, v2 );
537       SGfloat normalLength = sgLengthVec3( n );
538       if( normalLength > 0.00001 )
539 	   sgNormaliseVec3( n );
540 
541       sgCopyVec3( normalList->get( indices[0] ), n );
542       sgCopyVec3( normalList->get( indices[1] ), n );
543       sgCopyVec3( normalList->get( indices[2] ), n );
544    }
545  }
546 
547 // addOneNodeToSSGFromPerFaceAndVertexTextureCoordinates: this function replicates each vertex (based on face usage) and
548 // assigns the appropriate texture coordinates to them (based on the per-face texture indices)
addOneNodeToSSGFromPerFaceAndVertexTextureCoordinates2(class ssgVertexArray * theVertices,class ssgListOfLists * thePerFaceAndVertexTextureCoordinates2,class ssgListOfLists * theFaces,class ssgSimpleState * currentState,class ssgLoaderOptions * current_options,class ssgBranch * curr_branch_)549 void ssgLoaderWriterMesh::addOneNodeToSSGFromPerFaceAndVertexTextureCoordinates2( class ssgVertexArray *theVertices,
550 										 class ssgListOfLists *thePerFaceAndVertexTextureCoordinates2,
551 										 class ssgListOfLists *theFaces,
552 										 class ssgSimpleState *currentState,// Pfusch, kludge. NIV135
553 										 class ssgLoaderOptions* current_options,
554 										 class ssgBranch *curr_branch_) // was: AddOneNode2SSGFromCPFAV
555 
556 {
557    int i, j;
558 
559    assert( theVertices!=NULL );
560    assert( theFaces!=NULL );
561 
562    // note: I am changing theVertices here, but that is allowed.
563    class ssgTexCoordArray *perVertexTextureCoordinates2 = new ssgTexCoordArray( theVertices->getNum() );
564    sgVec2 unUsed;
565    unUsed[0]=-99999; // FixMe: It would be nicer to have an extra array of booleans
566    unUsed[1]=-99999;
567    for( i=0; i<theVertices->getNum(); i++)
568      perVertexTextureCoordinates2->add( unUsed );
569    for( i=0; i<theFaces->getNum(); i++)
570      {
571 	class ssgIndexArray *oneFace = *((class ssgIndexArray **) theFaces->get( i ));
572 	class ssgTexCoordArray *textureCoordsForOneFace = *( (ssgTexCoordArray **) thePerFaceAndVertexTextureCoordinates2->get( i ) );
573 	if ( textureCoordsForOneFace != NULL ) // It is allowed that some or even all faces are untextured.
574 	  {
575 	     for( j=0; j<oneFace->getNum(); j++ )
576 	       {
577 		  short *ps = oneFace->get(j);
578 		  float *newTextureCoordinate2 = textureCoordsForOneFace->get( j );
579 		  float *oldTextureCoordinate2 = perVertexTextureCoordinates2->get( *ps );
580 
581 		  assert( oldTextureCoordinate2 != NULL );
582 		  if ((oldTextureCoordinate2[0]==-99999) && (oldTextureCoordinate2[1]==-99999)) // tc unused until now. Use it
583 		    {
584 		       sgVec2 pv; // FixMe: mem leak?
585 		       pv[0]=newTextureCoordinate2[0];
586 		       pv[1]=newTextureCoordinate2[1];
587 		       perVertexTextureCoordinates2->set( pv, *ps );
588 		    }
589 		  else
590 		    { // can we simply use the "old" value?
591 		       if ( TC_EPSILON < ABS ( newTextureCoordinate2[0]-oldTextureCoordinate2[0] ) +
592 			    ABS ( newTextureCoordinate2[1]-oldTextureCoordinate2[1] ))
593 			 { // NO, we can't. Duplicate vertex
594 			    // not allowed: theVertices->add(theVertices->get(*ps));
595 			    // create duplicate 3D. FixMe: clone needed?
596 
597 			    float * f = theVertices->get(*ps);
598 			    sgVec3 v;
599 			    v[0] = f[0]; v[1] = f[1]; v[2] = f[2];
600 			    theVertices->add( v );
601 			    sgVec2 pv;
602 			    pv[0]=newTextureCoordinate2[0];
603 			    pv[1]=newTextureCoordinate2[1];
604 			    perVertexTextureCoordinates2->add( pv ); // create duplicate 2D
605 			    *ps=theVertices->getNum()-1;  // use duplicate
606 			    assert ( *oneFace->get(j) == theVertices->getNum()-1);
607 			 }
608 		    }
609 	       }
610 	  }
611      }
612    addOneNodeToSSGFromPerVertexTextureCoordinates2(theVertices, perVertexTextureCoordinates2, theFaces, currentState,
613 						  current_options, curr_branch_);
614 }
615 
addOneNodeToSSGFromPerVertexTextureCoordinates2(class ssgVertexArray * theVertices,class ssgTexCoordArray * theTextureCoordinates2,class ssgListOfLists * theFaces,class ssgSimpleState * currentState,class ssgLoaderOptions * current_options,class ssgBranch * curr_branch_)616 void ssgLoaderWriterMesh::addOneNodeToSSGFromPerVertexTextureCoordinates2( class ssgVertexArray *theVertices,
617 									   class ssgTexCoordArray *theTextureCoordinates2,
618 									   class ssgListOfLists *theFaces,
619 									   class ssgSimpleState *currentState,// kludge NIV135
620 									   class ssgLoaderOptions* current_options,
621 									   class ssgBranch *curr_branch_) // was: AddOneNode2SSGFromCPV
622 {
623    int i, j;
624    //start Normals, FixMe, kludge NIV135
625 
626    ssgNormalArray *normalList = new ssgNormalArray( theVertices->getNum() );
627    sgVec3 kludge;
628    for( i=0; i<theVertices->getNum(); i++ )
629      normalList->add(kludge); //currentMesh.vl->get(i));
630 
631    class ssgIndexArray* indexList = new ssgIndexArray ( theFaces->getNum() * 3 ) ; // there are MINIMAL n * 3 indexes
632 
633    for( i=0; i<theFaces->getNum(); i++ )
634      {
635 	class ssgIndexArray *oneFace = *((class ssgIndexArray **) theFaces->get( i ));
636 	if ( oneFace->getNum() >= 3 )
637 	  {
638 	     for(j=0;j<oneFace->getNum();j++)
639 	       {
640 		  if (j<3)
641 		    indexList->add(*oneFace->get(j));
642 		  else // add a complete triangle
643 		    {
644 		       indexList->add(*oneFace->get(0));
645 		       indexList->add(*oneFace->get(j-1));
646 		       indexList->add(*oneFace->get(j));
647 		    }
648 	       }
649 	  }
650      }
651    recalcNormals( indexList, theVertices, normalList ); // Fixme, NIV14: only do this if there are no normals in the file
652 
653    ssgColourArray* colours = NULL ;
654 
655    if ( currentState -> isEnabled ( GL_LIGHTING ) )
656      {
657 	if ( colours == NULL )
658 	  {
659 	     colours = new ssgColourArray ( 1 ) ;
660          sgVec4 currentDiffuseColour;
661          sgCopyVec4(currentDiffuseColour, currentState->getMaterial(GL_DIFFUSE));
662          colours -> add ( currentDiffuseColour ) ;
663 	  }
664      }
665    ssgVtxArray* leaf = new ssgVtxArray ( GL_TRIANGLES, theVertices, normalList, theTextureCoordinates2, colours, indexList ) ;
666    leaf -> setCullFace ( TRUE ) ;
667    leaf -> setState ( currentState ) ;
668 
669    ssgEntity *model = current_options -> createLeaf ( leaf, NULL)  ;
670    assert( model != NULL );
671 	 model->setName(name);
672    curr_branch_->addKid(model);
673 }
674 
setName(const char * meshName)675 void ssgLoaderWriterMesh::setName( const char *meshName )
676 {
677 	delete [] name;
678 	if ( !meshName )
679 		name = NULL;
680 	else
681 		name = ulStrDup(meshName);
682 }
683 
684 
addToSSG(class ssgSimpleState * currentState,class ssgLoaderOptions * current_options,class ssgBranch * curr_branch_)685 void ssgLoaderWriterMesh::addToSSG(
686 				   class ssgSimpleState *currentState,// FixMe, kludge. NIV135
687 				   class ssgLoaderOptions* current_options,
688 				   class ssgBranch *curr_branch_ )
689 {
690    int i, j, k;
691    unsigned short oldVertexIndex, newVertexIndex;
692    class ssgIndexArray *thisFace;
693 
694 #ifdef WRITE_MESH_TO_STDOUT
695 	if ( theMaterials == NULL )
696 		ulSetError(UL_DEBUG, "( theMaterials == NULL )");
697 	else
698 	{
699 		ulSetError(UL_DEBUG, "%d Materials:", theMaterials->getNum());
700 		for(i=0;i<theMaterials->getNum();i++)
701 		{ ulSetError(UL_DEBUG, "%ld", (long)theMaterials->get(i));
702 		}
703 	}
704 	if ( materialIndices == NULL )
705 		ulSetError(UL_DEBUG, "( materialIndices == NULL )");
706 	else
707 	{
708 		ulSetError(UL_DEBUG, "%d Material Indexes:", materialIndices->getNum());
709 		for(i=0;i<materialIndices->getNum();i++)
710 		{ short s=*(materialIndices->get(i));
711 			ulSetError(UL_DEBUG, "%ld", (long)s);
712 		}
713 	}
714 #endif
715   if ( theMaterials == NULL )
716 	{
717 	   if ( perFaceAndVertexTextureCoordinate2Lists == NULL )
718 	     addOneNodeToSSGFromPerVertexTextureCoordinates2( theVertices, perVertexTextureCoordinates2 /* may be NULL */, theFaces, currentState, current_options, curr_branch_);
719 	   else
720 	     addOneNodeToSSGFromPerFaceAndVertexTextureCoordinates2(theVertices, perFaceAndVertexTextureCoordinate2Lists, theFaces, currentState,
721 				     current_options, curr_branch_);
722 	}
723   else
724   {
725 		assert( theVertices != NULL );
726 		assert( theFaces != NULL );
727 		// FixMe: What about faces without state? They should have material -1
728 		for( i=0; i < theMaterials->getNum(); i++ )
729 	  {
730 	     // I often allocate too much; This is wastefull on memory, but fast since it never "resizes":
731 	     class ssgVertexArray *newVertices = new ssgVertexArray ( theVertices->getNum() );
732 	     class ssgListOfLists *newFaces = new ssgListOfLists ( theFaces->getNum() );
733 	     class ssgIndexArray *oldVertexIndexToNewVertexIndex = new ssgIndexArray ( theVertices->getNum() );
734 	     class ssgListOfLists *newPerFaceAndVertexTextureCoordinate2Lists = NULL;
735 	     class ssgTexCoordArray *newPerVertexTextureCoordinates2 = NULL;
736 
737 	     if(  perFaceAndVertexTextureCoordinate2Lists != NULL )
738 	       newPerFaceAndVertexTextureCoordinate2Lists = new ssgListOfLists();
739 	     if ( perVertexTextureCoordinates2 != NULL )
740 	       newPerVertexTextureCoordinates2 = new ssgTexCoordArray();
741 
742 	     for (j=0; j<theVertices->getNum(); j++)
743 	       oldVertexIndexToNewVertexIndex->add ( short(0xFFFF) ); // 0xFFFF stands for "unused in new Mesh"
744 
745 	     // Go through all the old Faces, look for the correct material and copy those
746 	     // faces and indexes into the new
747 	     // FixMe, 2do, NIV135: if the Materials just differ through the colour, one would not need
748 	     // several meshes, but could use the colour array. However, this is not possible,
749 	     // if they differ by for example the texture
750 	     assert( materialIndices != NULL );
751 	     for ( j=0; j<theFaces->getNum(); j++ )
752 	       if ( i == *(materialIndices->get(
753 						// for *.x-files, there may be less materialIndices than faces. I then simply repeat
754 						// the last index all the time:
755 						j<materialIndices->getNum() ? j : materialIndices->getNum()-1 ))
756 				 							)
757 		 {
758 		    // take this face
759 		    thisFace = *((class ssgIndexArray **) theFaces->get( j ));
760 		    newFaces->add( (class ssgSimpleList **)&thisFace);
761 		    //thisFace = *((class ssgIndexArray **) newFaces->get( newFaces->getNum()-1 ));
762 
763 		    if( perFaceAndVertexTextureCoordinate2Lists != NULL )
764 		      newPerFaceAndVertexTextureCoordinate2Lists ->add( perFaceAndVertexTextureCoordinate2Lists -> get( j ) );
765 
766 		    for( k=0; k < thisFace->getNum(); k++ )
767 		      {
768 			 oldVertexIndex = * thisFace->get(k);
769 			 newVertexIndex = *oldVertexIndexToNewVertexIndex->get( oldVertexIndex );
770 
771 			 if ( 0xFFFF == newVertexIndex )
772 			   {
773 			      newVertexIndex = newVertices->getNum();
774 			      newVertices->add( theVertices->get( oldVertexIndex ) );
775 			      oldVertexIndexToNewVertexIndex->set( newVertexIndex, oldVertexIndex );
776 
777 			 if ( perVertexTextureCoordinates2 != NULL )
778 			   newPerVertexTextureCoordinates2 -> add( perVertexTextureCoordinates2->get( oldVertexIndex ) );
779 			 }
780 			 // From here on the indexes in thisFace are only valid in relation to
781 			 // newVertices and newtextureCoordinatePerVertex. Since this face will not be used for any
782 			 // further material, this doesn't lead to problems.
783 			 thisFace->set( newVertexIndex, k );
784 		      }
785 		 }
786 #ifdef WRITE_MESH_TO_STDOUT
787 	     ulSetError(UL_DEBUG, "NumVert: %d", newVertices->getNum());
788 	     for(j=0;j<newVertices->getNum();j++)
789 	       { float *f=newVertices->get(j);
790 		  ulSetError(UL_DEBUG, "%f, %f, %f",f[0], f[1], f[2]);
791 	       }
792 	     for(j=0;j<newFaces->getNum();j++)
793 			{
794 			   thisFace = *((class ssgIndexArray **) newFaces->get( j ));
795 			   fprintf(stderr, "%d EP:", thisFace->getNum());
796 			   for(k=0;k<thisFace->getNum();k++)
797 			     {
798 				oldVertexIndex = * thisFace->get(k);
799 				fprintf(stderr, "%d, ", oldVertexIndex);
800 			     }
801 			   putc('\n', stderr);
802 			}
803 #endif
804 	     if ( newFaces->getNum() > 0 )
805 	       {
806 		  currentState = *theMaterials->get(i);
807 		  if ( perFaceAndVertexTextureCoordinate2Lists == NULL )
808 		    // FixMe: textureCoordinatePerVertex-indices are not compatible to newVertices-indices?!?
809 		    addOneNodeToSSGFromPerVertexTextureCoordinates2( newVertices, newPerVertexTextureCoordinates2 /* may be NULL */, newFaces, currentState, current_options, curr_branch_);
810 		  else
811 		    addOneNodeToSSGFromPerFaceAndVertexTextureCoordinates2(newVertices, newPerFaceAndVertexTextureCoordinate2Lists, newFaces, currentState,
812 					    current_options, curr_branch_);
813 	       }
814 	  }
815   }
816 }
817 
checkMe()818 int ssgLoaderWriterMesh::checkMe()
819 // returns TRUE; if ok.
820 // Writes out errors by calling ulSetError with severity UL_WARNING,
821 // and a bit of debug info as UL_DEBUG
822 // May stop on first error.
823 
824 // FixMe; todo: textureCoordinatePerVertex and tCPFAV. NIV135
825 {
826    int i, oneIndex;
827    class ssgIndexArray * vertexIndsForOneFace;
828    class ssgTexCoordArray * textureCoordsForOneFace;
829 
830   // **** check theVertices *****
831 	if ( theVertices == NULL )
832 	{ if (( materialIndices == NULL ) &&
833 	      (theFaces == NULL ) &&
834 	      ( perFaceAndVertexTextureCoordinate2Lists == NULL ))
835        {	ulSetError( UL_DEBUG, "LoaderWriterMesh::checkMe(): The mesh is empty\n");
836 	  return TRUE;
837        }
838 	   else
839 	     {	ulSetError( UL_WARNING, "LoaderWriterMesh::checkMe(): No theVertices is NULL; but not the rest!\n");
840 		return FALSE;
841 	     }
842 
843 	}
844 	// **** check materialIndices and theMaterials *****
845 	/* FixMe; kludge: 2do. NIV135
846 	// one index per face:
847 	class ssgIndexArray *materialIndices;
848 
849 	theMaterials
850 	*/
851 	if ((( theMaterials == NULL ) && ( materialIndices != NULL )) ||
852 		  (( theMaterials != NULL ) && ( materialIndices == NULL )))
853 	{	ulSetError( UL_WARNING, "LoaderWriterMesh::checkMe(): "
854 	                     "One of theMaterials and materialIndices was NULL and the other != NULL!\n");
855 		return FALSE;
856 	}
857 	if ( materialIndices != NULL )
858 	{ for (i=0;i<materialIndices->getNum();i++)
859 		{ oneIndex = *materialIndices->get(i);
860 			assert(theMaterials!=NULL);
861 	    if (( oneIndex < 0 ) || ( oneIndex >= theMaterials->getNum()))
862 			{	ulSetError( UL_WARNING, "LoaderWriterMesh::checkMe(): "
863 													 "Material index out of range. Index = %d, "
864 													 "theMaterials->getNum() = %d.\n",
865 													 oneIndex, theMaterials->getNum());
866 				return FALSE;
867 			}
868 		}
869 	}
870 
871 
872 	// **** check theFaces *****
873 	// Each sublist is of type ssgIndexArray and contains the indexes of the vertices:
874 	if ( theFaces == NULL )
875 	{	ulSetError( UL_WARNING, "LoaderWriterMesh::checkMe(): There are vertices but no faces.\n");
876 		return FALSE;
877 	}
878 	for(i=0;i<theFaces->getNum();i++)
879 	{
880 	   vertexIndsForOneFace = *((ssgIndexArray **) theFaces->get ( i ));
881 	   if ( vertexIndsForOneFace == NULL )
882 	     {	ulSetError( UL_WARNING, "LoaderWriterMesh::checkMe(): the vertexindexes for one face are NULL!\n");
883 		return FALSE;
884 	     }
885 	}
886    // **** check textureCoordinates *****
887    // Each sublist is of type ssgTexCoordArray and contains the texture coordinates
888 	if ( perFaceAndVertexTextureCoordinate2Lists != NULL ) // may be NULL
889 	{ if ( theFaces->getNum() != perFaceAndVertexTextureCoordinate2Lists->getNum())
890 		{	ulSetError( UL_WARNING, "LoaderWriterMesh::checkMe(): "
891 		              "There must be as many faces in theFaces as in textureCoordinates. But "
892 		              "theFaces->getNum() =%d, tCPFAV->getNum() = %d!\n",
893 									theFaces->getNum(), perFaceAndVertexTextureCoordinate2Lists->getNum());
894 			return FALSE;
895 		}
896 		for(i=0;i<perFaceAndVertexTextureCoordinate2Lists->getNum();i++)
897 		{
898 		   textureCoordsForOneFace = *((ssgTexCoordArray **) perFaceAndVertexTextureCoordinate2Lists->get ( i ));
899 		   if ( textureCoordsForOneFace  != NULL ) // It is allowed that some or even all faces are untextured.
900 		     {
901 			vertexIndsForOneFace = *((ssgIndexArray **) theFaces->get ( i ));
902 			if ( textureCoordsForOneFace->getNum() != vertexIndsForOneFace ->getNum())
903 			  {
904 			     ulSetError( UL_WARNING, "LoaderWriterMesh::checkMe(): Face %d: "
905 					 "Each face must have as many texture corrdinates (or none) as vertices. But "
906 					 "textureCoordsForOneFace->getNum() =%d, vertexIndsForOneFace ->getNum() = %d!\n",
907 					 i, textureCoordsForOneFace->getNum(), vertexIndsForOneFace ->getNum());
908 			     return FALSE;
909 			  }
910 		     }
911 		}
912 	}
913    return TRUE; // success
914 }
915