Logo Search packages:      
Sourcecode: plib version File versions  Download package

ssgLoaderWriterStuff.cxx

/*
     PLIB - A Suite of Portable Game Libraries
     Copyright (C) 1998,2002  Steve Baker
 
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
     License as published by the Free Software Foundation; either
     version 2 of the License, or (at your option) any later version.
 
     This library is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     Library General Public License for more details.
 
     You should have received a copy of the GNU Library General Public
     License along with this library; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 
     For further information visit http://plib.sourceforge.net

     $Id: ssgLoaderWriterStuff.cxx 2060 2006-01-05 20:54:15Z fayjf $
*/

// ssgLoaderWriterStuff.cxx
// Here you will find classes and functions you can use to 
// implement loaders and writers for ssg
// Also, there is the parser for loading ASCII files, which 
// has its own file ssgParser.cxx and there are functions like
// the stripifier that are usefull not only for loaders/writers.
//
// 1. Version written by Wolfram Kuss (Wolfram.Kuss@t-online.de) 
// in Nov of 2000
// Distributed with Steve Bakers plib under the LGPL licence

#include "ssgLocal.h"
#include "ssgLoaderWriterStuff.h"


#undef ABS
#undef MIN
#undef MAX
#define ABS(x) ((x) >= 0 ? (x) : -(x))
#define MIN(a,b) ((a) <= (b) ? (a) : (b))
#define MAX(a,b) ((a) >= (b) ? (a) : (b))
#define MIN3(a,b,c) ((a) <= (b) ? MIN(a,c) : MIN(b,c))
#define MAX3(a,b,c) ((a) >= (b) ? MAX(a,c) : MAX(b,c))

// texture coord epsilon
#define TC_EPSILON 0.01


sgVec4 currentDiffuse;

// ***********************************************************************
// ********************  small utility functions  ************************
// ***********************************************************************

void ssgAccumVerticesAndFaces( ssgEntity* node, sgMat4 transform, ssgVertexArray* vertices,
                         ssgIndexArray*  indices, SGfloat epsilon, ssgSimpleStateArray* ssa,
                         ssgIndexArray*  materialIndices, ssgTexCoordArray *texCoordArray)
