Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

gfx/CLODTerrainRenderer.cpp

Go to the documentation of this file.
00001 //
00002 // This code is a hacked up version of the Demeter Terrain
00003 // code from http://www.terrainengine.com
00004 // (hacked up because I removed the SDL and CommonC++
00005 //  dependencies, and helpded it compile with gcc3.x)
00006 // -David Jung.
00007 //
00008 
00009 // Demeter Terrain Visualization Library by Clay Fowler
00010 // Copyright (C) 2001 Clay Fowler
00011 
00012 /*
00013 This library is free software; you can redistribute it and/or
00014 modify it under the terms of the GNU Library General Public
00015 License as published by the Free Software Foundation; either
00016 version 2 of the License, or (at your option) any later version.
00017 
00018 This library is distributed in the hope that it will be useful,
00019 but WITHOUT ANY WARRANTY; without even the implied warranty of
00020 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00021 Library General Public License for more details.
00022 
00023 You should have received a copy of the GNU Library General Public
00024 License along with this library; if not, write to the
00025 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00026 Boston, MA  02111-1307, USA.
00027 */
00028 
00029 #include <iostream>
00030 extern "C" {
00031 #define GL_GLEXT_PROTOTYPES
00032 #include <GL/gl.h>
00033 #include <GL/glext.h>
00034 }
00035 
00036 #include <gfx/CLODTerrainRenderer>
00037 #include <base/BitArray>
00038 
00039 
00040 #include <string>
00041 
00042 #include <osg/Image>
00043 
00044 #include <osgDB/Registry>
00045 #include <osgDB/ReadFile>
00046 
00047 using std::cout;
00048 using std::endl;
00049 using std::flush;
00050 using std::vector;
00051 using std::string;
00052 
00053 using namespace gfx;
00054 using namespace demeter;
00055 
00056 using base::BitArray;
00057 
00058 #ifndef GLAPIENTRY
00059 #define GLAPIENTRY
00060 #endif
00061 
00062 #define GL_CLAMP_TO_EDGE_EXT                0x812F
00063 #define GL_TEXTURE0_ARB                     0x84C0
00064 #define GL_TEXTURE1_ARB                     0x84C1
00065 #define GL_COMBINE_RGB_EXT                                      0x8571
00066 #define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT     0x81A8
00067 #define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT     0x81A9
00068 #define COMPRESSED_RGB_S3TC_DXT1_EXT        0x83F0
00069 
00070 typedef void (GLAPIENTRY *PFNGLMULTITEXCOORD2FARBPROC)(GLenum texture,GLfloat s,GLfloat t);
00071 typedef void (GLAPIENTRY *PFNGLACTIVETEXTUREARBPROC)(GLenum texture);
00072 #ifdef _USE_VERTEX_ARRAYS_
00073 typedef void (GLAPIENTRY *PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count);
00074 typedef void (GLAPIENTRY *PFNGLUNLOCKARRAYSEXTPROC) (void);
00075 #endif
00076 
00077 
00078 PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB_ptr = NULL;
00079 PFNGLACTIVETEXTUREARBPROC glActiveTextureARB_ptr = NULL;
00080 #ifdef _USE_VERTEX_ARRAYS_
00081     PFNGLLOCKARRAYSEXTPROC glLockArraysEXT_ptr = NULL;
00082     PFNGLUNLOCKARRAYSEXTPROC glUnlockArraysEXT_ptr = NULL;
00083 #endif
00084 
00085 
00086 Settings* pSettingsInstance = NULL; // Singleton instance of the global settings
00087 
00088 float numBlocks = 0.0f;
00089 float numLevels = 0.0f;
00090 float hashDelta = 0.0f;
00091 
00092 GLuint CreateTexture(Uint8* pTexels,int width,int height,int rowLength,int border,int internalFormat,bool bClamp,bool bColorKey = false);
00093 void LoadImage(char* szFilename,int* pWidth,int* pHeight,Uint8** pBuffer,bool bColorKey = false);
00094 int RayPlaneIntersect(Ray *ray,Plane *plane,Vector* point,float *distance);
00095 int RayBoxIntersect(Ray *ray,Box *box,Vector *point,float *distance);
00096 bool IsPowerOf2(double number);
00097 
00098 TerrainBlock::TerrainBlock(TerrainBlock* pParent)
00099 {
00100     m_pChildren = NULL;
00101     m_pParent = pParent;
00102     m_pTriangleStrip = NULL;
00103 #ifdef _USE_RAYTRACING_SUPPORT_
00104         m_pTriangles = NULL;
00105 #endif
00106 }
00107 
00108 TerrainBlock::TerrainBlock(int homeVertex,int stride,Terrain* pTerrain,TerrainBlock* pParent)
00109 {
00110     m_pTriangleStrip = NULL;
00111     m_pParent = pParent;
00112     m_HomeIndex = homeVertex;
00113     m_Stride = stride;
00114     static int numBlocksBuilt = 0;
00115 
00116         if (Settings::GetInstance()->IsVerbose())
00117         {
00118         if (hashDelta <= numBlocksBuilt++)
00119         {
00120             cout << "#" << flush;
00121             numBlocksBuilt = 0;
00122         }
00123         }
00124 // Find this block's bounding box.
00125     float minElevation = pTerrain->GetElevation(homeVertex);
00126     float maxElevation = pTerrain->GetElevation(homeVertex);
00127     for (int i = homeVertex; i <= homeVertex + pTerrain->GetWidthVertices() * m_Stride; i += pTerrain->GetWidthVertices())
00128     {
00129       for (int j = i; j < i + m_Stride; j++)
00130         {
00131           float elevation = pTerrain->GetElevation(j);
00132           if (elevation < minElevation)
00133             minElevation = elevation;
00134           if (maxElevation < elevation)
00135             maxElevation = elevation;
00136         }
00137     }
00138     Vector boxUpperLeft,boxLowerRight,boxCenter;
00139     boxUpperLeft.x = pTerrain->m_pVertices[homeVertex].x + pTerrain->m_OffsetX;
00140     boxUpperLeft.y = pTerrain->m_pVertices[homeVertex].y + pTerrain->m_OffsetY;
00141     boxUpperLeft.z = maxElevation;
00142     boxLowerRight.x = pTerrain->m_pVertices[homeVertex + m_Stride * pTerrain->GetWidthVertices() + m_Stride].x + pTerrain->m_OffsetX;
00143     boxLowerRight.y = pTerrain->m_pVertices[homeVertex + m_Stride * pTerrain->GetWidthVertices() + m_Stride].y + pTerrain->m_OffsetY;
00144     boxLowerRight.z = minElevation;
00145     boxCenter.x = (boxUpperLeft.x + boxLowerRight.x) * 0.5f;
00146     boxCenter.y = (boxUpperLeft.y + boxLowerRight.y) * 0.5f;
00147     boxCenter.z = (boxUpperLeft.z + boxLowerRight.z) * 0.5f;
00148     m_BoundingBoxUpperCenter = boxCenter;
00149     m_BoundingBoxLowerCenter = boxCenter;
00150     m_BoundingBoxUpperCenter.z = boxUpperLeft.z;
00151     m_BoundingBoxLowerCenter.z = boxLowerRight.z;
00152 
00153 // Recursively build children blocks of this block.
00154     if (2 < m_Stride)
00155     {
00156       m_pChildren = new TerrainBlock*[4];
00157       int childrenStride = m_Stride / 2;
00158       m_pChildren[0] = new TerrainBlock(homeVertex,                                                                                                                                     childrenStride,pTerrain,this);
00159       m_pChildren[1] = new TerrainBlock(homeVertex + childrenStride,                                                                                                    childrenStride,pTerrain,this);
00160       m_pChildren[2] = new TerrainBlock(homeVertex + childrenStride * pTerrain->GetWidthVertices() + childrenStride,    childrenStride,pTerrain,this);
00161       m_pChildren[3] = new TerrainBlock(homeVertex + childrenStride * pTerrain->GetWidthVertices(),                                     childrenStride,pTerrain,this);
00162     }
00163     CalculateGeometry(pTerrain);
00164 }
00165 
00166 TerrainBlock::~TerrainBlock()
00167 {
00168   m_pParent = NULL;
00169   m_pTriangleStrip = NULL;
00170   if (m_pChildren != NULL && 2 < m_Stride)
00171     {
00172       for (int i = 0; i < 4; i++)
00173         {
00174           delete m_pChildren[i];
00175           m_pChildren[i] = NULL;
00176         }
00177       delete[] m_pChildren;
00178     }
00179 }
00180 
00181 bool TerrainBlock::IsActive()
00182 {
00183   return m_bIsActive;
00184 }
00185 
00186 void TerrainBlock::Tessellate(double* pMatModelView,double* pMatProjection,int* pViewport,TriangleStrip* pTriangleStrips,TriangleFan* pTriangleFans,int* pCountStrips,int* pCountFans,Terrain* pTerrain)
00187 {
00188   if ((*pCountStrips < pTerrain->m_MaxNumberOfPrimitives) && pTerrain->CubeInFrustum(m_BoundingBoxUpperCenter.x,m_BoundingBoxUpperCenter.y,m_CubeCenterZ,m_CubeSize))
00189     {
00190       if (m_Stride == 2)
00191         {
00192           int offset;
00193           
00194           pTerrain->SetVertexStatus(m_HomeIndex,1);
00195           pTriangleStrips[*pCountStrips].m_pVertices[0] = m_HomeIndex;
00196           offset = m_HomeIndex + pTerrain->GetWidthVertices();
00197           pTerrain->SetVertexStatus(offset,1);
00198           pTriangleStrips[*pCountStrips].m_pVertices[1] = offset;
00199           offset = m_HomeIndex + 1;
00200           pTerrain->SetVertexStatus(offset,1);
00201           pTriangleStrips[*pCountStrips].m_pVertices[2] = offset;
00202           offset = m_HomeIndex + 1 + pTerrain->GetWidthVertices();
00203           pTerrain->SetVertexStatus(offset,1);
00204           pTriangleStrips[*pCountStrips].m_pVertices[3] = offset;
00205           offset = m_HomeIndex + 2;
00206           pTerrain->SetVertexStatus(offset,1);
00207           pTriangleStrips[*pCountStrips].m_pVertices[4] = offset;
00208           offset = m_HomeIndex + 2 + pTerrain->GetWidthVertices();
00209           pTerrain->SetVertexStatus(offset,1);
00210           pTriangleStrips[*pCountStrips].m_pVertices[5] = offset;
00211           pTriangleStrips[*pCountStrips].m_NumberOfVertices = 6;
00212           pTriangleStrips[*pCountStrips].m_bEnabled = true;
00213           *pCountStrips = *pCountStrips + 1;
00214           
00215           if (*pCountStrips < pTerrain->m_MaxNumberOfPrimitives)
00216             {
00217               offset = pTerrain->GetWidthVertices() + m_HomeIndex;
00218               pTerrain->SetVertexStatus(offset,1);
00219               pTriangleStrips[*pCountStrips].m_pVertices[0] = offset;
00220               offset = pTerrain->GetWidthVertices() + m_HomeIndex + pTerrain->GetWidthVertices();
00221               pTerrain->SetVertexStatus(offset,1);
00222               pTriangleStrips[*pCountStrips].m_pVertices[1] = offset;
00223               offset = pTerrain->GetWidthVertices() + m_HomeIndex + 1;
00224               pTerrain->SetVertexStatus(offset,1);
00225               pTriangleStrips[*pCountStrips].m_pVertices[2] = offset;
00226               offset = pTerrain->GetWidthVertices() + m_HomeIndex + 1 + pTerrain->GetWidthVertices();
00227               pTerrain->SetVertexStatus(offset,1);
00228               pTriangleStrips[*pCountStrips].m_pVertices[3] = offset;
00229               offset = pTerrain->GetWidthVertices() + m_HomeIndex + 2;
00230               pTerrain->SetVertexStatus(offset,1);
00231               pTriangleStrips[*pCountStrips].m_pVertices[4] = offset;
00232               offset = pTerrain->GetWidthVertices() + m_HomeIndex + 2 + pTerrain->GetWidthVertices();
00233               pTerrain->SetVertexStatus(offset,1);
00234               pTriangleStrips[*pCountStrips].m_pVertices[5] = offset;
00235               pTriangleStrips[*pCountStrips].m_NumberOfVertices = 6;
00236               pTriangleStrips[*pCountStrips].m_bEnabled = true;
00237               *pCountStrips = *pCountStrips + 1;
00238             }
00239           
00240           m_bIsActive = true;
00241         }
00242       else
00243         {
00244           if (pTerrain->m_MaximumVisibleBlockSize < m_Stride)
00245             {
00246               m_pChildren[0]->Tessellate(pMatModelView,pMatProjection,pViewport,pTriangleStrips,pTriangleFans,pCountStrips,pCountFans,pTerrain);
00247               m_pChildren[1]->Tessellate(pMatModelView,pMatProjection,pViewport,pTriangleStrips,pTriangleFans,pCountStrips,pCountFans,pTerrain);
00248               m_pChildren[2]->Tessellate(pMatModelView,pMatProjection,pViewport,pTriangleStrips,pTriangleFans,pCountStrips,pCountFans,pTerrain);
00249               m_pChildren[3]->Tessellate(pMatModelView,pMatProjection,pViewport,pTriangleStrips,pTriangleFans,pCountStrips,pCountFans,pTerrain);
00250               m_bIsActive = false;
00251               m_bChildrenActive = true;
00252             }
00253           else
00254             {
00255               double screenTopX,screenTopY,screenTopZ,screenBottomX,screenBottomY,screenBottomZ;
00256               float halfWidth = m_CubeSize * 0.5f;
00257               // Check the vertical screen size of the block 
00258               gluProject(m_BoundingBoxUpperCenter.x,m_BoundingBoxUpperCenter.y,m_BoundingBoxUpperCenter.z,pMatModelView,pMatProjection,pViewport,&screenTopX,&screenTopY,&screenTopZ);
00259               gluProject(m_BoundingBoxLowerCenter.x,m_BoundingBoxLowerCenter.y,m_BoundingBoxLowerCenter.z,pMatModelView,pMatProjection,pViewport,&screenBottomX,&screenBottomY,&screenBottomZ);
00260               float screenDistVertical = fabs(screenTopY - screenBottomY);
00261                                 // Use both the X and Y axes to find the horizontal screen size of the block by using the larger of the two.
00262               gluProject(m_BoundingBoxUpperCenter.x - halfWidth,m_BoundingBoxUpperCenter.y,m_BoundingBoxUpperCenter.z,pMatModelView,pMatProjection,pViewport,&screenTopX,&screenTopY,&screenTopZ);
00263               gluProject(m_BoundingBoxLowerCenter.x + halfWidth,m_BoundingBoxLowerCenter.y,m_BoundingBoxLowerCenter.z,pMatModelView,pMatProjection,pViewport,&screenBottomX,&screenBottomY,&screenBottomZ);
00264               float screenDistX = fabs(screenTopX - screenBottomX);
00265               gluProject(m_BoundingBoxUpperCenter.x,m_BoundingBoxUpperCenter.y - halfWidth,m_BoundingBoxUpperCenter.z,pMatModelView,pMatProjection,pViewport,&screenTopX,&screenTopY,&screenTopZ);
00266               gluProject(m_BoundingBoxLowerCenter.x,m_BoundingBoxLowerCenter.y + halfWidth,m_BoundingBoxLowerCenter.z,pMatModelView,pMatProjection,pViewport,&screenBottomX,&screenBottomY,&screenBottomZ);
00267               float screenDistY = fabs(screenTopX - screenBottomX);
00268               float screenDistHorizontal = screenDistX < screenDistY ? screenDistY : screenDistX;
00269               
00270                                 // Use the smaller of vertical and horizontal screen size to decide whether or not the block should be simplified.
00271               float screenDist = screenDistHorizontal < screenDistVertical ? screenDistHorizontal : screenDistVertical;
00272               
00273               if (screenDist <= pTerrain->GetDetailThreshold())
00274                 {
00275                   // This block is simplified, so add its triangles to the list and stop recursing.
00276                   CreateTriangleStrip(pTriangleStrips,pCountStrips,pTerrain);
00277                   m_bIsActive = true;
00278                   m_bChildrenActive = false;
00279                 }
00280               else
00281                 {
00282                   m_pChildren[0]->Tessellate(pMatModelView,pMatProjection,pViewport,pTriangleStrips,pTriangleFans,pCountStrips,pCountFans,pTerrain);
00283                   m_pChildren[1]->Tessellate(pMatModelView,pMatProjection,pViewport,pTriangleStrips,pTriangleFans,pCountStrips,pCountFans,pTerrain);
00284                   m_pChildren[2]->Tessellate(pMatModelView,pMatProjection,pViewport,pTriangleStrips,pTriangleFans,pCountStrips,pCountFans,pTerrain);
00285                   m_pChildren[3]->Tessellate(pMatModelView,pMatProjection,pViewport,pTriangleStrips,pTriangleFans,pCountStrips,pCountFans,pTerrain);
00286                   m_bIsActive = false;
00287                   m_bChildrenActive = true;
00288                 }
00289             }
00290         }
00291     }
00292   else
00293     {
00294       m_bIsActive = false;
00295       m_bChildrenActive = false;
00296     }
00297 }
00298 
00299 inline void TerrainBlock::CreateTriangleStrip(TriangleStrip* pTriangleStrips,int* pCount,Terrain* pTerrain)
00300 {
00301   if (*pCount < pTerrain->m_MaxNumberOfPrimitives)
00302     {
00303       pTerrain->SetVertexStatus(m_HomeIndex,1);
00304       pTriangleStrips[*pCount].m_pVertices[0] = m_HomeIndex;
00305       int offset = m_HomeIndex + pTerrain->GetWidthVertices() * m_Stride;
00306       pTerrain->SetVertexStatus(offset,1);
00307       pTriangleStrips[*pCount].m_pVertices[1] = offset;
00308       offset = m_HomeIndex + m_Stride;
00309       pTerrain->SetVertexStatus(offset,1);
00310       pTriangleStrips[*pCount].m_pVertices[2] = offset;
00311       offset = m_HomeIndex + m_Stride + pTerrain->GetWidthVertices() * m_Stride;
00312       pTerrain->SetVertexStatus(offset,1);
00313       pTriangleStrips[*pCount].m_pVertices[3] = offset;
00314       pTriangleStrips[*pCount].m_bEnabled = true;
00315       pTriangleStrips[*pCount].m_NumberOfVertices = 4;
00316       
00317       m_pTriangleStrip = &pTriangleStrips[*pCount];
00318       *pCount = *pCount + 1;
00319     }
00320 }
00321 
00322 void TerrainBlock::EnableStrip(bool bEnabled)
00323 {
00324   m_pTriangleStrip->m_bEnabled = false;
00325 }
00326 
00327 inline int TerrainBlock::GetStride()
00328 {
00329   return m_Stride;
00330 }
00331 
00332 inline TerrainBlock* TerrainBlock::GetParent()
00333 {
00334   return m_pParent;
00335 }
00336 
00337 inline int TerrainBlock::GetHomeIndex()
00338 {
00339   return m_HomeIndex;
00340 }
00341 
00342 void TerrainBlock::RepairCracks(Terrain* pTerrain,TriangleStrip* pTriangleStrips,TriangleFan* pTriangleFans,int* pCountStrips,int* pCountFans)
00343 {
00344   if (2 < m_Stride)
00345     {
00346       if (m_bIsActive)
00347         {
00348           int halfStride = m_Stride / 2;
00349           int bottomLeft = m_HomeIndex + m_Stride * pTerrain->GetWidthVertices();
00350           int bottomRight = bottomLeft + m_Stride;
00351           int i,previousVertex=0;
00352           int v0;
00353           int numVertices = 0;
00354           
00355           bool bNeedToFix = false;
00356           for (i = m_HomeIndex + m_Stride - 1; m_HomeIndex < i && !bNeedToFix; i--)
00357             bNeedToFix = (pTerrain->GetVertexStatus(i) == 1);
00358           if (!bNeedToFix)
00359             {
00360               for (i = m_HomeIndex + pTerrain->GetWidthVertices(); i < m_HomeIndex + m_Stride * pTerrain->GetWidthVertices() && !bNeedToFix; i += pTerrain->GetWidthVertices())
00361                 bNeedToFix = (pTerrain->GetVertexStatus(i) == 1);
00362               if (!bNeedToFix)
00363                 {
00364                   for (i = bottomLeft + 1; i < bottomRight && !bNeedToFix; i++)
00365                     bNeedToFix = (pTerrain->GetVertexStatus(i) == 1);
00366                   if (!bNeedToFix)
00367                     {
00368                       for (i = bottomRight - pTerrain->GetWidthVertices(); m_HomeIndex + m_Stride < i && !bNeedToFix; i -= pTerrain->GetWidthVertices())
00369                         bNeedToFix = (pTerrain->GetVertexStatus(i) == 1);
00370                     }
00371                 }
00372             }
00373           
00374           if (bNeedToFix)
00375             {
00376               EnableStrip(false);
00377               v0 = m_HomeIndex + halfStride + halfStride * pTerrain->GetWidthVertices();
00378               Assert(0 <= v0);
00379               Assert(v0 < pTerrain->GetNumberOfVertices());
00380               pTriangleFans[*pCountFans].m_pVertices[0] = v0;
00381               numVertices = 0;
00382               for (i = m_HomeIndex + m_Stride; m_HomeIndex <= i; i--)
00383                 {
00384                   Assert(0 <= i);
00385                   Assert(i < pTerrain->GetNumberOfVertices());
00386                   if (pTerrain->GetVertexStatus(i) == 1)
00387                     {
00388                       if (++numVertices == MAX_VERTICES_PER_FAN - 1)
00389                         {
00390                           // We have reached the maximum size for a fan, so start a new fan.
00391                           pTriangleFans[*pCountFans].m_NumberOfVertices = numVertices;
00392                           *pCountFans = *pCountFans + 1;
00393                           pTriangleFans[*pCountFans].m_pVertices[0] = v0;
00394                           pTriangleFans[*pCountFans].m_pVertices[1] = previousVertex;
00395                           numVertices = 2;
00396                         }
00397                       pTriangleFans[*pCountFans].m_pVertices[numVertices] = i;
00398                       previousVertex = i;
00399                     }
00400                 }
00401               for (i = m_HomeIndex + pTerrain->GetWidthVertices(); i <= m_HomeIndex + m_Stride * pTerrain->GetWidthVertices(); i += pTerrain->GetWidthVertices())
00402                 {
00403                   Assert(0 <= i);
00404                   Assert(i < pTerrain->GetNumberOfVertices());
00405                   if(pTerrain->GetVertexStatus(i) == 1)
00406                     {
00407                       if (++numVertices == MAX_VERTICES_PER_FAN - 1)
00408                         {
00409                           // We have reached the maximum size for a fan, so start a new fan.
00410                           pTriangleFans[*pCountFans].m_NumberOfVertices = numVertices;
00411                           *pCountFans = *pCountFans + 1;
00412                           pTriangleFans[*pCountFans].m_pVertices[0] = v0;
00413                           pTriangleFans[*pCountFans].m_pVertices[1] = previousVertex;
00414                           numVertices = 2;
00415                         }
00416                       pTriangleFans[*pCountFans].m_pVertices[numVertices] = i;
00417                       previousVertex = i;
00418                     }
00419                 }
00420               for (i = bottomLeft; i <= bottomRight; i++)
00421                 {
00422                   Assert(0 <= i);
00423                   Assert(i < pTerrain->GetNumberOfVertices());
00424                   if (pTerrain->GetVertexStatus(i) == 1)
00425                     {
00426                       if (++numVertices == MAX_VERTICES_PER_FAN - 1)
00427                         {
00428                           // We have reached the maximum size for a fan, so start a new fan.
00429                           pTriangleFans[*pCountFans].m_NumberOfVertices = numVertices;
00430                           *pCountFans = *pCountFans + 1;
00431                           pTriangleFans[*pCountFans].m_pVertices[0] = v0;
00432                           pTriangleFans[*pCountFans].m_pVertices[1] = previousVertex;
00433                           numVertices = 2;
00434                         }
00435                       pTriangleFans[*pCountFans].m_pVertices[numVertices] = i;
00436                       previousVertex = i;
00437                     }
00438                 }
00439               for (i = bottomRight - pTerrain->GetWidthVertices(); m_HomeIndex + m_Stride <= i; i -= pTerrain->GetWidthVertices())
00440                 {
00441                   Assert(0 <= i);
00442                   Assert(i < pTerrain->GetNumberOfVertices());
00443                   if(pTerrain->GetVertexStatus(i) == 1)
00444                     {
00445                       if (++numVertices == MAX_VERTICES_PER_FAN - 1)
00446                         {
00447                           // We have reached the maximum size for a fan, so start a new fan.
00448                           pTriangleFans[*pCountFans].m_NumberOfVertices = numVertices;
00449                           *pCountFans = *pCountFans + 1;
00450                           pTriangleFans[*pCountFans].m_pVertices[0] = v0;
00451                           pTriangleFans[*pCountFans].m_pVertices[1] = previousVertex;
00452                           numVertices = 2;
00453                         }
00454                       pTriangleFans[*pCountFans].m_pVertices[numVertices] = i;
00455                       previousVertex = i;
00456                     }
00457                 }
00458               pTriangleFans[*pCountFans].m_NumberOfVertices = numVertices + 1;
00459               *pCountFans = *pCountFans + 1;
00460             }
00461         }
00462       else if (m_bChildrenActive)
00463         {
00464           m_pChildren[0]->RepairCracks(pTerrain,pTriangleStrips,pTriangleFans,pCountStrips,pCountFans);
00465           m_pChildren[1]->RepairCracks(pTerrain,pTriangleStrips,pTriangleFans,pCountStrips,pCountFans);
00466           m_pChildren[2]->RepairCracks(pTerrain,pTriangleStrips,pTriangleFans,pCountStrips,pCountFans);
00467           m_pChildren[3]->RepairCracks(pTerrain,pTriangleStrips,pTriangleFans,pCountStrips,pCountFans);
00468         }
00469     }
00470 }
00471 
00472 void TerrainBlock::CalculateGeometry(Terrain* pTerrain)
00473 {
00474   float height = m_BoundingBoxUpperCenter.z - m_BoundingBoxLowerCenter.z;
00475   float width = m_Stride * pTerrain->GetVertexSpacing();
00476   if (width < height)
00477     m_CubeSize = height;
00478   else
00479     m_CubeSize = width;
00480   m_CubeCenterZ = 0.5f * (m_BoundingBoxUpperCenter.z + m_BoundingBoxLowerCenter.z);
00481   
00482   float halfCube = m_CubeSize / 2.0f;
00483   m_BoundingBox.m_Min.x = m_BoundingBoxUpperCenter.x - halfCube;
00484   m_BoundingBox.m_Min.y = m_BoundingBoxUpperCenter.y - halfCube;
00485   m_BoundingBox.m_Min.z = m_CubeCenterZ - halfCube;
00486   m_BoundingBox.m_Max.x = m_BoundingBoxUpperCenter.x + halfCube;
00487   m_BoundingBox.m_Max.y = m_BoundingBoxUpperCenter.y + halfCube;
00488   m_BoundingBox.m_Max.z = m_CubeCenterZ + halfCube;
00489   
00490 #ifdef _USE_RAYTRACING_SUPPORT_
00491   // Build triangles for ray intersection and collision detection.
00492   if (m_Stride == 2)
00493     {
00494       m_pTriangles = new Triangle[8];
00495       m_pTriangles[0].DefineFromPoints(pTerrain->m_pVertices[m_HomeIndex],pTerrain->m_pVertices[m_HomeIndex + pTerrain->GetWidthVertices()],pTerrain->m_pVertices[m_HomeIndex + 1]);
00496       m_pTriangles[1].DefineFromPoints(pTerrain->m_pVertices[m_HomeIndex + 1],pTerrain->m_pVertices[m_HomeIndex + pTerrain->GetWidthVertices()],pTerrain->m_pVertices[m_HomeIndex + pTerrain->GetWidthVertices() + 1]);
00497       m_pTriangles[2].DefineFromPoints(pTerrain->m_pVertices[m_HomeIndex + 1],pTerrain->m_pVertices[m_HomeIndex + 1 + pTerrain->GetWidthVertices()],pTerrain->m_pVertices[m_HomeIndex + 2]);
00498       m_pTriangles[3].DefineFromPoints(pTerrain->m_pVertices[m_HomeIndex + 2],pTerrain->m_pVertices[m_HomeIndex + 1 + pTerrain->GetWidthVertices()],pTerrain->m_pVertices[m_HomeIndex + 2 + pTerrain->GetWidthVertices()]);
00499       m_pTriangles[4].DefineFromPoints(pTerrain->m_pVertices[m_HomeIndex + pTerrain->GetWidthVertices()],pTerrain->m_pVertices[m_HomeIndex + pTerrain->GetWidthVertices() + pTerrain->GetWidthVertices()],pTerrain->m_pVertices[m_HomeIndex  + pTerrain->GetWidthVertices() + 1]);
00500       m_pTriangles[5].DefineFromPoints(pTerrain->m_pVertices[m_HomeIndex + pTerrain->GetWidthVertices() + 1],pTerrain->m_pVertices[m_HomeIndex + pTerrain->GetWidthVertices() + pTerrain->GetWidthVertices()],pTerrain->m_pVertices[m_HomeIndex  + pTerrain->GetWidthVertices() + pTerrain->GetWidthVertices() + 1]);
00501       m_pTriangles[6].DefineFromPoints(pTerrain->m_pVertices[m_HomeIndex + pTerrain->GetWidthVertices() + 1],pTerrain->m_pVertices[m_HomeIndex + pTerrain->GetWidthVertices() + 1 + pTerrain->GetWidthVertices()],pTerrain->m_pVertices[m_HomeIndex  + pTerrain->GetWidthVertices() + 2]);
00502       m_pTriangles[7].DefineFromPoints(pTerrain->m_pVertices[m_HomeIndex + pTerrain->GetWidthVertices() + 2],pTerrain->m_pVertices[m_HomeIndex + pTerrain->GetWidthVertices() + 1 + pTerrain->GetWidthVertices()],pTerrain->m_pVertices[m_HomeIndex  + pTerrain->GetWidthVertices() + 2 + pTerrain->GetWidthVertices()]);*/
00503     }
00504 #endif
00505 }
00506 
00507 void TerrainBlock::DummyFunc(Terrain* pTerrain)
00508 {
00509   // Forces all exported methods to be referenced on GNU compilers - NEVER CALL
00510   printf("%d",pTerrain->GetHeightVertices());
00511   pTerrain->GetElevation(0.0f,0.0f);
00512   pTerrain->GetVertexSpacing();
00513   pTerrain->GetWidth();
00514   pTerrain->GetHeight();
00515   Settings::GetInstance()->GetScreenHeight();
00516   Settings::GetInstance()->GetScreenWidth();
00517 }
00518 
00519 void TerrainBlock::Write(FILE* file)
00520 {
00521   fwrite(&m_Stride,sizeof(int),1,file);
00522   fwrite(&m_HomeIndex,sizeof(int),1,file);
00523   fwrite(&m_BoundingBoxUpperCenter,sizeof(Vector),1,file);
00524   fwrite(&m_BoundingBoxLowerCenter,sizeof(Vector),1,file);
00525   if (2 < m_Stride)
00526     {
00527       for (int i = 0; i < 4; i++)
00528         m_pChildren[i]->Write(file);
00529     }
00530 }
00531 
00532 void TerrainBlock::Read(FILE* file,Terrain* pTerrain)
00533 {
00534   fread(&m_Stride,sizeof(int),1,file);
00535   fread(&m_HomeIndex,sizeof(int),1,file);
00536   fread(&m_BoundingBoxUpperCenter,sizeof(Vector),1,file);
00537   fread(&m_BoundingBoxLowerCenter,sizeof(Vector),1,file);
00538   if (2 < m_Stride)
00539     {
00540       m_pChildren = new TerrainBlock*[4];
00541       for (int i = 0; i < 4; i++)
00542         {
00543           m_pChildren[i] = new TerrainBlock(this);
00544           m_pChildren[i]->Read(file,pTerrain);
00545         }
00546     }
00547   CalculateGeometry(pTerrain);
00548 }
00549 
00550 Terrain::Terrain(char* szElevationsFilename,char* szTextureFilename,char* szDetailTextureFilename,float vertexSpacing,float elevationScale,int maxNumTriangles,bool bUseBorders) : Referenced()
00551 {
00552   // Set all default values
00553   m_szSourceURL = NULL;
00554   m_MaxNumberOfPrimitives = maxNumTriangles / 4;
00555   m_pTriangleStrips = NULL;
00556   m_pTriangleFans = NULL;
00557   m_szTextureFilename = NULL;
00558   m_szDetailTextureFilename = new char[5];
00559   sprintf(m_szDetailTextureFilename,"none");
00560   m_pVertices = NULL;
00561   m_CommonTextureRepeats = 20.0f;
00562   m_pVertexStatus = NULL;
00563   m_pRootBlock = NULL;
00564   m_pCommonTexture = NULL;
00565   m_VertexSpacing = vertexSpacing;
00566   m_MaximumVisibleBlockSize = 128;
00567   Uint8 red;
00568   Uint8 green;
00569   Uint8 blue;
00570   // Load elevation data
00571   char* szFullFilename;
00572   Settings::GetInstance()->PrependMediaPath(szElevationsFilename,&szFullFilename);
00573   osg::ref_ptr<osg::Image> pImage = osgDB::Registry::instance()->readImage(szFullFilename,true).getImage();
00574   if (pImage == NULL)
00575     {
00576       String msg("Failed to load elevation image file '");
00577       throw new std::invalid_argument(Exception(msg));
00578     }
00579   else
00580     {
00581       // Test to see if the image is a power of 2 in both width and height.
00582       if (!IsPowerOf2((double)pImage->s()) || !IsPowerOf2((double)pImage->t()))
00583         {
00584           pImage->ensureValidSizeForTexturing(8192);
00585         }
00586       
00587       // Test to see if the image is 24-bit color.
00588       if (pImage->getPixelSizeInBits() != 24)
00589         {
00590           String msg("The elevation image file '");
00591           msg += szFullFilename;
00592           msg += "' is NOT a 24-bit image. Elevation files must be 24-bit images.";
00593           throw new std::invalid_argument(Exception(msg));
00594         }
00595       
00596       int pitch = 3 * pImage->s(); // why 3? !!!
00597       m_WidthVertices = pImage->s() + 1; // Add 1 dummy pixel line to edge for block strides
00598       m_HeightVertices = pImage->t() + 1;
00599       m_NumberOfVertices = m_WidthVertices * m_HeightVertices;
00600       m_pVertices = new Vector[m_WidthVertices * m_HeightVertices];
00601       int i,j;
00602       float x,y;
00603       Uint8* pImagePixels = (Uint8*)pImage->data();
00604       y = m_HeightVertices * m_VertexSpacing;
00605       m_MaxElevation = 0.0f;
00606       for (i = pImage->t() * pitch - pitch,j = 0; i >= 0; i -= pitch,y -= m_VertexSpacing)
00607         {
00608           if (i == pImage->t() * pitch)
00609             {
00610               x=0.0f;
00611               for (int m = 0; m < m_WidthVertices; m++,j++,x += m_VertexSpacing)
00612                 {
00613                   m_pVertices[j].x = x;
00614                   m_pVertices[j].y = y;
00615                   m_pVertices[j].z = m_pVertices[j - m_WidthVertices].z;
00616                 }
00617             }
00618           else
00619             {
00620               Uint8* pImageRow = pImagePixels + i;
00621               x=0.0f;
00622               int bytesPerPixel = pImage->getPixelSizeInBits() / 8;
00623               for (Uint8* pImagePixel = pImageRow; pImagePixel < pImageRow + pImage->s() * bytesPerPixel; pImagePixel += bytesPerPixel,j++,x += m_VertexSpacing)
00624                 {
00625                   Uint32* pCurrentPixel = (Uint32*)pImagePixel;
00626                   //              SDL_GetRGB(*pCurrentPixel,pImage->dataType(),&red,&green,&blue);
00627                   red   = (*pCurrentPixel) & 0xff; // !!!! check this is ok for Intel endian
00628                   green = ((*pCurrentPixel) & 0xff00) >> 8; // (we should really use dataType intelligently!)
00629                   blue  = ((*pCurrentPixel) & 0xff0000) >> 16;
00630                   m_pVertices[j].x = x;
00631                   m_pVertices[j].y = y;
00632                   m_pVertices[j].z = red * elevationScale;
00633                   if (m_MaxElevation < m_pVertices[j].z)
00634                     m_MaxElevation = m_pVertices[j].z;
00635                 }
00636               m_pVertices[j].x = m_WidthVertices * m_VertexSpacing;
00637               m_pVertices[j].y = y;
00638               m_pVertices[j].z = m_pVertices[j - 1].z;
00639               if (m_MaxElevation < m_pVertices[j].z)
00640                 m_MaxElevation = m_pVertices[j].z;
00641               j++; // Account for dummy column on right edge
00642               x += m_VertexSpacing;
00643             }
00644         }
00645       
00646       x = 0.0f;
00647       for (i = m_NumberOfVertices - m_WidthVertices; i < m_NumberOfVertices; i++)
00648         m_pVertices[i].z = m_pVertices[i - m_WidthVertices].z;
00649       
00650     }
00651   m_DetailThreshold = 4.0f;
00652   BuildBlocks();
00653   SetTexture(szTextureFilename,bUseBorders);
00654   if (szDetailTextureFilename != NULL)
00655     SetCommonTexture(szDetailTextureFilename);
00656   delete[] szFullFilename;
00657 }
00658 
00659 Terrain::Terrain(char* szCompiledMapFilename,int maxNumTriangles,bool bUseBorders,float offsetX,float offsetY) : Referenced()
00660 {
00661   m_szSourceURL = NULL;
00662   Init(szCompiledMapFilename,maxNumTriangles,bUseBorders,offsetX,offsetY);
00663 }
00664 
00665 Terrain::Terrain(char* szURL,char* szCompiledMapFilename,int maxNumTriangles,bool bUseBorders) : Referenced()
00666 {
00667   m_szSourceURL = new char[strlen(szURL) + 1];
00668   sprintf(m_szSourceURL,szURL);
00669   if (DownloadFile(szCompiledMapFilename))
00670     Init(szCompiledMapFilename,maxNumTriangles,bUseBorders);
00671 }                       
00672 
00673 Terrain::~Terrain()
00674 {
00675   while (!m_Textures.empty())
00676     {
00677       vector<Texture*>::iterator iter = m_Textures.begin();
00678       Texture* pTexture = *iter;
00679       m_Textures.erase(iter);
00680       delete pTexture;
00681     }
00682   
00683   if (m_pCommonTexture != NULL)
00684     delete m_pCommonTexture;
00685   
00686   delete[] m_pTriangleStrips;
00687   delete[] m_pTriangleFans;
00688   delete[] m_pVertices;
00689   delete m_pVertexStatus;
00690   delete[] m_szTextureFilename;
00691   delete[] m_szDetailTextureFilename;
00692   delete m_pRootBlock;
00693 }
00694 
00695 void Terrain::Init(char* szCompiledMapFilename,int maxNumTriangles,bool bUseBorders,float offsetX,float offsetY)
00696 {
00697   m_MaxNumberOfPrimitives = maxNumTriangles / 4;
00698   m_pTriangleStrips = NULL;
00699   m_pTriangleFans = NULL;
00700   m_pCommonTexture = NULL;
00701   m_DetailThreshold = 4.0f;
00702   m_pVertices = NULL;
00703   m_pRootBlock = NULL;
00704   m_pVertexStatus = NULL;
00705   m_szTextureFilename = NULL;
00706   m_szDetailTextureFilename = new char[5];
00707   sprintf(m_szDetailTextureFilename,"none");
00708   m_MaximumVisibleBlockSize = 24;
00709   m_CommonTextureRepeats = 20.0f;
00710   m_OffsetX = offsetX;
00711   m_OffsetY = offsetY;
00712   
00713   if(!Settings::GetInstance()->IsHeadless())
00714     {
00715 #ifdef _USE_VERTEX_ARRAYS_
00716       glLockArraysEXT_ptr = (PFNGLLOCKARRAYSEXTPROC)SDL_GL_GetProcAddress("glLockArraysEXT");
00717       glUnlockArraysEXT_ptr = (PFNGLUNLOCKARRAYSEXTPROC)SDL_GL_GetProcAddress("glUnlockArraysEXT");
00718 #endif
00719       if (glActiveTextureARB_ptr == NULL)
00720         {
00721           // !!! put something back here that check properly
00722           //      glActiveTextureARB_ptr = (PFNGLACTIVETEXTUREARBPROC)SDL_GL_GetProcAddress("glActiveTextureARB");
00723           glActiveTextureARB_ptr = glActiveTextureARB;
00724           //      glMultiTexCoord2fARB_ptr = (PFNGLMULTITEXCOORD2FARBPROC)SDL_GL_GetProcAddress("glMultiTexCoord2fARB");
00725           glMultiTexCoord2fARB_ptr = glMultiTexCoord2fARB;
00726           if(!glActiveTextureARB_ptr || !glMultiTexCoord2fARB_ptr)
00727             {
00728               cout << "TERRAIN: ERROR: Multitexture extensions not supported by this OpenGL vendor!" << endl;
00729               exit(-1);
00730             }
00731         }
00732       m_bMultiTextureSupported = true;
00733 #ifdef _USE_VERTEX_ARRAYS_
00734       glVertexPointer(3,GL_FLOAT,0,m_pVertices);
00735       
00736       // Generate texture coordinate arrays
00737       float* pTextureMain = new float[m_NumberOfVertices * 2];
00738       float* pTextureDetail = new float[m_NumberOfVertices * 2];
00739       float u = 0.0f;
00740       float v = 0.0f;
00741       float deltaU = (float)m_NumberOfTextureTilesWidth / (float)m_WidthVertices;
00742       float deltaV = (float)m_NumberOfTextureTilesHeight / (float)m_HeightVertices;
00743       int k = 0;
00744       for (int i = 0; i < m_NumberOfVertices; i += m_WidthVertices)
00745         {
00746           u = 0.0f;
00747           for (int j = i; j < i + m_WidthVertices; j++)
00748             {
00749               pTextureMain[k] = u;
00750               pTextureMain[k + 1] = v;
00751               pTextureDetail[k] = u;// * 100.0f;
00752               pTextureDetail[k + 1] = v;// * 100.0f;
00753               k += 2;
00754               u += deltaU;
00755             }
00756           v += deltaV;
00757         }
00758       
00759       glActiveTextureARB_ptr(GL_TEXTURE0_ARB);
00760       glTexCoordPointer(2,GL_FLOAT,0,pTextureMain);
00761       glEnableClientState(GL_TEXTURE_COORD_ARRAY);
00762       
00763       glEnableClientState(GL_VERTEX_ARRAY);
00764       
00765       glLockArraysEXT_ptr(0,m_NumberOfVertices);
00766 #endif
00767     }
00768   Read(szCompiledMapFilename,bUseBorders);
00769 }
00770 
00771 inline bool Terrain::IsMultiTextureSupported()
00772 {
00773   return m_bMultiTextureSupported;
00774 }
00775 
00776 inline int Terrain::GetNumberOfVertices()
00777 {
00778   return m_NumberOfVertices;
00779 }
00780 
00781 bool Terrain::Write(char* szCompiledMapFilename)
00782 {
00783   bool bSuccess = false;
00784   try
00785     {
00786       char* szFullFilename;
00787       Settings::GetInstance()->PrependMediaPath(szCompiledMapFilename,&szFullFilename);
00788       FILE* file = fopen(szFullFilename,"wb");
00789       delete[] szFullFilename;
00790       int byteCount = 0;
00791       if (file != NULL)
00792         {
00793           fwrite(&m_VertexSpacing,sizeof(float),1,file);
00794           fwrite(&m_WidthVertices,sizeof(int),1,file);
00795           fwrite(&m_HeightVertices,sizeof(int),1,file);
00796           
00797           for (int i = 0; i < m_WidthVertices * m_HeightVertices; i++)
00798             {
00799               fwrite(&m_pVertices[i].z,sizeof(float),1,file);
00800               byteCount += sizeof(float);
00801             }   
00802           
00803           int len = strlen(m_szTextureFilename);
00804           fwrite(&len,sizeof(int),1,file);
00805           byteCount += sizeof(int);
00806           fwrite(m_szTextureFilename,sizeof(char),strlen(m_szTextureFilename),file);
00807           byteCount += sizeof(char) * strlen(m_szTextureFilename);
00808           len = strlen(m_szDetailTextureFilename);
00809           fwrite(&len,sizeof(int),1,file);
00810           byteCount += sizeof(int);
00811           fwrite(m_szDetailTextureFilename,sizeof(char),strlen(m_szDetailTextureFilename),file);
00812           byteCount += sizeof(char) * strlen(m_szDetailTextureFilename);
00813           cout << "TERRAIN: Size = " << byteCount << endl;
00814           fclose(file);
00815           bSuccess = true;
00816         }
00817       else
00818         cout << "TERRAIN: Unable to create output file = " << szCompiledMapFilename << endl;
00819     }
00820   catch(...)
00821     {           
00822     }
00823   return bSuccess;
00824 }
00825 
00826 bool Terrain::Read(char* szCompiledMapFilename,bool bUseBorders)
00827 {
00828   bool bSuccess = false;
00829   char* szFullFilename;
00830   if (szCompiledMapFilename[0] != '/') // not absolute path
00831     Settings::GetInstance()->PrependMediaPath(szCompiledMapFilename,&szFullFilename);
00832   else {
00833     szFullFilename = new char[strlen(szCompiledMapFilename)+1];
00834     strcpy(szFullFilename, szCompiledMapFilename);
00835   }
00836   FILE* file = fopen(szFullFilename,"rb");
00837   if (file != NULL)
00838     {
00839       fread(&m_VertexSpacing,sizeof(float),1,file);
00840       fread(&m_WidthVertices,sizeof(int),1,file);
00841       fread(&m_HeightVertices,sizeof(int),1,file);
00842       m_NumberOfVertices = m_WidthVertices * m_HeightVertices;
00843       delete[] m_pVertices;
00844       m_pVertices = new Vector[m_WidthVertices * m_HeightVertices];
00845       
00846       int i = 0;
00847       
00848       m_MaxElevation = 0.0f;
00849       for (i = 0; i < m_NumberOfVertices; i++)
00850         {
00851           fread(&m_pVertices[i].z,sizeof(float),1,file);
00852           if (m_MaxElevation < m_pVertices[i].z)
00853             m_MaxElevation = m_pVertices[i].z;
00854         }
00855       
00856       for (i = 0; i < m_HeightVertices; i++)
00857         {
00858           for (int j = 0; j < m_WidthVertices; j++)
00859             {
00860               long int index = i * m_WidthVertices + j;
00861               Assert(index < m_NumberOfVertices);
00862               m_pVertices[index].x = (float)j * m_VertexSpacing;
00863               m_pVertices[index].y = (float)i * m_VertexSpacing;
00864             }   
00865         }
00866       
00867       int len;
00868       fread(&len,sizeof(int),1,file);
00869       m_szTextureFilename = new char[len + 1];
00870       fread(m_szTextureFilename,sizeof(char),len,file);
00871       m_szTextureFilename[len] = '\0';
00872       
00873       fread(&len,sizeof(int),1,file);
00874       m_szDetailTextureFilename = new char[len + 1];
00875       fread(m_szDetailTextureFilename,sizeof(char),len,file);
00876       m_szDetailTextureFilename[len] = '\0';
00877       
00878       delete m_pVertexStatus;
00879       m_pVertexStatus = new base::BitArray(m_WidthVertices * m_HeightVertices);
00880       delete m_pRootBlock;
00881       BuildBlocks();
00882       if (SetTexture(m_szTextureFilename,bUseBorders))
00883         {               
00884           if (strcmp(m_szDetailTextureFilename,"none") != 0)
00885             bSuccess = SetCommonTexture(m_szDetailTextureFilename);
00886           else
00887             bSuccess = true;
00888         }
00889       fclose(file);
00890     }
00891   else
00892     {
00893       string msg("Compiled map file '");
00894       msg += szFullFilename;
00895       msg += "' not found.";
00896       throw new std::invalid_argument(Exception(msg));
00897     }
00898   delete[] szFullFilename;
00899   return bSuccess;
00900 }
00901 
00902 void Terrain::UpdateNeighbor(Terrain* pTerrain,Terrain::DIRECTION direction)
00903 {
00904   int thisVertex,otherVertex;
00905   if (direction == Terrain::DIR_SOUTH)
00906     {
00907       for (thisVertex = 0,otherVertex = m_NumberOfVertices - m_WidthVertices; thisVertex < m_WidthVertices; thisVertex++,otherVertex++)
00908         {
00909           if (GetVertexStatus(thisVertex))
00910             pTerrain->SetVertexStatus(otherVertex,true);
00911         }
00912     }
00913   else if (direction == Terrain::DIR_NORTH)
00914     {
00915       for (thisVertex = m_NumberOfVertices - m_WidthVertices,otherVertex = 0; thisVertex < m_NumberOfVertices; thisVertex++,otherVertex++)
00916         {
00917           if (GetVertexStatus(thisVertex))
00918             pTerrain->SetVertexStatus(otherVertex,true);
00919         }
00920     }
00921   else if (direction == Terrain::DIR_WEST)
00922     {
00923       for (thisVertex = 0,otherVertex = m_WidthVertices - 1; thisVertex < m_NumberOfVertices; thisVertex += m_WidthVertices,otherVertex += m_WidthVertices)
00924         if (GetVertexStatus(thisVertex))
00925           pTerrain->SetVertexStatus(otherVertex,true);
00926     }
00927   else if (direction == Terrain::DIR_EAST)
00928     {
00929       for (thisVertex = m_WidthVertices - 1,otherVertex = 0; thisVertex < m_NumberOfVertices; thisVertex += m_WidthVertices,otherVertex += m_WidthVertices)
00930         if (GetVertexStatus(thisVertex))
00931           pTerrain->SetVertexStatus(otherVertex,true);
00932     }
00933   else if (direction == Terrain::DIR_NORTHWEST)
00934     {
00935       if (GetVertexStatus(m_NumberOfVertices - m_WidthVertices))
00936         pTerrain->SetVertexStatus(m_WidthVertices - 1,true);
00937     }
00938   else if (direction == Terrain::DIR_NORTHEAST)
00939     {
00940       if (GetVertexStatus(m_NumberOfVertices - 1))
00941         pTerrain->SetVertexStatus(0,true);
00942     }
00943   else if (direction == Terrain::DIR_SOUTHEAST)
00944     {
00945       if (GetVertexStatus(m_WidthVertices - 1))
00946         pTerrain->SetVertexStatus(m_NumberOfVertices - m_WidthVertices,true);
00947     }
00948   else if (direction == Terrain::DIR_SOUTHWEST)
00949     {
00950       if (GetVertexStatus(0))
00951         pTerrain->SetVertexStatus(m_NumberOfVertices - 1,true);
00952     }
00953 }
00954 
00955 inline float Terrain::GetElevation(int index)
00956 {
00957   return m_pVertices[index].z;
00958 }
00959 
00960 inline float Terrain::GetElevation(float x,float y)
00961 {
00962   Plane plane;
00963   int   vertexID;
00964   float elevation;
00965   
00966   x -= m_OffsetX;
00967   y -= m_OffsetY;
00968   
00969 #ifdef _PROTECT_ACCESS_
00970   if (x < 0.0f || y < 0.0f || GetWidth() < x || GetHeight() < y)
00971     elevation = 0.0f;
00972   else
00973     {
00974 #endif
00975       vertexID = ((int)(y / m_VertexSpacing)) * m_WidthVertices + ((int)(x / m_VertexSpacing));
00976       
00977       if ((fmod(y,m_VertexSpacing) + fmod(x,m_VertexSpacing)) <= m_VertexSpacing)
00978         plane.defineFromPoints(m_pVertices[vertexID],m_pVertices[vertexID + m_WidthVertices],m_pVertices[vertexID + 1]);
00979       else
00980         plane.defineFromPoints(m_pVertices[vertexID + 1],m_pVertices[vertexID + 1 + m_WidthVertices],m_pVertices[vertexID + m_WidthVertices]);
00981       
00982       elevation = -1.0f * ((plane.a * x + plane.b * y + plane.d) / plane.c);
00983 #ifdef _PROTECT_ACCESS_
00984     }
00985 #endif
00986   
00987   return elevation;
00988 }
00989 
00990 inline void Terrain::GetNormal(float x,float y,float& normalX,float& normalY,float& normalZ)
00991 {
00992   Plane plane;
00993   int   vertexID;
00994 #ifdef _PROTECT_ACCESS_
00995   if (x < 0.0f || y < 0.0f || GetWidth() < x || GetHeight() < y)
00996     {
00997       normalX = normalY = 0.0f;
00998       normalZ = 1.0f;
00999     }
01000   else
01001     {
01002 #endif
01003       vertexID = (int)(y / m_VertexSpacing) * m_WidthVertices + (int)(x / m_VertexSpacing);
01004       
01005       if ((fmod(y,m_VertexSpacing) - fmod(x,m_VertexSpacing)) >= 0.0f)
01006         plane.defineFromPoints(m_pVertices[vertexID],m_pVertices[vertexID + 1],m_pVertices[vertexID + m_WidthVertices]);
01007       else
01008         plane.defineFromPoints(m_pVertices[vertexID + 1],m_pVertices[vertexID + 1 + m_WidthVertices],m_pVertices[vertexID + m_WidthVertices]);
01009 
01010       normalX = plane.a;
01011       normalY = plane.b;
01012       normalZ = plane.c;
01013 #ifdef _PROTECT_ACCESS_
01014     }
01015 #endif
01016 }
01017 
01018 void Terrain::SetDetailThreshold(float threshold)
01019 {
01020   m_DetailThreshold = threshold;
01021 }
01022 
01023 float Terrain::GetDetailThreshold()
01024 {
01025   return m_DetailThreshold;
01026 }
01027 
01028 int Terrain::GetWidthVertices()
01029 {
01030   return m_WidthVertices;
01031 }
01032 
01033 int Terrain::GetHeightVertices()
01034 {
01035   return m_HeightVertices;
01036 }
01037 
01038 float Terrain::GetWidth() const
01039 {
01040   return (float)(m_WidthVertices - 1) * m_VertexSpacing;
01041 }
01042 
01043 float Terrain::GetHeight() const
01044 {
01045   return (float)(m_HeightVertices - 1) * m_VertexSpacing;
01046 }
01047 
01048 float Terrain::GetMaxElevation() const
01049 {
01050   return m_MaxElevation;        
01051 }
01052 
01053 float Terrain::GetVertexElevation(int index) const
01054 {
01055 #ifdef _PROTECT_ACCESS_
01056   if (index < 0 || m_NumberOfVertices <= index)
01057     return 0.0f;
01058   else
01059 #endif
01060     return m_pVertices[index].z;
01061 }
01062 
01063 void Terrain::SetVertexElevation(int index,float newElevation)
01064 {
01065 #ifdef _PROTECT_ACCESS_
01066   if (0 <= index && index < m_NumberOfVertices)
01067 #endif
01068     m_pVertices[index].z = newElevation;        
01069 }
01070 
01071 float Terrain::GetVertexSpacing()
01072 {
01073   return m_VertexSpacing;
01074 }
01075 
01076 void Terrain::BuildBlocks()
01077 {
01078   if (Settings::GetInstance()->IsHeadless())
01079     return;
01080   numLevels = 0.0f;
01081   numBlocks = 0.0f;
01082   for (int i = m_WidthVertices - 1; 2 <= i; i /= 2)
01083     numLevels += 1.0f;
01084   for (double j = 0.0f; j < numLevels; j += 1.0f)
01085     numBlocks += pow(4,j);
01086   if (Settings::GetInstance()->IsVerbose())
01087     {
01088       cout << "TERRAIN: Building " << numBlocks << " blocks; please wait..." << endl;
01089 #ifdef _USE_RAYTRACING_SUPPORT_
01090       cout << "TERRAIN: Memory required at runtime for blocks = " << numBlocks * (sizeof(TerrainBlock) + 8 * sizeof(Triangle)) << " bytes" << endl;
01091 #else  
01092       cout << "TERRAIN: Memory required at runtime for blocks = " << numBlocks * sizeof(TerrainBlock) << " bytes" << endl;
01093 #endif
01094       cout << ".............................." << endl;
01095       hashDelta = (double)numBlocks / 30.0f;
01096       cout << "#" << flush;
01097     }
01098   m_pVertexStatus = new BitArray(m_WidthVertices * m_HeightVertices);
01099   // We assume that the terrain's width is always a power of 2 + 1!
01100   m_pRootBlock = new TerrainBlock(0,m_WidthVertices - 1,this,NULL);
01101   if (Settings::GetInstance()->IsVerbose())
01102     cout << endl;
01103 }
01104 
01105 inline void Terrain::SetVertexStatus(int vertexIndex,bool status)
01106 {
01107   if (status)
01108     m_pVertexStatus->SetBit(vertexIndex);
01109   else
01110     m_pVertexStatus->ClearBit(vertexIndex);
01111 }
01112 
01113 inline bool Terrain::GetVertexStatus(int vertexIndex)
01114 {
01115   return m_pVertexStatus->IsBitSet(vertexIndex);
01116 }
01117 
01118 int Terrain::Tessellate()
01119 {
01120   if (m_pTriangleStrips == NULL)
01121     {
01122       long int maxNumStrips = (GetWidthVertices() - 1) * (GetHeightVertices() - 1);
01123       try
01124         {
01125           if (m_MaxNumberOfPrimitives < maxNumStrips)
01126             maxNumStrips = m_MaxNumberOfPrimitives;
01127           if (Settings::GetInstance()->IsVerbose())
01128             cout << "TERRAIN: Allocating " << maxNumStrips << " triangle strips and fans (" << maxNumStrips * sizeof(TriangleStrip) + maxNumStrips * sizeof(TriangleFan) << " bytes)\n" << endl;
01129           m_pTriangleStrips = new TriangleStrip[maxNumStrips];
01130           m_pTriangleFans = new TriangleFan[maxNumStrips];
01131           if (m_pTriangleStrips == NULL || m_pTriangleFans == NULL)
01132             {
01133               cout << "TERRAIN: " << "Not enough memory to build terrain triangles" << endl;
01134               exit(1);
01135             }
01136         }
01137       catch(...)
01138         {
01139           cout << "TERRAIN: " << "Not enough memory to build terrain triangles" << endl;
01140           exit(1);
01141         }
01142     }
01143   
01144   double matModelview[16];
01145   double matProjection[16];
01146   GLint viewport[4];
01147   glGetDoublev(GL_MODELVIEW_MATRIX, matModelview);
01148   glGetDoublev(GL_PROJECTION_MATRIX, matProjection);
01149   glGetIntegerv(GL_VIEWPORT,viewport);
01150   
01151   ExtractFrustum();
01152   
01153   m_pVertexStatus->Clear();
01154   m_CountStrips = m_CountFans = 0;
01155   m_pRootBlock->Tessellate(matModelview,matProjection,viewport,m_pTriangleStrips,m_pTriangleFans,&m_CountStrips,&m_CountFans,this);
01156   return m_CountStrips * 2 + m_CountFans * 6;
01157 }
01158 
01159 bool Terrain::SetCommonTexture(char* szFilename)
01160 {
01161   bool bSuccess = false;
01162   if (m_szSourceURL != NULL)
01163     DownloadFile(szFilename);
01164   m_szDetailTextureFilename = new char[strlen(szFilename) + 1];
01165   sprintf(m_szDetailTextureFilename,szFilename);
01166   char* szFullFilename;
01167   Settings::GetInstance()->PrependMediaPath(szFilename,&szFullFilename);
01168   if (!Settings::GetInstance()->IsCompilerOnly())
01169     {
01170       if (Settings::GetInstance()->IsVerbose())
01171         cout << "TERRAIN: Setting common texture to " << szFilename << endl;
01172       int width,height;
01173       Uint8* pBuffer;
01174       LoadImage(szFullFilename,&width,&height,&pBuffer);
01175       if (width == 0)
01176         {
01177           string msg("Failed to load detail texture image file '");
01178           msg += szFullFilename;
01179           msg += "'; This means that the file was not found or it is not an image type that Demeter can read.";
01180           throw new std::invalid_argument(Exception(msg));
01181         }
01182       else
01183         {
01184           // Test to see if the image is a power of 2 in both width and height.
01185           if (!IsPowerOf2(width) || !IsPowerOf2(height))
01186             {
01187               string msg("The detail texture image file '");
01188               msg += szFullFilename;
01189               msg += "' is NOT a power of 2 in both width and height.\nTexture files must be a power of 2 in both width and height.";
01190               throw new std::invalid_argument(Exception(msg));
01191             }
01192           m_pCommonTexture = new Texture(pBuffer,width,height,width,0,false,Settings::GetInstance()->IsTextureCompression());
01193           delete[] pBuffer;
01194           bSuccess = true;
01195           if (Settings::GetInstance()->IsVerbose())
01196             cout << "TERRAIN: Common texture set with successfully" << endl;
01197         }
01198       delete[] szFullFilename;
01199     }
01200   else
01201     {
01202       FILE* testFile = fopen(szFullFilename,"rb");
01203       if (testFile)
01204         {
01205           bSuccess = true;
01206           fclose(testFile);     
01207         }
01208     }
01209   return bSuccess;
01210 }
01211 
01212 bool Terrain::DownloadFile(char* szFilename)
01213 {
01214   char szFullURLName[1024];
01215   char* szTempFilename;
01216   char* szLocalFilename;
01217   
01218   sprintf(szFullURLName,"%s/%s",m_szSourceURL,szFilename);
01219   Settings::GetInstance()->PrependMediaPath("temp.bin",&szTempFilename);
01220   Settings::GetInstance()->PrependMediaPath(szFilename,&szLocalFilename);
01221   bool success = false; //download(szFullURLName,szTempFilename,szLocalFilename);
01222   
01223   delete[] szTempFilename;
01224   delete[] szLocalFilename;
01225   
01226   return success;
01227 }
01228 
01229 bool Terrain::SetTexture(char* szFilename,bool bUseBorders)
01230 {
01231   if (Settings::GetInstance()->IsHeadless())
01232     return true;
01233   bool bSuccess = false;
01234   if (m_szSourceURL != NULL)
01235     DownloadFile(m_szTextureFilename);
01236   m_szTextureFilename = new char[strlen(szFilename) + 1];
01237   sprintf(m_szTextureFilename,szFilename);
01238   char* szFullFilename;
01239   Settings::GetInstance()->PrependMediaPath(szFilename,&szFullFilename);
01240   if (!Settings::GetInstance()->IsCompilerOnly())
01241     {
01242       if (Settings::GetInstance()->IsVerbose())
01243         cout << "TERRAIN: Setting texture to '" << szFullFilename << "'" << endl;
01244       int width,height;
01245       Uint8* pBuffer;
01246       LoadImage(szFullFilename,&width,&height,&pBuffer);
01247       if (width == 0)
01248         {
01249           string msg("Failed to load texture image file '");
01250           msg += szFullFilename;
01251           msg += "'; This means that the file was not found or it is not an image type that Demeter can read.";
01252           throw new std::invalid_argument(Exception(msg));
01253         }
01254       else
01255         {
01256           // Test to see if the image is a power of 2 in both width and height.
01257           if (!IsPowerOf2(width) || !IsPowerOf2(height))
01258             {
01259               string msg("The texture image file '");
01260               msg += szFullFilename;
01261               msg += "' is NOT a power of 2 in both width and height.\nTexture files must be a power of 2 in both width and height.";
01262               throw new std::invalid_argument(Exception(msg));
01263             }
01264           ChopTexture(pBuffer,width,height,256,bUseBorders);
01265           delete[] pBuffer;
01266           bSuccess = true;
01267           if (Settings::GetInstance()->IsVerbose())
01268             cout << "TERRAIN: Texture set successfully" << endl;
01269         }
01270     }
01271   else
01272     {
01273       FILE* fileTest = fopen(szFullFilename,"rb");
01274       if (fileTest)
01275         {
01276           bSuccess = true;
01277           fclose(fileTest);     
01278         }
01279     }
01280   delete[] szFullFilename;
01281   return bSuccess;
01282 }
01283 
01284 void Terrain::ChopTexture(Uint8* pImage,int width,int height,int tileSize,bool bUseBorders)
01285 {
01286   // It is assumed that the image is in a 3-byte per pixel, RGB format, with no padding on the pixel rows
01287   m_TextureTileWidth = (int)(((float)(m_WidthVertices / (width / tileSize))) * m_VertexSpacing);
01288   m_TextureTileHeight = (int)(((float)(m_HeightVertices / (height / tileSize))) * m_VertexSpacing);
01289   m_NumberOfTextureTilesWidth = width / tileSize;
01290   m_NumberOfTextureTilesHeight = height / tileSize;
01291   m_NumberOfTextureTiles = (width / tileSize) * (height / tileSize);
01292   m_TileSize = tileSize;
01293   
01294   if (bUseBorders)
01295     {
01296       unsigned char* pBorderedImage = new Uint8[(width + 2) * (height + 2) * 3];
01297       
01298       int i;
01299       // Create a temporary version of the original texture that is surrounded by a 1-pixel border.
01300       for (i = 0; i < height; i++)
01301         for (int j = 0; j < width * 3; j++)
01302           pBorderedImage[(i + 1) * (width + 2) * 3 + j + 3] = pImage[i * width * 3 + j];
01303       
01304       // Create texture tiles by roaming across the bordered image.
01305       //      int k = 0;
01306       for (i = 0; i < height; i += tileSize)
01307         {
01308           for (int j = 0; j < width; j += tileSize)
01309             {
01310               Uint8* pTile = pBorderedImage + i * (width + 2) * 3 + j * 3;
01311 #ifdef _USE_VERTEX_ARRAYS_
01312               Texture* pTexture = new Texture(pTile,tileSize,tileSize,width + 2,1,false,Settings::GetInstance()->IsTextureCompression());
01313               m_Textures.push_back(pTexture);
01314 #else
01315               Texture* pTexture = new Texture(pTile,tileSize,tileSize,width + 2,1,true,Settings::GetInstance()->IsTextureCompression());
01316               m_Textures.push_back(pTexture);
01317 #endif
01318             }
01319         }
01320       delete[] pBorderedImage;
01321     }
01322   else
01323     {
01324       // Create texture tiles by roaming across the bordered image.
01325       //int k = 0;
01326       for (int i = 0; i < height; i += tileSize)
01327         {
01328           for (int j = 0; j < width; j += tileSize)
01329             {
01330                 Uint8* pTile = pImage + i * width * 3 + j * 3;
01331 #ifdef _USE_VERTEX_ARRAYS_
01332                 Texture* pTexture = new Texture(pTile,tileSize,tileSize,width,0,false,Settings::GetInstance()->IsTextureCompression());
01333                 m_Textures.push_back(pTexture);
01334 #else
01335                 Texture* pTexture = new Texture(pTile,tileSize,tileSize,width,0,true,Settings::GetInstance()->IsTextureCompression());
01336                 m_Textures.push_back(pTexture);
01337 #endif
01338             }
01339         }
01340     }
01341 }
01342 
01343 /*
01344 void Terrain::DrawTile(SDL_Surface* pSurface,int index,int width,int height)
01345 {
01346   int texWidth = m_TileSize;
01347   int texHeight = m_TileSize;
01348   Uint8* pBuffer = m_pTiles[index];
01349   if (0 < texWidth)
01350     {
01351       if (SDL_LockSurface(pSurface) < 0)
01352         cout << "TERRAIN: ERROR: Couldn't lock the display surface" << endl;
01353       Uint8* pTargetBuffer = (Uint8 *)pSurface->pixels;
01354       
01355       for (int i = 0; i < height - 1; i++)
01356         {
01357           for (int j = 0; j < width - 1; j++)
01358             {
01359               int texOffset = i * texWidth * 3 + j * 3;
01360               int surfaceOffset = i * pSurface->pitch + j * pSurface->format->BytesPerPixel;
01361               int red = pBuffer[texOffset];
01362               int green = pBuffer[texOffset + 1];
01363               int blue = pBuffer[texOffset + 2];
01364               Uint32 pixel = SDL_MapRGB(pSurface->format,red,green,blue);
01365               Uint32* pTargetPixel = (Uint32*)(pTargetBuffer + surfaceOffset);
01366               *pTargetPixel = pixel;
01367             }
01368         }
01369       
01370       SDL_UnlockSurface(pSurface);
01371       SDL_UpdateRect(pSurface,0,0,0,0);
01372       delete[] pBuffer;
01373     }
01374 }
01375 
01376 void Terrain::DrawTexture(SDL_Surface* pSurface,int width,int height)
01377 {
01378   int texWidth,texHeight;
01379   Uint8* pBuffer;
01380   LoadImage(m_szTextureFilename,&texWidth,&texHeight,&pBuffer);
01381   if (0 < texWidth)
01382     {
01383       if (SDL_LockSurface(pSurface) < 0)
01384         cout << "TERRAIN: ERROR: Couldn't lock the display surface" << endl;
01385       Uint8* pTargetBuffer = (Uint8 *)pSurface->pixels;
01386       
01387       for (int i = 0; i < height - 1; i++)
01388         {
01389           for (int j = 0; j < width - 1; j++)
01390             {
01391               int texOffset = i * texWidth * 3 + j * 3;
01392               int surfaceOffset = i * pSurface->pitch + j * pSurface->format->BytesPerPixel;
01393               int red = pBuffer[texOffset];
01394               int green = pBuffer[texOffset + 1];
01395               int blue = pBuffer[texOffset + 2];
01396               Uint32 pixel = SDL_MapRGB(pSurface->format,red,green,blue);
01397               Uint32* pTargetPixel = (Uint32*)(pTargetBuffer + surfaceOffset);
01398               *pTargetPixel = pixel;
01399             }
01400         }
01401       
01402       SDL_UnlockSurface(pSurface);
01403       SDL_UpdateRect(pSurface,0,0,0,0);
01404       delete[] pBuffer;
01405     }
01406 }
01407 */
01408 
01409 void Terrain::SetMaximumVisibleBlockSize(int stride)
01410 {
01411   m_MaximumVisibleBlockSize = stride;
01412 }
01413 
01414 float Terrain::GetCommonTextureRepeats()
01415 {
01416   return m_CommonTextureRepeats;
01417 }
01418 
01419 void Terrain::SetCommonTextureRepeats(float commonTextureRepeats)
01420 {
01421   m_CommonTextureRepeats = commonTextureRepeats;
01422 }
01423 
01424 int Terrain::ModelViewMatrixChanged()
01425 {
01426   int count = Tessellate();
01427   m_pRootBlock->RepairCracks(this,m_pTriangleStrips,m_pTriangleFans,&m_CountStrips,&m_CountFans);
01428   return count;
01429 }
01430 
01431 void Terrain::Render()
01432 {
01433   int i,j;
01434   bool bUseMultiTexture = (m_bMultiTextureSupported && m_pCommonTexture != NULL);
01435   
01436   glFrontFace(GL_CW);
01437   glEnable(GL_CULL_FACE);
01438   glCullFace(GL_BACK);
01439   
01440   if (bUseMultiTexture)
01441     {
01442       glActiveTextureARB_ptr(GL_TEXTURE0_ARB);
01443       glEnable(GL_TEXTURE_2D);
01444       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
01445       glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_REPLACE);
01446       
01447       glActiveTextureARB_ptr(GL_TEXTURE1_ARB);
01448       glEnable(GL_TEXTURE_2D);
01449       glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_MODULATE);
01450       glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_RGB_EXT,GL_ADD);
01451       glBindTexture(GL_TEXTURE_2D,m_pCommonTexture->UploadTexture());
01452     }
01453   else
01454     glEnable(GL_TEXTURE_2D);
01455   
01456   for (i = 0; i < m_CountStrips; i++)
01457     m_pTriangleStrips[i].Setup(this);
01458   
01459   for (i = 0; i < m_CountFans; i++)
01460     m_pTriangleFans[i].Setup(this);
01461   
01462   if (bUseMultiTexture)
01463     glActiveTextureARB_ptr(GL_TEXTURE0_ARB);
01464   
01465   glNormal3f(0.0f,0.0f,1.0f);
01466   
01467   // Prevent state thrashing by rendering one texture at a time...
01468   for (i = 0; i < m_NumberOfTextureTiles; i++)
01469     {
01470       bool firstTime = true;
01471       for (j = 0; j < m_CountStrips; j++)
01472         {
01473           if (m_pTriangleStrips[j].textureId == i)
01474             {
01475               if (firstTime)
01476                 {
01477                   glBindTexture(GL_TEXTURE_2D,GetTerrainTile(i));
01478                   firstTime = false;
01479                 }
01480               m_pTriangleStrips[j].Render(this);
01481             }
01482         }
01483       for (j = 0; j < m_CountFans; j++)
01484         {
01485           if (m_pTriangleFans[j].textureId == i)
01486             {
01487               if (firstTime)
01488                 {
01489                   glBindTexture(GL_TEXTURE_2D,GetTerrainTile(i));
01490                   firstTime = false;
01491                 }
01492               m_pTriangleFans[j].Render(this);
01493             }
01494         }
01495       if (Settings::GetInstance()->UseDynamicTextures() && firstTime)
01496         {
01497           UnloadTerrainTile(i);
01498         }
01499     }
01500   glFrontFace(GL_CCW);
01501   // Turn multi-texture back off again so the client application doesn't end up in an unexpected state.
01502   //    if (bUseMultiTexture)
01503   //    {
01504   //            glActiveTextureARB_ptr(GL_TEXTURE1_ARB);
01505   //            glDisable(GL_TEXTURE_2D);
01506   //            glActiveTextureARB_ptr(GL_TEXTURE0_ARB);
01507   //            glDisable(GL_TEXTURE_2D);
01508   //    }
01509 }
01510 
01511 void Terrain::DisableTextures()
01512 {
01513   if (m_bMultiTextureSupported)
01514     {
01515       glActiveTextureARB_ptr(GL_TEXTURE0_ARB);
01516       glDisable(GL_TEXTURE_2D);
01517       glActiveTextureARB_ptr(GL_TEXTURE1_ARB);
01518       glDisable(GL_TEXTURE_2D);
01519     }
01520   else
01521     glDisable(GL_TEXTURE_2D);
01522 }
01523 
01524 void Terrain::EnableTextures()
01525 {
01526   if (m_bMultiTextureSupported)
01527     {
01528       glActiveTextureARB_ptr(GL_TEXTURE0_ARB);
01529       glEnable(GL_TEXTURE_2D);
01530       glActiveTextureARB_ptr(GL_TEXTURE1_ARB);
01531       glEnable(GL_TEXTURE_2D);
01532     }
01533   else
01534     glEnable(GL_TEXTURE_2D);
01535 }
01536 
01537 TriangleStrip::TriangleStrip()
01538 {
01539 }
01540 
01541 TriangleStrip::~TriangleStrip()
01542 {
01543 }
01544 
01545 inline void TriangleStrip::Setup(Terrain* pTerrain)
01546 {
01547   if (m_bEnabled)
01548     {
01549       minX = pTerrain->m_pVertices[m_pVertices[0]].x;
01550       minY = pTerrain->m_pVertices[m_pVertices[0]].y;
01551       for (int i = 1; i < m_NumberOfVertices; i++)
01552         {
01553           if (pTerrain->m_pVertices[m_pVertices[i]].x < minX)
01554             minX = pTerrain->m_pVertices[m_pVertices[i]].x;
01555           if (pTerrain->m_pVertices[m_pVertices[i]].y < minY)
01556             minY = pTerrain->m_pVertices[m_pVertices[i]].y;
01557         }
01558       int tileY = (int)minY / pTerrain->GetTextureTileHeight();
01559       int tileX = (int)minX / pTerrain->GetTextureTileWidth();
01560       textureId = tileY * pTerrain->GetNumberOfTextureTilesWidth() + tileX;
01561     }
01562 }
01563 
01564 inline void TriangleStrip::Render(Terrain* pTerrain)
01565 {
01566   if (m_bEnabled)
01567     {
01568       // IMPORTANT NOTE: Using glDrawElements() is a modest speed gain, but we lose multi-texturing and the use of different
01569       // texture coordinates for a single vertex! If there is some way to still have these features while using glDrawElements,
01570       // then re-enable this code in place of the rest of this method.
01571 #ifdef _USE_VERTEX_ARRAYS_
01572       glDrawElements(GL_TRIANGLE_STRIP,m_NumberOfVertices,GL_UNSIGNED_INT,m_pVertices);
01573 #else
01574       float texU,texV;
01575       glBegin(GL_TRIANGLE_STRIP);
01576       for (int i = 0; i < m_NumberOfVertices; i++)
01577         {
01578           texU = pTerrain->m_pVertices[m_pVertices[i]].x / (float)pTerrain->GetTextureTileWidth();
01579           texV = pTerrain->m_pVertices[m_pVertices[i]].y / (float)pTerrain->GetTextureTileHeight();
01580           if ((float)texU - (int)texU < EPSILON)
01581             texU = 1.0f;
01582           else
01583             texU = (float)texU - (int)texU;
01584           if ((float)texV - (int)texV < EPSILON)
01585             texV = 1.0f;
01586           else
01587             texV = (float)texV - (int)texV;
01588           if (fabs(1.0f - texU) <= EPSILON && fabs(minX - pTerrain->m_pVertices[m_pVertices[i]].x) <= EPSILON)
01589             texU = 0.0f;
01590           if (fabs(1.0f - texV) <= EPSILON && fabs(minY - pTerrain->m_pVertices[m_pVertices[i]].y) <= EPSILON)
01591             texV = 0.0f;
01592           if (!pTerrain->m_bMultiTextureSupported)
01593             glTexCoord2f(texU,texV);
01594           else
01595             {
01596               glMultiTexCoord2fARB_ptr(GL_TEXTURE0_ARB,texU,texV);
01597               glMultiTexCoord2fARB_ptr(GL_TEXTURE1_ARB,texU * pTerrain->GetCommonTextureRepeats(),texV * pTerrain->GetCommonTextureRepeats());
01598             }
01599           glVertex3f(pTerrain->m_pVertices[m_pVertices[i]].x + pTerrain->m_OffsetX,pTerrain->m_pVertices[m_pVertices[i]].y + pTerrain->m_OffsetY,pTerrain->m_pVertices[m_pVertices[i]].z);
01600         }
01601       glEnd();
01602 #endif
01603     }
01604 }
01605 
01606 TriangleFan::TriangleFan()
01607 {
01608 }
01609 
01610 TriangleFan::~TriangleFan()
01611 {
01612 }
01613 
01614 inline void TriangleFan::Setup(Terrain* pTerrain)
01615 {
01616   minX = pTerrain->m_pVertices[m_pVertices[0]].x;
01617   minY = pTerrain->m_pVertices[m_pVertices[0]].y;
01618   for (int i = 1; i < m_NumberOfVertices; i++)
01619     {
01620       if (pTerrain->m_pVertices[m_pVertices[i]].x < minX)
01621         minX = pTerrain->m_pVertices[m_pVertices[i]].x;
01622       if (pTerrain->m_pVertices[m_pVertices[i]].y < minY)
01623         minY = pTerrain->m_pVertices[m_pVertices[i]].y;
01624     }
01625   int tileY = (int)minY / pTerrain->GetTextureTileHeight();
01626   int tileX = (int)minX / pTerrain->GetTextureTileWidth();
01627   textureId = tileY * pTerrain->GetNumberOfTextureTilesWidth() + tileX;
01628 }
01629 
01630 inline void TriangleFan::Render(Terrain* pTerrain)
01631 {
01632   // IMPORTANT NOTE: Using glDrawElements() is a modest speed gain, but we lose multi-texturing and the use of different
01633   // texture coordinates for a single vertex! If there is some way to still have these features while using glDrawElements,
01634   // then re-enable this code in place of the rest of this method.
01635 #ifdef _USE_VERTEX_ARRAYS_
01636   glDrawElements(GL_TRIANGLE_FAN,m_NumberOfVertices,GL_UNSIGNED_INT,m_pVertices);
01637 #else
01638   float texU,texV;
01639   glBegin(GL_TRIANGLE_FAN);
01640   for (int i = 0; i < m_NumberOfVertices; i++)
01641     {
01642       texU = (pTerrain->m_pVertices[m_pVertices[i]].x) / (float)pTerrain->GetTextureTileWidth();
01643       texV = (pTerrain->m_pVertices[m_pVertices[i]].y) / (float)pTerrain->GetTextureTileHeight();
01644       if ((float)texU - (int)texU < EPSILON)
01645         texU = 1.0f;
01646       else
01647         texU = (float)texU - (int)texU;
01648       if ((float)texV - (int)texV < EPSILON)
01649         texV = 1.0f;
01650       else
01651         texV = (float)texV - (int)texV;
01652       if (fabs(1.0f - texU) <= EPSILON && fabs(minX - pTerrain->m_pVertices[m_pVertices[i]].x) <= EPSILON)
01653         texU = 0.0f;
01654       if (fabs(1.0f - texV) <= EPSILON && fabs(minY - pTerrain->m_pVertices[m_pVertices[i]].y) <= EPSILON)
01655         texV = 0.0f;
01656       if (!pTerrain->m_bMultiTextureSupported)
01657         glTexCoord2f(texU,texV);
01658       else
01659         {
01660           glMultiTexCoord2fARB_ptr(GL_TEXTURE0_ARB,texU,texV);
01661           glMultiTexCoord2fARB_ptr(GL_TEXTURE1_ARB,texU * pTerrain->GetCommonTextureRepeats(),texV * pTerrain->GetCommonTextureRepeats());
01662         }
01663       glVertex3f(pTerrain->m_pVertices[m_pVertices[i]].x + pTerrain->m_OffsetX,pTerrain->m_pVertices[m_pVertices[i]].y + pTerrain->m_OffsetY,pTerrain->m_pVertices[m_pVertices[i]].z);
01664     }
01665   glEnd();
01666 #endif
01667 }
01668 
01669 inline int Terrain::GetTextureTileWidth()
01670 {
01671   return m_TextureTileWidth;
01672 }
01673 
01674 inline int Terrain::GetTextureTileHeight()
01675 {
01676   return m_TextureTileHeight;
01677 }
01678 
01679 inline int Terrain::GetNumberOfTextureTilesWidth()
01680 {
01681   return m_NumberOfTextureTilesWidth;
01682 }
01683 
01684 inline int Terrain::GetNumberOfTextureTilesHeight()
01685 {
01686   return m_NumberOfTextureTilesHeight;
01687 }
01688 
01689 inline GLuint Terrain::GetTerrainTile(int index)
01690 {
01691   Texture* pTexture = m_Textures[index];
01692   GLuint val = pTexture->UploadTexture();
01693   return val;
01694 }
01695 
01696 inline void Terrain::UnloadTerrainTile(int index)
01697 {
01698   Texture* pTexture = m_Textures[index];
01699   pTexture->UnloadTexture();
01700 }
01701 
01702 inline void Terrain::ExtractFrustum()
01703 {
01704   float proj[16];
01705   float modl[16];
01706   float clip[16];
01707   float t;
01708   /* Get the current PROJECTION matrix from OpenGL */
01709   glGetFloatv(GL_PROJECTION_MATRIX, proj);
01710   /* Get the current MODELVIEW matrix from OpenGL */
01711   glGetFloatv(GL_MODELVIEW_MATRIX, modl);
01712   /* Combine the two matrices (multiply projection by modelview) */
01713   clip[ 0] = modl[ 0] * proj[ 0] + modl[ 1] * proj[ 4] + modl[ 2] * proj[ 8] + modl[ 3] * proj[12];
01714   clip[ 1] = modl[ 0] * proj[ 1] + modl[ 1] * proj[ 5] + modl[ 2] * proj[ 9] + modl[ 3] * proj[13];
01715   clip[ 2] = modl[ 0] * proj[ 2] + modl[ 1] * proj[ 6] + modl[ 2] * proj[10] + modl[ 3] * proj[14];
01716   clip[ 3] = modl[ 0] * proj[ 3] + modl[ 1] * proj[ 7] + modl[ 2] * proj[11] + modl[ 3] * proj[15];
01717   clip[ 4] = modl[ 4] * proj[ 0] + modl[ 5] * proj[ 4] + modl[ 6] * proj[ 8] + modl[ 7] * proj[12];
01718   clip[ 5] = modl[ 4] * proj[ 1] + modl[ 5] * proj[ 5] + modl[ 6] * proj[ 9] + modl[ 7] * proj[13];
01719   clip[ 6] = modl[ 4] * proj[ 2] + modl[ 5] * proj[ 6] + modl[ 6] * proj[10] + modl[ 7] * proj[14];
01720   clip[ 7] = modl[ 4] * proj[ 3] + modl[ 5] * proj[ 7] + modl[ 6] * proj[11] + modl[ 7] * proj[15];
01721   clip[ 8] = modl[ 8] * proj[ 0] + modl[ 9] * proj[ 4] + modl[10] * proj[ 8] + modl[11] * proj[12];
01722   clip[ 9] = modl[ 8] * proj[ 1] + modl[ 9] * proj[ 5] + modl[10] * proj[ 9] + modl[11] * proj[13];
01723   clip[10] = modl[ 8] * proj[ 2] + modl[ 9] * proj[ 6] + modl[10] * proj[10] + modl[11] * proj[14];
01724   clip[11] = modl[ 8] * proj[ 3] + modl[ 9] * proj[ 7] + modl[10] * proj[11] + modl[11] * proj[15];
01725   clip[12] = modl[12] * proj[ 0] + modl[13] * proj[ 4] + modl[14] * proj[ 8] + modl[15] * proj[12];
01726   clip[13] = modl[12] * proj[ 1] + modl[13] * proj[ 5] + modl[14] * proj[ 9] + modl[15] * proj[13];
01727   clip[14] = modl[12] * proj[ 2] + modl[13] * proj[ 6] + modl[14] * proj[10] + modl[15] * proj[14];
01728   clip[15] = modl[12] * proj[ 3] + modl[13] * proj[ 7] + modl[14] * proj[11] + modl[15] * proj[15];
01729   /* Extract the numbers for the RIGHT plane */
01730   m_Frustum[0][0] = clip[ 3] - clip[ 0];
01731   m_Frustum[0][1] = clip[ 7] - clip[ 4];
01732   m_Frustum[0][2] = clip[11] - clip[ 8];
01733   m_Frustum[0][3] = clip[15] - clip[12];
01734   /* Normalize the result */
01735   t = sqrt(m_Frustum[0][0] * m_Frustum[0][0] + m_Frustum[0][1] * m_Frustum[0][1] + m_Frustum[0][2] * m_Frustum[0][2]);
01736   m_Frustum[0][0] /= t;
01737   m_Frustum[0][1] /= t;
01738   m_Frustum[0][2] /= t;
01739   m_Frustum[0][3] /= t;
01740   /* Extract the numbers for the LEFT plane */
01741   m_Frustum[1][0] = clip[ 3] + clip[ 0];
01742   m_Frustum[1][1] = clip[ 7] + clip[ 4];
01743   m_Frustum[1][2] = clip[11] + clip[ 8];
01744   m_Frustum[1][3] = clip[15] + clip[12];
01745   /* Normalize the result */
01746   t = sqrt(m_Frustum[1][0] * m_Frustum[1][0] + m_Frustum[1][1] * m_Frustum[1][1] + m_Frustum[1][2] * m_Frustum[1][2]);
01747   m_Frustum[1][0] /= t;
01748   m_Frustum[1][1] /= t;
01749   m_Frustum[1][2] /= t;
01750   m_Frustum[1][3] /= t;
01751   /* Extract the BOTTOM plane */
01752   m_Frustum[2][0] = clip[ 3] + clip[ 1];
01753   m_Frustum[2][1] = clip[ 7] + clip[ 5];
01754   m_Frustum[2][2] = clip[11] + clip[ 9];
01755   m_Frustum[2][3] = clip[15] + clip[13];
01756   /* Normalize the result */
01757   t = sqrt(m_Frustum[2][0] * m_Frustum[2][0] + m_Frustum[2][1] * m_Frustum[2][1] + m_Frustum[2][2] * m_Frustum[2][2]);
01758   m_Frustum[2][0] /= t;
01759   m_Frustum[2][1] /= t;
01760   m_Frustum[2][2] /= t;
01761   m_Frustum[2][3] /= t;
01762   /* Extract the TOP plane */
01763   m_Frustum[3][0] = clip[ 3] - clip[ 1];
01764   m_Frustum[3][1] = clip[ 7] - clip[ 5];
01765   m_Frustum[3][2] = clip[11] - clip[ 9];
01766   m_Frustum[3][3] = clip[15] - clip[13];
01767   /* Normalize the result */
01768   t = sqrt(m_Frustum[3][0] * m_Frustum[3][0] + m_Frustum[3][1] * m_Frustum[3][1] + m_Frustum[3][2] * m_Frustum[3][2]);
01769   m_Frustum[3][0] /= t;
01770   m_Frustum[3][1] /= t;
01771   m_Frustum[3][2] /= t;
01772   m_Frustum[3][3] /= t;
01773   /* Extract the FAR plane */
01774   m_Frustum[4][0] = clip[ 3] - clip[ 2];
01775   m_Frustum[4][1] = clip[ 7] - clip[ 6];
01776   m_Frustum[4][2] = clip[11] - clip[10];
01777   m_Frustum[4][3] = clip[15] - clip[14];
01778   /* Normalize the result */
01779   t = sqrt(m_Frustum[4][0] * m_Frustum[4][0] + m_Frustum[4][1] * m_Frustum[4][1] + m_Frustum[4][2] * m_Frustum[4][2]);
01780   m_Frustum[4][0] /= t;
01781   m_Frustum[4][1] /= t;
01782   m_Frustum[4][2] /= t;
01783   m_Frustum[4][3] /= t;
01784   /* Extract the NEAR plane */
01785   m_Frustum[5][0] = clip[ 3] + clip[ 2];
01786   m_Frustum[5][1] = clip[ 7] + clip[ 6];
01787   m_Frustum[5][2] = clip[11] + clip[10];
01788   m_Frustum[5][3] = clip[15] + clip[14];
01789   /* Normalize the result */
01790   t = sqrt(m_Frustum[5][0] * m_Frustum[5][0] + m_Frustum[5][1] * m_Frustum[5][1] + m_Frustum[5][2] * m_Frustum[5][2]);
01791   m_Frustum[5][0] /= t;
01792   m_Frustum[5][1] /= t;
01793   m_Frustum[5][2] /= t;
01794   m_Frustum[5][3] /= t;
01795 }
01796 
01797 inline bool Terrain::CubeInFrustum(float x, float y, float z, float size)
01798 {
01799   for(int p = 0; p < 6; p++)
01800     {
01801       if(m_Frustum[p][0] * (x - size) + m_Frustum[p][1] * (y - size) + m_Frustum[p][2] * (z - size) + m_Frustum[p][3] > 0)
01802         continue;
01803       if(m_Frustum[p][0] * (x + size) + m_Frustum[p][1] * (y - size) + m_Frustum[p][2] * (z - size) + m_Frustum[p][3] > 0)
01804         continue;
01805       if(m_Frustum[p][0] * (x - size) + m_Frustum[p][1] * (y + size) + m_Frustum[p][2] * (z - size) + m_Frustum[p][3] > 0)
01806         continue;
01807       if(m_Frustum[p][0] * (x + size) + m_Frustum[p][1] * (y + size) + m_Frustum[p][2] * (z - size) + m_Frustum[p][3] > 0)
01808         continue;
01809       if(m_Frustum[p][0] * (x - size) + m_Frustum[p][1] * (y - size) + m_Frustum[p][2] * (z + size) + m_Frustum[p][3] > 0)
01810         continue;
01811       if(m_Frustum[p][0] * (x + size) + m_Frustum[p][1] * (y - size) + m_Frustum[p][2] * (z + size) + m_Frustum[p][3] > 0)
01812         continue;
01813       if(m_Frustum[p][0] * (x - size) + m_Frustum[p][1] * (y + size) + m_Frustum[p][2] * (z + size) + m_Frustum[p][3] > 0)
01814         continue;
01815       if(m_Frustum[p][0] * (x + size) + m_Frustum[p][1] * (y + size) + m_Frustum[p][2] * (z + size) + m_Frustum[p][3] > 0)
01816         continue;
01817       return false;
01818     }
01819   return true;
01820 }
01821 
01822 #ifdef _USE_RAYTRACING_SUPPORT_
01823 float Terrain::IntersectRay(float startX,float startY,float startZ,float dirX,float dirY,float dirZ,float& intersectX,float& intersectY,float& intersectZ)
01824 {
01825   Ray ray;
01826   float distance = INFINITY;
01827   Vector point;
01828   point.x = point.y = point.z = -1.0f;
01829   
01830   ray.m_Origin.x = startX;
01831   ray.m_Origin.y = startY;
01832   ray.m_Origin.z = startZ;
01833   ray.m_Direction.x = dirX;
01834   ray.m_Direction.y = dirY;
01835   ray.m_Direction.z = dirZ;
01836   ray.m_Direction.Normalize();
01837   m_pRootBlock->IntersectRay(ray,point,distance,this);
01838   intersectX = point.x;
01839   intersectY = point.y;
01840   intersectZ = point.z;
01841   return distance;
01842 }
01843 #endif
01844 
01845 inline void Terrain::SetLatticePosition(int x,int y)
01846 {
01847   m_LatticePositionX = x;
01848   m_LatticePositionY = y;
01849 }
01850 
01851 inline void Terrain::GetLatticePosition(int& x,int& y)
01852 {
01853   x = m_LatticePositionX;
01854   y = m_LatticePositionY;
01855 }
01856 
01857 #ifdef _USE_RAYTRACING_SUPPORT_
01858 void TerrainBlock::IntersectRay(Ray& ray,Vector& intersectionPoint,float& lowestDistance,Terrain* pTerrain)
01859 {
01860   // First test ray against this block's bounding box.
01861   if (RayBoxIntersect(&ray,&m_BoundingBox,NULL,NULL))
01862     {
01863       if (2 < m_Stride)
01864         {
01865           m_pChildren[0]->IntersectRay(ray,intersectionPoint,lowestDistance,pTerrain);
01866           m_pChildren[1]->IntersectRay(ray,intersectionPoint,lowestDistance,pTerrain);
01867           m_pChildren[2]->IntersectRay(ray,intersectionPoint,lowestDistance,pTerrain);
01868           m_pChildren[3]->IntersectRay(ray,intersectionPoint,lowestDistance,pTerrain);
01869         }
01870       else
01871         {
01872           float distance;
01873           Vector point;
01874           for (int i = 0; i < 8; i++)
01875             {
01876               if (RayPlaneIntersect(&ray,m_pTriangles[i].GetPlane(),&point,&distance) == 1)
01877                 {
01878                   if (i == 0 || i == 2 || i == 4 || i == 6)
01879                     {
01880                       if (m_pTriangles[i].GetVertex(0)->x <= point.x &&
01881                           m_pTriangles[i].GetVertex(0)->y <= point.y &&
01882                           point.x <= m_pTriangles[i].GetVertex(2)->x &&
01883                           point.y <= m_pTriangles[i].GetVertex(1)->y &&
01884                           ((fmod(point.y,pTerrain->m_VertexSpacing) + fmod(point.x,pTerrain->m_VertexSpacing)) <= pTerrain->m_VertexSpacing))
01885                         {
01886                           if (distance < lowestDistance)
01887                             {
01888                               lowestDistance = distance;
01889                               intersectionPoint.x = point.x;
01890                               intersectionPoint.y = point.y;
01891                               intersectionPoint.z = point.z;
01892                             }
01893                         }
01894                     }
01895                   else
01896                     {
01897                       if (m_pTriangles[i].GetVertex(1)->x <= point.x &&
01898                           m_pTriangles[i].GetVertex(0)->y <= point.y &&
01899                           point.x <= m_pTriangles[i].GetVertex(2)->x &&
01900                           point.y <= m_pTriangles[i].GetVertex(1)->y &&
01901                           ((fmod(point.y,pTerrain->m_VertexSpacing) + fmod(point.x,pTerrain->m_VertexSpacing)) >= pTerrain->m_VertexSpacing))
01902                         {
01903                           if (distance < lowestDistance)
01904                             {
01905                               lowestDistance = distance;
01906                               intersectionPoint.x = point.x;
01907                               intersectionPoint.y = point.y;
01908                               intersectionPoint.z = point.z;
01909                             }
01910                         }
01911                     }
01912                 }
01913             }
01914         }
01915     }
01916 }
01917 
01918 int RayPlaneIntersect(Ray *ray,Plane *plane,Vector* point,float *distance)
01919 {
01920   float                 vd,vo,PnDOTRo,t;
01921   
01922   vd = plane->a * ray->m_Direction.x + plane->b * ray->m_Direction.y + plane->c * ray->m_Direction.z;
01923   if (vd == 0.0)
01924     // The plane is parallel to the ray. I've never seen this happen but someday it will . . .
01925     return -1;
01926   if (vd > 0.0)
01927     {
01928       // The plane is facing away from the ray so no intersection occurs.
01929       return -2;
01930     }
01931   PnDOTRo = plane->a * ray->m_Origin.x + plane->b * ray->m_Origin.y + plane->c * ray->m_Origin.z;
01932   vo = -1.0f * (PnDOTRo + plane->d);
01933   t = vo / vd;
01934   if (t < 0.0f)
01935     // The intersection occurs behind the ray's origin.
01936     return -3;
01937   point->x = ray->m_Origin.x + ray->m_Direction.x * t;
01938   point->y = ray->m_Origin.y + ray->m_Direction.y * t;
01939   point->z = ray->m_Origin.z + ray->m_Direction.z * t;
01940   if (distance != NULL)
01941     *distance = t;
01942   return 1;
01943 }
01944 
01945 int RayBoxIntersect(Ray *ray,Box *box,Vector *point,float *distance)
01946 {
01947   float         tnear,tfar,t1,t2;
01948   
01949   tnear = -INFINITY;
01950   tfar = INFINITY;
01951   
01952   // Find intersection with x-aligned planes of box.
01953   // If the ray is parallel to the box and not within the planes of the box it misses.
01954   if (ray->m_Direction.x == 0.0)
01955     if ((ray->m_Origin.x < box->m_Min.x) && (ray->m_Origin.x > box->m_Max.x))
01956       return 0;
01957   // Calculate intersection distance with the box's planes.
01958   t1 = (box->m_Min.x - ray->m_Origin.x) / ray->m_Direction.x;
01959   t2 = (box->m_Max.x - ray->m_Origin.x) / ray->m_Direction.x;
01960   if (t1 > t2)
01961     {
01962       float tmp = t1;
01963       t1 = t2;
01964       t2 = tmp;
01965     }
01966   if (t1 > tnear)
01967     tnear = t1;
01968   if (t2 < tfar)
01969     tfar = t2;
01970   if (tnear > tfar)
01971     return 0;
01972   if (tfar < 0.0)
01973     return 0;
01974   // Find intersection with y-aligned planes of box.
01975   // If the ray is parallel to the box and not within the planes of the box it misses.
01976   if (ray->m_Direction.y == 0.0)
01977     if ((ray->m_Origin.y < box->m_Min.y) && (ray->m_Origin.y > box->m_Max.y))
01978       return 0;
01979   // Calculate intersection distance with the box's planes.
01980   t1 = (box->m_Min.y - ray->m_Origin.y) / ray->m_Direction.y;
01981   t2 = (box->m_Max.y - ray->m_Origin.y) / ray->m_Direction.y;
01982   if (t1 > t2)
01983     {
01984       float tmp = t1;
01985       t1 = t2;
01986       t2 = tmp;
01987     }
01988   if (t1 > tnear)
01989     tnear = t1;
01990   if (t2 < tfar)
01991     tfar = t2;
01992   if (tnear > tfar)
01993     return 0;
01994   if (tfar < 0.0)
01995     return 0;
01996   // Find intersection with z-aligned planes of box.
01997   // If the ray is parallel to the box and not within the planes of the box it misses.
01998   if (ray->m_Direction.z == 0.0)
01999     if ((ray->m_Origin.z < box->m_Min.z) && (ray->m_Origin.z > box->m_Max.z))
02000       return 0;
02001   // Calculate intersection distance with the box's planes.
02002   t1 = (box->m_Min.z - ray->m_Origin.z) / ray->m_Direction.z;
02003   t2 = (box->m_Max.z - ray->m_Origin.z) / ray->m_Direction.z;
02004   if (t1 > t2)
02005     {
02006       float tmp = t1;
02007       t1 = t2;
02008       t2 = tmp;
02009     }
02010   if (t1 > tnear)
02011     tnear = t1;
02012   if (t2 < tfar)
02013     tfar = t2;
02014   if (tnear > tfar)
02015     return 0;
02016   if (tfar < 0.0)
02017     return 0;
02018   // If we survived all of the tests, the box is hit.
02019   if (point != NULL)
02020     {
02021       point->x = ray->m_Origin.x + tnear * ray->m_Direction.x;
02022       point->y = ray->m_Origin.y + tnear * ray->m_Direction.y;
02023       point->z = ray->m_Origin.z + tnear * ray->m_Direction.z;
02024       *distance = tnear;
02025     }
02026   return 1;
02027 }
02028 #endif
02029 
02030 void LoadImage(char* szFilename,int* pWidth,int* pHeight,Uint8** pBuffer,bool bColorKey)
02031 {
02032   osg::ref_ptr<osg::Image> pImage = osgDB::Registry::instance()->readImage(szFilename,true).getImage();
02033   if (pImage != NULL)
02034     {
02035       *pWidth = pImage->s();
02036       *pHeight = pImage->t();
02037       int pitch = 3 * pImage->s(); // why3?? !!!
02038 
02039       Uint8* pBufferTemp;
02040       if (bColorKey)
02041         pBufferTemp = new Uint8[*pWidth * *pHeight * 4];
02042       else
02043         pBufferTemp = new Uint8[*pWidth * *pHeight * 3];
02044       int i,j;
02045       Uint8* pImagePixels = (Uint8*)pImage->data();
02046       int bytesPerPixel = pImage->getPixelSizeInBits() / 8;
02047       for (i = pImage->t() * pitch - pitch,j = 0; i >= 0; i -= pitch)
02048         {
02049           Uint8* pImageRow = pImagePixels + i;
02050           for (Uint8* pImagePixel = pImageRow; pImagePixel < pImageRow + pImage->s() * bytesPerPixel; pImagePixel += bytesPerPixel)
02051             {
02052               Uint8 red,green,blue,alpha;
02053               Uint32* pCurrentPixel = (Uint32*)pImagePixel;
02054               if (bColorKey) {
02055                 red   = (*pCurrentPixel) & 0xff; // !!!! check this is ok for Intel endian
02056                 green = ((*pCurrentPixel) & 0xff00) >> 8; // (we should really use dataType intelligently!)
02057                 blue  = ((*pCurrentPixel) & 0xff0000) >> 16;
02058                 alpha = ((*pCurrentPixel) & 0xff000000) >> 24;
02059                 //              SDL_GetRGBA(*pCurrentPixel,pImage->format,&red,&green,&blue,&alpha);
02060               }
02061               else {
02062                 red   = (*pCurrentPixel) & 0xff; // !!!! check this is ok for Intel endian
02063                 green = ((*pCurrentPixel) & 0xff00) >> 8; // (we should really use dataType intelligently!)
02064                 blue  = ((*pCurrentPixel) & 0xff0000) >> 16;
02065                 alpha = ((*pCurrentPixel) & 0xff000000) >> 24;
02066                 //              SDL_GetRGBA(*pCurrentPixel,pImage->format,&red,&green,&blue,&alpha);
02067               }
02068               pBufferTemp[j++] = red;
02069               pBufferTemp[j++] = green;
02070               pBufferTemp[j++] = blue;
02071               if (bColorKey)
02072                 {
02073                   pBufferTemp[j++] = alpha;
02074                 }
02075             }
02076         }
02077       *pBuffer = pBufferTemp;
02078       //      SDL_FreeSurface(pImage);
02079     }
02080   else
02081     {
02082       *pWidth = 0;
02083       *pHeight = 0;
02084       *pBuffer = NULL;
02085     }
02086 }
02087 
02088 GLuint CreateTexture(Uint8* pTexels,int width,int height,int rowLength,int border,int internalFormat,bool bClamp,bool bColorKey)
02089 {
02090   GLuint texId;
02091   glGenTextures(1,&texId);
02092   glBindTexture(GL_TEXTURE_2D,texId);
02093   if (bClamp)
02094     {
02095       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
02096       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
02097     }
02098   else
02099     {
02100       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
02101       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
02102     }
02103   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
02104   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
02105   glPixelStorei(GL_UNPACK_ROW_LENGTH,rowLength);
02106   glPixelStorei(GL_UNPACK_ALIGNMENT,1);
02107   if (bColorKey)
02108     {
02109       glTexImage2D(GL_TEXTURE_2D,0,internalFormat,width + 2 * border,height + 2 * border,border,GL_RGBA,GL_UNSIGNED_BYTE,pTexels);
02110       gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGBA,width,height,GL_RGBA,GL_UNSIGNED_BYTE,pTexels);
02111     }
02112   else
02113     {
02114       glTexImage2D(GL_TEXTURE_2D,0,internalFormat,width + 2 * border,height + 2 * border,border,GL_RGB,GL_UNSIGNED_BYTE,pTexels);
02115       gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGB,width,height,GL_RGB,GL_UNSIGNED_BYTE,pTexels);
02116     }
02117   glPixelStorei(GL_UNPACK_ROW_LENGTH,0);
02118   return texId;
02119 }
02120 
02121 inline bool IsPowerOf2(double number)
02122 {
02123   const int MAX_POWER = 1024;
02124   bool isPowerOf2 = false;
02125   for(int i = 0; i < MAX_POWER && !isPowerOf2; i++)
02126     {
02127       if (pow(2.0,i) == number)
02128         isPowerOf2 = true;
02129     }
02130   return isPowerOf2;
02131 }
02132 
02133 Settings::Settings()
02134 {
02135   m_szMediaPath = NULL;
02136   m_bVerbose = false;
02137   m_bIsCompilerOnly = false;
02138   m_IsHeadless = false;
02139   m_UseDynamicTextures = false;
02140 }
02141 
02142 Settings::~Settings()
02143 {
02144   if (m_szMediaPath != NULL)
02145     delete[] m_szMediaPath;
02146 }
02147 
02148 Settings* Settings::GetInstance()
02149 {
02150   if (pSettingsInstance == NULL)
02151     pSettingsInstance = new Settings();
02152   return pSettingsInstance;
02153 }
02154 
02155 bool Settings::SetProperty(char* szProperty,char* szValue)
02156 {
02157   bool bSuccess = false;
02158   
02159   if (strcmp(szProperty,"verbose") == 0)
02160     {
02161       SetVerbose(strcmp(szValue,"true") == 0);
02162       bSuccess = true;
02163     }
02164   
02165   return bSuccess;
02166 }
02167 
02168 bool Settings::GetProperty(char* szProperty,char* szValue)
02169 {
02170   bool bSuccess = false;
02171   
02172   if (strcmp(szProperty,"verbose") == 0)
02173     {
02174       sprintf(szValue,m_bVerbose ? "true" : "false");
02175       bSuccess = true;
02176     }
02177   else if (strcmp(szProperty,"glinfo") == 0)
02178     {
02179       sprintf(szValue,"OpenGL Vendor: %s; OpenGL Extensions Supported: %s",glGetString(GL_VENDOR),glGetString(GL_EXTENSIONS));
02180       bSuccess = true;
02181     }
02182   
02183   return bSuccess;
02184 }
02185 
02186 inline void Settings::SetUseDynamicTextures(bool use)
02187 {
02188   m_UseDynamicTextures = use;
02189 }
02190 
02191 inline bool Settings::UseDynamicTextures()
02192 {
02193   return m_UseDynamicTextures;
02194 }
02195 
02196 void Settings::SetMediaPath(char* szPath)
02197 {
02198   char separator = '/';
02199 
02200   m_bCompressTextures = false;
02201   if (m_szMediaPath != NULL)
02202     delete[] m_szMediaPath;
02203   if (szPath[strlen(szPath) - 1] == separator)
02204     {
02205       m_szMediaPath = new char[strlen(szPath) + 1];
02206       sprintf(m_szMediaPath,szPath);
02207     }
02208   else
02209     {
02210       m_szMediaPath = new char[strlen(szPath) + 2];
02211       sprintf(m_szMediaPath,"%s%c",szPath,separator);
02212     }
02213 }
02214 
02215 void Settings::GetMediaPath(char** szPath)
02216 {
02217   char* szOutput = new char[strlen(m_szMediaPath) + 1];
02218   sprintf(szOutput,m_szMediaPath);
02219   *szPath = szOutput;
02220 }
02221 
02222 void Settings::PrependMediaPath(char* szFilename,char** pszFullFilename)
02223 {
02224   char* szFull = new char[strlen(szFilename) + strlen(m_szMediaPath) + 2];
02225   sprintf(szFull,"%s%s",m_szMediaPath,szFilename);
02226   *pszFullFilename = szFull;
02227 }
02228 
02229 void Settings::SetHeadless(bool isHeadless)
02230 {
02231   m_IsHeadless = isHeadless;
02232 }
02233 
02234 bool Settings::IsHeadless()
02235 {
02236   return m_IsHeadless;
02237 }
02238 
02239 void Settings::SetVerbose(bool bVerbose)
02240 {
02241   m_bVerbose = bVerbose;
02242 }
02243 
02244 bool Settings::IsVerbose()
02245 {
02246   return m_bVerbose;
02247 }
02248 
02249 inline int Settings::GetScreenWidth()
02250 {
02251   return m_ScreenWidth;
02252 }
02253 
02254 inline void Settings::SetScreenWidth(int width)
02255 {
02256   m_ScreenWidth = width;
02257 }
02258 
02259 inline int Settings::GetScreenHeight()
02260 {
02261   return m_ScreenHeight;
02262 }
02263 
02264 inline void Settings::SetScreenHeight(int height)
02265 {
02266   m_ScreenHeight = height;
02267 }
02268 
02269 inline bool Settings::IsCompilerOnly()
02270 {
02271   return m_bIsCompilerOnly;
02272 }
02273 
02274 void Settings::SetCompilerOnly(bool bIsCompilerOnly)
02275 {
02276   m_bIsCompilerOnly = bIsCompilerOnly;
02277 }
02278 
02279 void Settings::SetTextureCompression(bool bCompress)
02280 {
02281   m_bCompressTextures = bCompress;
02282 }
02283 
02284 inline bool Settings::IsTextureCompression()
02285 {
02286   return m_bCompressTextures;
02287 }
02288 
02289 Vector& Vector::operator = (const Vector& v)
02290 {
02291   x = v.x;
02292   y = v.y;
02293   z = v.z;
02294   return *this;
02295 }
02296 
02297 inline float Vector::Normalize(float tolerance)
02298 {
02299   float length = GetLength();
02300   
02301   if (length > tolerance)
02302     {
02303       float invLength = 1.0f / length;
02304       x *= invLength;
02305       y *= invLength;
02306       z *= invLength;
02307     }
02308   else
02309     {
02310       length = 0.0;
02311     }
02312   
02313   return length;
02314 }
02315 
02316 inline float Vector::GetLength()
02317 {
02318   return sqrt(x*x + y*y + z*z);
02319 }
02320 
02321 Plane::Plane(Vector& p1,Vector& p2,Vector& p3)
02322 {
02323   defineFromPoints(p1,p2,p3);
02324 }
02325 
02326 inline void Plane::defineFromPoints(Vector& p1,Vector& p2,Vector& p3)
02327 {
02328   Vector v1,v2,normal;
02329   // Find the normal of the polygon defined by the three points(cross product of 2 vertex vectors)
02330   v1.x = p2.x - p1.x;
02331   v1.y = p2.y - p1.y;
02332   v1.z = p2.z - p1.z;
02333   
02334   v2.x = p3.x - p1.x;
02335   v2.y = p3.y - p1.y;
02336   v2.z = p3.z - p1.z;
02337   
02338   v1.Normalize();
02339   v2.Normalize();
02340   // Find surface normal based on cross product.
02341   normal.x = v1.y * v2.z - v2.y * v1.z;
02342   normal.y = v2.x * v1.z - v1.x * v2.z;
02343   normal.z = v1.x * v2.y - v2.x * v1.y;
02344   normal.Normalize();
02345   // This surface normal represents the a,b,c components of the plane equation.
02346   a = normal.x;
02347   b = normal.y;
02348   c = normal.z;
02349   // The d component is calculated from Ax + By + Cz + D = 0
02350   d = -(a * p1.x + b * p1.y + c * p1.z);
02351 }
02352 
02353 Triangle::Triangle()
02354 {
02355 }
02356 
02357 Triangle::~Triangle()
02358 {
02359 }
02360 
02361 void Triangle::DefineFromPoints(Vector& p1,Vector& p2,Vector& p3)
02362 {
02363   m_pVertices[0].x = p1.x;
02364   m_pVertices[0].y = p1.y;
02365   m_pVertices[0].z = p1.z;
02366   m_pVertices[1].x = p2.x;
02367   m_pVertices[1].y = p2.y;
02368   m_pVertices[1].z = p2.z;
02369   m_pVertices[2].x = p3.x;
02370   m_pVertices[2].y = p3.y;
02371   m_pVertices[2].z = p3.z;
02372 #ifdef _USE_RAYTRACING_SUPPORT_
02373   m_Plane.defineFromPoints(p3,p2,p1);
02374 #endif
02375 }
02376 
02377 inline Vector* Triangle::GetVertex(int index)
02378 {
02379   return &m_pVertices[index];
02380 }
02381 
02382 #ifdef _USE_RAYTRACING_SUPPORT_
02383 Plane* Triangle::GetPlane()
02384 {
02385   return &m_Plane;
02386 }
02387 #endif
02388 
02389 
02390 TerrainLattice::TerrainLattice(int widthTerrains,int heightTerrains,float terrainWidth,float terrainHeight)
02391 {
02392   m_WidthTerrains = widthTerrains;
02393   m_HeightTerrains = heightTerrains;
02394   m_TerrainWidth = terrainWidth;
02395   m_TerrainHeight = terrainHeight;
02396   m_pTerrains = new Terrain*[widthTerrains * heightTerrains];
02397   for (int i = 0; i < widthTerrains * heightTerrains; i++)
02398     m_pTerrains[i] = NULL;
02399   m_WidthActiveTerrains = m_HeightActiveTerrains = 1;
02400 }
02401 
02402 TerrainLattice::~TerrainLattice()
02403 {
02404   delete[] m_pTerrains;
02405 }
02406 
02407 void TerrainLattice::AddTerrain(Terrain* pTerrain,int positionX,int positionY)
02408 {
02409   m_pTerrains[positionY * m_WidthTerrains + positionX] = pTerrain;
02410   pTerrain->SetLatticePosition(positionX,positionY);
02411 }
02412 
02413 Terrain* TerrainLattice::GetTerrain(int positionX,int positionY)
02414 {
02415   return m_pTerrains[positionY * m_WidthTerrains + positionX];
02416 }
02417 
02418 Terrain* TerrainLattice::GetTerrainRelative(Terrain* pTerrain,Terrain::DIRECTION direction)
02419 {
02420   int offsetX,offsetY;
02421   switch (direction)
02422     {
02423     case Terrain::DIR_NORTH:
02424       offsetX = 0;
02425       offsetY = 1;
02426       break;
02427     case Terrain::DIR_NORTHEAST:
02428       offsetX = 1;
02429       offsetY = 1;
02430       break;
02431     case Terrain::DIR_EAST:
02432       offsetX = 1;
02433       offsetY = 0;
02434       break;
02435     case Terrain::DIR_SOUTHEAST:
02436       offsetX = 1;
02437       offsetY = -1;
02438       break;
02439     case Terrain::DIR_SOUTH:
02440       offsetX = 0;
02441       offsetY = -1;
02442       break;
02443     case Terrain::DIR_SOUTHWEST:
02444       offsetX = -1;
02445       offsetY = -1;
02446       break;
02447     case Terrain::DIR_WEST:
02448       offsetX = -1;
02449       offsetY = 0;
02450       break;
02451     case Terrain::DIR_NORTHWEST:
02452       offsetX = -1;
02453       offsetY = 1;
02454       break;
02455     default:
02456       offsetX=offsetY=0;
02457     }
02458   return GetTerrainRelative(pTerrain,offsetX,offsetY);
02459 }
02460 
02461 
02462 Terrain* TerrainLattice::GetTerrainRelative(Terrain* pTerrain,int positionX,int positionY)
02463 {
02464   Terrain* pRequestedTerrain = NULL;
02465   if (-1 <= positionX && positionX <= 1 && -1 <= positionY && positionY <= 1)
02466     {
02467       int x,y;
02468       pTerrain->GetLatticePosition(x,y);
02469       x += positionX;
02470       y += positionY;
02471       
02472       Terrain* pTerrainCenter = m_pTerrains[m_CurrentTerrainIndex[Terrain::DIR_CENTER]];
02473       int centerX,centerY;
02474       pTerrainCenter->GetLatticePosition(centerX,centerY);
02475       if (abs(x - centerX) <= m_WidthActiveTerrains && abs(y - centerY) <= m_HeightActiveTerrains)
02476         {               
02477           if (0 <= x && x < m_WidthTerrains && 0 <= y && y < m_HeightTerrains)
02478             pRequestedTerrain = GetTerrain(x,y);
02479         }
02480     }
02481   return pRequestedTerrain;
02482 }
02483 
02484 Terrain* TerrainLattice::GetTerrainAtPoint(float x,float y)
02485 {
02486   int indexX = (int)x / (int)m_TerrainWidth;
02487   int indexY = (int)y / (int)m_TerrainHeight;
02488   if (0 <= indexX && indexX < m_WidthTerrains && 0 <= indexY && indexY < m_HeightTerrains)
02489     return GetTerrain(indexX,indexY);
02490   else
02491     return NULL;
02492 }
02493 
02494 void TerrainLattice::SetCameraPosition(float x,float y,float z)
02495 {
02496   int indexX = (int)x / (int)m_TerrainWidth;
02497   int indexY = (int)y / (int)m_TerrainHeight;
02498   m_CurrentTerrainIndex[Terrain::DIR_CENTER] = indexY * m_WidthTerrains + indexX;
02499   m_CurrentTerrainIndex[Terrain::DIR_SOUTH] = 0 < indexY ? m_CurrentTerrainIndex[Terrain::DIR_CENTER] - m_WidthTerrains : -1;
02500   m_CurrentTerrainIndex[Terrain::DIR_SOUTHEAST] = (0 < indexY && indexX < m_WidthTerrains - 1) ? m_CurrentTerrainIndex[Terrain::DIR_CENTER] - m_WidthTerrains + 1 : -1;
02501   m_CurrentTerrainIndex[Terrain::DIR_SOUTHWEST] = 0 < indexX && 0 < indexY ? m_CurrentTerrainIndex[Terrain::DIR_CENTER] - m_WidthTerrains - 1 : -1;
02502   m_CurrentTerrainIndex[Terrain::DIR_EAST] = indexX < m_WidthTerrains - 1 ? m_CurrentTerrainIndex[Terrain::DIR_CENTER] + 1 : -1;
02503   m_CurrentTerrainIndex[Terrain::DIR_WEST] = 0 < indexX ? m_CurrentTerrainIndex[Terrain::DIR_CENTER] - 1 : -1;
02504   m_CurrentTerrainIndex[Terrain::DIR_NORTH] = indexY < m_HeightTerrains - 1 ? m_CurrentTerrainIndex[Terrain::DIR_CENTER] + m_WidthTerrains : -1;
02505   m_CurrentTerrainIndex[Terrain::DIR_NORTHEAST] = (indexX < m_WidthTerrains - 1 && indexY < m_HeightTerrains - 1) ? m_CurrentTerrainIndex[Terrain::DIR_CENTER] + m_WidthTerrains + 1 : -1;
02506   m_CurrentTerrainIndex[Terrain::DIR_NORTHWEST] = (indexY < m_HeightTerrains - 1 && 0 < indexX) ? m_CurrentTerrainIndex[Terrain::DIR_CENTER] + m_WidthTerrains - 1 : -1;
02507   
02508   for (int i = 0; i < m_WidthTerrains * m_HeightTerrains; i++)
02509     {
02510       bool active = false;
02511       for (int dir = 0; dir < 9 && !active; dir++)
02512         active = (i == m_CurrentTerrainIndex[dir]);
02513       if (!active && m_pTerrains[i] != NULL)
02514         {
02515           vector<TerrainLoadListener*>::iterator iter = m_TerrainLoadListeners.begin();
02516           while (iter != m_TerrainLoadListeners.end())
02517             {
02518               TerrainLoadListener* pListener = *iter;
02519               pListener->TerrainUnloading(m_pTerrains[i]);
02520               iter++;
02521             }
02522           delete m_pTerrains[i];
02523           m_pTerrains[i] = NULL;
02524         }
02525       else if (active && m_pTerrains[i] == NULL)
02526         {
02527           LoadTerrain(i);
02528           vector<TerrainLoadListener*>::iterator iter = m_TerrainLoadListeners.begin();
02529           while (iter != m_TerrainLoadListeners.end())
02530             {
02531               TerrainLoadListener* pListener = *iter;
02532               pListener->TerrainLoaded(m_pTerrains[i]);
02533               iter++;
02534             }
02535         }
02536     }
02537 }
02538 
02539 void TerrainLattice::LoadTerrain(int index)
02540 {
02541   int indexX = index % m_WidthTerrains;
02542   int indexY = index / m_WidthTerrains;
02543   char szMapName[1024];
02544   sprintf(szMapName,"%d-%d-%s",indexX,indexY,m_BaseName.c_str());
02545   
02546   Terrain* pTerrain = new Terrain(szMapName,m_MaxNumTriangles,m_bUseBorders,(float)indexX * m_TerrainWidth,(float)indexY * m_TerrainHeight);
02547   if (m_TerrainWidth == 0.0f)
02548     {
02549       m_TerrainWidth = pTerrain->GetWidth();
02550       m_TerrainHeight = pTerrain->GetHeight();
02551     }
02552   pTerrain->SetMaximumVisibleBlockSize(m_MaxBlockSize);
02553   pTerrain->SetCommonTextureRepeats(m_CommonRepeats);
02554   AddTerrain(pTerrain,indexX,indexY);
02555 }
02556 
02557 void TerrainLattice::SetDetailThreshold(float threshold)
02558 {
02559   for (int i = 0; i < 9; i++)
02560     {
02561       if (0 <= m_CurrentTerrainIndex[i])
02562         m_pTerrains[m_CurrentTerrainIndex[i]]->SetDetailThreshold(threshold);
02563     }
02564 }
02565 
02566 inline float TerrainLattice::GetElevation(float x,float y)
02567 {
02568   Terrain* pTerrain = GetTerrainAtPoint(x,y);
02569   if (pTerrain != NULL)
02570     return pTerrain->GetElevation(x,y);
02571   else
02572     return 0.0f;
02573 }
02574 
02575 inline Terrain::DIRECTION TerrainLattice::GetOppositeDirection(Terrain::DIRECTION direction)
02576 {
02577   Terrain::DIRECTION oppositeDirection;
02578   switch (direction)
02579     {
02580     case Terrain::DIR_NORTH:
02581       oppositeDirection = Terrain::DIR_SOUTH;
02582       break;
02583     case Terrain::DIR_NORTHEAST:
02584       oppositeDirection = Terrain::DIR_SOUTHWEST;
02585       break;
02586     case Terrain::DIR_EAST:
02587       oppositeDirection = Terrain::DIR_WEST;
02588       break;
02589     case Terrain::DIR_SOUTHEAST:
02590       oppositeDirection = Terrain::DIR_NORTHWEST;
02591       break;
02592     case Terrain::DIR_SOUTH:
02593       oppositeDirection = Terrain::DIR_NORTH;
02594       break;
02595     case Terrain::DIR_SOUTHWEST:
02596       oppositeDirection = Terrain::DIR_NORTHEAST;
02597       break;
02598     case Terrain::DIR_WEST:
02599       oppositeDirection = Terrain::DIR_EAST;
02600       break;
02601     case Terrain::DIR_NORTHWEST:
02602       oppositeDirection = Terrain::DIR_SOUTHEAST;
02603       break;
02604     case Terrain::DIR_CENTER:
02605       oppositeDirection = Terrain::DIR_CENTER;
02606       break;
02607     default:
02608       oppositeDirection = Terrain::DIR_CENTER;
02609     }
02610   return oppositeDirection;
02611 }
02612 
02613 void TerrainLattice::Tessellate()
02614 {
02615   int i;
02616   for (i = 0; i < 9; i++)
02617     {
02618       if (m_CurrentTerrainIndex[i] != -1)
02619         m_pTerrains[m_CurrentTerrainIndex[i]]->Tessellate();
02620     }
02621   
02622   for (i = 0; i < 9; i++)
02623     {
02624       if (m_CurrentTerrainIndex[i] != -1)
02625         {
02626           for (int direction = 0; direction < 8; direction++)
02627             {
02628               if (direction != Terrain::DIR_CENTER)
02629                 {
02630                   Terrain* pTerrain = GetTerrainRelative(m_pTerrains[m_CurrentTerrainIndex[i]],(Terrain::DIRECTION)direction);
02631                   if (pTerrain != NULL)
02632                     {
02633                       m_pTerrains[m_CurrentTerrainIndex[i]]->UpdateNeighbor(pTerrain,(Terrain::DIRECTION)direction);
02634                       pTerrain->UpdateNeighbor(m_pTerrains[m_CurrentTerrainIndex[i]],GetOppositeDirection((Terrain::DIRECTION)direction));
02635                     }
02636                 }
02637             }
02638         }
02639     }
02640   
02641   for (i = 0; i < 9; i++)
02642     {
02643       if (m_CurrentTerrainIndex[i] != -1)
02644         m_pTerrains[m_CurrentTerrainIndex[i]]->m_pRootBlock->RepairCracks(m_pTerrains[m_CurrentTerrainIndex[i]],m_pTerrains[m_CurrentTerrainIndex[i]]->m_pTriangleStrips,m_pTerrains[m_CurrentTerrainIndex[i]]->m_pTriangleFans,&m_pTerrains[m_CurrentTerrainIndex[i]]->m_CountStrips,&m_pTerrains[m_CurrentTerrainIndex[i]]->m_CountFans);
02645     }
02646   
02647 }
02648 
02649 void TerrainLattice::Render()
02650 {
02651   for (int i = 0; i < 9; i++)
02652     {
02653       if (m_CurrentTerrainIndex[i] != -1)
02654         m_pTerrains[m_CurrentTerrainIndex[i]]->Render();
02655     }
02656 }
02657 
02658 void TerrainLattice::Load(char* szBaseName,int maxNumTriangles,int maxBlockSize,float commonRepeats,bool bUseBorders)
02659 {
02660   int i,j;
02661   bool horizontalExists,verticalExists,anyExist;
02662   
02663   i = j = 0;
02664   m_TerrainWidth = m_TerrainHeight = 0.0f;
02665   m_WidthTerrains = m_HeightTerrains = 0;
02666   verticalExists = true;
02667   anyExist = false;
02668   
02669   m_BaseName = szBaseName;
02670   m_MaxNumTriangles = maxNumTriangles;
02671   m_MaxBlockSize = maxBlockSize;
02672   m_CommonRepeats = commonRepeats;
02673   m_bUseBorders = bUseBorders;
02674   
02675   while(verticalExists)
02676     {
02677       verticalExists = false;
02678       horizontalExists = true;
02679       while (horizontalExists)
02680         {
02681           char szMapName[1024];
02682           sprintf(szMapName,"%d-%d-%s",i,j,szBaseName);
02683           char* szFullFilename;
02684           Settings::GetInstance()->PrependMediaPath(szMapName,&szFullFilename);
02685           FILE* file = fopen(szFullFilename,"rb");
02686           horizontalExists = (file != NULL);
02687           if (horizontalExists)
02688             {
02689               fclose(file);
02690               verticalExists = true;
02691               anyExist = true;
02692               if (i == 0 && j == 0)
02693                 {
02694                   Terrain* pTerrain = new Terrain(szMapName,maxNumTriangles,bUseBorders,(float)i * m_TerrainWidth,(float)j * m_TerrainHeight);
02695                   m_TerrainWidth = pTerrain->GetWidth();
02696                   m_TerrainHeight = pTerrain->GetHeight();
02697                   delete pTerrain;
02698                 }
02699               i++;
02700               if (j == 0)
02701                 m_WidthTerrains++;
02702             }
02703           else
02704             i = 0;
02705         }
02706       if (verticalExists)
02707         {
02708           m_HeightTerrains++;
02709           j++;
02710         }
02711     }
02712   if (!anyExist)
02713     {
02714       char* szMediaPath;
02715       Settings::GetInstance()->GetMediaPath(&szMediaPath);
02716       string msg = "Compiled map files for ";
02717       msg += szBaseName;
02718       msg += " could not be found at ";
02719       msg += szMediaPath;
02720       delete[] szMediaPath;
02721       throw new std::invalid_argument(Exception(msg));
02722     }
02723 }
02724 
02725 void TerrainLattice::AddTerrainLoadListener(TerrainLoadListener& listener)
02726 {
02727   m_TerrainLoadListeners.push_back(&listener);
02728 }
02729 
02730 void TerrainLattice::RemoveTerrainLoadListener(TerrainLoadListener& listener)
02731 {
02732   bool found = false;
02733   vector<TerrainLoadListener*>::iterator iter = m_TerrainLoadListeners.begin();
02734   while (iter != m_TerrainLoadListeners.end() && !found)
02735     {
02736       TerrainLoadListener* pListener = *iter;
02737       if (pListener == &listener)
02738         {
02739           m_TerrainLoadListeners.erase(iter);
02740           found = true;
02741         }
02742       else
02743         iter++;
02744     }
02745 }
02746 
02747 inline float TerrainLattice::GetWidth()
02748 {
02749   return m_WidthTerrains * m_TerrainWidth;
02750 }
02751 
02752 inline float TerrainLattice::GetHeight()
02753 {
02754   return m_HeightTerrains * m_TerrainHeight;
02755 }
02756 
02757 Texture::Texture(Uint8* pBuffer,int width,int height,int rowLength,int borderSize,bool bClamp,bool useCompression)
02758 {
02759   m_pBuffer = new Uint8[height * width * 3];
02760   int k = 0;
02761   for (int i = 0; i < height; i++)
02762     {
02763       for (int j = 0; j < width * 3; j++,k++)
02764         {
02765           m_pBuffer[k] = pBuffer[i * rowLength * 3 + j];
02766         }
02767     }
02768   m_Width = width;
02769   m_Height = height;
02770   m_UseCompression = useCompression;
02771   m_BorderSize = borderSize;
02772   m_TextureID = 0;
02773   m_bClamp = bClamp;
02774 }
02775 
02776 Texture::~Texture()
02777 {
02778   if (m_TextureID != 0)
02779     {
02780       glDeleteTextures(1,&m_TextureID);
02781       m_TextureID = 0;
02782     }
02783   if (m_pBuffer != NULL)
02784     {
02785       delete[] m_pBuffer;
02786       m_pBuffer = NULL;
02787     }
02788 }
02789 
02790 GLuint Texture::UploadTexture()
02791 {
02792   if (m_TextureID == 0)
02793     {
02794       int textureFormat;
02795       textureFormat = m_UseCompression ? COMPRESSED_RGB_S3TC_DXT1_EXT : GL_RGB4;
02796       m_TextureID = CreateTexture(m_pBuffer,m_Width,m_Height,m_Width,0,textureFormat,m_bClamp);
02797     }
02798   return m_TextureID;
02799 }
02800 
02801 void Texture::UnloadTexture()
02802 {
02803   if (m_TextureID != 0)
02804     {
02805       glDeleteTextures(1,&m_TextureID);
02806       m_TextureID = 0;
02807     }
02808 }

Generated on Thu Jul 29 15:56:18 2004 for OpenSim by doxygen 1.3.6