This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

| Quake3 BSP Converter Submitted by

Q3BSP is a Windows console application that will convert any valid Quake 3 BSP file into an organized polygon mesh and export the results into a standardized ASCII file format, VRML 1.0. I encourage users of this software to expand this tool to export in other popular ASCII file formats, especially ones which support multiple U/V channels.
This utility will convert a Quake3 BSP into a valid polygon mesh and output the results into two seperate VRML 1.0 files. The first VRML file contains all the U/V mapping and texture mapping information for channel #1, and the second VRML file will contain all of the U/V mapping and texture names for the second U/V channel, which contains all lightmap information. You can then directly import these files into any number of 3d editing tools, including 3d Studio Max... ... description and release notes continued in the readme.txt, found in the zip file.

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/patch.h] - (2,282 bytes)

    #ifndef PATCH_H

    #define PATCH_H

    //############################################################################
    //##                                                                        ##
    //##  PATCH.H                                                               ##
    //##                                                                        ##
    //##  Converts a Quake3 Bezier patch into a hard coded polygon mesh.        ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    #include "vformat.h"

    class PatchSurface
    {
    public:
      PatchSurface(const LightMapVertex *control_points,int npoints,int controlx,int controly);
      ~PatchSurface(void);

      const LightMapVertex * GetVerts(void) const { return mPoints; };
      const unsigned short * GetIndices(void) const { return mIndices; };
      int GetIndiceCount(void) const { return mCount; };

    private:
      bool FindSize(int controlx,int controly,const LightMapVertex *cp,int &sizex,int &sizey) const;
      void FillPatch(int controlx,int controly,int sizex,int sizey,LightMapVertex *points);
      void FillCurve(int numcp, int size, int stride,LightMapVertex *p);

      int FindLevel(const Vector3d<float> &cv0,
                    const Vector3d<float> &cv1,
                    const Vector3d<float> &cv2) const;

      int                  mCount;
      LightMapVertex      *mPoints;       // vertices produced.
      unsigned short      *mIndices;      // indices into those vertices
    };

    #endif

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/rect.h] - (2,645 bytes)

    #ifndef RECT_H

    #define RECT_H

    //############################################################################
    //##                                                                        ##
    //##  RECT.H                                                                ##
    //##                                                                        ##
    //##  Misc. Support structure.  Defines an AABB bounding region.            ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    #include "vector.h"

    template <class Type> class Rect3d
    {
    public:
      Rect3d(void)
      {
        r1.Set(0,0,0);
        r2.Set(0,0,0);
      };

      Rect3d(const Vector3d<Type> &v1,const Vector3d<Type>& v2)
      {
        r1 = v1;
        r2 = v2;
      };

      Rect3d(Type x1,Type y1,Type z1,
             Type x2,Type y2,Type z2)
      {
        r1.Set(x1,y1,z1);
        r2.Set(x2,y2,z2);
      };

      void Set(Type x1,Type y1,Type z1,Type x2,Type y2,Type z2)
      {

        Type temp;

        if ( x1 > x2 )
        {
          temp = x2;
          x2   = x1;
          x1   = temp;
        }

        if ( y1 > y2 )
        {
          temp = y2;
          y2   = y1;
          y1   = temp;
        }

        if ( z1 > z2 )
        {
          temp = z2;
          z2   = z1;
          z1   = temp;
        }

        r1.Set(x1,y1,z1);
        r2.Set(x2,y2,z2);

      };

      void InitMinMax(void)
      {
        r1.Set(1E9,1E9,1E9);
        r2.Set(-1E9,-1E9,-1E9);
      };

      void MinMax(const Vector3d<Type> &pos)
      {
    	  MinMax(pos.GetX(),pos.GetY(),pos.GetZ());
      };

      void MinMax(Type x,Type y,Type z)
      {
        if ( x < r1.GetX() ) r1.SetX(x);
        if ( y < r1.GetY() ) r1.SetY(y);
        if ( z < r1.GetZ() ) r1.SetZ(z);

        if ( x > r2.GetX() ) r2.SetX(x);
        if ( y > r2.GetY() ) r2.SetY(y);
        if ( z > r2.GetZ() ) r2.SetZ(z);
      };

      Vector3d<Type> r1;
      Vector3d<Type> r2;
    };

    #endif

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/stable.h] - (2,285 bytes)

    #ifndef STABLE_H

    #define STABLE_H

    //############################################################################
    //##                                                                        ##
    //##  STABLE.H                                                              ##
    //##                                                                        ##
    //##  Misc. Support structure.  Defines table of strings, no duplicates.    ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    #include "stl.h"
    #include <string.h>

    class CharPtrLess
    {
    public:
    	bool operator()(const char *v1,const char *v2) const
      {
        int v = stricmp(v1,v2);
        if ( v < 0 ) return true;
        return false;
      };
    };

    typedef std::set< const char *, CharPtrLess > CharPtrSet;

    class StringTable
    {
    public:
      StringTable(void)
      {
      };

      ~StringTable(void)
      {
        CharPtrSet::iterator i;
        for (i=mStrings.begin(); i!=mStrings.end(); i++)
        {
          char *str = (char *)(*i);
          delete str;
        }
      }

      const char * Get(const char *str)
      {
        CharPtrSet::iterator found;
        found = mStrings.find( str );
        if ( found != mStrings.end() ) return (*found);
        int l = strlen(str);
        char *mem = new char[l+1];
        strcpy(mem,str);
        mStrings.insert( mem );
        return mem;
      };

      const char * Get(const String &str)
      {
        return Get( str.c_str() );
      };

    private:
      CharPtrSet mStrings;
    };

    #endif

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/stringdict.h] - (3,738 bytes)

    #ifndef STRINGDICT_H
    #define STRINGDICT_H

    #include "stl.h"
    #include <string.h>

    //############################################################################
    //##                                                                        ##
    //##  STRINGDICT.H                                                          ##
    //##                                                                        ##
    //##  Global collection of all strings in application, no duplicates.       ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    #include "stable.h"

    class StringRef
    {
    public:
      StringRef(void)
      {
        mString = "null";
      };

      inline StringRef(const char *str);
      inline StringRef(const String &str);
    	inline StringRef(const StringRef &str);

      operator const char *() const
      {
        return mString;
      };

      operator const String () const
      {
        return mString;
      };

      const char * Get(void) const { return mString; };

      void Set(const char *str)
      {
        mString = str;
      };

    	const StringRef &operator= (const StringRef& rhs )
      {
        mString = rhs.Get();
    		return *this;
      };

      bool operator== ( const StringRef& rhs ) const
      {
        return rhs.mString == mString;
      };

      bool operator< ( const StringRef& rhs ) const
      {
        return rhs.mString < mString;
      };

      bool operator!= ( const StringRef& rhs ) const
      {
        return rhs.mString != mString;
      };

      bool operator> ( const StringRef& rhs ) const
      {
        return rhs.mString > mString;
      };

      bool operator<= ( const StringRef& rhs ) const
      {
        return rhs.mString < mString;
      };

      bool operator>= ( const StringRef& rhs ) const
      {
        return rhs.mString >= mString;
      };

    private:
      const char *mString; // the actual char ptr
    };

    class StringDict
    {
    public:

      StringRef Get(const char *text)
      {
        const char *foo = mStringTable.Get(text);
        StringRef ref;
        ref.Set(foo);
        return ref;
      }

      StringRef Get(const String &text)
      {
        return Get( text.c_str() );
      };

      static StringDict& gStringDict(void)  // global instance
      {
        if ( !gSingleton ) gSingleton = new StringDict;
        return *gSingleton;
      }

      static void ExplicitDestroy(void)
      {
        delete gSingleton;
        gSingleton = 0;
      }

    private:
      static StringDict *gSingleton;
      StringTable mStringTable;

    };

    typedef std::vector< StringRef > StringRefVector;
    typedef std::vector< StringRefVector > StringRefVectorVector;
    typedef std::set< StringRef > StringRefSet;

    #define SGET(x) StringDict::gStringDict().Get(x)

    inline StringRef::StringRef(const char *str)
    {
      StringRef ref = SGET(str);
      mString = ref.mString;
    };

    inline StringRef::StringRef(const String &str)
    {
      StringRef ref = SGET(str);
      mString = ref.mString;
    };

    inline StringRef::StringRef(const StringRef &str)
    {
      mString = str.Get();
    };

    #endif

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/q3shader.h] - (2,968 bytes)

    #ifndef Q3SHADER_H

    #define Q3SHADER_H

    //############################################################################
    //##                                                                        ##
    //##  Q3SHADER.H                                                            ##
    //##                                                                        ##
    //##  Reads a Quake3 Shader file.                                           ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    #include "stringdict.h"
    #include "arglist.h"

    class QuakeShader
    {
    public:
      QuakeShader(const StringRef &ref)
      {
        mName = ref;
      };
      const StringRef& GetName(void) const { return mName; };
      void AddTexture(const StringRef& ref)
      {
        String ifoo = ref;
        if ( ifoo == "chrome_env" ) return;
        if ( ifoo == "tinfx" ) return;

        mTextures.push_back(ref);
      };
      bool GetBaseTexture(StringRef &ref)
      {
        if ( !mTextures.size() ) return false;
        ref = mTextures[0];
        return true;
      }
    private:
      StringRef       mName; // name of shader.
      StringRefVector mTextures;
    };

    typedef std::map< StringRef, QuakeShader *> QuakeShaderMap;

    class QuakeShaderFactory : public ArgList
    {
    public:
      QuakeShaderFactory(void);
      ~QuakeShaderFactory(void);

      QuakeShader * Locate(const String &str);
      QuakeShader * Locate(const StringRef &str);

      void AddShader(const String &sname);

      static QuakeShaderFactory &gQuakeShaderFactory(void)
      {
        if ( !gSingleton )
        {
          gSingleton = new QuakeShaderFactory;
        }
        return *gSingleton;
      }

      static void ExplicitDestroy(void)  // explicitely destroy the global intance
      {
        delete gSingleton;
        gSingleton = 0;
      }

      void Process(const StringVector &args);

      /// get stripped down version of the name
      bool GetName(const String& str,char *stripped);

    private:
      int          mBraceCount;
      QuakeShader *mCurrent;

      void ShaderString(const char *str);

      QuakeShaderMap mShaders; // all shaders available.

      static QuakeShaderFactory *gSingleton; // global instance of data
    };

    #endif

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/arglist.h] - (2,050 bytes)

    #ifndef ARGLIST_H
    #define ARGLIST_H

    #include "stl.h"

    //############################################################################
    //##                                                                        ##
    //##  ARGLIST.H                                                             ##
    //##                                                                        ##
    //##  Parses a string into a series of arguments.                           ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    class ArgList
    {
    public:
      ArgList( void );
      ArgList( const String& line );
      ~ArgList( void );
      ArgList( const ArgList& copy );
      ArgList& operator= ( const ArgList& copy );
      ArgList& operator= ( const String& line );

      void Set( const String& line );

      const String& operator[]( int argc ) const;
      String& operator[]( int argc );

      operator String (void) const;

      // lower case to emulate an STL container
      bool empty( void ) const;
      int size( void ) const;
      void clear( void );

      void Push( const String& arg );

      const StringVector & Get(void) const { return mArgs; }
    protected:
      void Copy( const ArgList& copy );
      StringVector mArgs;
    };

    #endif // ARGLIST_H

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/plane.h] - (6,446 bytes)

    #ifndef PLANE_H
    #define PLANE_H

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>

    //############################################################################
    //##                                                                        ##
    //##  PLANE.H                                                               ##
    //##                                                                        ##
    //##  Support structure, defines a plane in 3space.                         ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    #include "stl.h"
    #include "vector.h"

    #define PLANE_EPSILON 0.0001f

    class Plane
    {
    public:
      Vector3d<float> N; // Ax By Cz
      float D;           // D defines plane equation.
      float InverseZ; // pre-compued -1.0/NormalZ to speed up intersection computation
      Plane(void)
      {
        N.Set(0,0,1);
        InverseZ = 1;
        D = 0;
      };

      Plane(const float *p)
      {
        N.x = p[0];
        N.y = p[1];
        N.z = p[2];
        D   = p[3];
        InverseZ = 1.0f / N.z;
      }

      bool operator==(const Plane &a) const
      {
        float dx = (float)fabs( N.x - a.N.x );
        if ( dx > PLANE_EPSILON ) return false;

        float dy = (float)fabs( N.y - a.N.y );
        if ( dy > PLANE_EPSILON ) return false;

        float dz = (float)fabs( N.z - a.N.z );
        if ( dz > PLANE_EPSILON ) return false;

        float dd = (float)fabs( D - a.D );
        if ( dd > PLANE_EPSILON ) return false;

        return true;
      };

      // distance from this point to the plane.
      float DistToPt(const Vector3d<float> &pos) const
      {
        return (pos.x*N.x + pos.y*N.y + pos.z*N.z)+D;
      };

      bool Intersect(const Vector3d<float> &p1,
                     const Vector3d<float> &p2,
                     Vector3d<float> §)
      {
        float dp1 = DistToPt(p1);
        float dp2 = DistToPt(p2);

        if ( dp1 <= 0 )
        {
          if ( dp2 <= 0 ) return false;
        }
        else
        {
          if ( dp2 > 0 ) return false;
        }

        Vector3d<float> dir = p2 - p1;
        float dot1 = dir.Dot(N);
        float dot2 = dp1 - D;
        float    t = -(D + dot2 ) / dot1;
        sect.x = (dir.x*t)+p1.x;
        sect.y = (dir.y*t)+p1.y;
        sect.z = (dir.z*t)+p1.z;
        return true;
      };

      void PlaneTest(const Vector3d<float> &pos,int &code,int bit)
      {
        float dist = DistToPt(pos);
        if ( dist > 0 ) code|=bit;
      };

      bool Inside(const Vector3d<float> &pos) const
      {
        float dist = DistToPt(pos);
        if ( dist <= 0 ) return true;
        return false;
      };

      // test inclusion/exclusion/intersection between plane and box
      bool Exclude(bool &isect,const Vector3d<float> &bMin,const Vector3d<float> &bMax)
      {

        Vector3d<float> neg, pos;

        if ( N.x > 0.0f)
        {
          if ( N.y > 0.0f)
          {
            if ( N.z > 0.0f)
            {
              pos.x = bMax.x; pos.y = bMax.y; pos.z = bMax.z;
              neg.x = bMin.x; neg.y = bMin.y; neg.z = bMin.z;
            }
            else
            {
              pos.x = bMax.x; pos.y = bMax.y; pos.z = bMin.z;
              neg.x = bMin.x; neg.y = bMin.y; neg.z = bMax.z;
            }
          }
          else
          {
            if (N.z > 0.0f)
            {
              pos.x = bMax.x; pos.y = bMin.y; pos.z = bMax.z;
              neg.x = bMin.x; neg.y = bMax.y; neg.z = bMin.z;
            }
            else
            {
              pos.x = bMax.x; pos.y = bMin.y; pos.z = bMin.z;
              neg.x = bMin.x; neg.y = bMax.y; neg.z = bMax.z;
            }
          }
        }
        else
        {
          if (N.y > 0.0f)
          {
            if (N.z > 0.0f)
            {
              pos.x = bMin.x; pos.y = bMax.y; pos.z = bMax.z;
              neg.x = bMax.x; neg.y = bMin.y; neg.z = bMin.z;
            }
            else
            {
              pos.x = bMin.x; pos.y = bMax.y; pos.z = bMin.z;
              neg.x = bMax.x; neg.y = bMin.y; neg.z = bMax.z;
            }
          }
          else
          {
            if (N.z > 0.0f)
            {
              pos.x = bMin.x; pos.y = bMin.y; pos.z = bMax.z;
              neg.x = bMax.x; neg.y = bMax.y; neg.z = bMin.z;
            }
            else
            {
              pos.x = bMin.x; pos.y = bMin.y; pos.z = bMin.z;
              neg.x = bMax.x; neg.y = bMax.y; neg.z = bMax.z;
            }
          }
        }

        if ( DistToPt(neg) > 0) return true; // is excluded!
          else if ( DistToPt(pos) > 0) isect = true; // does intersect plane!

        return false; // not completely excluded yet.
      }

      void Print(const char *name) const
      {
        printf("%s N=(%.2f,%.2f,%.2f) D=(%.2f)\n",name,N.x,N.y,N.z,D);
      };

      void Print(FILE *fph,const char *name) const
      {
        fprintf(fph,"%s N=(%.2f,%.2f,%.2f) D=(%.2f)\n",name,N.x,N.y,N.z,D);
      };

      void Compute(const Vector3d<float> &A,
                   const Vector3d<float> &B,
                   const Vector3d<float> &C)
      {
        float vx,vy,vz,wx,wy,wz,vw_x,vw_y,vw_z,mag;

        vx = (B.x - C.x);
        vy = (B.y - C.y);
        vz = (B.z - C.z);

        wx = (A.x - B.x);
        wy = (A.y - B.y);
        wz = (A.z - B.z);

        vw_x = vy * wz - vz * wy;
        vw_y = vz * wx - vx * wz;
        vw_z = vx * wy - vy * wx;

        mag = sqrtf((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z));

        if ( mag < 0.000001f )
        {
          mag = 0;
        }
        else
        {
          mag = 1.0f/mag;
        }

        N.x = vw_x * mag;
        N.y = vw_y * mag;
        N.z = vw_z * mag;

        D = 0.0f - ((N.x*A.x)+(N.y*A.y)+(N.z*A.z));

    	if ( N.z != 0.0f )
          InverseZ = -1.0f / N.z; // compute inverse Z
    	else
    	  InverseZ = 0;
      };

      float SolveZ(float x,float y) const
      {
        float z = (N.y*y + N.x*x + D) * InverseZ;
        return z;
      };

    };

    typedef std::vector< Plane > PlaneVector;

    #endif

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/loadbmp.h] - (2,116 bytes)

    #ifndef LOADBMP_H
    #define LOADBMP_H

    //############################################################################
    //##                                                                        ##
    //##  LOADBMP.H                                                             ##
    //##                                                                        ##
    //##  Utility routines, reads and writes BMP files.  This is *windows*      ##
    //##  specific, the only piece of code that relies on windows and would     ##
    //##  need to be ported for other OS implementations.                       ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    //Helper functions for turning a preloaded .BMP file into a bitmap in memory
    //NOTE that the Bpp parameter is BYTES per pixel, not bits!
    #include "stl.h"

    class Bmp
    {
    public:
      unsigned char *LoadBMP(const String &fname, int &wid, int &hit, int &Bpp);
      unsigned char *LoadBMP(const unsigned char *data, int &wid, int &hit, int &Bpp);
      void SaveBMP(const char *fname,const unsigned char *data, int wid, int hit, int Bpp);

      void SwapRGB(unsigned char *dest, const unsigned char *src, unsigned int size);
      void SwapVertically(unsigned char *dest, const unsigned char *src, int wid, int hit, int Bpp);
    };

    #endif

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/q3def.h] - (6,281 bytes)

    #ifndef Q3DEF_H

    #define Q3DEF_H

    //############################################################################
    //##                                                                        ##
    //##  Q3DEF.H                                                               ##
    //##                                                                        ##
    //##  Defines various Quake 3 BSP data structures.                          ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    #include "stl.h"
    #include "stringdict.h"
    #include <string.h>
    #include "vector.h"
    #include "rect.h"
    #include "plane.h"
    #include "vformat.h"

    typedef std::vector< Plane > PlaneVector;

    // Face types in Quake3
    enum FaceType
    {
      FACETYPE_NORMAL=1,
      FACETYPE_MESH=2,
      FACETYPE_TRISURF=3,
      FACETYPE_FLARE=4
    };

    // Reference to a type of shader.
    class ShaderReference
    {
    public:
      ShaderReference(const unsigned char *mem)
      {
        memcpy(mName,mem,64);
        memcpy(mUnknown,&mem[64],sizeof(int)*2);
      }
      void GetTextureName(char *tname);
    private:
      char mName[64];     // hard coded by this size, the shader name.
      int  mUnknown[2];   // unknown 2 integer data in shader reference.
    };

    typedef std::vector< ShaderReference > ShaderReferenceVector;

    /* BSP lumps in the order they appear in the header */
    enum QuakeLumps
    {
      Q3_ENTITIES=0,
      Q3_SHADERREFS,
      Q3_PLANES,
      Q3_NODES,
      Q3_LEAFS,
      Q3_LFACES,
      Q3_LBRUSHES, // leaf brushes
      Q3_MODELS,
      Q3_BRUSHES,
      Q3_BRUSH_SIDES,
      Q3_VERTS,
      Q3_ELEMS,
      Q3_FOG,
      Q3_FACES,
      Q3_LIGHTMAPS,
      Q3_LIGHTGRID,
      Q3_VISIBILITY,
      NUM_LUMPS
    };

    class QuakeLump
    {
    public:
      int GetFileOffset(void) const { return mFileOffset; };
      int GetFileLength(void) const { return mFileLength; };
    private:
    // Exactly comforms to raw data in Quake3 BSP file.
      int mFileOffset;         // offset address of 'lump'
      int mFileLength;         // file length of lump.
    };

    class QuakeHeader
    {
    public:
      bool SetHeader(const void *mem); // returns true if valid quake header.
      const void * LumpInfo(QuakeLumps lump,const void *mem,int &lsize,int &lcount);
    private:
    // Exactly conforms to raw data in Quake3 BSP file.
      int  mId;        // id number.
      int  mVersion;   // version number.
      QuakeLump mLumps[NUM_LUMPS];
    };

    class QuakeNode
    {
    public:
      QuakeNode(void) { };
      QuakeNode(const int *node);
      int GetLeftChild(void) const { return mLeftChild; };
      int GetRightChild(void) const { return mRightChild; };
      const Rect3d<float>& GetBound(void) const { return mBound; };
      int GetPlane(void) const { return mPlane; };
    private:
      int mPlane;          // index to dividing plane.
      int mLeftChild;      // index to left child node.
      int mRightChild;     // index to right child node.
      Rect3d<float> mBound; // bounding box for node.
    };

    typedef std::vector< QuakeNode > QuakeNodeVector;

    class QuakeLeaf
    {
    public:
      QuakeLeaf(void) { };
      QuakeLeaf(const int *leaf);
      const Rect3d<float>& GetBound(void) const { return mBound; };
      int GetCluster(void) const { return mCluster; };
      int GetFirstFace(void) const { return mFirstFace; };
      int GetFaceCount(void) const { return mFaceCount; };
    private:
      int mCluster; // which visibility cluster we are in.
      int mArea;    // unknown ?
      Rect3d<float> mBound; // bounding box for leaf node.
      int mFirstFace;   // index to first face.
      int mFaceCount;   // number of faces.
      int mFirstUnknown; // unknown 'first' indicator.
      int mNumberUnknowns; // number of unknown thingies.
    };

    typedef std::vector< QuakeLeaf > QuakeLeafVector;

    class QuakeVertex
    {
    public:
      QuakeVertex(void) { };
      QuakeVertex(const int *vert);

      void Get(LightMapVertex &vtx) const;

      void Get(Vector3d<float> &p) const
      {
        p = mPos;
      };

    //**private:
      Vector3d<float>   mPos;
      Vector2d<float>   mTexel1;
      Vector2d<float>   mTexel2;
      Vector3d<float>   mNormal;
      unsigned int       mColor;
    };

    typedef std::vector< QuakeVertex > QuakeVertexVector;

    class QuakeModel
    {
    public:
      QuakeModel(void) { };
      QuakeModel(const int *mem);
    private:
      Rect3d<float> mBound;
      int           mFirstFace;
      int           mFcount;
      int           mFirstUnknown;
      int           mUcount;
    };

    typedef std::vector< QuakeModel > QuakeModelVector;

    class QuakeFace
    {
    public:
      QuakeFace(void) { };
      QuakeFace(const int *face);
      ~QuakeFace(void);

      void Build(const UShortVector &elements,
                 const QuakeVertexVector &vertices,
                 ShaderReferenceVector &shaders,
                 const StringRef &name,
                 const StringRef &code,
                 VertexMesh &mesh);

    private:
      int      mFrameNo;
      unsigned int mShader;       // 'shader' numer used by this face.
      int      mUnknown;      // Unknown integer in the face specification.
      FaceType mType;    // type of face.
      int      mFirstVertice; // index into vertex list.
      int      mVcount;       // number of vertices.
      int      mFirstElement; // start of indexed list
      int      mEcount;       // number of elements.
      int      mLightmap;     // lightmap index
      int      mOffsetX;
      int      mOffsetY;
      int      mSizeX;
      int      mSizeY;
      Vector3d<float> mOrig;
      Rect3d<float>  mBound;
      Vector3d<float> mNormal;
      int        mControlX;
      int        mControlY;
    };

    typedef std::vector< QuakeFace > QuakeFaceVector;

    #endif

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/vector.h] - (16,378 bytes)

    #ifndef VECTOR_H

    #define VECTOR_H

    //############################################################################
    //##                                                                        ##
    //##  VECTOR.H                                                              ##
    //##                                                                        ##
    //##  Defines a 3d and/or 2d data point using a template.           .       ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    #include <math.h>
    #include "stl.h"

    template <class Type> class Vector3d
    {
      friend class Matrix;
    public:
      Vector3d(void) { };  // null constructor, does not inialize point.

      Vector3d(const Vector3d &a) // constructor copies existing vector.
      {
        x = a.x;
        y = a.y;
        z = a.z;
      };

      Vector3d(Type a,Type b,Type c) // construct with initial point.
      {
        x = a;
        y = b;
        z = c;
      };

      bool operator==(const Vector3d<Type> &a) const
      {
        if ( a.x == x && a.y == y && a.z == z ) return true;
        return false;
      };

      bool operator!=(const Vector3d<Type> &a) const
      {
        if ( a.x != x || a.y != y || a.z != z ) return true;
        return false;
      };

    // Operators
        Vector3d& operator = (const Vector3d& A)          // ASSIGNMENT (=)
          { x=A.x; y=A.y; z=A.z;
            return(*this);  };

        Vector3d operator + (const Vector3d& A) const     // ADDITION (+)
          { Vector3d Sum(x+A.x, y+A.y, z+A.z);
            return(Sum); };

        Vector3d operator - (const Vector3d& A) const     // SUBTRACTION (-)
          { Vector3d Diff(x-A.x, y-A.y, z-A.z);
            return(Diff); };

        Vector3d operator * (const float s) const       // MULTIPLY BY SCALAR (*)
          { Vector3d Scaled(x*s, y*s, z*s);
            return(Scaled); };

        Vector3d operator / (const float s) const       // DIVIDE BY SCALAR (/)
        {
          float r = 1.0f / s;
            Vector3d Scaled(x*r, y*r, z*r);
            return(Scaled);
        };

        void operator += (const Vector3d A)             // ACCUMULATED VECTOR ADDITION (+=)
          { x+=A.x; y+=A.y; z+=A.z; };
        void operator -= (const Vector3d A)             // ACCUMULATED VECTOR SUBTRACTION (+=)
          { x-=A.x; y-=A.y; z-=A.z; };
        void operator *= (const float s)        // ACCUMULATED SCALAR MULTIPLICATION (*=) (bpc 4/24/2000)
          {x*=s; y*=s; z*=s;}

        Vector3d operator - (void) const                // NEGATION (-)
          { Vector3d Negated(-x, -y, -z);
            return(Negated); };

        Type operator [] (const int i) const         // ALLOWS VECTOR ACCESS AS AN ARRAY.
          { return( (i==0)?x:((i==1)?y:z) ); };
        Type & operator [] (const int i)
          { return( (i==0)?x:((i==1)?y:z) ); };
    //

      // accessor methods.
      Type GetX(void) const { return x; };
      Type GetY(void) const { return y; };
      Type GetZ(void) const { return z; };

      void SetX(Type t)   { x   = t; };
      void SetY(Type t)   { y   = t; };
      void SetZ(Type t)   { z   = t; };

      void Set(Type a,Type b,Type c)
      {
        x = a;
        y = b;
        z = c;
      };

      void Zero(void)
      {
        x = y = z = 0;
      };

    // return -(*this).
    	Vector3d negative(void) const
    	{
    		Vector3d result;
    		result.x = -x;
    		result.y = -y;
    		result.z = -z;
    		return result;
    	}

    	Type Magnitude(void) const
    	{
    		return Type(sqrtf(x * x + y * y + z * z));
    	};

      void Lerp(const Vector3d<Type>& from,const Vector3d<Type>& to,float slerp)
      {
        *this = to-from; // delta on all 3 axis
        *this*=slerp;    // times interpolant distance.
        *this+=from;     // plus source
      };

      // Highly specialized interpolate routine.  Will compute the interpolated position
      // shifted forward or backwards along the ray defined between (from) and (to).
      // Reason for existance is so that when a bullet collides with a wall, for
      // example, you can generate a graphic effect slightly *before* it hit the
      // wall so that the effect doesn't sort into the wall itself.
      void Interpolate(const Vector3d<float> &from,const Vector3d<float> &to,float offset)
      {
        x = to.x-from.x;
        y = to.y-from.y;
        z = to.z-from.z;
        float d = sqrtf( x*x + y*y + z*z );
        float recip = 1.0f / d;
        x*=recip;
        y*=recip;
        z*=recip; // normalize vector
        d+=offset; // shift along ray
        x = x*d + from.x;
        y = y*d + from.y;
        z = z*d + from.z;
      };

    /** Computes the reflection vector between two vectors.*/
      void Reflection(const Vector3d<Type> &a,const Vector3d<Type> &b)// compute reflection vector.
      {
    /* original
      	Vector c;
      	Vector d;
      	Vector e;

    		float dot = 2.0f*a->dot_product(b);

    		c.x = b->x*dot;
    		c.y = b->y*dot;
    		c.z = b->z*dot;

    		d.x = c.x - a->x;
    		d.y = c.y - a->y;
    		d.z = c.z - a->z;

    		x = -d.x;
    		y = -d.y;
    		z = -d.z;
    */
        //converted to fit our Vector class
      	Vector3d<float> c;
      	Vector3d<float> d;

    		float dot = a.Dot(b) * 2.0f;

    		c = b * dot;

    		d = c - a;

    		x = -d.x;
    		y = -d.y;
    		z = -d.z;
      };

      void AngleAxis(Type angle,const Vector3d<Type>& axis)
      {
        x = axis.x*angle;
        y = axis.y*angle;
        z = axis.z*angle;
      };

      Type Length(void) const          // length of vector.
      {
        return Type(sqrt( x*x + y*y + z*z ));
      };

      Type Length2(void) const         // squared distance, prior to square root.
      {
        Type l2 = x*x+y*y+z*z;
        return l2;
      };

      Type Distance(const Vector3d<Type> &a) const   // distance between two points.
      {
        Vector3d<Type> d(a.x-x,a.y-y,a.z-z);
        return d.Length();
      }

      Type DistanceXY(const Vector3d<Type> &a) const
      {
    	float dx = a.x - x;
    	float dy = a.y - y;
        float dist = dx*dx + dy*dy;
    	return dist;
      }

      Type Distance2(const Vector3d<Type> &a) const  // squared distance.
      {
        float dx = a.x - x;
        float dy = a.y - y;
        float dz = a.z - z;
        return dx*dx + dy*dy + dz*dz;
      };

      Type Partial(const Vector3d<Type> &p) const
      {
        return (x*p.y) - (p.x*y);
      }

      Type Area(const Vector3d<Type> &p1,const Vector3d<Type> &p2) const
      {
        Type A = Partial(p1);
        A+= p1.Partial(p2);
        A+= p2.Partial(*this);
        return A*0.5f;
      }

      Type Normalize(void)       // normalize to a unit vector, returns distance.
      {
        Type l = Length(); // get length.
        if ( l != 0 )
        {
          x/=l;
          y/=l;
          z/=l;
        }
        else
        {
          x = y = z = 0;
        }
        return l;
      };

      Type Dot(const Vector3d<Type> &a) const        // computes dot product.
      {
    		return (x * a.x + y * a.y + z * a.z );
      };

      void Cross(const Vector3d<Type> &a,const Vector3d<Type> &b)  // cross two vectors result in this one.
      {
        x = a.y*b.z - a.z*b.y;
        y = a.z*b.x - a.x*b.z;
        z = a.x*b.y - a.y*b.x;
      };

      /******************************************/
      // Check if next edge (b to c) turns inward
      //
      //    Edge from a to b is already in face
      //    Edge from b to c is being considered for addition to face
      /******************************************/
      bool Concave(const Vector3d<float>& a,const Vector3d<float>& b)
      {
      	float vx,vy,vz,wx,wy,wz,vw_x,vw_y,vw_z,mag,nx,ny,nz,mag_a,mag_b;

      	wx = b.x - a.x;
      	wy = b.y - a.y;
      	wz = b.z - a.z;

      	mag_a = (float) sqrtf((wx * wx) + (wy * wy) + (wz * wz));

      	vx = x - b.x;
      	vy = y - b.y;
      	vz = z - b.z;

      	mag_b = (float) sqrtf((vx * vx) + (vy * vy) + (vz * vz));

      	vw_x = (vy * wz) - (vz * wy);
      	vw_y = (vz * wx) - (vx * wz);
      	vw_z = (vx * wy) - (vy * wx);

      	mag = (float) sqrtf((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z));

      	// Check magnitude of cross product, which is a sine function
      	// i.e., mag (a x b) = mag (a) * mag (b) * sin (theta);
      	// If sin (theta) small, then angle between edges is very close to
      	// 180, which we may want to call a concavity.	Setting the
      	// CONCAVITY_TOLERANCE value greater than about 0.01 MAY cause
      	// face consolidation to get stuck on particular face.	Most meshes
      	// convert properly with a value of 0.0

      	if (mag/(mag_a*mag_b) <= 0.0f )	return true;

        mag = 1.0f / mag;

      	nx = vw_x * mag;
      	ny = vw_y * mag;
      	nz = vw_z * mag;

      	// Dot product of tri normal with cross product result will
      	// yield positive number if edges are convex (+1.0 if two tris
      	// are coplanar), negative number if edges are concave (-1.0 if
      	// two tris are coplanar.)

      	mag = ( x * nx) + ( y * ny) + ( z * nz);

      	if (mag > 0.0f ) return false;

      	return(true);
      };

      bool PointTestXY(const Vector3d<float> &i,const Vector3d<float> &j) const
      {
        if (((( i.y <= y ) && ( y  < j.y )) ||
             (( j.y <= y ) && ( y  < i.y ))) &&
              ( x < (j.x - i.x) * (y - i.y) / (j.y - i.y) + i.x)) return true;
        return false;
      }

      // test to see if this point is inside the triangle specified by
      // these three points on the X/Y plane.
      bool PointInTriXY(const Vector3d<float> &p1,
                      const Vector3d<float> &p2,
                      const Vector3d<float> &p3) const
      {
        float ax  = p3.x - p2.x;
        float ay  = p3.y - p2.y;
        float bx  = p1.x - p3.x;
        float by  = p1.y - p3.y;
        float cx  = p2.x - p1.x;
        float cy  = p2.y - p1.y;
        float apx = x - p1.x;
        float apy = y - p1.y;
        float bpx = x - p2.x;
        float bpy = y - p2.y;
        float cpx = x - p3.x;
        float cpy = y - p3.y;

        float aCROSSbp = ax*bpy - ay*bpx;
        float cCROSSap = cx*apy - cy*apx;
        float bCROSScp = bx*cpy - by*cpx;

        return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));
      };

      // test to see if this point is inside the triangle specified by
      // these three points on the X/Y plane.
      bool PointInTriYZ(const Vector3d<float> &p1,
                      const Vector3d<float> &p2,
                      const Vector3d<float> &p3) const
      {
        float ay  = p3.y - p2.y;
        float az  = p3.z - p2.z;
        float by  = p1.y - p3.y;
        float bz  = p1.z - p3.z;
        float cy  = p2.y - p1.y;
        float cz  = p2.z - p1.z;
        float apy = y - p1.y;
        float apz = z - p1.z;
        float bpy = y - p2.y;
        float bpz = z - p2.z;
        float cpy = y - p3.y;
        float cpz = z - p3.z;

        float aCROSSbp = ay*bpz - az*bpy;
        float cCROSSap = cy*apz - cz*apy;
        float bCROSScp = by*cpz - bz*cpy;

        return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));
      };

      // test to see if this point is inside the triangle specified by
      // these three points on the X/Y plane.
      bool PointInTriXZ(const Vector3d<float> &p1,
                      const Vector3d<float> &p2,
                      const Vector3d<float> &p3) const
      {
        float az  = p3.z - p2.z;
        float ax  = p3.x - p2.x;
        float bz  = p1.z - p3.z;
        float bx  = p1.x - p3.x;
        float cz  = p2.z - p1.z;
        float cx  = p2.x - p1.x;
        float apz = z - p1.z;
        float apx = x - p1.x;
        float bpz = z - p2.z;
        float bpx = x - p2.x;
        float cpz = z - p3.z;
        float cpx = x - p3.x;

        float aCROSSbp = az*bpx - ax*bpz;
        float cCROSSap = cz*apx - cx*apz;
        float bCROSScp = bz*cpx - bx*cpz;

        return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));
      };

    //private:

      Type x;
      Type y;
      Type z;
    };

    template <class Type> class Vector2d
    {
    public:
      Vector2d(void) { };  // null constructor, does not inialize point.

      Vector2d(const Vector2d &a) // constructor copies existing vector.
      {
        x = a.x;
        y = a.y;
      };

      Vector2d(Type a,Type b) // construct with initial point.
      {
        x = a;
        y = b;
      };

      Vector2d & operator+=(const Vector2d &a) // += operator.
      {
        x+=a.x;
        y+=a.y;
        return *this;
      };

      Vector2d & operator-=(const Vector2d &a)
      {
        x-=a.x;
        y-=a.y;
        return *this;
      };

      Vector2d & operator*=(const Vector2d &a)
      {
        x*=a.x;
        y*=a.y;
        return *this;
      };

      Vector2d & operator/=(const Vector2d &a)
      {
        x/=a.x;
        y/=a.y;
        return *this;
      };

      bool operator==(const Vector2d<Type> &a) const
      {
        if ( a.x == x && a.y == y ) return true;
        return false;
      };

      bool operator!=(const Vector2d &a) const
      {
        if ( a.x != x || a.y != y ) return true;
        return false;
      };

      Vector2d operator+(Vector2d a) const
      {
        a.x+=x;
        a.y+=y;
        return a;
      };

      Vector2d operator-(Vector2d a) const
      {
        a.x = x-a.x;
        a.y = y-a.y;
        return a;
      };

      Vector2d operator - (void) const
      {
        return negative();
      };

      Vector2d operator*(Vector2d a) const
      {
        a.x*=x;
        a.y*=y;
        return a;
      };

    	Vector2d operator*(Type c) const
      {
        Vector2d<Type> a;

    		a.x = x * c;
    		a.y = y * c;

        return a;
      };

      Vector2d operator/(Vector2d a) const
      {
        a.x = x/a.x;
        a.y = y/a.y;
        return a;
      };

    	Type Dot(const Vector2d<Type> &a) const        // computes dot product.
      {
    		return (x * a.x + y * a.y );
      };

      Type GetX(void) const { return x; };
      Type GetY(void) const { return y; };

      void SetX(Type t) { x   = t; };
      void SetY(Type t) { y   = t; };

      void Set(Type a,Type b)
      {
        x = a;
        y = b;
      };

      void Zero(void)
      {
        x = y = z = 0;
      };

    	Vector2d negative(void) const
    	{
    		Vector2d result;
    		result.x = -x;
    		result.y = -y;
    		return result;
    	}

    	Type magnitude(void) const
    	{
    		return (Type) sqrtf(x * x + y * y );
    	}

      void Reflection(Vector2d &a,Vector2d &b); // compute reflection vector.

      Type Length(void) const          // length of vector.
      {
        return Type(sqrtf( x*x + y*y ));
      };

      Type Length2(void)        // squared distance, prior to square root.
      {
        return x*x+y*y;
      }

      Type Distance(const Vector2d &a) const   // distance between two points.
      {
        Type dx = a.x - x;
        Type dy = a.y - y;
        Type d  = dx*dx+dy*dy;
        return sqrtf(d);
      };

      Type Distance2(Vector2d &a) // squared distance.
      {
        Type dx = a.x - x;
        Type dy = a.y - y;
        return dx*dx + dy *dy;
      };

      void Lerp(const Vector2d<Type>& from,const Vector2d<Type>& to,float slerp)
      {
        x = to.x - from.x;
        y = to.y - from.y;
        x*=slerp;
        y*=slerp;
        x+=from.x;
        y+=from.y;
      };

      void Cross(const Vector2d<Type> &a,const Vector2d<Type> &b)  // cross two vectors result in this one.
      {
        x = a.y*b.x - a.x*b.y;
        y = a.x*b.x - a.x*b.x;
      };

    	Type Normalize(void)       // normalize to a unit vector, returns distance.
      {
        Type l = Length();
        if ( l != 0 )
        {
          l = 1.0f / l;
          x*=l;
          y*=l;
        }
        else
        {
          x = y = 0;
        }
        return l;
      };

    //private:
      Type x;
      Type y;
    };

    typedef std::vector< Vector3d<float> > Vector3dVector;
    typedef std::vector< Vector2d<float> > Vector2dVector;

    template <class Type> Vector3d<Type> operator * (Type s, const Vector3d<Type> &v )
          { Vector3d <Type> Scaled(v.x*s, v.y*s, v.z*s);
            return(Scaled); };

    template <class Type> Vector2d<Type> operator * (Type s, const Vector2d<Type> &v )
          { Vector2d <Type> Scaled(v.x*s, v.y*s);
            return(Scaled); };

    // Support for line segments.
    class Line
    {
    public:
      Line(const Vector3d<float> &from,const Vector3d<float> &to)
      {
        mP1 = from;
        mP2 = to;
      };
      // Test for the intersection of two lines.

      bool Intersect(const Line& src,Vector3d<float> §);
    private:
      Vector3d<float> mP1;
      Vector3d<float> mP2;

    };

    #endif

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/stl.h] - (2,184 bytes)

    #ifndef STL_H

    #define STL_H

    //############################################################################
    //##                                                                        ##
    //##  STL.H                                                                 ##
    //##                                                                        ##
    //##  Common include header.  Includes most of STL and sets up some very    ##
    //##  common type definitions.                                              ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    #pragma warning( disable:4786 )  // warning C4503: '  ' : decorated name length exceeded, name was truncated
    #pragma warning( disable:4503	)
    #pragma warning(disable:4800) // int forced to bool

    #include <string>
    #include <map>
    #include <hash_map>
    #include <vector>
    #include <set>
    #include <list>
    #include <queue>
    #include <deque>
    #include <stack>
    #include <iostream>
    #include <algorithm>
    #include <assert.h>

    typedef std::string String;

    typedef std::vector<String> StringVector;
    typedef std::vector< StringVector > StringVectorVector;

    typedef std::vector< int > IntVector;
    typedef std::vector< char > CharVector;
    typedef std::vector< short > ShortVector;
    typedef std::vector< unsigned short > UShortVector;
    typedef std::queue< int > IntQueue;

    #endif

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/arglist.cpp] - (5,407 bytes)

    #include <ctype.h>
    #include <assert.h>

    #include "arglist.h"

    //############################################################################
    //##                                                                        ##
    //##  ARGLIST.CPP                                                             ##
    //##                                                                        ##
    //##  Parses a string into a series of arguments.                           ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    int TranslateEscapedChar( int ch )
    {
      switch( ch )
      {
      case 't':
        ch = '\t';
        break;
      case 'n':
        ch = '\n';
        break;
      case 'f':
        ch = '\f';
        break;
      }
      return ch;
    }

    ArgList::ArgList( void )
    {
    }

    ArgList::ArgList( const String& line )
    {
      Set( line );
    }

    ArgList::~ArgList( void )
    {
    }

    ArgList::ArgList( const ArgList& copy )
    {
      Copy( copy );
    }

    ArgList& ArgList::operator= ( const ArgList& copy )
    {
      Copy( copy );
      return *this;
    }

    ArgList& ArgList::operator= ( const String& line )
    {
      Set( line );
      return *this;
    }

    void ArgList::Copy( const ArgList& copy )
    {
      mArgs = copy.mArgs;
    }

    void ArgList::Set( const String& line )
    {
      enum State
      {
        LINE_START,
        LINE_SPACE,
        LINE_ARG,
        LINE_ESCAPED,
        LINE_QUOTED,
        LINE_QUOTEDESCAPED
      };
      State state;
      CharVector curArg;

      state = LINE_START;
      curArg.clear();
      mArgs.clear();

      for(unsigned int index = 0; index < line.size(); ++index )
      {
        int ch = line[index];

        if( ch == '\n' )
        {
          break;
        }

        switch( state )
        {
    ProcessCharNormally:  // I know, a goto.  But it was convenient. ;)
        case LINE_ARG:
          if( ch == '"' )
          {
            state = LINE_QUOTED;
          }
          else if( ch == '\\' )
          {
            state = LINE_ESCAPED;
          }
          else if( isspace( ch ) )
          {
            String foo( &curArg[0], curArg.size() );
            mArgs.push_back( foo );
            curArg.clear();
            state = LINE_SPACE;
          }
          else
          {
            curArg.push_back( ch );
          }
          break;

        case LINE_START:
          if( !isspace( ch ) )
          {
            state = LINE_ARG;
            goto ProcessCharNormally;
          }
          break;

        case LINE_SPACE:
          if( !isspace( ch ) )
          {
            state = LINE_ARG;
            goto ProcessCharNormally;
          }
          break;

        case LINE_QUOTED:
          if( ch == '"' )
          {
            state = LINE_ARG;
          }
    // Don't process escape characters inside quoted strings!!!
    //      else if( ch == '\\' )
    //      {
    //        state = LINE_QUOTEDESCAPED;
    //      }
          else
          {
            curArg.push_back( ch );
          }
          break;

        case LINE_ESCAPED:
          ch = TranslateEscapedChar( ch );
          state = LINE_ARG;
          curArg.push_back( ch );
          break;

        case LINE_QUOTEDESCAPED:
          ch = TranslateEscapedChar( ch );
          state = LINE_QUOTED;
          curArg.push_back( ch );
          break;
        }
      }

      switch( state )
      {
      case LINE_ARG:
      case LINE_QUOTED:
      case LINE_ESCAPED:
      case LINE_QUOTEDESCAPED:
        {
        String foo( &curArg[0], curArg.size() );
        mArgs.push_back( foo );
        }
        break;

      case LINE_START:
      case LINE_SPACE:
        break;
      }
    }

    int ArgList::size( void ) const
    {
      return mArgs.size();
    }

    bool ArgList::empty( void ) const
    {
      return mArgs.empty();
    }

    const String& ArgList::operator[]( int argc ) const
    {
      return mArgs[argc];
    }

    String& ArgList::operator[]( int argc )
    {
      return mArgs[argc];
    }

    ArgList::operator String ( void ) const
    {
      CharVector result;

      result.clear();
      for(unsigned int argc = 0; argc < mArgs.size(); ++argc )
      {
        if( argc != 0 )
        {
          result.push_back( ' ' );
        }

        if( mArgs[argc].size() != 0 )
        {
          for(unsigned int index = 0; index < mArgs[argc].size(); ++index )
          {
            const String &foo = mArgs[argc];
            int ch = foo[index];

            assert( ch != '\0' );
            if( isspace( ch ) || ch == '"' || ch == '\\' )
            {
              result.push_back( '\\' );
            }
            result.push_back( ch );
          }
        }
        else
        {
          result.push_back( '"' );
          result.push_back( '"' );
        }
      }
      return String( &result[0], result.size() );
    }

    void ArgList::clear( void )
    {
      mArgs.clear();
    }

    void ArgList::Push( const String& arg )
    {
      mArgs.push_back( arg );
    }

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/loadbmp.cpp] - (7,604 bytes)

    //############################################################################
    //##                                                                        ##
    //##  LOADBMP.CPP                                                           ##
    //##                                                                        ##
    //##  Utility routines, reads and writes BMP files.  This is *windows*      ##
    //##  specific, the only piece of code that relies on windows and would     ##
    //##  need to be ported for other OS implementations.                       ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    #include "loadbmp.h"

    #define WIN32_LEAN_AND_MEAN
    #define VC_EXTRALEAN
    #define WIN32_EXTRA_LEAN
    #include <windows.h>

    #include "fload.h"

    unsigned char * Bmp::LoadBMP(const String &fname, int &wid, int &hit, int &bpp)
    {
      Fload data(fname);

      unsigned char *mem = (unsigned char *)data.GetData();
      if ( !mem ) return 0;
      return LoadBMP(mem,wid,hit,bpp);
    }

    unsigned char *Bmp::LoadBMP(const unsigned char *data, int &wid, int &hit, int &Bpp)
    {
      //First things first, init working variables
      if ( !data ) return NULL;
      const unsigned char *p = data;   //working pointer into DIB
      wid = 0;
      hit = 0;
      Bpp = 0;

      //Note: We declare and use a BITMAPINFOHEADER, even though the header
      //  may be of one of the newer types, because we don't need to know the
      //  actual header size in order to find the bitmap bits.  (The offset
      //  is given by bfOffBits)
      BITMAPFILEHEADER *filehdr;
      BITMAPINFOHEADER *infohdr;

      filehdr = (BITMAPFILEHEADER *) p;
      infohdr = (BITMAPINFOHEADER *) (p + sizeof(BITMAPFILEHEADER));
      char *blah = (char*)(infohdr + sizeof(infohdr));

      if ( infohdr->biSize == sizeof(BITMAPCOREHEADER) )
      {
        //Old-style OS/2 bitmap header, we don't support it
        return NULL;
      }
      else
      {
        wid = infohdr->biWidth;
        hit = infohdr->biHeight;
        Bpp = (infohdr->biBitCount / 8);
      }

    //  if ( Bpp != 1 && Bpp != 3 ) return NULL;    //We only support 8bit and 24bit files

      //Set pointer to beginning of packed pixel data
      p = data + filehdr->bfOffBits;

      //FIXME: This assumes a non-compressed bitmap (no RLE)
      long siz;
    #if 0
      int remainder = wid % 4;
      if (remainder != 0)
        siz = (wid + (4-remainder)) * hit * Bpp;
      else
        siz = wid * hit * Bpp;
    #else
      int linesize = ((((Bpp * wid)-1)/4)+1)*4;
      siz = hit * linesize;
    #endif
      unsigned char *mem = new unsigned char[siz];

      assert (mem);

      if ( Bpp == 1 )
      {

        const unsigned char *base_source = &p[(hit-1)*wid];
        unsigned char *base_dest   = mem;

        for (int y=0; y<hit; y++)
        {
          unsigned char *dest = base_dest;
          const unsigned char *source = base_source;
          memcpy(dest,source,wid);
          base_dest+=(wid);
          base_source-=(wid);
        }

      }
      else
      {
        const unsigned char *base_source = &p[(hit-1)*wid*3];
        unsigned char *base_dest   = mem;

        for (int y=0; y<hit; y++)
        {
          unsigned char *dest = base_dest;
          const unsigned char *source = base_source;

          for (int x=0; x<wid; x++)
          {
            dest[0] = source[2];
            dest[1] = source[1];
            dest[2] = source[0];
            dest+=3;
            source+=3;
          }

          base_dest+=(wid*3);
          base_source-=(wid*3);

        }

      }
      return mem;
    }

    void Bmp::SaveBMP(const char *fname,const unsigned char *inputdata, int wid, int hit, int Bpp)
    {
      FILE *fph = fopen(fname,"wb");
      if ( !fph ) return;

      unsigned char *data = 0;
      if ( Bpp == 1 )
      {
        data = (unsigned char *) inputdata;
      }
      else
      {
        const unsigned char *source;
        unsigned char *dest   = new unsigned char[wid*hit*3];
        data = dest; // data to save has flipped RGB order.

        int bwid = wid*3;

        source = &inputdata[(hit-1)*bwid];

        for (int y=0; y<hit; y++)
        {
          memcpy(dest,source,bwid);
          dest+=bwid;
          source-=bwid;
        }

        //swap RGB!!
        if ( 1 )
        {
          unsigned char *swap = data;
          int size = wid*hit;
          for (int i=0; i<size; i++)
          {
            unsigned char c = swap[0];
            swap[0] = swap[2];
            swap[2] = c;
            swap+=3;
          }
        }
      }

      BITMAPFILEHEADER filehdr;
      BITMAPINFOHEADER infohdr;

      DWORD offset = sizeof(filehdr) + sizeof(infohdr);
      if ( Bpp == 1 )
      {
        //Leave room in file for the color table
        offset += (256 * sizeof(RGBQUAD));
      }

      DWORD sizeImage;
      int remainder = wid % 4;
      int linesize;
      if (remainder != 0)
        linesize = wid + (4-remainder);
      else
        linesize = wid;
      sizeImage = linesize * hit * Bpp;

      filehdr.bfType = *((WORD*)"BM");
      filehdr.bfSize = offset + sizeImage;
      filehdr.bfReserved1 = 0;
      filehdr.bfReserved2 = 0;
      filehdr.bfOffBits = offset;

      infohdr.biSize = sizeof(infohdr);
      infohdr.biWidth = wid;
      infohdr.biHeight = hit;
      infohdr.biPlanes = 1;
      infohdr.biBitCount = Bpp * 8;
      infohdr.biCompression = BI_RGB;
      infohdr.biSizeImage = sizeImage;
      infohdr.biClrUsed = 0;
      infohdr.biClrImportant = 0;
      infohdr.biXPelsPerMeter = 72;
      infohdr.biYPelsPerMeter = 72;

      unsigned int writtencount = 0;

      fwrite(&filehdr, sizeof(filehdr),1,fph);

      writtencount += sizeof(filehdr);

      fwrite(&infohdr, sizeof(infohdr),1,fph);
      writtencount += sizeof(infohdr);

      if ( Bpp == 1 )
      {
        //Generate a greyscale color table for this image
        RGBQUAD rgbq;
        rgbq.rgbReserved = 0;
        for ( int i=0; i<256; i++ )
        {
          rgbq.rgbBlue = i;
          rgbq.rgbGreen = i;
          rgbq.rgbRed = i;
          fwrite(&rgbq, sizeof(RGBQUAD),1,fph);
          writtencount += sizeof(RGBQUAD);
        }
      }

      unsigned char *p = data;
      for ( unsigned int i = 0; i < sizeImage; i+=linesize)
      {
        fwrite((void*)p, linesize,1,fph);
        p+=linesize;
        writtencount+=linesize;
      }

      assert ( writtencount == filehdr.bfSize );

      if ( Bpp == 3 )
      {
        delete data;
      }

      fclose(fph);
    }

    void Bmp::SwapRGB(unsigned char *dest, const unsigned char *src, unsigned int size)
    {
      const unsigned char *s = src;
      unsigned char *d = dest;

      for ( unsigned int i=0; i< size; i+=3  )
      {
        unsigned char tmp = s[2];   //in case src and dest point to the same place
        d[2] = s[0];
        d[1] = s[1];
        d[0] = tmp;
        d += 3;
        s += 3;
      }
    }

    void Bmp::SwapVertically(unsigned char *dest, const unsigned char *src, int wid, int hit, int Bpp)
    {
      const unsigned char *s = src;

      int rowSize = wid * Bpp;

      unsigned char *d = dest + (rowSize * (hit-1));

      for ( int r=0 ; r < hit; ++r )
      {
        memcpy(d, s, rowSize);
        s += rowSize;
        d -= rowSize;
      }
    }

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/q3shader.cpp] - (6,065 bytes)

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

    //############################################################################
    //##                                                                        ##
    //##  Q3SHADER.CPP                                                          ##
    //##                                                                        ##
    //##  Reads a Quake3 Shader file.                                           ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    #include "q3shader.h"
    #include "fload.h"

    QuakeShaderFactory *QuakeShaderFactory::gSingleton=0; // global instance of data

    QuakeShaderFactory::QuakeShaderFactory(void)
    {
    #if 1
      AddShader("base.shader");
      AddShader("base_button.shader");
      AddShader("common.shader");
      AddShader("base_floor.shader");
      AddShader("base_light.shader");
      AddShader("base_object.shader");
      AddShader("base_support.shader");
      AddShader("base_trim.shader");
      AddShader("base_wall.shader");
      AddShader("ctf.shader");
      AddShader("eerie.shader");
      AddShader("gfx.shader");
      AddShader("gothic_block.shader");
      AddShader("gothic_floor.shader");
      AddShader("gothic_light.shader");
      AddShader("gothic_trim.shader");
      AddShader("gothic_wall.shader");
      AddShader("hell.shader");
      AddShader("liquid.shader");
      AddShader("menu.shader");
      AddShader("models.shader");
      AddShader("organics.shader");
      AddShader("sfx.shader");
      AddShader("shrine.shader");
      AddShader("skin.shader");
      AddShader("sky.shader");
      AddShader("test.shader");
    #endif
    }

    QuakeShaderFactory::~QuakeShaderFactory(void)
    {
      QuakeShaderMap::iterator i;
      for (i=mShaders.begin(); i!=mShaders.end(); ++i)
      {
        QuakeShader *shader = (*i).second;
        delete shader;
      }
    }

    QuakeShader * QuakeShaderFactory::Locate(const String &str)
    {
      return Locate(StringDict::gStringDict().Get(str));
    }

    QuakeShader * QuakeShaderFactory::Locate(const StringRef &str)
    {
      QuakeShaderMap::iterator found;
      found = mShaders.find(str);
      if ( found != mShaders.end() ) return (*found).second;
      return 0;
    }

    void QuakeShaderFactory::AddShader(const String &sname)
    {

      mBraceCount = 0;
      mCurrent    = 0;

      printf("***********SHADER PROCESS : %s \n",sname.c_str());

      Fload shader(sname);

      while ( 1 )
      {

        char *str = shader.GetString();

        if ( !str ) break;
        ShaderString(str); // process one string.
      }

      delete mCurrent;
      mCurrent = 0;
    }

    void QuakeShaderFactory::ShaderString(const char *str)
    {
      char workspace[1024];

      char *dest = workspace;

      while ( *str )
      {
        if ( str[0] == '//' && str[1] == '//' ) break;
        *dest++ = *str++;
      }
      *dest = 0;
      int len = strlen(workspace);
      if ( len == 0 ) return;

      ArgList::Set( workspace ); // crunch it into arguments.
      // now ready to process it as a series of arguments!
      if ( mArgs.size() ) Process(mArgs);
    }

    void QuakeShaderFactory::Process(const StringVector &args)
    {

      if ( args[0] == "{" )
      {
        mBraceCount++;
      }
      else
      {
        if ( args[0] == "}" )
        {
          mBraceCount--;

          if ( mBraceCount == 0 )
          {
            if ( mCurrent )
            {
              const StringRef& ref = mCurrent->GetName();
              QuakeShaderMap::iterator found;
              found = mShaders.find(ref);
              if ( found != mShaders.end() )
              {
                printf("Can't add shader %s, it already exists!!\n",ref);
              }
              else
              {
                mShaders[ref] = mCurrent;
                printf("Added shader: %s\n",ref);
                mCurrent = 0;
              }
            }
            else
            {
              printf("Got closing brace without valid shader defined.\n");
            }
          }
          else
          {
            if ( mBraceCount < 0 )
            {
              printf("Missmatched closing brace situation!??\n");
              mBraceCount = 0;
            }
          }
        }
        else
        {
          if ( !mBraceCount )
          {
            delete mCurrent; // if didn't process the last one
            mCurrent = 0;
            char name[256];
            if ( GetName(args[0],name) )
            {
              StringRef ref = StringDict::gStringDict().Get(name);
              mCurrent = new QuakeShader(ref);
            }
          }
          else
          {
            // process command!
            if ( args[0] == "map" && args.size() == 2 && mCurrent )
            {
              char name[256];
              if ( GetName(args[1],name) )
              {
                const StringRef ref = StringDict::gStringDict().Get(name);
                mCurrent->AddTexture(ref);
                printf("Adding texture %s\n",ref);
              }
            }
          }
        }
      }
    }

    bool QuakeShaderFactory::GetName(const String &str,char *tname)
    {
      int len = str.size();
      if ( !len ) return false;
      const char *foo = str.c_str();
      foo = &foo[len-1];
      while ( *foo && *foo != '/' ) foo--;
      if ( !*foo ) return false;
      foo++;
      char *dest = tname;
      while ( *foo )
      {
        *dest++ = *foo++;
      }
      *dest = 0;

      len = strlen(tname);
      if ( len >= 4 )
      {
        if ( tname[len-4] == '.' )
        {
          tname[len-4] = 0;
        }
      }
      return true;
    }

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/stringdict.cpp] - (1,435 bytes)

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

    //############################################################################
    //##                                                                        ##
    //##  STRINGDICT.CPP                                                        ##
    //##                                                                        ##
    //##  Global collection of all strings in application, no duplicates.       ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    #include "stringdict.h"

    StringDict *StringDict::gSingleton=0;

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/patch.cpp] - (5,982 bytes)

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

    //############################################################################
    //##                                                                        ##
    //##  PATCH.CPP                                                             ##
    //##                                                                        ##
    //##  Converts a Quake3 Bezier patch into a hard coded polygon mesh.        ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    #include "patch.h"

    #define LEVEL_WIDTH(lvl) ((1 << (lvl+1)) + 1)
    #define MAXMESHLEVEL 5
    #define MINDIST (0.4f*0.4f)

    PatchSurface::PatchSurface(const LightMapVertex *cp,
                               int npoints,
                               int controlx,
                               int controly)
    {
      int sizex,sizey;
      FindSize(controlx,controly,cp,sizex,sizey);

      int size = sizex*sizey;
      mPoints = new LightMapVertex[size];

      int stepx = (sizex-1) / (controlx-1);
      int stepy = (sizey-1) / (controly-1);
      const LightMapVertex *control = cp;

      for (int y=0; y<sizey; y+=stepy)
      {
        for (int x=0; x<sizex; x+=stepx)
        {
          int p = y*sizex+x;
          mPoints[p] = *control++;
        }
      }

      FillPatch(controlx,controly,sizex,sizey,mPoints);

      mCount = (sizex-1)*(sizey-1)*6;

      if ( 1 )
      {
        mIndices = new unsigned short[mCount];
        unsigned short *foo = mIndices;
        for (int y=0; y < sizey-1; ++y)
        {
        	for (int x = 0; x < sizex-1; ++x)
        	{
            *foo++ = y*sizex+x;
            *foo++ = (y+1)*sizex+x;
            *foo++ = y*sizex+x+1;

            *foo++ = y*sizex+x+1;
            *foo++ = (y+1)*sizex+x;
            *foo++ = (y+1)*sizex+x+1;
        	}
        }
      }
    }

    PatchSurface::~PatchSurface(void)
    {
      delete mIndices;
      delete mPoints;
    }

    bool PatchSurface::FindSize(int controlx,int controly,const LightMapVertex *cp,int &sizex,int &sizey) const
    {
      /* Find non-coincident pairs in u direction */

      bool found=false;

      const LightMapVertex *a=0;
      const LightMapVertex *b=0;

      for (int v=0; v <controly; v++)
      {
    	  for (int u=0; u < controlx; u+=2)
      	{

    	    a = &cp[v * controlx + u];
    	    b = &cp[v * controlx + u + 2];

          if ( a->mPos.x != b->mPos.x ||
               a->mPos.y != b->mPos.y ||
               a->mPos.z != b->mPos.z )
    	    {
        		found = true;
    	    	break;
    	    }
       	}
      	if (found) break;
      }

      if (!found)
      {
        printf("Bad mesh control points\n");
        return false;
      }

      /* Find subdivision level in u */
      int levelx = FindLevel(a[0].mPos,a[1].mPos,b[0].mPos);
      sizex = (LEVEL_WIDTH(levelx) - 1) * ((controlx-1) / 2) + 1;

      for (int u=0; u <controlx; v++)
      {
    	  for (int v=0; v < controly; v+=2)
      	{

    	    a = &cp[v * controlx + u];
    	    b = &cp[ ((v+2) * controlx) + u ];

          if ( a->mPos.x != b->mPos.x ||
               a->mPos.y != b->mPos.y ||
               a->mPos.z != b->mPos.z )
    	    {
        		found = true;
    	    	break;
    	    }
       	}
      	if (found) break;
      }

      if (!found)
      {
        printf("Bad mesh control points\n");
        return false;
      }

      /* Find subdivision level in u */
      int levely = FindLevel(a[0].mPos,a[1].mPos,b[0].mPos);
      sizey = (LEVEL_WIDTH(levely) - 1) * ((controly-1) / 2) + 1;

      return true;
    }

    int PatchSurface::FindLevel(const Vector3d<float> &cv0,
                                const Vector3d<float> &cv1,
                                const Vector3d<float> &cv2) const
    {
      int level;
      Vector3d<float> a,b,dist;

      Vector3d<float> v0 = cv0; // init control points.
      Vector3d<float> v1 = cv1;
      Vector3d<float> v2 = cv2;

      /* Subdivide on the left until tolerance is reached */
      for (level=0; level <MAXMESHLEVEL-1; level++)
      {
    	  /* Subdivide on the left */
        a.Lerp(v0,v1,0.5f);
        b.Lerp(v1,v2,0.5f);
        v2.Lerp(a,b,0.5f);

    	  /* Find distance moved */
        dist = v2-v1;

        float dist2 = dist.x*dist.x + dist.y*dist.y + dist.z*dist.z;
        if ( dist2 < MINDIST ) break;

    	  /* Insert new middle vertex */
        v1 = a;
      }

      return level;
    }

    void PatchSurface::FillPatch(int controlx,int controly,int sizex,int sizey,LightMapVertex *p)
    {
      int stepx = (sizex-1) / (controlx-1);
      for (int u = 0; u < sizex; u += stepx)
      {
      	FillCurve(controly, sizey,sizex,p+u);
      }
      for (int v = 0; v < sizey; v++)
      {
      	FillCurve(controlx, sizex, 1, p + v * sizex);
      }
    }

    void PatchSurface::FillCurve(int numcp, int size, int stride,LightMapVertex *p)
    {
      int step, halfstep, i, mid;
      LightMapVertex a,b;

      step = (size-1) / (numcp-1);

      while (step > 0)
      {
    	  halfstep = step / 2;
      	for (i=0; i < size-1; i += step*2)
    	  {
    	    mid = (i+step)*stride;
          a.Lerp(p[i*stride],p[mid],0.5f);
          b.Lerp(p[mid],p[(i+step*2)*stride],0.5f);
          p[mid].Lerp(a,b,0.5f);

    //	    vec_avg(p[i*stride], p[mid], a);
    //	    vec_avg(p[mid], p[(i+step*2)*stride], b);
    //	    vec_avg(a, b, p[mid]);

    	    if (halfstep > 0)
    	    {
    		    p[(i+halfstep)*stride]   = a;
        		p[(i+3*halfstep)*stride] = b;
    	    }
    	  }
      	step /= 2;
      }
    }

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/fload.h] - (1,969 bytes)

    #ifndef FLOAD_H

    #define FLOAD_H

    //############################################################################
    //##                                                                        ##
    //##  FLOAD.H                                                               ##
    //##                                                                        ##
    //##  Loads a file into a block of memory.                                  ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    // Load a binary image block into memory.  Could come from a file on disk
    // or a database.  Access method is not defined.  Will destruct allocated
    // memory when Fload instance goes away!!!  Make your own local copy of
    // it if you need it to stay around.

    #include "stl.h"
    #include "stringdict.h"

    #include <stdio.h>

    class Fload
    {
    public:
      Fload(const String& fname);

      ~Fload(void);

      void * GetData(void) const { return mData; };
      int    GetLen(void) const { return mLen; };

      char * GetString(void);

    private:
      StringRef mName;
      void *mData;
      int   mLen;
      char *mReadLoc;
      int   mReadLen;
    };

    #endif

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/fload.cpp] - (2,888 bytes)

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

    //############################################################################
    //##                                                                        ##
    //##  FLOAD.CPP                                                             ##
    //##                                                                        ##
    //##  Loads a file into a block of memory.                                  ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    #include "fload.h"

    Fload::Fload(const String& fname)
    {
      mName = SGET( fname );
      mData = 0;
      mLen = 0;

      FILE *fph = fopen( mName, "rb");
      if ( fph )
      {
        fseek(fph, 0L, SEEK_END);
        mLen = ftell(fph);
        if ( mLen )
        {
          fseek(fph, 0L, SEEK_SET);
          mData = (void *) new unsigned char[mLen];
          assert( mData );
          if ( mData )
          {
            int r = fread(mData, mLen, 1, fph);
            assert( r );
            if ( !r )
            {
              delete mData;
              mData = 0;
            }
          }
        }
        fclose(fph);
      }
      mReadLoc = (char *)mData;
      mReadLen = mLen;
    }

    Fload::~Fload(void)
    {
      delete mData;
    }

    char * Fload::GetString(void)
    {
      if ( !mReadLoc )
      {
        return 0;
      }

      // now advance read pointer to end of string and stomp a zero
      // byte on top of it as a null string terminator.
      while ( *mReadLoc == 0 || *mReadLoc == 10 || *mReadLoc == 13 )
      {
        mReadLoc++;
        mReadLen--;
        if ( !mReadLen )
        {
          mReadLoc = 0;
          return 0;
        }
      }

      char *ret = mReadLoc; // current read location is string location

      while ( *mReadLoc && *mReadLoc != 10 && *mReadLoc != 13 )
      {
        mReadLoc++;
        mReadLen--;
        if ( !mReadLen )
        {
          mReadLoc = 0;
          break;
        }
      }

      if ( mReadLen ) *mReadLoc = 0; // replace line feeds with null terminated strings.

      if ( mReadLoc ) mReadLoc++;
      mReadLen--;

      if ( !mReadLen )
      {
        mReadLoc = 0;
      }
      return ret;
    }

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/q3bsp.cpp] - (12,838 bytes)

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

    //############################################################################
    //##                                                                        ##
    //##  Q3BSP.CPP                                                             ##
    //##                                                                        ##
    //##  Class to load Quake3 BSP files, interpret them, organize them into    ##
    //##  a triangle mesh, and save them out in various ASCII file formats.     ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    #include "q3bsp.h"
    #include "q3shader.h"
    #include "patch.h"

    #include "fload.h"
    #include "loadbmp.h"

    Quake3BSP::Quake3BSP(const StringRef &fname,
                         const StringRef &code)
    {
      mMesh = 0;

      mOk = false;
      mName     = fname;
      mCodeName = code;

      String ifoo = fname;
      String str = ifoo+".bsp";

      Fload data(str);

      void *mem = data.GetData();
      int   len = data.GetLen();
      if ( mem )
      {

        mOk = mHeader.SetHeader(mem);

        if ( mOk )
        {
          ReadFaces(mem);
          ReadElements(mem);
          ReadVertices(mem);
          ReadLightmaps(mem);
          ReadShaders(mem);
          BuildVertexBuffers();
        }
      }
    }

    Quake3BSP::~Quake3BSP(void)
    {
      delete mMesh;
    }

    bool QuakeHeader::SetHeader(const void *mem)  // returns true if valid quake header.
    {
      const int *ids = (const int *) mem;
      #define BSPHEADERID  (*(int*)"IBSP")
      #define BSPVERSION 46
      if ( ids[0] != BSPHEADERID ) return false;
      if ( ids[1] != BSPVERSION ) return false;
      mId      = ids[0];
      mVersion = ids[1];
      const QuakeLump *lump = (const QuakeLump *) &ids[2];
      for (int i=0; i<NUM_LUMPS; i++) mLumps[i] = *lump++;
      return true;
    }

    void Quake3BSP::ReadShaders(const void *mem)
    {
      assert( mOk );
      int lsize;
      int lcount;

      const unsigned char *smem = (const unsigned char *) mHeader.LumpInfo(Q3_SHADERREFS,mem,lsize,lcount);

      mShaders.clear();
      mShaders.reserve( lcount );

      for (int i=0; i<lcount; i++)
      {
        ShaderReference s(smem);
        mShaders.push_back(s);
        smem+=lsize;
      }

    }

    const void * QuakeHeader::LumpInfo(QuakeLumps lump,
                                     const void *mem,
                                     int &lsize,
                                     int &lcount)
    {

      switch ( lump )
      {
        case Q3_SHADERREFS:
          lsize = 64+sizeof(int)*2;
          break;
        case Q3_PLANES:
          lsize = sizeof(float)*4; // size of a plane equations.
          break;
        case Q3_NODES:
          lsize = sizeof(int)*9;
          break;
        case Q3_LEAFS:
          lsize = sizeof(int)*12;
          break;
        case Q3_FACES:
          lsize = sizeof(int)*26;
          break;
        case Q3_VERTS:
          lsize = sizeof(int)*11;
          break;
        case Q3_LFACES:
          lsize = sizeof(int);
          break;
        case Q3_ELEMS:
          lsize = sizeof(int);
          break;
        case Q3_MODELS:
          lsize = sizeof(int)*10;
          break;
        case Q3_LIGHTMAPS:
          lsize = 1;
          break;
        case Q3_VISIBILITY:
          lsize = 1;
          break;
        default:
          assert( 0 ); // unsupported query type
      }

      int flen = mLumps[lump].GetFileLength();

      assert( flen );
      assert( (flen%lsize) == 0 ); // must be evenly divisible by lump size.
      lcount = flen/lsize; // number of lump items.

      const char *foo = (const char *)mem;
      foo = &foo[ mLumps[lump].GetFileOffset() ];
      return (const void *) foo;
    }

    QuakeNode::QuakeNode(const int *node)
    {
      mPlane = node[0];
      mLeftChild = node[1];
      mRightChild = node[2];

      mBound.r1.x = float( node[3] );
      mBound.r1.y = float( node[4] );
      mBound.r1.z = float( node[5] );
      mBound.r2.x = float( node[6] );
      mBound.r2.y = float( node[7] );
      mBound.r2.z = float( node[8] );

    }

    QuakeLeaf::QuakeLeaf(const int *node)
    {
      mCluster = node[0];
      mArea    = node[1];

      mBound.r1.x = float( node[2] );
      mBound.r1.y = float( node[3] );
      mBound.r1.z = float( node[4] );

      mBound.r2.x = float( node[5] );
      mBound.r2.y = float( node[6] );
      mBound.r2.z = float( node[7] );

      mFirstFace      = node[8];
      mFaceCount      = node[9];
      mFirstUnknown   = node[10];
      mNumberUnknowns = node[11];
    }

    QuakeFace::QuakeFace(const int *face)
    {
      mFrameNo = 0;

      const float *fface = (const float *) face;

      mShader       = face[0];
      mUnknown      = face[1];

      mType         = (FaceType)face[2];

      mFirstVertice = face[3];
      mVcount       = face[4];
      mFirstElement = face[5];
      mEcount       = face[6];
      mLightmap     = face[7];
      mOffsetX      = face[8];
      mOffsetY      = face[9];
      mSizeX        = face[10];
      mSizeY        = face[11];

      mOrig.x       = fface[12];
      mOrig.y       = fface[13];
      mOrig.z       = fface[14];

      mBound.r1.x   = fface[15];
      mBound.r1.y   = fface[16];
      mBound.r1.z   = fface[17];

      mBound.r2.x   = fface[18];
      mBound.r2.y   = fface[19];
      mBound.r2.z   = fface[20];

      mNormal.x     = fface[21];
      mNormal.y     = fface[22];
      mNormal.z     = fface[23];

      mControlX     = face[24];
      mControlY     = face[25];

      static int faceno=0;

      if ( mType == FACETYPE_TRISURF )
      {
        printf("Face: %d\n",faceno++);
        printf("Shader: %d\n",mShader);
        printf("Unknown: %d\n",mUnknown);
        printf("Type: %d\n",mType);
        printf("FirstVertice: %d\n",mFirstVertice);
        printf("Vcount: %d\n",mVcount);
        printf("FirstElement: %d\n",mFirstElement);
        printf("Ecount: %d\n",mEcount);
        printf("Lightmap: %d\n",mLightmap);
        printf("OffsetX: %d\n",mOffsetX);
        printf("OffsetY: %d\n",mOffsetY);
        printf("SizeX: %d\n",mSizeX);
        printf("SizeY: %d\n",mSizeY);
        printf("ControlX: %d\n",mControlX);
        printf("ControlY: %d\n",mControlY);
      }

    }

    QuakeFace::~QuakeFace(void)
    {
    }

    QuakeVertex::QuakeVertex(const int *vert)
    {
      const float *fvert = (const float *) vert;

      mPos.x = fvert[0];
      mPos.y = fvert[1];
      mPos.z = fvert[2];

      mTexel1.x = fvert[3];
      mTexel1.y = fvert[4];

      mTexel2.x = fvert[5];
      mTexel2.y = fvert[6];

      mNormal.x = fvert[7];
      mNormal.y = fvert[8];
      mNormal.z = fvert[9];

      mColor    = (unsigned int) vert[10];

    }

    void Quake3BSP::ReadFaces(const void *mem)
    {
      assert( mOk );
      int lsize;
      int lcount;
      const int *faces = (const int *) mHeader.LumpInfo(Q3_FACES,mem,lsize,lcount);
      assert( lsize == sizeof(int)*26 );

      mFaces.clear();
      mFaces.reserve( lcount );

      for (int i=0; i<lcount; i++)
      {
        QuakeFace f(faces);

        mFaces.push_back(f);

        faces+=26;
      }
    }

    void Quake3BSP::ReadVertices(const void *mem)
    {
      assert( mOk );
      int lsize;
      int lcount;
      const int *vertices = (const int *) mHeader.LumpInfo(Q3_VERTS,mem,lsize,lcount);
      assert( lsize == sizeof(int)*11 );

      mVertices.clear();
      mVertices.reserve( lcount );

      mBound.InitMinMax();

      for (int i=0; i<lcount; i++)
      {
        QuakeVertex v(vertices);

        #define RECIP (1.0f/45.0f)

        v.mPos.x*=RECIP;
        v.mPos.y*=-RECIP;
        v.mPos.z*=RECIP;

        mBound.MinMax(v.mPos);
        mVertices.push_back(v);
        vertices+=11;
      }
    }

    void Quake3BSP::ReadLightmaps(const void *mem)
    {
      assert( mOk );

      int lsize;
      int lcount;
      const unsigned char *maps = (const unsigned char *) mHeader.LumpInfo(Q3_LIGHTMAPS,mem,lsize,lcount);
      unsigned char *lmaps = new unsigned char[lcount];
      memcpy(lmaps,maps,lcount);

      for (int j=0; j<lcount; j++)
      {
        unsigned int c = lmaps[j];
        lmaps[j] = (unsigned char) c;
      }

      #define LMWID 128
      #define LMHIT 128
      #define LMSIZE (LMWID*LMHIT*3)

      int texcount = lcount / LMSIZE;

      Bmp bmp;

      unsigned char *map = lmaps;

      for (int i=0; i<texcount; i++)
      {
        char scratch[256];
        sprintf(scratch,"lm%s%02d",mCodeName,i);
        String sname = scratch;
        String bname = sname+".bmp";
        bmp.SaveBMP(bname.c_str(),map,LMWID,LMHIT,3);
        map+=LMSIZE;
      }

      delete lmaps;

    }

    void Quake3BSP::ReadElements(const void *mem)
    {
      assert( mOk );
      int lsize;
      int lcount;
      const int *elements = (const int *) mHeader.LumpInfo(Q3_ELEMS,mem,lsize,lcount);
      assert( lsize == sizeof(int) );

      mElements.clear();
      mElements.reserve( lcount );

      for (int i=0; i<lcount; i++)
      {
        unsigned short ic = (unsigned short)(*elements);
        mElements.push_back(ic);
        elements++;
      }
    }

    void QuakeVertex::Get(LightMapVertex &vtx) const
    {
      vtx.mPos.x    = mPos.x;
      vtx.mPos.y    = mPos.y;
      vtx.mPos.z    = mPos.z;

      vtx.mTexel1.x = mTexel1.x;
      vtx.mTexel1.y = mTexel1.y;

      vtx.mTexel2.x = mTexel2.x;
      vtx.mTexel2.y = mTexel2.y;
    }

    void Quake3BSP::BuildVertexBuffers(void)
    {
      mMesh = 0;
      mMesh = new VertexMesh;

      QuakeFaceVector::iterator i;
      for (i=mFaces.begin(); i!=mFaces.end(); ++i)
      {
        (*i).Build(mElements,mVertices,mShaders,mName,mCodeName,*mMesh);
      }
    }

    void QuakeFace::Build(const UShortVector &elements,
                          const QuakeVertexVector &vertices,
                          ShaderReferenceVector &shaders,
                          const StringRef &sourcename,
                          const StringRef &code,
                          VertexMesh &mesh)
    {
      assert( mVcount < 1024 );
      assert( mShader >= 0 && mShader < shaders.size() );
      StringRef mat;

      static StringRef oname = StringDict::gStringDict().Get("outside");
      static StringRef inside  = StringDict::gStringDict().Get("inside");

      StringRef name = inside;

      int type = 0;

      LightMapVertex verts[1024];

      for (int i=0; i<mVcount; i++)
      {
        vertices[ i+mFirstVertice ].Get(verts[i]);
      }

      char scratch[256];
      char texname[256];

      shaders[ mShader ].GetTextureName(texname);

      if ( strcmp("toxicskytim_ctf1",texname) == 0 ) return;
      if ( mLightmap < 0 ) return;

      StringRef basetexture = StringDict::gStringDict().Get(texname);

      QuakeShader *shader = QuakeShaderFactory::gQuakeShaderFactory().Locate(basetexture);

      if ( shader )
      {
        shader->GetBaseTexture(basetexture);
        printf("Shader uses texture: %s\n",basetexture);
      }
      sprintf(scratch,"%s+lm%s%02d",basetexture,
              code,
              mLightmap);

      mat = StringDict::gStringDict().Get(scratch);

      char lmapspace[256];
      sprintf(lmapspace,"lm%s%02d",code,mLightmap);
      StringRef lmap = SGET(lmapspace);

      switch ( mType )
      {
        case FACETYPE_NORMAL:
        case FACETYPE_TRISURF:
              if ( 1 )
              {
                assert( (mEcount%3) == 0 );
                const unsigned short *idx = &elements[mFirstElement];
                int tcount = mEcount/3;
                for (int j=0; j<tcount; j++)
                {
                  int i1 = idx[0];
                  int i2 = idx[1];
                  int i3 = idx[2];

                  mesh.AddTri(mat,verts[i1], verts[i2], verts[i3] );

                  idx+=3;
                }
              }
              break;
        case FACETYPE_MESH:
            if ( 1 )
            {
              PatchSurface surface(verts,mVcount,mControlX,mControlY);
              const LightMapVertex *vlist = surface.GetVerts();
              const unsigned short *indices = surface.GetIndices();
              int tcount = surface.GetIndiceCount()/3;

              for (int j=0; j<tcount; j++)
              {

                int i1 = *indices++;
                int i2 = *indices++;
                int i3 = *indices++;

                mesh.AddTri(mat,vlist[i1], vlist[i2], vlist[i3] );

              }
            }
            break;
        case FACETYPE_FLARE:
          break;
        default:
    //      assert( 0 );
          break;
      }
    }

    void ShaderReference::GetTextureName(char *tname)
    {
      strcpy(tname,"null");
      int len = strlen(mName);
      if ( !len ) return;
      const char *foo = &mName[len-1];
      while ( *foo && *foo != '/' ) foo--;
      if ( !*foo ) return;
      foo++;
      char *dest = tname;
      while ( *foo )
      {
        *dest++ = *foo++;
      }
      *dest = 0;
    }

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/q3bsp.h] - (2,731 bytes)

    #ifndef Q3BSP_H

    #define Q3BSP_H

    //############################################################################
    //##                                                                        ##
    //##  Q3BSP.H                                                               ##
    //##                                                                        ##
    //##  Class to load Quake3 BSP files, interpret them, organize them into    ##
    //##  a triangle mesh, and save them out in various ASCII file formats.     ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    #include "stl.h" // common STL definitions
    #include "q3def.h" // include quake3 data structures.
    #include "stringdict.h"
    #include "vector.h"

    // Loads a quake3 bsp file.
    class Quake3BSP
    {
    public:
      Quake3BSP(const StringRef &fname,
                const StringRef &code);

      ~Quake3BSP(void);

      VertexMesh * GetVertexMesh(void) const { return mMesh; };

    private:
      void ReadFaces(const void *mem); // load all faces (suraces) in the bsp
      void ReadVertices(const void *mem); // load all vertex data.
      void ReadLightmaps(const void *mem); // load all lightmap data.
      void ReadElements(const void *mem); // load indices for indexed primitives
      void ReadShaders(const void *mem); // names of the 'shaders' (i.e. texture)

      void BuildVertexBuffers(void);

      bool              mOk;       // quake BSP properly loaded.
      StringRef         mName;     // name of quake BSP
      StringRef         mCodeName;     // short reference code for BSP
      QuakeHeader       mHeader;   // header of quake BSP loaded.
      QuakeFaceVector   mFaces;    // all faces
      QuakeVertexVector mVertices; // all vertices.
      ShaderReferenceVector mShaders; // shader references
      UShortVector      mElements; // indices for draw primitives.
      Rect3d<float>     mBound;
      VertexMesh       *mMesh; // organized mesh
    };

    #endif

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/vformat.h] - (5,649 bytes)

    #ifndef VFORMAT_H

    #define VFORMAT_H

    //############################################################################
    //##                                                                        ##
    //##  VFORMAT.H                                                             ##
    //##                                                                        ##
    //##  Defines a LightMapVertex, which is a vertex with two U/V channels.    ##
    //##  Also defines a class to organize a triangle soup into an ordered mesh ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    #include "vector.h"
    #include "stringdict.h"
    #include "rect.h"

    class LightMapVertex
    {
    public:
      LightMapVertex(void)
      {
      };

      LightMapVertex(float x,float y,float z,float u1,float v1,float u2,float v2)
      {
        mPos.Set(x,y,z);
        mTexel1.Set(u1,v1);
        mTexel2.Set(u2,v2);
      }

      void GetPos(Vector3d<float> &pos) const { pos = mPos; };
      const Vector3d<float>& GetPos(void) const { return mPos; };

      float GetX(void) const { return mPos.x; };
      float GetY(void) const { return mPos.y; };
      float GetZ(void) const { return mPos.z; };

      void Lerp(const LightMapVertex &a,const LightMapVertex &b,float p)
      {
        mPos.Lerp(a.mPos,b.mPos,p);
        mTexel1.Lerp(a.mTexel1,b.mTexel1,p);
        mTexel2.Lerp(a.mTexel2,b.mTexel2,p);
      };

      void Set(int index,const float *pos,const float *texel1,const float *texel2)
      {
        const float * p = &pos[index*3];

        const float * tv1 = &texel1[index*2];
        const float * tv2 = &texel2[index*2];

        mPos.x     = p[0];
        mPos.y     = p[1];
        mPos.z     = p[2];
        mTexel1.x  = tv1[0];
        mTexel1.y  = tv1[1];
        mTexel2.x  = tv2[0];
        mTexel2.y  = tv2[1];
      };

      Vector3d<float> mPos;
      Vector2d<float> mTexel1;
      Vector2d<float> mTexel2;

    };

    typedef std::vector< LightMapVertex > VertexVector;

    class VertexLess
    {
    public:

    	bool operator()(int v1,int v2) const;

      static void SetSearch(const LightMapVertex& match,VertexVector *list)
      {
        mFind = match;
        mList = list;
      };

    private:
      const LightMapVertex& Get(int index) const
      {
        if ( index == -1 ) return mFind;
    	  VertexVector &vlist = *mList;
        return vlist[index];
      }
      static LightMapVertex mFind; // vertice to locate.
      static VertexVector  *mList;
    };

    typedef std::set<int, VertexLess > VertexSet;

    class VertexPool
    {
    public:

      int GetVertex(const LightMapVertex& vtx)
      {
        VertexLess::SetSearch(vtx,&mVtxs);
        VertexSet::iterator found;
        found = mVertSet.find( -1 );
        if ( found != mVertSet.end() )
        {
          return *found;
        }
        int idx = mVtxs.size();
        assert( idx >= 0 && idx < 65536 );
        mVtxs.push_back( vtx );
        mVertSet.insert( idx );
        return idx;
      };

      void GetPos(int idx,Vector3d<float> &pos) const
      {
        pos = mVtxs[idx].mPos;
      }

      const LightMapVertex& Get(int idx) const
      {
        return mVtxs[idx];
      };

      int GetSize(void) const
      {
        return mVtxs.size();
      };

      void Clear(int reservesize)  // clear the vertice pool.
      {
        mVertSet.clear();
        mVtxs.clear();
        mVtxs.reserve(reservesize);
      };

      const VertexVector& GetVertexList(void) const { return mVtxs; };

      void Set(const LightMapVertex& vtx)
      {
        mVtxs.push_back(vtx);
      }

      int GetVertexCount(void) const
      {
        return mVtxs.size();
      };

      bool GetVertex(int i,Vector3d<float> &vect) const
      {
        vect = mVtxs[i].mPos;
        return true;
      };

      void SaveVRML(FILE *fph,bool tex1);

    private:
      VertexSet      mVertSet; // ordered list.
      VertexVector   mVtxs;  // set of vertices.
    };

    class VertexSection
    {
    public:
      VertexSection(const StringRef &name)
      {
        mName = name;
        mBound.InitMinMax();
      };

      void AddTri(const LightMapVertex &v1,
                  const LightMapVertex &v2,
                  const LightMapVertex &v3);

      void SaveVRML(FILE *fph,bool tex1);

    private:

      void AddPoint(const LightMapVertex &p);

      StringRef     mName;
      Rect3d<float> mBound;
      UShortVector  mIndices;
      VertexPool    mPoints;
    };

    typedef std::map< StringRef, VertexSection * > VertexSectionMap;

    class VertexMesh
    {
    public:
      VertexMesh(void)
      {
        mLastSection = 0;
        mBound.InitMinMax();
      };

      ~VertexMesh(void);

      void AddTri(const StringRef &name,
                  const LightMapVertex &v1,
                  const LightMapVertex &v2,
                  const LightMapVertex &v3);

      void SaveVRML(const String &name,  // base file name
                    bool tex1) const;          // texture channel 1=(true)

    private:
      StringRef        mLastName;
      VertexSection   *mLastSection;
      VertexSectionMap mSections;
      Rect3d<float>    mBound; // bounding region for whole mesh
    };

    #endif

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/vformat.cpp] - (7,794 bytes)

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

    //############################################################################
    //##                                                                        ##
    //##  VFORMAT.CPP                                                           ##
    //##                                                                        ##
    //##  Defines a LightMapVertex, which is a vertex with two U/V channels.    ##
    //##  Also defines a class to organize a triangle soup into an ordered mesh ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    #include "vformat.h"

    LightMapVertex VertexLess::mFind;
    VertexVector * VertexLess::mList=0;

    bool VertexLess::operator()(int v1,int v2) const
    {

      const LightMapVertex& a = Get(v1);
      const LightMapVertex& b = Get(v2);

      if ( a.GetX() < b.GetX() ) return true;
      if ( a.GetX() > b.GetX() ) return false;

      if ( a.GetY() < b.GetY() ) return true;
      if ( a.GetY() > b.GetY() ) return false;

      if ( a.GetZ() < b.GetZ() ) return true;
      if ( a.GetZ() > b.GetZ() ) return false;

      if ( a.mTexel1.x < b.mTexel1.x ) return true;
      if ( a.mTexel1.x > b.mTexel1.x ) return false;

      if ( a.mTexel1.y < b.mTexel1.y ) return true;
      if ( a.mTexel1.y > b.mTexel1.y ) return false;

      if ( a.mTexel2.x < b.mTexel2.x ) return true;
      if ( a.mTexel2.x > b.mTexel2.x ) return false;

      if ( a.mTexel2.y < b.mTexel2.y ) return true;
      if ( a.mTexel2.y > b.mTexel2.y ) return false;

      return false;
    };

    VertexMesh::~VertexMesh(void)
    {
      VertexSectionMap::iterator i;
      for (i=mSections.begin(); i!=mSections.end(); ++i)
      {
        VertexSection *section = (*i).second;
        delete section;
      }
    }

    void VertexMesh::AddTri(const StringRef &name,const LightMapVertex &v1,const LightMapVertex &v2,const LightMapVertex &v3)
    {
      VertexSection *section;

      if ( name == mLastName )
      {
        section = mLastSection;
      }
      else
      {
        VertexSectionMap::iterator found;
        found = mSections.find( name );
        if ( found != mSections.end() )
        {
          section = mLastSection = (*found).second;
          mLastName = name;
        }
        else
        {
          mLastSection = section = new VertexSection( name );
          mSections[name] = section;
          mLastName = name;
        }
      }

      assert( section );

      section->AddTri( v1, v2, v3 );

      mBound.MinMax( v1.mPos );
      mBound.MinMax( v2.mPos );
      mBound.MinMax( v3.mPos );

    }

    void VertexSection::AddTri(const LightMapVertex &v1,
                const LightMapVertex &v2,
                const LightMapVertex &v3)
    {
      mBound.MinMax(v1.mPos);
      mBound.MinMax(v2.mPos);
      mBound.MinMax(v3.mPos);

      AddPoint(v1);
      AddPoint(v2);
      AddPoint(v3);

    }

    void VertexSection::AddPoint(const LightMapVertex &p)
    {
      unsigned short idx = (unsigned short)mPoints.GetVertex(p);
      mIndices.push_back(idx);
    };

    void VertexMesh::SaveVRML(const String &name,  // base file name
                  bool tex1) const           // texture channel 1=(true)
    {
      if ( mSections.size() )
      {
        String oname = name+".wrl";
        FILE *fph = fopen(oname.c_str(),"wb");

        if ( fph )
        {
          fprintf(fph,"#VRML V1.0 ascii\n");
          fprintf(fph,"Separator {\n");
          fprintf(fph,"  ShapeHints {\n");
          fprintf(fph,"    shapeType SOLID\n");
          fprintf(fph,"    vertexOrdering COUNTERCLOCKWISE\n");
          fprintf(fph,"    faceType CONVEX\n");
          fprintf(fph,"  }\n");

          VertexSectionMap::const_iterator i;

          for (i=mSections.begin(); i!=mSections.end(); ++i)
          {
            (*i).second->SaveVRML(fph,tex1);
          }

          fprintf(fph,"}\n");

          fclose(fph);
        }
      }
    }

    void VertexSection::SaveVRML(FILE *fph,bool tex1)
    {
      // save it into a VRML file!
      static int itemcount=1;

      fprintf(fph,"DEF item%d Separator {\n",itemcount++);
      fprintf(fph,"Translation { translation 0 0 0 }\n");
      fprintf(fph,"Material {\n");
      fprintf(fph,"  ambientColor 0.1791 0.06536 0.06536\n");
      fprintf(fph,"  diffuseColor 0.5373 0.1961 0.1961\n");
      fprintf(fph,"  specularColor 0.9 0.9 0.9\n");
      fprintf(fph,"  shininess 0.25\n");
      fprintf(fph,"  transparency 0\n");
      fprintf(fph,"}\n");
      fprintf(fph,"Texture2 {\n");

      const char *foo = mName;
      char scratch[256];

      if ( !tex1 )
      {
        while ( *foo && *foo != '+' ) foo++;
        char *dest = scratch;
        if ( *foo == '+' )
        {
          foo++;
          while ( *foo ) *dest++ = *foo++;
        }
        *dest = 0;
      }
      else
      {
        char *dest = scratch;
        while ( *foo && *foo != '+' ) *dest++ = *foo++;
        *dest = 0;
      }

      if ( tex1 )
        fprintf(fph,"  filename %c%s.tga%c\n",0x22,scratch,0x22);
      else
        fprintf(fph,"  filename %c%s.bmp%c\n",0x22,scratch,0x22);

      fprintf(fph,"}\n");

      mPoints.SaveVRML(fph,tex1);

      int tcount = mIndices.size()/3;

      if ( 1 )
      {
        fprintf(fph,"  IndexedFaceSet { coordIndex [\n");
        UShortVector::iterator j= mIndices.begin();
        for (int i=0; i<tcount; i++)
        {
          int i1 = *j;
          j++;
          int i2 = *j;
          j++;
          int i3 = *j;
          j++;
          if ( i == (tcount-1) )
            fprintf(fph,"  %d, %d, %d, -1]\n",i1,i2,i3);
          else
            fprintf(fph,"  %d, %d, %d, -1,\n",i1,i2,i3);
        }
      }

      if ( 1 )
      {
        fprintf(fph,"  textureCoordIndex [\n");
        UShortVector::iterator j= mIndices.begin();
        for (int i=0; i<tcount; i++)
        {
          int i1 = *j;
          j++;
          int i2 = *j;
          j++;
          int i3 = *j;
          j++;
          if ( i == (tcount-1) )
            fprintf(fph,"  %d, %d, %d, -1]\n",i1,i2,i3);
          else
            fprintf(fph,"  %d, %d, %d, -1,\n",i1,i2,i3);
        }
      }
      fprintf(fph,"  }\n");
      fprintf(fph,"}\n");
    };

    void VertexPool::SaveVRML(FILE *fph,bool tex1)
    {
      if ( 1 )
      {
        fprintf(fph,"  Coordinate3 { point [\n");
        int count = mVtxs.size();
        for (int i=0; i<count; i++)
        {
          const LightMapVertex &vtx = mVtxs[i];
          if ( i == (count-1) )
            fprintf(fph,"  %f %f %f]\n",vtx.mPos.x,vtx.mPos.y,vtx.mPos.z);
          else
            fprintf(fph,"  %f %f %f,\n",vtx.mPos.x,vtx.mPos.y,vtx.mPos.z);
        }
        fprintf(fph,"   }\n");
      }
      if ( 1 )
      {
        fprintf(fph,"  TextureCoordinate2 { point [\n");
        int count = mVtxs.size();

        for (int i=0; i<count; i++)
        {
          const LightMapVertex &vtx = mVtxs[i];

          if ( !tex1 ) // if saving second U/V channel.
          {
            if ( i == (count-1) )
              fprintf(fph,"  %f %f]\n",vtx.mTexel2.x,1.0f-vtx.mTexel2.y);
            else
              fprintf(fph,"  %f %f,\n",vtx.mTexel2.x,1.0f-vtx.mTexel2.y);
          }
          else
          {
            if ( i == (count-1) )
              fprintf(fph,"  %f %f]\n",vtx.mTexel1.x,1.0f-vtx.mTexel1.y);
            else
              fprintf(fph,"  %f %f,\n",vtx.mTexel1.x,1.0f-vtx.mTexel1.y);
          }
        }

        fprintf(fph,"   }\n");
      }
    }