// Accumulates all vertices and Faces (indexes of vertices making up faces)
// from node and any node below.
// Calls itself recursively.
// If indices is NULL, no face info is accumulated
// if epsilon is < 0.0, it is ignored. Else vertices are only accumulated if 
// there is no vertex inside epsilon yet
{

   assert( vertices != NULL );
   assert( (epsilon < 0.0) || (indices == NULL) ); // sorry: using epsilon AND using indices not implemented
   if ( ssa != NULL ) { assert( indices != NULL ); }
   assert ( ((ssa==NULL) && (materialIndices==NULL)) || ((ssa!=NULL) && (materialIndices!=NULL)));
   if ( node->isAKindOf( ssgTypeTransform() ) ) {
      sgMat4 local_transform;
      ssgTransform *t_node = (ssgTransform*)node;
    
      t_node->getTransform(local_transform);
      sgPostMultMat4( local_transform, transform );

      for (ssgEntity* kid = t_node->getKid(0); kid != NULL; 
         kid = t_node->getNextKid()) {
       ssgAccumVerticesAndFaces( kid, local_transform, vertices, indices, epsilon, ssa, materialIndices, texCoordArray);
      }
   } 
   else if ( node->isAKindOf( ssgTypeBranch() ) ) {
      ssgBranch *b_node = (ssgBranch*)node;
      for (ssgEntity* kid = b_node->getKid(0); kid != NULL;
         kid = b_node->getNextKid()) {
       ssgAccumVerticesAndFaces( kid, transform, vertices, indices, epsilon, ssa, materialIndices, texCoordArray);
      }    
   } 
   else if ( node->isAKindOf( ssgTypeLeaf() ) ) {
      ssgLeaf* l_node = (ssgLeaf*)node;
      int i, vert_low = vertices->getNum();
      
      int useTexture = FALSE;
      if ( texCoordArray )
      if ( l_node->getState() )
        if (l_node->getState()->isAKindOf(ssgTypeSimpleState())) 
          { 
             ssgSimpleState * ss = (ssgSimpleState *) l_node->getState();
             if ( ss->isEnabled ( GL_TEXTURE_2D ) )
// wk kludge!!!                                 if ( l_node -> getNumTexCoords () == l_node -> getNumVertices() )
             useTexture = TRUE;
          }
    
      for (i = 0; i < l_node->getNumVertices(); i++) {
       sgVec3 new_vertex;
       sgXformVec3(new_vertex, l_node->getVertex(i), transform);
       
       if ( epsilon < 0.0 )
         {
            vertices->add(new_vertex);
            if ( useTexture )
            texCoordArray ->add ( l_node->getTexCoord(i) );
            else if ( texCoordArray )
            texCoordArray ->add ( _ssgTexCoord00 );
         }
       else
         { 
            int j, bFound = FALSE, nv1 = vertices -> getNum ();
            for ( j = 0; j < nv1; j++)
            {
               float *oldvertex = vertices -> get(j);
               if (( new_vertex[0] - oldvertex[0] > -epsilon) &&
                   ( new_vertex[0] - oldvertex[0] < epsilon) &&
                   ( new_vertex[1] - oldvertex[1] > -epsilon) &&
                   ( new_vertex[1] - oldvertex[1] < epsilon) &&
                   ( new_vertex[2] - oldvertex[2] > -epsilon) &&
                   ( new_vertex[2] - oldvertex[2] < epsilon))
                 { 
                  float *f = 0;
                  if ( useTexture )
                    {
                       assert( texCoordArray ); // if texCoordArray would be NULL, useTexture would not be set.
                       f = texCoordArray -> get(j);
                    }
                  if ( !useTexture || ((l_node->getTexCoord(i)[0] == f[0]) &&
                                   (l_node->getTexCoord(i)[1] == f[1])))
                    {
                       bFound = TRUE;
                       break;
                    }
                 }
            }
            if ( ! bFound )
            {
               vertices -> add ( new_vertex );
               if ( useTexture )
                 texCoordArray ->add ( l_node->getTexCoord(i) );
               else if ( texCoordArray )
                 texCoordArray ->add ( _ssgTexCoord00 );
            }
         }
      }

      if ( indices != NULL )
      {
         int index=-1;
         if ( ssa != NULL )
           { 
            ssgState *s = l_node->getState();
            if ( s != NULL )
              { index = ssa->findIndex (reinterpret_cast <class ssgSimpleState *> (s) );
                 if ( index < 0 )
                   { ssa -> add(reinterpret_cast <class ssgSimpleState *> (s) );
                    index = ssa->getNum()-1;
                   }
              }
           }
         for (i = 0; i < l_node->getNumTriangles(); i++) {
            short v1, v2, v3;
            l_node->getTriangle(i, &v1, &v2, &v3);
            indices->add( vert_low + v1 );
            indices->add( vert_low + v2 );
            indices->add( vert_low + v3 );
            if ( materialIndices != NULL )
            materialIndices->add(index); // index is -1 for leafs without state
         }
      }
   }
   if ( texCoordArray )
     {
      assert( vertices->getNum() == texCoordArray->getNum() );
     }
} ;


/*
  ssgTriangulate - triangulate a simple polygon.
*/

static int triangulateConcave(sgVec3 *coords, int *w, int n, int x, int y, int *tris)
{
   struct Vtx {
      int index;
      float x, y;
      Vtx *next;
   };

   Vtx buf[16], *arr, *p0, *p1, *p2, *m0, *m1, *m2, *t;
   int i, chk, num_tris;
   float a0, a1, a2, b0, b1, b2, c0, c1, c2;

   /* construct a circular linked list of the vertices */
   arr = (n > 16) ? new Vtx [ n ] : buf;
   p0 = &arr[0];
   p0->index = w ? w[0] : 0;
   p0->x = coords[p0->index][x];
   p0->y = coords[p0->index][y];
   p1 = p0;
   p2 = 0;
   for (i = 1; i < n; i++) {
      p2 = &arr[i];
      p2->index = w ? w[i] : i;
      p2->x = coords[p2->index][x];
      p2->y = coords[p2->index][y];
      p1->next = p2;
      p1 = p2;
   }
   p2->next = p0;

   m0 = p0;
   m1 = p1 = p0->next;
   m2 = p2 = p1->next;
   chk = 0;
   num_tris = 0;

   while (p0 != p2->next) {
      if (chk && m0 == p0 && m1 == p1 && m2 == p2) {
       /* no suitable vertex found.. */
         ulSetError(UL_WARNING, "ssgTriangulate: Self-intersecting polygon.");       
       if (arr != buf)
         delete [] arr;
         return 0;
      }
      chk = 1;

      a0 = p1->y - p2->y;
      a1 = p2->y - p0->y;
      a2 = p0->y - p1->y;
      b0 = p2->x - p1->x;
      b1 = p0->x - p2->x;
      b2 = p1->x - p0->x;
      
      if (b0 * a2 - b2 * a0 < 0) {
       /* current angle is concave */
         p0 = p1;
         p1 = p2;
         p2 = p2->next;
      }
      else {
       /* current angle is convex */
         float xmin = MIN3(p0->x, p1->x, p2->x);
         float xmax = MAX3(p0->x, p1->x, p2->x);
         float ymin = MIN3(p0->y, p1->y, p2->y);
         float ymax = MAX3(p0->y, p1->y, p2->y);
         
       c0 = p1->x * p2->y - p2->x * p1->y;
       c1 = p2->x * p0->y - p0->x * p2->y;
       c2 = p0->x * p1->y - p1->x * p0->y;

         for (t = p2->next; t != p0; t = t->next) {
          /* see if the triangle contains this vertex */
            if (xmin <= t->x && t->x <= xmax && 
                ymin <= t->y && t->y <= ymax &&
            a0 * t->x + b0 * t->y + c0 > 0 &&
            a1 * t->x + b1 * t->y + c1 > 0 &&            
            a2 * t->x + b2 * t->y + c2 > 0)
             break;
       }

         if (t != p0) {
            p0 = p1;
            p1 = p2;
            p2 = p2->next;
         }
         else {
          /* extract this triangle */
          tris[3 * num_tris + 0] = p0->index;
          tris[3 * num_tris + 1] = p1->index;
          tris[3 * num_tris + 2] = p2->index;
          num_tris++;
            
          p0->next = p1 = p2;
          p2 = p2->next;
            
            m0 = p0;
            m1 = p1;
            m2 = p2;
            chk = 0;
         }
      }
   }

   tris[3 * num_tris + 0] = p0->index;
   tris[3 * num_tris + 1] = p1->index;
   tris[3 * num_tris + 2] = p2->index;
   num_tris++;

   if (arr != buf)
     delete [] arr;

   return num_tris;
}

