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

OgreTerrainRenderable.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002 terrainrenderable.cpp  -  description
00003 -------------------
00004 begin                : Sat Oct 5 2002
00005 copyright            : (C) 2002 by Jon Anderson
00006 email                : janders@users.sf.net
00007 ***************************************************************************/
00008 
00009 /***************************************************************************
00010 *                                                                         *
00011 *   This program is free software; you can redistribute it and/or modify  *
00012 *   it under the terms of the GNU Lesser General Public License as published by  *
00013 *   the Free Software Foundation; either version 2 of the License, or     *
00014 *   (at your option) any later version.                                   *
00015 *                                                                         *
00016 ***************************************************************************/
00017 
00018 #include "OgreTerrainRenderable.h"
00019 #include <OgreSceneNode.h>
00020 #include <OgreRenderQueue.h>
00021 #include <OgreRenderOperation.h>
00022 #include <OgreCamera.h>
00023 #include <OgreRoot.h>
00024 
00025 
00026 namespace Ogre
00027 {
00028 #define POSITION_BINDING 0
00029 #define NORMAL_BINDING 1
00030 #define TEXCOORD_BINDING 2
00031 #define COLOUR_BINDING 3
00032 
00033 TerrainBufferCache gIndexCache;
00034 
00035 size_t TerrainRenderable::mRenderedTris = 0;
00036 
00037 String TerrainRenderable::mType = "TerrainMipMap";
00038 
00039 LevelArray TerrainRenderable::mLevelIndex;
00040 bool TerrainRenderable::mLevelInit = false;
00041 
00042 TerrainRenderable::TerrainRenderable()
00043     : mTerrain(0)
00044 {
00045     mForcedRenderLevel = -1;
00046 
00047     mMinLevelDistSqr = 0;
00048 
00049     mInit = false;
00050     mRenderLevelChanged = true;
00051 
00052     mColored = false;
00053     mLit = false;
00054 
00055     for ( int i = 0; i < 4; i++ )
00056     {
00057         mNeighbors[ i ] = 0;
00058     }
00059 
00060     _initLevelIndexes();
00061 
00062 }
00063 
00064 TerrainRenderable::~TerrainRenderable()
00065 {
00066 
00067     deleteGeometry();
00068 }
00069 
00070 void TerrainRenderable::deleteGeometry()
00071 {
00072     if(mTerrain)
00073         delete mTerrain;
00074 
00075     if ( mMinLevelDistSqr != 0 )
00076         delete [] mMinLevelDistSqr;
00077 }
00078 
00079 void TerrainRenderable::init( TerrainOptions &options )
00080 {
00081     //ensure that the size works
00082     if ( ! _checkSize( options.size ) )
00083     {
00084         printf( "Terrain block must size: 2^n+1 ( it's %d )\n", options.size );
00085         return ;
00086     }
00087 
00088     if ( options.max_mipmap != 0 )
00089     {
00090         int i = ( int ) 1 << ( options.max_mipmap - 1 ) ;
00091 
00092         if ( ( i + 1 ) > options.size )
00093         {
00094             printf( "Invalid maximum mipmap specifed, must be n, such that 2^(n-1)+1 < options.size \n" );
00095             return ;
00096         }
00097     }
00098 
00099     deleteGeometry();
00100 
00101     //calculate min and max heights;
00102     Real min = 256000, max = 0;
00103 
00104     /* Initialize the variables */
00105     mLit = options.lit;
00106 
00107     mColored = options.colored;
00108 
00109     mNearPlane = options.near_plane;
00110 
00111     mMaxPixelError = options.max_pixel_error;
00112 
00113     mVertResolution = options.vert_res;
00114 
00115     mTopCoord = options.top_coord;
00116 
00117     mSize = options.size;
00118 
00119     mWorldSize = options.world_size;
00120 
00121     mNumMipMaps = options.max_mipmap;
00122 
00123     mTerrain = new VertexData;
00124     mTerrain->vertexStart = 0;
00125     mTerrain->vertexCount = mSize * mSize;
00126 
00127     VertexDeclaration* decl = mTerrain->vertexDeclaration;
00128     VertexBufferBinding* bind = mTerrain->vertexBufferBinding;
00129 
00130     // positions
00131     size_t offset = 0;
00132     decl->addElement(POSITION_BINDING, 0, VET_FLOAT3, VES_POSITION);
00133     decl->addElement(NORMAL_BINDING, 0, VET_FLOAT3, VES_NORMAL);
00134     // texture coord sets
00135     decl->addElement(TEXCOORD_BINDING, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
00136     offset += VertexElement::getTypeSize(VET_FLOAT2);
00137     decl->addElement(TEXCOORD_BINDING, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 1);
00138     offset += VertexElement::getTypeSize(VET_FLOAT2);
00139     decl->addElement(COLOUR_BINDING, 0, VET_COLOUR, VES_DIFFUSE);
00140 
00141     HardwareVertexBufferSharedPtr vbuf =
00142         HardwareBufferManager::getSingleton().createVertexBuffer(
00143             decl->getVertexSize(POSITION_BINDING),
00144             mTerrain->vertexCount, 
00145             HardwareBuffer::HBU_STATIC_WRITE_ONLY, true);
00146 
00147     bind->setBinding(POSITION_BINDING, vbuf);
00148 
00149     vbuf =
00150         HardwareBufferManager::getSingleton().createVertexBuffer(
00151             decl->getVertexSize(NORMAL_BINDING),
00152             mTerrain->vertexCount, 
00153             HardwareBuffer::HBU_STATIC_WRITE_ONLY);
00154 
00155     bind->setBinding(NORMAL_BINDING, vbuf);
00156 
00157     vbuf =
00158         HardwareBufferManager::getSingleton().createVertexBuffer(
00159             offset,
00160             mTerrain->vertexCount, 
00161             HardwareBuffer::HBU_STATIC_WRITE_ONLY);
00162 
00163     bind->setBinding(TEXCOORD_BINDING, vbuf);
00164 
00165     vbuf =
00166         HardwareBufferManager::getSingleton().createVertexBuffer(
00167             decl->getVertexSize(COLOUR_BINDING),
00168             mTerrain->vertexCount, 
00169             HardwareBuffer::HBU_STATIC_WRITE_ONLY);
00170 
00171     bind->setBinding(COLOUR_BINDING, vbuf);
00172 
00173     mInit = true;
00174 
00175     mRenderLevel = 1;
00176 
00177     mMinLevelDistSqr = new Real[ mNumMipMaps ];
00178 
00179 
00180     mScale.x = options.scalex;
00181 
00182     mScale.y = options.scaley;
00183 
00184     mScale.z = options.scalez;
00185 
00186 
00187     RGBA* pCol = static_cast<RGBA*>( vbuf->lock(HardwareBuffer::HBL_DISCARD) );
00188     for ( int i = 0; i < mSize*mSize; i++ )
00189     {
00190         *pCol++ = 0xFFFFFFFF;
00191     }
00192     vbuf->unlock();
00193 
00194     int endx = options.startx + options.size;
00195 
00196     int endz = options.startz + options.size;
00197 
00198     Vector3 left, down, here;
00199 
00200     vbuf = bind->getBuffer(POSITION_BINDING);
00201 
00202     Real* pPos = static_cast<Real*>(vbuf->lock(HardwareBuffer::HBL_DISCARD));
00203 
00204     HardwareVertexBufferSharedPtr vtexbuf = bind->getBuffer(TEXCOORD_BINDING);
00205 
00206     Real* pTex = static_cast<Real*>(vtexbuf->lock(HardwareBuffer::HBL_DISCARD));
00207 
00208     for ( int j = options.startz; j < endz; j++ )
00209     {
00210         for ( int i = options.startx; i < endx; i++ )
00211         {
00212             Real height = options._worldheight( i, j ) * options.scaley;
00213 
00214             *pPos++ = ( Real ) i * options.scalex; //x
00215             *pPos++ = height; //y
00216             *pPos++ = ( Real ) j * options.scalez; //z
00217 
00218             *pTex++ = ( Real ) i / ( Real ) options.world_size ;
00219             *pTex++ = ( Real ) ( Real ) j / ( Real ) options.world_size;
00220 
00221             *pTex++ = ( ( Real ) i / ( Real ) mSize ) * options.detail_tile;
00222             *pTex++ = ( ( Real ) ( Real ) j / ( Real ) mSize ) * options.detail_tile;
00223 
00224             if ( height < min )
00225                 min = ( Real ) height;
00226 
00227             if ( height > max )
00228                 max = ( Real ) height;
00229         }
00230     }
00231 
00232     vtexbuf->unlock();
00233     vbuf->unlock();
00234 
00235     mBounds.setExtents( ( Real ) options.startx * options.scalex, min, ( Real ) options.startz * options.scalez,
00236                         ( Real ) ( endx - 1 ) * options.scalex, max, ( Real ) ( endz - 1 ) * options.scalez );
00237 
00238 
00239     mCenter = Vector3( ( options.startx * options.scalex + endx - 1 ) / 2,
00240                        ( min + max ) / 2,
00241                        ( options.startz * options.scalez + endz - 1 ) / 2 );
00242 
00243 
00244     Real C = _calculateCFactor();
00245 
00246     _calculateMinLevelDist2( C );
00247     _calculateNormals();
00248 
00249 }
00250 
00251 void TerrainRenderable::_getNormalAt( float x, float z, Vector3 * result )
00252 {
00253 
00254     Vector3 here, left, down;
00255     here.x = x;
00256     here.y = getHeightAt( x, z );
00257     here.z = z;
00258 
00259     left.x = x - 1;
00260     left.y = getHeightAt( x - 1, z );
00261     left.z = z;
00262 
00263     down.x = x;
00264     down.y = getHeightAt( x, z + 1 );
00265     down.z = z + 1;
00266 
00267     left = left - here;
00268 
00269     down = down - here;
00270 
00271     left.normalise();
00272     down.normalise();
00273 
00274     *result = left.crossProduct( down );
00275     result -> normalise();
00276 
00277     // result->x = - result->x;
00278     // result->y = - result->y;
00279     // result->z = - result->z;
00280 }
00281 
00282 void TerrainRenderable::_calculateNormals()
00283 {
00284     Vector3 norm;
00285 
00286     HardwareVertexBufferSharedPtr vbuf = 
00287         mTerrain->vertexBufferBinding->getBuffer(NORMAL_BINDING);
00288     Real* pNorm = static_cast<Real*>( vbuf->lock(HardwareBuffer::HBL_DISCARD) );
00289 
00290     for ( int j = 0; j < mSize; j++ )
00291     {
00292         for ( int i = 0; i < mSize; i++ )
00293         {
00294 
00295             _getNormalAt( _vertex( i, j, 0 ), _vertex( i, j, 2 ), &norm );
00296 
00297             //  printf( "Normal = %5f,%5f,%5f\n", norm.x, norm.y, norm.z );
00298 
00299             *pNorm++ = norm.x;
00300             *pNorm++ = norm.y;
00301             *pNorm++ = norm.z;
00302         }
00303 
00304     }
00305     vbuf->unlock();
00306 }
00307 
00308 void TerrainRenderable::_notifyCurrentCamera( Camera* cam )
00309 {
00310 
00311     if ( mForcedRenderLevel >= 0 )
00312     {
00313         mRenderLevel = mForcedRenderLevel;
00314         return ;
00315     }
00316 
00317 
00318     int old_level = mRenderLevel;
00319 
00320     Vector3 cpos = cam -> getPosition();
00321     Vector3 diff = mCenter - cpos;
00322 
00323     Real L = diff.squaredLength();
00324 
00325     current_L = L;
00326 
00327 
00328     mRenderLevel = -1;
00329 
00330     for ( int i = 0; i < mNumMipMaps; i++ )
00331     {
00332         if ( mMinLevelDistSqr[ i ] > L )
00333         {
00334             mRenderLevel = i - 1;
00335             break;
00336         }
00337     }
00338 
00339     if ( mRenderLevel < 0 )
00340         mRenderLevel = mNumMipMaps - 1;
00341 
00342 
00343     // mRenderLevel = 4;
00344 
00345 }
00346 
00347 void TerrainRenderable::_updateRenderQueue( RenderQueue* queue )
00348 {
00349     queue->addRenderable( this );
00350 }
00351 
00352 void TerrainRenderable::getRenderOperation( RenderOperation& op )
00353 {
00354     //setup indexes for vertices and uvs...
00355 
00356     if ( !mInit )
00357     {
00358         printf( "Uninitialized\n" );
00359         return ;
00360     }
00361 
00362     /*
00363     int j=0;
00364     for( j=0; j<mSize; j+= (mRenderLevel*2) ) //depth
00365     {
00366     int i=0;
00367     if( j != 0 )
00368     {
00369     //two degenerate tris to turn the corner...
00370     pIndexes[nupIndexes] = _index(i, j+mRenderLevel ); nupIndexes++;
00371     pIndexes[numIndexes] = _index(i, j+mRenderLevel ); numIndexes++;
00372 }
00373 
00374     //forward strip...
00375     for( i=0; i<mSize; i+= mRenderLevel ) //accross
00376     {
00377     pIndexes[numIndexes] = _index(i, j ); numIndexes++;
00378     pIndexes[numIndexes] = _index(i, j+mRenderLevel ); numIndexes++;
00379 }
00380     i -= mRenderLevel; //backtrack...
00381 
00382 
00383     //degenerate tris to turn the corner...
00384 
00385     pIndexes[numIndexes] = _index(i, j+mRenderLevel ); numIndexes++;
00386     pIndexes[numIndexes] = _index(i, j+mRenderLevel ); numIndexes++;
00387 
00388     //back strip
00389     for( i = mSize-mRenderLevel; i>=0; i-=mRenderLevel )
00390     {
00391     pIndexes[numIndexes] = _index(i, j+mRenderLevel ); numIndexes++;
00392     pIndexes[numIndexes] = _index(i, j ); numIndexes++;
00393 }
00394 
00395 }
00396     */
00397 
00398     int east = 0, west = 0, north = 0, south = 0;
00399 
00400     int step = 1 << mRenderLevel;
00401 
00402     int index_array = 0;
00403 
00404     int numIndexes = 0;
00405 
00406     if ( mNeighbors[ EAST ] != 0 && mNeighbors[ EAST ] -> mRenderLevel > mRenderLevel )
00407     {
00408         east = step; index_array |= TILE_EAST;
00409     }
00410 
00411     if ( mNeighbors[ WEST ] != 0 && mNeighbors[ WEST ] -> mRenderLevel > mRenderLevel )
00412     {
00413         west = step; index_array |= TILE_WEST;
00414     }
00415 
00416     if ( mNeighbors[ NORTH ] != 0 && mNeighbors[ NORTH ] -> mRenderLevel > mRenderLevel )
00417     {
00418         north = step; index_array |= TILE_NORTH;
00419     }
00420 
00421     if ( mNeighbors[ SOUTH ] != 0 && mNeighbors[ SOUTH ] -> mRenderLevel > mRenderLevel )
00422     {
00423         south = step; index_array |= TILE_SOUTH;
00424     }
00425 
00426     IndexData* indexData = 0;
00427 
00428     if ( mLevelIndex[ mRenderLevel ][ index_array ] != 0 )
00429     {
00430         indexData = mLevelIndex[ mRenderLevel ][ index_array ];
00431     }
00432     else
00433     {
00434         int new_length = ( mSize / step ) * ( mSize / step ) * 2 * 2 * 2 ;
00435         //this is the maximum for a level.  It wastes a little, but shouldn't be a problem.
00436         
00437         indexData = new IndexData;
00438         indexData->indexBuffer = 
00439             HardwareBufferManager::getSingleton().createIndexBuffer(
00440                 HardwareIndexBuffer::IT_16BIT,
00441                 new_length, HardwareBuffer::HBU_STATIC_WRITE_ONLY);//, false);
00442 
00443         gIndexCache.mCache.push_back( indexData );
00444 
00445         numIndexes = 0;
00446 
00447         unsigned short* pIdx = static_cast<unsigned short*>(
00448             indexData->indexBuffer->lock(0, 
00449               indexData->indexBuffer->getSizeInBytes(), 
00450               HardwareBuffer::HBL_DISCARD));
00451 
00452         for ( int j = north; j < mSize - 1 - south; j += step )
00453         {
00454             for ( int i = west; i < mSize - 1 - east; i += step )
00455             {
00456                 //triangles
00457                 *pIdx++ = _index( i, j ); numIndexes++;
00458                 *pIdx++ = _index( i, j + step ); numIndexes++;
00459                 *pIdx++ = _index( i + step, j ); numIndexes++;
00460 
00461                 *pIdx++ = _index( i, j + step ); numIndexes++;
00462                 *pIdx++ = _index( i + step, j + step ); numIndexes++;
00463                 *pIdx++ = _index( i + step, j ); numIndexes++;
00464             }
00465         }
00466 
00467         int substep = step << 1;
00468 
00469         if ( west > 0 )
00470         {
00471 
00472             for ( int j = 0; j < mSize - 1; j += substep )
00473             {
00474                 //skip the first bit of the corner if the north side is a different level as well.
00475                 if ( j > 0 || north == 0 )
00476                 {
00477                     *pIdx++ = _index( 0, j ); numIndexes++;
00478                     *pIdx++ = _index( step, j + step ); numIndexes++;
00479                     *pIdx++ = _index( step, j ); numIndexes++;
00480                 }
00481 
00482                 *pIdx++ = _index( step, j + step ); numIndexes++;
00483                 *pIdx++ = _index( 0, j ); numIndexes++;
00484                 *pIdx++ = _index( 0, j + step + step ); numIndexes++;
00485 
00486                 if ( j < mSize - 1 - substep || south == 0 )
00487                 {
00488                     *pIdx++ = _index( step, j + step ); numIndexes++;
00489                     *pIdx++ = _index( 0, j + step + step ); numIndexes++;
00490                     *pIdx++ = _index( step, j + step + step ); numIndexes++;
00491                 }
00492             }
00493         }
00494 
00495         if ( east > 0 )
00496         {
00497             int x = mSize - 1;
00498 
00499             for ( int j = 0; j < mSize - 1; j += substep )
00500             {
00501                 //skip the first bit of the corner if the north side is a different level as well.
00502                 if ( j > 0 || north == 0 )
00503                 {
00504                     *pIdx++ = _index( x, j ); numIndexes++;
00505                     *pIdx++ = _index( x - step, j ); numIndexes++;
00506                     *pIdx++ = _index( x - step, j + step ); numIndexes++;
00507                 }
00508 
00509                 *pIdx++ = _index( x, j ); numIndexes++;
00510                 *pIdx++ = _index( x - step, j + step ); numIndexes++;
00511                 *pIdx++ = _index( x, j + step + step ); numIndexes++;
00512 
00513                 if ( j < mSize - 1 - substep || south == 0 )
00514                 {
00515                     *pIdx++ = _index( x, j + step + step ); numIndexes++;
00516                     *pIdx++ = _index( x - step, j + step ); numIndexes++;
00517                     *pIdx++ = _index( x - step, j + step + step ); numIndexes++;
00518                 }
00519             }
00520         }
00521 
00522         if ( south > 0 )
00523         {
00524             int x = mSize - 1;
00525 
00526             for ( int j = 0; j < mSize - 1; j += substep )
00527             {
00528                 //skip the first bit of the corner if the north side is a different level as well.
00529                 if ( j > 0 || west == 0 )
00530                 {
00531                     *pIdx++ = _index( j, x - step ); numIndexes++;
00532                     *pIdx++ = _index( j, x ); numIndexes++;
00533                     *pIdx++ = _index( j + step, x - step ); numIndexes++;
00534                 }
00535 
00536                 *pIdx++ = _index( j + step, x - step ); numIndexes++;
00537                 *pIdx++ = _index( j, x ); numIndexes++;
00538                 *pIdx++ = _index( j + step + step, x ); numIndexes++;
00539 
00540                 if ( j < mSize - 1 - substep || east == 0 )
00541                 {
00542                     *pIdx++ = _index( j + step, x - step ); numIndexes++;
00543                     *pIdx++ = _index( j + step + step, x ); numIndexes++;
00544                     *pIdx++ = _index( j + step + step, x - step ); numIndexes++;
00545                 }
00546             }
00547 
00548         }
00549 
00550         if ( north > 0 )
00551         {
00552             for ( int j = 0; j < mSize - 1; j += substep )
00553             {
00554                 //skip the first bit of the corner if the north side is a different level as well.
00555                 if ( j > 0 || west == 0 )
00556                 {
00557                     *pIdx++ = _index( j, 0 ); numIndexes++;
00558                     *pIdx++ = _index( j, step ); numIndexes++;
00559                     *pIdx++ = _index( j + step, step ); numIndexes++;
00560                 }
00561 
00562                 *pIdx++ = _index( j, 0 ); numIndexes++;
00563                 *pIdx++ = _index( j + step, step ); numIndexes++;
00564                 *pIdx++ = _index( j + step + step, 0 ); numIndexes++;
00565 
00566                 if ( j < mSize - 1 - substep || east == 0 )
00567                 {
00568                     *pIdx++ = _index( j + step + step, 0 ); numIndexes++;
00569                     *pIdx++ = _index( j + step, step ); numIndexes++;
00570                     *pIdx++ = _index( j + step + step, step ); numIndexes++;
00571                 }
00572             }
00573 
00574         }
00575 
00576         indexData->indexBuffer->unlock();
00577         indexData->indexCount = numIndexes;
00578         indexData->indexStart = 0;
00579 
00580         mLevelIndex[ mRenderLevel ][ index_array ] = indexData;
00581     }
00582 
00583     op.useIndexes = true;
00584     op.operationType = RenderOperation::OT_TRIANGLE_LIST;
00585     op.vertexData = mTerrain;
00586     op.indexData = indexData;
00587 
00588     mRenderedTris += ( indexData->indexCount / 3 );
00589 
00590 
00591     mRenderLevelChanged = false;
00592 
00593 }
00594 
00595 void TerrainRenderable::getWorldTransforms( Matrix4* xform ) const
00596 {
00597     *xform = mParentNode->_getFullTransform();
00598 }
00599 
00600 const Quaternion& TerrainRenderable::getWorldOrientation(void) const
00601 {
00602     return mParentNode->_getDerivedOrientation();
00603 }
00604 const Vector3& TerrainRenderable::getWorldPosition(void) const
00605 {
00606     return mParentNode->_getDerivedPosition();
00607 }
00608 
00609 bool TerrainRenderable::_checkSize( int n )
00610 {
00611     for ( int i = 0; i < 10; i++ )
00612     {
00613         if ( ( ( 1 << i ) + 1 ) == n )
00614             return true;
00615     }
00616 
00617     return false;
00618 }
00619 
00620 
00621 void TerrainRenderable::_calculateMinLevelDist2( Real C )
00622 {
00623     //level 0 has no delta.
00624     mMinLevelDistSqr[ 0 ] = 0;
00625 
00626     for ( int level = 1; level < mNumMipMaps; level++ )
00627     {
00628         mMinLevelDistSqr[ level ] = 0;
00629 
00630         int step = 1 << level;
00631 
00632         for ( int j = 0; j < mSize - step; j += step )
00633         {
00634             for ( int i = 0; i < mSize - step; i += step )
00635             {
00636                 //check each height inbetween the steps.
00637                 Real h1 = _vertex( i, j, 1 );
00638                 Real h2 = _vertex( i + step, j, 1 );
00639                 Real h3 = _vertex( i + step, j + step, 1 );
00640                 Real h4 = _vertex( i, j + step, 1 );
00641 
00642                 for ( int z = 1; z < step; z++ )
00643                 {
00644                     for ( int x = 1; x < step; x++ )
00645                     {
00646 
00647                         Real zpct = z / step;
00648                         Real xpct = x / step;
00649 
00650                         //interpolated height
00651                         float top = h3 * ( 1.0f - xpct ) + xpct * h4;
00652                         float bottom = h1 * ( 1.0f - xpct ) + xpct * h2;
00653 
00654                         Real interp_h = top * ( 1.0f - zpct ) + zpct * bottom;
00655 
00656                         Real actual_h = _vertex( i + x, j + z, 1 );
00657                         Real delta = fabs( interp_h - actual_h );
00658 
00659                         Real D2 = delta * delta * C * C;
00660 
00661                         if ( mMinLevelDistSqr[ level ] < D2 )
00662                             mMinLevelDistSqr[ level ] = D2;
00663                     }
00664 
00665                 }
00666             }
00667         }
00668 
00669     }
00670 
00671     //make sure the levels are increasing...
00672     for ( int i = 1; i < mNumMipMaps; i++ )
00673     {
00674         if ( mMinLevelDistSqr[ i ] < mMinLevelDistSqr[ i - 1 ] )
00675             mMinLevelDistSqr[ i ] = mMinLevelDistSqr[ i - 1 ] + 1;
00676     }
00677 
00678 }
00679 
00680 void TerrainRenderable::_initLevelIndexes()
00681 {
00682     if ( mLevelInit )
00683         return ;
00684 
00685 
00686     if ( mLevelIndex.size() == 0 )
00687     {
00688         for ( int i = 0; i < 16; i++ )
00689         {
00690 
00691             mLevelIndex.push_back( IndexArray() );
00692 
00693             for ( int j = 0; j < 16; j++ )
00694             {
00695                 mLevelIndex[ i ].push_back( 0 );
00696             }
00697 
00698         }
00699 
00700 
00701     }
00702 
00703     mLevelInit = true;
00704 }
00705 
00706 void TerrainRenderable::_adjustRenderLevel( int i )
00707 {
00708 
00709     mRenderLevel = i;
00710     _alignNeighbors();
00711 
00712 }
00713 
00714 void TerrainRenderable::_alignNeighbors()
00715 {
00716 
00717     //ensure that there aren't any gaps...
00718 
00719     for ( int i = 0; i < 4;i++ )
00720     {
00721         if ( mNeighbors[ i ] != 0 && mNeighbors[ i ] ->mRenderLevel + 1 < mRenderLevel )
00722             mNeighbors[ i ] -> _adjustRenderLevel( mRenderLevel - 1 );
00723     }
00724 
00725     /*
00726 
00727     //always go up, rather than down...
00728           if ( mNeighbors[ EAST  ] != 0 && mNeighbors[ EAST ] ->mRenderLevel + 1 < mRenderLevel )
00729                  mNeighbors[ EAST ] -> _adjustRenderLevel(  mRenderLevel - 1 );
00730 
00731             if ( mNeighbors[ SOUTH  ] != 0 && mNeighbors[ SOUTH ] ->mRenderLevel + 1 < mRenderLevel )
00732                 mNeighbors[ SOUTH ] -> _adjustRenderLevel(  mRenderLevel - 1 );
00733     */
00734 }
00735 
00736 Real TerrainRenderable::_calculateCFactor()
00737 {
00738     Real A, T;
00739 
00740     A = ( Real ) mNearPlane / fabs( ( Real ) mTopCoord );
00741 
00742     T = 2 * ( Real ) mMaxPixelError / ( Real ) mVertResolution;
00743 
00744     return A / T;
00745 }
00746 
00747 float TerrainRenderable::getHeightAt( float x, float z )
00748 {
00749     Vector3 start;
00750     Vector3 end;
00751 
00752     start.x = _vertex( 0, 0, 0 );
00753     start.y = _vertex( 0, 0, 1 );
00754     start.z = _vertex( 0, 0, 2 );
00755 
00756     end.x = _vertex( mSize - 2, mSize - 2, 0 );
00757     end.y = _vertex( mSize - 2, mSize - 2, 1 );
00758     end.z = _vertex( mSize - 2, mSize - 2, 2 );
00759 
00760     /* Safety catch, if the point asked for is outside
00761      * of this tile, it will ask the appropriate tile
00762      */
00763 
00764     if ( x < start.x )
00765     {
00766         if ( mNeighbors[ WEST ] != 0 )
00767             return mNeighbors[ WEST ] ->getHeightAt( x, z );
00768         else
00769             x = start.x;
00770     }
00771 
00772     if ( x > end.x )
00773     {
00774         if ( mNeighbors[ EAST ] != 0 )
00775             return mNeighbors[ EAST ] ->getHeightAt( x, z );
00776         else
00777             x = end.x;
00778     }
00779 
00780     if ( z < start.z )
00781     {
00782         if ( mNeighbors[ NORTH ] != 0 )
00783             return mNeighbors[ NORTH ] ->getHeightAt( x, z );
00784         else
00785             z = start.z;
00786     }
00787 
00788     if ( z > end.z )
00789     {
00790         if ( mNeighbors[ SOUTH ] != 0 )
00791             return mNeighbors[ SOUTH ] ->getHeightAt( x, z );
00792         else
00793             z = end.z;
00794     }
00795 
00796 
00797 
00798     float x_pct = ( x - start.x ) / ( end.x - start.x );
00799     float z_pct = ( z - start.z ) / ( end.z - start.z );
00800 
00801     float x_pt = x_pct * ( float ) ( mSize - 2 );
00802     float z_pt = z_pct * ( float ) ( mSize - 2 );
00803 
00804     int x_index = ( int ) x_pt;
00805     int z_index = ( int ) z_pt;
00806 
00807     x_pct = x_pt - x_index;
00808     z_pct = z_pt - z_index;
00809 
00810     //bilinear interpolate to find the height.
00811 
00812     float t1 = _vertex( x_index, z_index, 1 );
00813     float t2 = _vertex( x_index + 1, z_index, 1 );
00814     float b1 = _vertex( x_index, z_index + 1, 1 );
00815     float b2 = _vertex( x_index + 1, z_index + 1, 1 );
00816 
00817     float midpoint = (b1 + t2) / 2.0;
00818 
00819     if (x_pct + z_pct <= 1) {
00820         b2 = midpoint + (midpoint - t1);
00821     } else {
00822         t1 = midpoint + (midpoint - b2);
00823     }
00824 
00825     float t = ( t1 * ( 1 - x_pct ) ) + ( t2 * ( x_pct ) );
00826     float b = ( b1 * ( 1 - x_pct ) ) + ( b2 * ( x_pct ) );
00827 
00828     float h = ( t * ( 1 - z_pct ) ) + ( b * ( z_pct ) );
00829 
00830     return h;
00831 }
00832 
00833 bool TerrainRenderable::intersectSegment( const Vector3 & start, const Vector3 & end, Vector3 * result )
00834 {
00835     Vector3 dir = end - start;
00836     Vector3 ray = start;
00837 
00838     //special case...
00839     if ( dir.x == 0 && dir.z == 0 )
00840     {
00841         if ( ray.y <= getHeightAt( ray.x, ray.z ) )
00842         {
00843             if ( result != 0 )
00844                 * result = start;
00845 
00846             return true;
00847         }
00848     }
00849 
00850     dir.normalise();
00851 
00852     //dir.x *= mScale.x;
00853     //dir.y *= mScale.y;
00854     //dir.z *= mScale.z;
00855 
00856     const Vector3 * corners = getBoundingBox().getAllCorners();
00857 
00858     //start with the next one...
00859     ray += dir;
00860 
00861 
00862     while ( ! ( ( ray.x < corners[ 0 ].x ) ||
00863                 ( ray.x > corners[ 4 ].x ) ||
00864                 ( ray.z < corners[ 0 ].z ) ||
00865                 ( ray.z > corners[ 4 ].z ) ) )
00866     {
00867 
00868 
00869         float h = getHeightAt( ray.x, ray.z );
00870 
00871         if ( ray.y <= h )
00872         {
00873             if ( result != 0 )
00874                 * result = ray;
00875 
00876             return true;
00877         }
00878 
00879         else
00880         {
00881             ray += dir;
00882         }
00883 
00884     }
00885 
00886     if ( ray.x < corners[ 0 ].x && mNeighbors[ WEST ] != 0 )
00887         return mNeighbors[ WEST ] ->intersectSegment( ray, end, result );
00888     else if ( ray.z < corners[ 0 ].z && mNeighbors[ NORTH ] != 0 )
00889         return mNeighbors[ NORTH ] ->intersectSegment( ray, end, result );
00890     else if ( ray.x > corners[ 4 ].x && mNeighbors[ EAST ] != 0 )
00891         return mNeighbors[ EAST ] ->intersectSegment( ray, end, result );
00892     else if ( ray.z > corners[ 4 ].z && mNeighbors[ SOUTH ] != 0 )
00893         return mNeighbors[ SOUTH ] ->intersectSegment( ray, end, result );
00894     else
00895     {
00896         if ( result != 0 )
00897             * result = Vector3( -1, -1, -1 );
00898 
00899         return false;
00900     }
00901 }
00902 
00903 void TerrainRenderable::_generateVertexLighting( const Vector3 &sun, ColourValue ambient )
00904 {
00905     if ( !mColored )
00906     {
00907         printf( "Can't generate terrain vertex lighting with out vertex colors enabled.\n" );
00908         return ;
00909     }
00910 
00911 
00912     Vector3 pt;
00913     Vector3 normal;
00914     Vector3 light;
00915 
00916     //for each point in the terrain, see if it's in the line of sight for the sun.
00917     for ( int i = 0; i < mSize; i++ )
00918     {
00919         for ( int j = 0; j < mSize; j++ )
00920         {
00921             //  printf( "Checking %f,%f,%f ", pt.x, pt.y, pt.z );
00922             pt.x = _vertex( i, j, 0 );
00923             pt.y = _vertex( i, j, 1 );
00924             pt.z = _vertex( i, j, 2 );
00925 
00926             light = sun - pt;
00927 
00928             light.normalise();
00929 
00930             if ( ! intersectSegment( pt, sun, 0 ) )
00931             {
00932                 //
00933                 _getNormalAt( _vertex( i, j, 0 ), _vertex( i, j, 2 ), &normal );
00934 
00935                 float l = light.dotProduct( normal );
00936 
00937                 ColourValue v;
00938                 v.r = ambient.r + l;
00939                 v.g = ambient.g + l;
00940                 v.b = ambient.b + l;
00941 
00942                 if ( v.r > 1 ) v.r = 1;
00943 
00944                 if ( v.g > 1 ) v.g = 1;
00945 
00946                 if ( v.b > 1 ) v.b = 1;
00947 
00948                 if ( v.r < 0 ) v.r = 0;
00949 
00950                 if ( v.g < 0 ) v.g = 0;
00951 
00952                 if ( v.b < 0 ) v.b = 0;
00953 
00954                 RGBA colour;
00955                 Root::getSingleton().convertColourValue( v, &colour );
00956                 HardwareVertexBufferSharedPtr vbuf = 
00957                     mTerrain->vertexBufferBinding->getBuffer(COLOUR_BINDING);
00958                 vbuf->writeData(_index( i, j ) * sizeof(RGBA), sizeof(RGBA), &colour);
00959             }
00960 
00961             else
00962             {
00963                 RGBA colour;
00964                 Root::getSingleton().convertColourValue( ambient, &colour );
00965 
00966                 HardwareVertexBufferSharedPtr vbuf = 
00967                     mTerrain->vertexBufferBinding->getBuffer(COLOUR_BINDING);
00968                 vbuf->writeData(_index( i, j ) * sizeof(RGBA), sizeof(RGBA), &colour);
00969             }
00970 
00971         }
00972 
00973     }
00974 
00975     printf( "." );
00976 }
00977 //-----------------------------------------------------------------------
00978 Real TerrainRenderable::getSquaredViewDepth(const Camera* cam) const
00979 {
00980     Vector3 diff = mCenter - cam->getDerivedPosition();
00981     // Use squared length to avoid square root
00982     return diff.squaredLength();
00983 }
00984 
00985 //-----------------------------------------------------------------------
00986 const LightList& TerrainRenderable::getLights(void) const
00987 {
00988     return mParentNode->getLights();
00989 }
00990 
00991 } //namespace

Copyright © 2002-2003 by The OGRE Team
Last modified Fri May 14 23:22:51 2004