Currently browsing [q3bsp_src.zip] (36,397 bytes) - [q3bsp/main.cpp] - (3,284 bytes)

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

    //############################################################################
    //##                                                                        ##
    //##  MAIN.CPP                                                              ##
    //##                                                                        ##
    //##  Console APP to load Q3BSP files, interpret them, organize them into   ##
    //##  a triangle mesh, and save them out in various ASCII file formats.     ##
    //##                                                                        ##
    //##  OpenSourced 12/5/2000 by John W. Ratcliff                             ##
    //##                                                                        ##
    //##  No warranty expressed or implied.                                     ##
    //##                                                                        ##
    //##  Part of the Q3BSP project, which converts a Quake 3 BSP file into a   ##
    //##  polygon mesh.                                                         ##
    //############################################################################
    //##                                                                        ##
    //##  Contact John W. Ratcliff at jratcliff@verant.com                      ##
    //############################################################################

    #include "q3bsp.h"

    void main(int argc,char **argv)
    {

      // Usage: q3bsp <name>.BSP
      if ( argc != 2 )
      {
        printf("Usage: q3bsp <name>.BSP\n");
        printf("Where <name> is the name of a valid Quake3 BSP file.\n\n");
        printf("This utility will convert a Quake3 BSP into a valid\n");
        printf("polygon mesh and output the results into two seperate VRML 1.0\n");
        printf("files.  The first VRML file contains all the U/V mapping and\n");
        printf("texture mapping information for channel #1, and the second\n");
        printf("VRML file will contain all of the U/V mapping and texture names\n");
        printf("for the second U/V channel, which contains all lightmap\n");
        printf("information.  You can then directly import these files into any\n");
        printf("number of 3d editing tools, including 3d Studio Max\n");

        printf("This tool also extracts the lightmap data and saves it out as a\n");
        printf("series of .BMP files.\n\n");
        printf("OpenSourced by John W. Ratcliff on December 5, 2000\n");
        printf("Merry Christmas!\n\n");
        printf("Contact Id Software about using Quake 3 data files in and\n");
        printf("Quake 3 editing tools for commercial software development\n");
        printf("projects.\n");
        exit(1);
      }

      Quake3BSP q( SGET(argv[1]), SGET("a") );

      VertexMesh *mesh = q.GetVertexMesh();
      if ( mesh )
      {
        // save VRML file using channel #1
        // save VRML file using channel #2
        String str = argv[1];
        String name1 = str + "1";
        String name2 = str + "2";
        printf("Saving U/V channel #1 to file %s.WRL\n",name1.c_str());
        mesh->SaveVRML(name1,true);
        printf("Saving U/V channel #2 to file %s.WRL\n",name2.c_str());
        mesh->SaveVRML(name2,false);
      }
      else
      {
        printf("Failed to crunch %s\n", argv[1]);
      }

    }

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.