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