int _ssgTriangulate( sgVec3 *coords, int *w, int n, int *tris )
{
   float *a, *b;
   int i, x, y;

   /* trivial case */
   if (n <= 3) {
      if (n == 3) {
       tris[0] = w ? w[0] : 0;
       tris[1] = w ? w[1] : 1;
       tris[2] = w ? w[2] : 2;
       return 1;
      }
      ulSetError(UL_WARNING, "ssgTriangulate: Invalid number of vertices (%d).", n);
      return 0;
   }

   /* compute areas */
   {
      float s[3], t[3];
      int swap;

      s[0] = s[1] = s[2] = 0;
      b = coords[w ? w[n - 1] : n - 1];

      for (i = 0; i < n; i++) {
       a = b;
       b = coords[w ? w[i] : i];
       s[0] += a[1] * b[2] - a[2] * b[1];
       s[1] += a[2] * b[0] - a[0] * b[2];
       s[2] += a[0] * b[1] - a[1] * b[0];
      }
   
      /* select largest area */
      t[0] = ABS(s[0]);
      t[1] = ABS(s[1]);
      t[2] = ABS(s[2]);
      i = t[0] > t[1] ? t[0] > t[2] ? 0 : 2 : t[1] > t[2] ? 1 : 2;
      swap = (s[i] < 0); /* swap coordinates if clockwise */
      x = (i + 1 + swap) % 3;
      y = (i + 2 - swap) % 3;
   }

   /* concave check */
   {
      float x0, y0, x1, y1;

      a = coords[w ? w[n - 2] : n - 2];
      b = coords[w ? w[n - 1] : n - 1];
      x1 = b[x] - a[x];
      y1 = b[y] - a[y];

      for (i = 0; i < n; i++) {
       a = b;
       b = coords[w ? w[i] : i];
       x0 = x1;
       y0 = y1;
       x1 = b[x] - a[x];
       y1 = b[y] - a[y];
       if (x0 * y1 - x1 * y0 < 0)
          return triangulateConcave(coords, w, n, x, y, tris);
      }
   }

   /* convert to triangles */
   {
      int v0 = 0, v1 = 1, v = n - 1; 
      int even = 1;
      for (i = 0; i < n - 2; i++) {
       if (even) {
          tris[3 * i + 0] = w ? w[v0] : v0;
          tris[3 * i + 1] = w ? w[v1] : v1;
          tris[3 * i + 2] = w ? w[v] : v;
          v0 = v1;
          v1 = v;
          v = v0 + 1;
       }
       else {
          tris[3 * i + 0] = w ? w[v1] : v1;
          tris[3 * i + 1] = w ? w[v0] : v0;
          tris[3 * i + 2] = w ? w[v] : v;
          v0 = v1;
          v1 = v;
          v = v0 - 1;
       }
       even = !even;
      }
   }
   return n - 2;
}



// ***********************************************************************
// ******************** class ssgLoaderWriterMesh ************************
// ***********************************************************************
 
