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

ssgLoadXPlaneObj.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: ssgLoadXPlaneObj.cxx 1728 2002-11-09 21:38:28Z sjbaker $
*/

/*
 * XPlane object loader for PLIB.
 * Written by Bernie Bright <bbright@bigpond.net.au>, Sept 2002.
 *
 * KNOWN ISSUES
 *
 * Only version 1 objects are handled.
 *
 * The .obj XPlane custom object file extension clashes with Wavefront objects.
 * For the moment, XPlane objects must be renamed with a .xpl extension.
 *
 * Point objects are not handled.
 */

#include <stdio.h>
#include <string.h>

#include "ssgLocal.h"

/**
 * XPlane .obj loader.
 */
00046 class ObjLoader
{
public:
    ObjLoader( const ssgLoaderOptions* options );

    ~ObjLoader();

    ssgEntity* load( const char* fname );

private:
    ssgState* get_state( const char* tfname );
    char* fgets( char* s, int size, FILE* fp );
    char* getline( char* line, size_t n, FILE* fp );
    char* getTextureName( const char* p, char* tname, size_t n );
    const char* file_extension( const char* fname );

private:
    ssgLoaderOptions* options;
    ssgBranch* root;
};

ObjLoader::ObjLoader( const ssgLoaderOptions* options_ )
    : options(0)
    , root(0)
{
    ssgSetCurrentOptions( const_cast<ssgLoaderOptions*>(options_) );
    this->options = ssgGetCurrentOptions();
}

ObjLoader::~ObjLoader()
{
}

ssgState*
ObjLoader::get_state( const char* tfname )
{
    if (tfname != 0)
    {
      ssgState* st = options->createState( const_cast<char*>(tfname) );
      if (st != 0)
          return st;
    }

    ssgSimpleState* st = new ssgSimpleState;
    st->setName( tfname );
    st->setMaterial( GL_SPECULAR, 0.0f, 0.0f, 0.0f );
    st->setMaterial( GL_EMISSION, 0.0f, 0.0f, 0.0f );
    st->setMaterial( GL_AMBIENT, 0.0f, 0.0f, 0.0f );
    st->setMaterial( GL_DIFFUSE, 0.0f, 0.0f, 0.0f );
    st->enable( GL_LIGHTING );
    st->setShadeModel( GL_SMOOTH );

    bool has_alpha = false;
    if (tfname != 0)
    {
      ssgTexture* tex = options->createTexture( const_cast<char*>(tfname) );
      has_alpha = tex->hasAlpha();
      st->setTexture(tex);
      st->enable( GL_TEXTURE_2D );
    }
    else
    {
      st->disable( GL_TEXTURE_2D );
    }

    if (has_alpha)
    {
      st->disable( GL_ALPHA_TEST );
      st->enable( GL_BLEND );
      st->setTranslucent();
    }
    else
    {
      st->disable( GL_ALPHA_TEST );
      st->disable( GL_BLEND );
      st->setOpaque();
    }

    return st;
}

/**
 * XPlane object files have either IBM (\r\n) or Apple (\r) line endings.
 * Handle both here.
 */
char*
00132 ObjLoader::fgets( char* s, int size, FILE* fp )
{
    char* p = s;
    int n = 0;
    int c = 0;

    for (--size; n < size; ++n)
    {
      c = getc(fp);
      if (c == EOF)
          return 0;

      if (c == '\r')
          break;
      *p++ = c;
    }

    *p = 0;

    c = getc(fp);
    if (c != '\n')
      ungetc( c, fp );

    return s;
}

/**
 * Read the next non-blank line.
 * Returns pointer to first non-whitespace character or NULL on error or EOF.
 */
char*
00163 ObjLoader::getline( char* line, size_t n, FILE* fp )
{
    for (;;)
    {
      char* p = fgets( line, n, fp );
      if (p == 0)
          return 0;

      // Skip leading whitespace.
      while (*p != 0 && isspace(*p))
          ++p;

      if (*p != 0)
          return p;
    }
}

/**
 * 
 */
