00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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;
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
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
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
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
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
00271 float screenDist = screenDistHorizontal < screenDistVertical ? screenDistHorizontal : screenDistVertical;
00272
00273 if (screenDist <= pTerrain->GetDetailThreshold())
00274 {
00275
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
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
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
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
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
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
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
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
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
00582 if (!IsPowerOf2((double)pImage->s()) || !IsPowerOf2((double)pImage->t()))
00583 {
00584 pImage->ensureValidSizeForTexturing(8192);
00585 }
00586
00587
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();
00597 m_WidthVertices = pImage->s() + 1;
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
00627 red = (*pCurrentPixel) & 0xff;
00628 green = ((*pCurrentPixel) & 0xff00) >> 8;
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++;
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
00722
00723 glActiveTextureARB_ptr = glActiveTextureARB;
00724
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
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;
00752 pTextureDetail[k + 1] = v;
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] != '/')
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
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
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;
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
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
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
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
01305
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
01325
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
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
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
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
01502
01503
01504
01505
01506
01507
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
01569
01570
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
01633
01634
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
01709 glGetFloatv(GL_PROJECTION_MATRIX, proj);
01710
01711 glGetFloatv(GL_MODELVIEW_MATRIX, modl);
01712
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
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
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
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
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
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
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
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
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
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
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
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
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
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
01925 return -1;
01926 if (vd > 0.0)
01927 {
01928
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
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
01953
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
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
01975
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
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
01997
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
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
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();
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;
02056 green = ((*pCurrentPixel) & 0xff00) >> 8;
02057 blue = ((*pCurrentPixel) & 0xff0000) >> 16;
02058 alpha = ((*pCurrentPixel) & 0xff000000) >> 24;
02059
02060 }
02061 else {
02062 red = (*pCurrentPixel) & 0xff;
02063 green = ((*pCurrentPixel) & 0xff00) >> 8;
02064 blue = ((*pCurrentPixel) & 0xff0000) >> 16;
02065 alpha = ((*pCurrentPixel) & 0xff000000) >> 24;
02066
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
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
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
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
02346 a = normal.x;
02347 b = normal.y;
02348 c = normal.z;
02349
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 }