void ssgLoaderWriterMesh::reInit(void) // was: ReInit
{
   theVertices = NULL ; 
   materialIndices = NULL ; 
   theFaces = NULL ;
   perFaceAndVertexTextureCoordinate2Lists = NULL ;
   theMaterials   = NULL ;
   perVertexTextureCoordinates2 = NULL ;
       name = NULL ;
   textureCoordinatesArePerVertex = TRUE ;
}
      
ssgLoaderWriterMesh::ssgLoaderWriterMesh()
{
   reInit();
}

ssgLoaderWriterMesh::~ssgLoaderWriterMesh()
{}

void ssgLoaderWriterMesh::deletePerFaceAndVertexTextureCoordinates2() // was: deleteTCPFAV
{}

// creation stuff:

void ssgLoaderWriterMesh::createVertices( int numReservedVertices ) // was: ThereAreNVertices
{
   assert( theVertices == NULL );
   theVertices = new ssgVertexArray ( numReservedVertices );
}

void ssgLoaderWriterMesh::addVertex( sgVec3 v ) 
{
      assert( theVertices!=NULL );
      theVertices->add ( v );
}

void ssgLoaderWriterMesh::setVertices( class ssgVertexArray *vertexArray )
{
   assert( theVertices == NULL );
   theVertices = vertexArray;
}

void ssgLoaderWriterMesh::setPerVertexTextureCoordinates2( class ssgTexCoordArray *texCoordArray )
{
   assert( perVertexTextureCoordinates2 == NULL );
   perVertexTextureCoordinates2 = texCoordArray;
}

void ssgLoaderWriterMesh::createFaces( int numReservedFaces ) // was: ThereAreNFaces
{
      assert( theFaces == NULL );
      theFaces = new ssgListOfLists ( numReservedFaces );
}

void ssgLoaderWriterMesh::addFace( ssgIndexArray **indexArray ) 
{
      assert( theFaces!=NULL );
      theFaces->add ( (ssgSimpleList **)indexArray );
}

void ssgLoaderWriterMesh::addFaceFromIntegerArray( int numVertices, int *vertices )
{
   int j;
   class ssgIndexArray *oneFace = new ssgIndexArray( numVertices ); 
   oneFace->ref();
   for( j=0; j<numVertices; j++ )
     oneFace->add( vertices[j] );

   addFace( (ssgIndexArray **) &oneFace );
}

void ssgLoaderWriterMesh::createPerFaceAndVertexTextureCoordinates2( int numReservedTextureCoordinateLists ) // was: ThereAreNTCPFAV
{
   assert( perFaceAndVertexTextureCoordinate2Lists == NULL );
   perFaceAndVertexTextureCoordinate2Lists = new ssgListOfLists( numReservedTextureCoordinateLists );
}

void ssgLoaderWriterMesh::addPerFaceAndVertexTextureCoordinate2( ssgTexCoordArray **textureCoordinates2 ) // was: addTCPFAV
{
   assert( perFaceAndVertexTextureCoordinate2Lists != NULL );
   perFaceAndVertexTextureCoordinate2Lists->add( (ssgSimpleList **)textureCoordinates2 );
}

void ssgLoaderWriterMesh::createPerVertexTextureCoordinates2( int numReservedTextureCoordinates )
{
   assert( perVertexTextureCoordinates2 == NULL );
   perVertexTextureCoordinates2 = new ssgTexCoordArray ( numReservedTextureCoordinates );
}

void ssgLoaderWriterMesh::addPerVertexTextureCoordinate2( sgVec2 textureCoordinate ) 
{
   assert( perVertexTextureCoordinates2 != NULL );
   perVertexTextureCoordinates2->add ( textureCoordinate );
}

void ssgLoaderWriterMesh::createMaterialIndices( int numReservedMaterialIndices ) // ThereAreNMaterialIndexes
{
   assert( materialIndices == NULL );
   materialIndices = new ssgIndexArray ( numReservedMaterialIndices );
}

void ssgLoaderWriterMesh::addMaterialIndex( short materialIndex ) 
{
   assert( materialIndices != NULL );
   materialIndices->add ( materialIndex );
}

void ssgLoaderWriterMesh::createMaterials( int numReservedMaterials ) // ThereAreNMaterials( int n ) 
{
   assert( theMaterials == NULL );
   theMaterials = new ssgSimpleStateList( numReservedMaterials );
}

void ssgLoaderWriterMesh::addMaterial ( class ssgSimpleState **simpleState ) 
{
   assert( theMaterials != NULL );
   theMaterials->add( simpleState );
}