char*
ObjLoader::getTextureName( const char* p, char* buf, size_t bufsize )
{
    if (p == 0 || buf == 0)
      return 0;

    while (*p != 0 && isspace(*p))
      ++p;

    size_t n = 0;
    char* bp = buf;
    for ( ; *p != 0 && n < bufsize && !isspace(*p); ++n, ++bp, ++p)
    {
      // Replace ':' path separator with '/'.
      *bp = *p == ':' ? '/' : *p;
    }

    if (n < bufsize)
      *bp = 0;

    return const_cast<char*>(p);
}

const char*
ObjLoader::file_extension( const char *fname )
{
    const char* p = fname + strlen(fname);

    while (p != fname && *p != '/' && *p != '.' )
      --p;

    return p;
}

ssgEntity*
ObjLoader::load( const char* fname )
{
    char mname[1024];
    options->makeModelPath( mname, fname );

    FILE* fp = fopen( fname, "r" );
    if (fp == 0)
    {
      ulSetError( UL_WARNING,
                "ssgLoadXPlaneObj: Failed to open '%s' for reading.",
                fname );
      return 0;
    }

    char line[ 1024 ];

    // Read obj header.
    char* p = getline( line, sizeof(line), fp );
    if (p == 0)
    {
      ulSetError( UL_WARNING, "ssgLoadXPlaneObj: expected header." );
      fclose(fp);
      return 0;
    }

    if (*p != 'I' && *p != 'A')
    {
      ulSetError( UL_WARNING,
                "ssgLoadXPlaneObj: invalid header, expected 'I' or 'A'" );
      fclose(fp);
      return 0;
    }
    
    p = getline( line, sizeof(line), fp );
    if (p == 0)
    {
      ulSetError( UL_WARNING,
                "ssgLoadXPlaneObj: unexpected EOF while reading header." );
      fclose(fp);
      return 0;
    }

    root = new ssgTransform();
    root->setName( fname );

    if (*p == '2')
    {
      // Version 2 obj file.
      ulSetError( UL_WARNING,
                "ssgLoadXPlaneObj: Version 2 not yet implemented" );

      fclose( fp );
      delete root;
      return 0;

      // TODO: implement V2.
    }
    else
    {
      // Version 1 obj file.

      // Version number is optional.
      if (*p == '1')
      {
          // get TextureDef
          p = getline( line, sizeof(line), fp );
          if (p == 0)
          {
            ulSetError( UL_WARNING,
                      "ssgLoadXPlaneObj: unexpected EOF "
                      "while reading data." );
            fclose(fp);
            return 0;
          }
      }

      int type = 0;
      char* endp;
      do
      {
          type = strtol( p, &endp, 10 );
          switch (type)
          {
          case 4:
            {
                // Get texture filename.
                // Allow room for extension and terminator.
                char tname[ 251 + 4 + 1 ];
                endp = getTextureName( endp, tname, 251 );
                if (endp == 0)
                {
                  ulSetError( UL_WARNING,
                            "ssgLoadXPlaneObj: Error reading TextureDef" );
                  delete root;
                  fclose( fp );
                  return 0;
                }

                strcat( tname, ".bmp" );

                // TODO: check for comment following texture name.

                sgVec3* vc = new sgVec3[4];
                sgVec2* tc = new sgVec2[4];
                sgVec4* cc = new sgVec4[1];

                for (int i = 0; i < 4; ++i)
                {
                  p = getline( line, sizeof(line), fp );
                  // Read vertices, swapping y and z.
                  sscanf( p, "%f%f%f", &vc[i][0], &vc[i][2], &vc[i][1] );
                }

                sgSetVec2( tc[0], 1.0f, 1.0f );
                sgSetVec2( tc[1], 1.0f, 0.0f );
                sgSetVec2( tc[2], 0.0f, 0.0f );
                sgSetVec2( tc[3], 0.0f, 1.0f );

                sgSetVec4( cc[0], 1.0f, 1.0f, 1.0f, 1.0f );

                ssgVertexArray* vl   = new ssgVertexArray( 4, vc );
                ssgTexCoordArray* tl = new ssgTexCoordArray( 4, tc );
                ssgNormalArray* nl   = new ssgNormalArray();
                ssgColourArray* cl   = new ssgColourArray( 1, cc );

                ssgVtxTable* vtab = new ssgVtxTable( GL_POLYGON,
                                           vl, nl, tl, cl );
                vtab->setState( get_state( tname ) );
                root->addKid( vtab );
            }
            break;

          case 3:
            {
                // Get texture filename.
                // Allow room for extension and terminator.
                char tname[ 251 + 4 + 1 ];
                endp = getTextureName( endp, tname, 251 );
                strcat( tname, ".bmp" );

                sgVec3* vc = new sgVec3[3];
                sgVec2* tc = new sgVec2[3];
                sgVec4* cc = new sgVec4[1];

                for (int i = 0; i < 3; ++i)
                {
                  p = getline( line, sizeof(line), fp );
                  // Read vertices, swapping y and z.
                  sscanf( p, "%f%f%f", &vc[i][0], &vc[i][2], &vc[i][1] );
                }

                sgSetVec2( tc[0], 1.0f, 1.0f );
                sgSetVec2( tc[1], 1.0f, 0.0f );
                sgSetVec2( tc[2], 0.0f, 0.0f );

                sgSetVec4( cc[0], 1.0f, 1.0f, 1.0f, 1.0f );

                ssgVertexArray* vl   = new ssgVertexArray( 3, vc );
                ssgTexCoordArray* tl = new ssgTexCoordArray( 3, tc );
                ssgNormalArray* nl   = new ssgNormalArray();
                ssgColourArray* cl   = new ssgColourArray( 1, cc );

                ssgVtxTable* vtab = new ssgVtxTable( GL_POLYGON,
                                           vl, nl, tl, cl );
                vtab->setState( get_state( tname ) );
                root->addKid( vtab );
            }
            break;

          case 2:
            {
                float r, g, b;
                sscanf( endp, "%f%f%f", &r, &g, &b );

                sgVec3* vc = new sgVec3[2];
                sgVec4* cc = new sgVec4[1];
                for (int i = 0; i < 2; ++i)
                {
                  p = getline( line, sizeof(line), fp );
                  // Read vertices, swapping y and z.
                  sscanf( p, "%f%f%f", &vc[i][0], &vc[i][2], &vc[i][1] );
                }

                // Scale rgb values to range 0..1
                sgSetVec4( cc[0], r/10.f, g/10.f, b/10.f, 1.0f );

                ssgVertexArray* vl   = new ssgVertexArray( 2, vc );
                ssgTexCoordArray* tl = new ssgTexCoordArray();
                ssgNormalArray* nl   = new ssgNormalArray();
                ssgColourArray* cl   = new ssgColourArray( 1, cc );

                ssgVtxTable* vtab = new ssgVtxTable( GL_LINES,
                                           vl, nl, tl, cl );
                ssgSimpleState* st = new ssgSimpleState;
                st->setMaterial( GL_SPECULAR, 0.0f, 0.0f, 0.0f );
                st->setMaterial( GL_EMISSION, 0.0f, 0.0f, 0.0f );
                st->setMaterial( GL_AMBIENT, 0.0f, 0.0f, 0.0f );
                st->setMaterial( GL_DIFFUSE, 0.0f, 0.0f, 0.0f );
                st->enable( GL_LIGHTING );
                st->setShadeModel( GL_SMOOTH );
                st->disable( GL_TEXTURE_2D );
                st->disable( GL_ALPHA_TEST );
                st->disable( GL_BLEND );
                st->setOpaque();
                vtab->setState( st );
                root->addKid( vtab );
            }
                break;

          case 1:
            {
                int r, g, b;
                sscanf( endp, "%d%d%d", &r, &g, &b );
                p = getline( line, sizeof(line), fp );
                float x, y, z;
                sscanf( p, "%f%f%f", &x, &z, &y );

                // TODO: create appropriate ssgEntity.
            }
            break;

          case 99:
            break;

          default:
            ulSetError( UL_WARNING,
                      "ssgLoadXPlaneObj: invalid line, '%s'", line );
            fclose(fp);
            delete root;
            return 0;
          }
      }
      while ((p = getline( line, sizeof(line), fp )) != 0 && type != 99);
    }

    fclose( fp );
    return root;
}

ssgEntity*
ssgLoadXPlaneOBJ( const char* fname, const ssgLoaderOptions* options )
{
    ObjLoader loader( options );
    return loader.load( fname );
}


Generated by  Doxygen 1.6.0   Back to index