static void recalcNormals( ssgIndexArray* indexList, ssgVertexArray* vertexList, ssgNormalArray *normalList ) 
// wl: modified to use more code from sg
{
   sgVec3 v1, v2, n;
   
   for (int i = 0; i < indexList->getNum() / 3; i++) {
      short indices[3] = { *indexList->get( i*3 ), *indexList->get( i*3 + 1), *indexList->get( i*3 + 2) };
      
      sgSubVec3(v1, vertexList->get(indices[1]), vertexList->get(indices[0]));
      sgSubVec3(v2, vertexList->get(indices[2]), vertexList->get(indices[0]));
      
      sgVectorProductVec3( n, v1, v2 );
      SGfloat normalLength = sgLengthVec3( n );
      if( normalLength > 0.00001 )
         sgNormaliseVec3( n );

      sgCopyVec3( normalList->get( indices[0] ), n );
      sgCopyVec3( normalList->get( indices[1] ), n );
      sgCopyVec3( normalList->get( indices[2] ), n );
   }
 }

// addOneNodeToSSGFromPerFaceAndVertexTextureCoordinates: this function replicates each vertex (based on face usage) and
// assigns the appropriate texture coordinates to them (based on the per-face texture indices)
void ssgLoaderWriterMesh::addOneNodeToSSGFromPerFaceAndVertexTextureCoordinates2( class ssgVertexArray *theVertices,
                                                             class ssgListOfLists *thePerFaceAndVertexTextureCoordinates2,
                                                             class ssgListOfLists *theFaces,
                                                             class ssgSimpleState *currentState,// Pfusch, kludge. NIV135
                                                             class ssgLoaderOptions* current_options,
                                                             class ssgBranch *curr_branch_) // was: AddOneNode2SSGFromCPFAV

{
   int i, j;
   
   assert( theVertices!=NULL );
   assert( theFaces!=NULL );
   
   // note: I am changing theVertices here, but that is allowed.
   class ssgTexCoordArray *perVertexTextureCoordinates2 = new ssgTexCoordArray( theVertices->getNum() );
   sgVec2 unUsed;
   unUsed[0]=-99999; // FixMe: It would be nicer to have an extra array of booleans
   unUsed[1]=-99999;
   for( i=0; i<theVertices->getNum(); i++)
     perVertexTextureCoordinates2->add( unUsed ); 
   for( i=0; i<theFaces->getNum(); i++)
     {
      class ssgIndexArray *oneFace = *((class ssgIndexArray **) theFaces->get( i ));
      class ssgTexCoordArray *textureCoordsForOneFace = *( (ssgTexCoordArray **) thePerFaceAndVertexTextureCoordinates2->get( i ) );
      if ( textureCoordsForOneFace != NULL ) // It is allowed that some or even all faces are untextured.
        {
           for( j=0; j<oneFace->getNum(); j++ )
             { 
              short *ps = oneFace->get(j);
              float *newTextureCoordinate2 = textureCoordsForOneFace->get( j );
              float *oldTextureCoordinate2 = perVertexTextureCoordinates2->get( *ps );
                              
              assert( oldTextureCoordinate2 != NULL );
              if ((oldTextureCoordinate2[0]==-99999) && (oldTextureCoordinate2[1]==-99999)) // tc unused until now. Use it
                { 
                   sgVec2 pv; // FixMe: mem leak?
                   pv[0]=newTextureCoordinate2[0];
                   pv[1]=newTextureCoordinate2[1];
                   perVertexTextureCoordinates2->set( pv, *ps );
                }
              else
                { // can we simply use the "old" value?
                   if ( TC_EPSILON < ABS ( newTextureCoordinate2[0]-oldTextureCoordinate2[0] ) +
                      ABS ( newTextureCoordinate2[1]-oldTextureCoordinate2[1] ))
                   { // NO, we can't. Duplicate vertex
                      // not allowed: theVertices->add(theVertices->get(*ps)); 
                      // create duplicate 3D. FixMe: clone needed?
                                       
                      float * f = theVertices->get(*ps);
                      sgVec3 v;
                      v[0] = f[0]; v[1] = f[1]; v[2] = f[2]; 
                      theVertices->add( v );
                      sgVec2 pv;
                      pv[0]=newTextureCoordinate2[0];
                      pv[1]=newTextureCoordinate2[1];
                      perVertexTextureCoordinates2->add( pv ); // create duplicate 2D
                      *ps=theVertices->getNum()-1;  // use duplicate
                      assert ( *oneFace->get(j) == theVertices->getNum()-1);
                   }
                }
             }
        }
     }
   addOneNodeToSSGFromPerVertexTextureCoordinates2(theVertices, perVertexTextureCoordinates2, theFaces, currentState,
                                      current_options, curr_branch_);
}

void ssgLoaderWriterMesh::addOneNodeToSSGFromPerVertexTextureCoordinates2( class ssgVertexArray *theVertices,
                                                         class ssgTexCoordArray *theTextureCoordinates2,
                                                         class ssgListOfLists *theFaces,
                                                         class ssgSimpleState *currentState,// kludge NIV135
                                                         class ssgLoaderOptions* current_options,
                                                         class ssgBranch *curr_branch_) // was: AddOneNode2SSGFromCPV
{
   int i, j;
   //start Normals, FixMe, kludge NIV135

   ssgNormalArray *normalList = new ssgNormalArray( theVertices->getNum() );
   sgVec3 kludge;
   for( i=0; i<theVertices->getNum(); i++ )
     normalList->add(kludge); //currentMesh.vl->get(i));

   class ssgIndexArray* indexList = new ssgIndexArray ( theFaces->getNum() * 3 ) ; // there are MINIMAL n * 3 indexes

   for( i=0; i<theFaces->getNum(); i++ )
     {
      class ssgIndexArray *oneFace = *((class ssgIndexArray **) theFaces->get( i )); 
      if ( oneFace->getNum() >= 3 )
        {   
           for(j=0;j<oneFace->getNum();j++)
             { 
              if (j<3)
                indexList->add(*oneFace->get(j));
              else // add a complete triangle
                {
                   indexList->add(*oneFace->get(0));
                   indexList->add(*oneFace->get(j-1));
                   indexList->add(*oneFace->get(j));
                }
             }
        }
     }
   recalcNormals( indexList, theVertices, normalList ); // Fixme, NIV14: only do this if there are no normals in the file
      
   ssgColourArray* colours = NULL ;
  
   if ( currentState -> isEnabled ( GL_LIGHTING ) )
     {
      if ( colours == NULL )
        {
           colours = new ssgColourArray ( 1 ) ;
         sgVec4 currentDiffuseColour;
         sgCopyVec4(currentDiffuseColour, currentState->getMaterial(GL_DIFFUSE));
         colours -> add ( currentDiffuseColour ) ;
        }
     }
   ssgVtxArray* leaf = new ssgVtxArray ( GL_TRIANGLES, theVertices, normalList, theTextureCoordinates2, colours, indexList ) ;
   leaf -> setCullFace ( TRUE ) ;
   leaf -> setState ( currentState ) ;
   
   ssgEntity *model = current_options -> createLeaf ( leaf, NULL)  ;
   assert( model != NULL );
       model->setName(name);
   curr_branch_->addKid(model);
}

void ssgLoaderWriterMesh::setName( const char *meshName )
{
      delete [] name;
      if ( !meshName )
            name = NULL;
      else
            name = ulStrDup(meshName);
}


void ssgLoaderWriterMesh::addToSSG(
                           class ssgSimpleState *currentState,// FixMe, kludge. NIV135
                           class ssgLoaderOptions* current_options,
                           class ssgBranch *curr_branch_ )
{ 
   int i, j, k;
   unsigned short oldVertexIndex, newVertexIndex;
   class ssgIndexArray *thisFace;
  
#ifdef WRITE_MESH_TO_STDOUT   
      if ( theMaterials == NULL )
            ulSetError(UL_DEBUG, "( theMaterials == NULL )");
      else
      {     
            ulSetError(UL_DEBUG, "%d Materials:", theMaterials->getNum());
            for(i=0;i<theMaterials->getNum();i++)
            { ulSetError(UL_DEBUG, "%ld", (long)theMaterials->get(i));
            }
      }
      if ( materialIndices == NULL )
            ulSetError(UL_DEBUG, "( materialIndices == NULL )");
      else
      {
            ulSetError(UL_DEBUG, "%d Material Indexes:", materialIndices->getNum());
            for(i=0;i<materialIndices->getNum();i++)
            { short s=*(materialIndices->get(i));
                  ulSetError(UL_DEBUG, "%ld", (long)s);
            }
      }
#endif
  if ( theMaterials == NULL )
      { 
         if ( perFaceAndVertexTextureCoordinate2Lists == NULL )
           addOneNodeToSSGFromPerVertexTextureCoordinates2( theVertices, perVertexTextureCoordinates2 /* may be NULL */, theFaces, currentState, current_options, curr_branch_);
         else
           addOneNodeToSSGFromPerFaceAndVertexTextureCoordinates2(theVertices, perFaceAndVertexTextureCoordinate2Lists, theFaces, currentState, 
                             current_options, curr_branch_);
      }
  else
  {   
            assert( theVertices != NULL );
            assert( theFaces != NULL );
            // FixMe: What about faces without state? They should have material -1
            for( i=0; i < theMaterials->getNum(); i++ )
        {   
           // I often allocate too much; This is wastefull on memory, but fast since it never "resizes":
           class ssgVertexArray *newVertices = new ssgVertexArray ( theVertices->getNum() );
           class ssgListOfLists *newFaces = new ssgListOfLists ( theFaces->getNum() );
           class ssgIndexArray *oldVertexIndexToNewVertexIndex = new ssgIndexArray ( theVertices->getNum() ); 
           class ssgListOfLists *newPerFaceAndVertexTextureCoordinate2Lists = NULL;
           class ssgTexCoordArray *newPerVertexTextureCoordinates2 = NULL;
           
           if(  perFaceAndVertexTextureCoordinate2Lists != NULL )
             newPerFaceAndVertexTextureCoordinate2Lists = new ssgListOfLists();
           if ( perVertexTextureCoordinates2 != NULL )
             newPerVertexTextureCoordinates2 = new ssgTexCoordArray();
           
           for (j=0; j<theVertices->getNum(); j++)
             oldVertexIndexToNewVertexIndex->add ( short(0xFFFF) ); // 0xFFFF stands for "unused in new Mesh"
           
           // Go through all the old Faces, look for the correct material and copy those
           // faces and indexes into the new
           // FixMe, 2do, NIV135: if the Materials just differ through the colour, one would not need
           // several meshes, but could use the colour array. However, this is not possible,
           // if they differ by for example the texture
           assert( materialIndices != NULL );
           for ( j=0; j<theFaces->getNum(); j++ )
             if ( i == *(materialIndices->get(
                                    // for *.x-files, there may be less materialIndices than faces. I then simply repeat 
                                    // the last index all the time:
                                    j<materialIndices->getNum() ? j : materialIndices->getNum()-1 )) 
                                                                  )
             { 
                // take this face
                thisFace = *((class ssgIndexArray **) theFaces->get( j )); 
                newFaces->add( (class ssgSimpleList **)&thisFace); 
                //thisFace = *((class ssgIndexArray **) newFaces->get( newFaces->getNum()-1 )); 
                
                if( perFaceAndVertexTextureCoordinate2Lists != NULL )
                  newPerFaceAndVertexTextureCoordinate2Lists ->add( perFaceAndVertexTextureCoordinate2Lists -> get( j ) );
                               
                for( k=0; k < thisFace->getNum(); k++ )
                  { 
                   oldVertexIndex = * thisFace->get(k);
                   newVertexIndex = *oldVertexIndexToNewVertexIndex->get( oldVertexIndex );

                   if ( 0xFFFF == newVertexIndex )
                     { 
                        newVertexIndex = newVertices->getNum();
                        newVertices->add( theVertices->get( oldVertexIndex ) );
                        oldVertexIndexToNewVertexIndex->set( newVertexIndex, oldVertexIndex );
                     
                   if ( perVertexTextureCoordinates2 != NULL )
                     newPerVertexTextureCoordinates2 -> add( perVertexTextureCoordinates2->get( oldVertexIndex ) );
                   }
                   // From here on the indexes in thisFace are only valid in relation to
                   // newVertices and newtextureCoordinatePerVertex. Since this face will not be used for any 
                   // further material, this doesn't lead to problems.
                   thisFace->set( newVertexIndex, k );
                  }     
             }
#ifdef WRITE_MESH_TO_STDOUT   
           ulSetError(UL_DEBUG, "NumVert: %d", newVertices->getNum());
           for(j=0;j<newVertices->getNum();j++)
             { float *f=newVertices->get(j);
              ulSetError(UL_DEBUG, "%f, %f, %f",f[0], f[1], f[2]);
             }
           for(j=0;j<newFaces->getNum();j++)
                  {
                     thisFace = *((class ssgIndexArray **) newFaces->get( j ));     
                     fprintf(stderr, "%d EP:", thisFace->getNum());
                     for(k=0;k<thisFace->getNum();k++)
                       {
                        oldVertexIndex = * thisFace->get(k);
                        fprintf(stderr, "%d, ", oldVertexIndex);
                       }
                     putc('\n', stderr);
                  }
#endif      
           if ( newFaces->getNum() > 0 )
             {
              currentState = *theMaterials->get(i);
              if ( perFaceAndVertexTextureCoordinate2Lists == NULL )
                // FixMe: textureCoordinatePerVertex-indices are not compatible to newVertices-indices?!?
                addOneNodeToSSGFromPerVertexTextureCoordinates2( newVertices, newPerVertexTextureCoordinates2 /* may be NULL */, newFaces, currentState, current_options, curr_branch_);
              else
                addOneNodeToSSGFromPerFaceAndVertexTextureCoordinates2(newVertices, newPerFaceAndVertexTextureCoordinate2Lists, newFaces, currentState, 
                                  current_options, curr_branch_);
             }
        }
  }
}
      
int ssgLoaderWriterMesh::checkMe()
// returns TRUE; if ok.
// Writes out errors by calling ulSetError with severity UL_WARNING,
// and a bit of debug info as UL_DEBUG
// May stop on first error.

// FixMe; todo: textureCoordinatePerVertex and tCPFAV. NIV135
{
   int i, oneIndex;
   class ssgIndexArray * vertexIndsForOneFace;
   class ssgTexCoordArray * textureCoordsForOneFace;

  // **** check theVertices *****
      if ( theVertices == NULL )
      { if (( materialIndices == NULL ) &&
            (theFaces == NULL ) &&
            ( perFaceAndVertexTextureCoordinate2Lists == NULL ))
       {    ulSetError( UL_DEBUG, "LoaderWriterMesh::checkMe(): The mesh is empty\n");
        return TRUE;
       }
         else
           {      ulSetError( UL_WARNING, "LoaderWriterMesh::checkMe(): No theVertices is NULL; but not the rest!\n");
            return FALSE;
           }
         
      }
      // **** check materialIndices and theMaterials *****
      /* FixMe; kludge: 2do. NIV135
      // one index per face:
      class ssgIndexArray *materialIndices; 

      theMaterials
      */
      if ((( theMaterials == NULL ) && ( materialIndices != NULL )) ||
              (( theMaterials != NULL ) && ( materialIndices == NULL )))
      {     ulSetError( UL_WARNING, "LoaderWriterMesh::checkMe(): "
                           "One of theMaterials and materialIndices was NULL and the other != NULL!\n");
            return FALSE;
      }
      if ( materialIndices != NULL ) 
      { for (i=0;i<materialIndices->getNum();i++)
            { oneIndex = *materialIndices->get(i);
                  assert(theMaterials!=NULL);
          if (( oneIndex < 0 ) || ( oneIndex >= theMaterials->getNum()))
                  {     ulSetError( UL_WARNING, "LoaderWriterMesh::checkMe(): "
                                                                               "Material index out of range. Index = %d, "
                                                                               "theMaterials->getNum() = %d.\n",
                                                                               oneIndex, theMaterials->getNum());
                        return FALSE;
                  }
            }
      }


      // **** check theFaces *****
      // Each sublist is of type ssgIndexArray and contains the indexes of the vertices:
      if ( theFaces == NULL )
      {     ulSetError( UL_WARNING, "LoaderWriterMesh::checkMe(): There are vertices but no faces.\n");
            return FALSE;
      }
      for(i=0;i<theFaces->getNum();i++)
      {
         vertexIndsForOneFace = *((ssgIndexArray **) theFaces->get ( i ));
         if ( vertexIndsForOneFace == NULL )
           {      ulSetError( UL_WARNING, "LoaderWriterMesh::checkMe(): the vertexindexes for one face are NULL!\n");
            return FALSE;
           }
      }
   // **** check textureCoordinates *****
   // Each sublist is of type ssgTexCoordArray and contains the texture coordinates
      if ( perFaceAndVertexTextureCoordinate2Lists != NULL ) // may be NULL
      { if ( theFaces->getNum() != perFaceAndVertexTextureCoordinate2Lists->getNum())
            {     ulSetError( UL_WARNING, "LoaderWriterMesh::checkMe(): "
                          "There must be as many faces in theFaces as in textureCoordinates. But "
                          "theFaces->getNum() =%d, tCPFAV->getNum() = %d!\n",
                                                      theFaces->getNum(), perFaceAndVertexTextureCoordinate2Lists->getNum());
                  return FALSE;
            }
            for(i=0;i<perFaceAndVertexTextureCoordinate2Lists->getNum();i++)
            {
               textureCoordsForOneFace = *((ssgTexCoordArray **) perFaceAndVertexTextureCoordinate2Lists->get ( i ));
               if ( textureCoordsForOneFace  != NULL ) // It is allowed that some or even all faces are untextured.
                 {
                  vertexIndsForOneFace = *((ssgIndexArray **) theFaces->get ( i ));
                  if ( textureCoordsForOneFace->getNum() != vertexIndsForOneFace ->getNum())
                    {
                       ulSetError( UL_WARNING, "LoaderWriterMesh::checkMe(): Face %d: "
                               "Each face must have as many texture corrdinates (or none) as vertices. But "
                               "textureCoordsForOneFace->getNum() =%d, vertexIndsForOneFace ->getNum() = %d!\n",
                               i, textureCoordsForOneFace->getNum(), vertexIndsForOneFace ->getNum());
                       return FALSE;
                    }
                 }
            }
      }
   return TRUE; // success
}

Generated by  Doxygen 1.6.0   Back to index