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 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004 (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://www.ogre3d.org/
00006 
00007 Copyright © 2000-2004 The OGRE Team
00008 Also see acknowledgements in Readme.html
00009 
00010 This program is free software; you can redistribute it and/or modify it under
00011 the terms of the GNU Lesser General Public License as published by the Free Software
00012 Foundation; either version 2 of the License, or (at your option) any later
00013 version.
00014 
00015 This program is distributed in the hope that it will be useful, but WITHOUT
00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00018 
00019 You should have received a copy of the GNU Lesser General Public License along with
00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00022 http://www.gnu.org/copyleft/lesser.txt.
00023 -----------------------------------------------------------------------------
00024 */
00025 /***************************************************************************
00026 terrainrenderable.cpp  -  description
00027 -------------------
00028 begin                : Sat Oct 5 2002
00029 copyright            : (C) 2002 by Jon Anderson
00030 email                : janders@users.sf.net
00031 
00032 Enhancements 2003 - 2004 (C) The OGRE Team
00033 
00034 ***************************************************************************/
00035 
00036 #include "OgreTerrainRenderable.h"
00037 #include "OgreSceneNode.h"
00038 #include "OgreRenderQueue.h"
00039 #include "OgreRenderOperation.h"
00040 #include "OgreCamera.h"
00041 #include "OgreRoot.h"
00042 #include "OgreTerrainSceneManager.h"
00043 #include "OgreLogManager.h"
00044 #include "OgreStringConverter.h"
00045 #include "OgreViewport.h"
00046 #include "OgreException.h"
00047 
00048 namespace Ogre
00049 {
00050     //-----------------------------------------------------------------------
00051     #define MAIN_BINDING 0
00052     #define DELTA_BINDING 1
00053     //-----------------------------------------------------------------------
00054     //-----------------------------------------------------------------------
00055     TerrainBufferCache TerrainRenderable::msIndexCache;
00056     String TerrainRenderable::mType = "TerrainMipMap";
00057     LevelArray TerrainRenderable::mLevelIndex;
00058     bool TerrainRenderable::mLevelInit = false;
00059     const TerrainOptions* TerrainRenderable::msOptions = 0;
00060     //-----------------------------------------------------------------------
00061     //-----------------------------------------------------------------------
00062 
00063     //-----------------------------------------------------------------------
00064     TerrainRenderable::TerrainRenderable(const String& name)
00065         : mTerrain(0), mName(name),  mDeltaBuffers(0), mPositionBuffer(0)
00066     {
00067         mForcedRenderLevel = -1;
00068         mLastNextLevel = -1;
00069         // Default query flags to top bit so users can exclude it if they wish
00070         mQueryFlags = 0x80000000;
00071 
00072         mMinLevelDistSqr = 0;
00073 
00074         mInit = false;
00075 
00076         for ( int i = 0; i < 4; i++ )
00077         {
00078             mNeighbors[ i ] = 0;
00079         }
00080 
00081         _initLevelIndexes();
00082 
00083     }
00084     //-----------------------------------------------------------------------
00085     TerrainRenderable::~TerrainRenderable()
00086     {
00087 
00088         deleteGeometry();
00089         _destroyLevelIndexes();
00090     }
00091     //-----------------------------------------------------------------------
00092     void TerrainRenderable::deleteGeometry()
00093     {
00094         if(mTerrain)
00095             delete mTerrain;
00096 
00097         if (mPositionBuffer)
00098             delete [] mPositionBuffer;
00099 
00100         if (mDeltaBuffers)
00101             delete [] mDeltaBuffers;
00102 
00103         if ( mMinLevelDistSqr != 0 )
00104             delete [] mMinLevelDistSqr;
00105     }
00106     //-----------------------------------------------------------------------
00107     void TerrainRenderable::initialise(int startx, int startz,  
00108         Real* pageHeightData)
00109     {
00110         if (!msOptions)
00111             msOptions = &(TerrainSceneManager::getOptions());
00112 
00113         if ( msOptions->maxGeoMipMapLevel != 0 )
00114         {
00115             int i = ( int ) 1 << ( msOptions->maxGeoMipMapLevel - 1 ) ;
00116 
00117             if ( ( i + 1 ) > msOptions->tileSize )
00118             {
00119                 printf( "Invalid maximum mipmap specifed, must be n, such that 2^(n-1)+1 < tileSize \n" );
00120                 return ;
00121             }
00122         }
00123 
00124         deleteGeometry();
00125 
00126         //calculate min and max heights;
00127         Real min = 256000, max = 0;
00128 
00129         mTerrain = new VertexData;
00130         mTerrain->vertexStart = 0;
00131         mTerrain->vertexCount = msOptions->tileSize * msOptions->tileSize;
00132 
00133         VertexDeclaration* decl = mTerrain->vertexDeclaration;
00134         VertexBufferBinding* bind = mTerrain->vertexBufferBinding;
00135 
00136         // positions
00137         size_t offset = 0;
00138         decl->addElement(MAIN_BINDING, offset, VET_FLOAT3, VES_POSITION);
00139         offset += VertexElement::getTypeSize(VET_FLOAT3);
00140         if (TerrainSceneManager::getOptions().lit)
00141         {
00142             decl->addElement(MAIN_BINDING, offset, VET_FLOAT3, VES_NORMAL);
00143             offset += VertexElement::getTypeSize(VET_FLOAT3);
00144         }
00145         // texture coord sets
00146         decl->addElement(MAIN_BINDING, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
00147         offset += VertexElement::getTypeSize(VET_FLOAT2);
00148         decl->addElement(MAIN_BINDING, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 1);
00149         offset += VertexElement::getTypeSize(VET_FLOAT2);
00150         if (TerrainSceneManager::getOptions().coloured)
00151         {
00152             decl->addElement(MAIN_BINDING, offset, VET_COLOUR, VES_DIFFUSE);
00153             offset += VertexElement::getTypeSize(VET_COLOUR);
00154         }
00155 
00156         // Create shared vertex buffer
00157         mMainBuffer =
00158             HardwareBufferManager::getSingleton().createVertexBuffer(
00159             decl->getVertexSize(MAIN_BINDING),
00160             mTerrain->vertexCount, 
00161             HardwareBuffer::HBU_STATIC_WRITE_ONLY);
00162         // Create system memory copy with just positions in it, for use in simple reads
00163         mPositionBuffer = new Real[mTerrain->vertexCount * 3];
00164 
00165         bind->setBinding(MAIN_BINDING, mMainBuffer);
00166 
00167         if (msOptions->lodMorph)
00168         {
00169             // Create additional element for delta
00170             decl->addElement(DELTA_BINDING, 0, VET_FLOAT1, VES_BLEND_WEIGHTS);
00171             // NB binding is not set here, it is set when deriving the LOD
00172         }
00173 
00174 
00175         mInit = true;
00176 
00177         mRenderLevel = 1;
00178 
00179         mMinLevelDistSqr = new Real[ msOptions->maxGeoMipMapLevel ];
00180 
00181         int endx = startx + msOptions->tileSize;
00182 
00183         int endz = startz + msOptions->tileSize;
00184 
00185         Vector3 left, down, here;
00186 
00187         const VertexElement* poselem = decl->findElementBySemantic(VES_POSITION);
00188         const VertexElement* texelem0 = decl->findElementBySemantic(VES_TEXTURE_COORDINATES, 0);
00189         const VertexElement* texelem1 = decl->findElementBySemantic(VES_TEXTURE_COORDINATES, 1);
00190         Real* pSysPos = mPositionBuffer;
00191 
00192         unsigned char* pBase = static_cast<unsigned char*>(mMainBuffer->lock(HardwareBuffer::HBL_DISCARD));
00193 
00194         for ( int j = startz; j < endz; j++ )
00195         {
00196             for ( int i = startx; i < endx; i++ )
00197             {
00198                 Real *pPos, *pTex0, *pTex1;
00199                 poselem->baseVertexPointerToElement(pBase, &pPos);
00200                 texelem0->baseVertexPointerToElement(pBase, &pTex0);
00201                 texelem1->baseVertexPointerToElement(pBase, &pTex1);
00202     
00203                 Real height = pageHeightData[j * msOptions->pageSize + i];
00204                 height = height * msOptions->scale.y; // scale height 
00205 
00206                 *pSysPos++ = *pPos++ = ( Real ) i * msOptions->scale.x; //x
00207                 *pSysPos++ = *pPos++ = height; // y
00208                 *pSysPos++ = *pPos++ = ( Real ) j * msOptions->scale.z; //z
00209 
00210                 *pTex0++ = ( Real ) i / ( Real ) msOptions->pageSize;
00211                 *pTex0++ = ( Real ) ( Real ) j / ( Real ) msOptions->pageSize;
00212 
00213                 *pTex1++ = ( ( Real ) i / ( Real ) msOptions->tileSize ) * msOptions->detailTile;
00214                 *pTex1++ = ( ( Real ) ( Real ) j / ( Real ) msOptions->tileSize ) * msOptions->detailTile;
00215 
00216                 if ( height < min )
00217                     min = ( Real ) height;
00218 
00219                 if ( height > max )
00220                     max = ( Real ) height;
00221 
00222                 pBase += mMainBuffer->getVertexSize();
00223             }
00224         }
00225 
00226         mMainBuffer->unlock();
00227 
00228         mBounds.setExtents( 
00229             ( Real ) startx * msOptions->scale.x, 
00230             min, 
00231             ( Real ) startz * msOptions->scale.z,
00232             ( Real ) ( endx - 1 ) * msOptions->scale.x, 
00233             max, 
00234             ( Real ) ( endz - 1 ) * msOptions->scale.z );
00235 
00236 
00237         mCenter = Vector3( ( startx * msOptions->scale.x + (endx - 1) * msOptions->scale.x ) / 2,
00238             ( min + max ) / 2,
00239             ( startz * msOptions->scale.z + (endz - 1) * msOptions->scale.z ) / 2 );
00240 
00241         // Create delta buffer list if required to morph
00242         if (msOptions->lodMorph)
00243         {
00244             // Create delta buffer for all except the lowest mip
00245             mDeltaBuffers = new HardwareVertexBufferSharedPtr[msOptions->maxGeoMipMapLevel - 1];
00246         }
00247 
00248         Real C = _calculateCFactor();
00249 
00250         _calculateMinLevelDist2( C );
00251         if (msOptions->lit)
00252             _calculateNormals();
00253 
00254     }
00255     //-----------------------------------------------------------------------
00256     void TerrainRenderable::_getNormalAt( float x, float z, Vector3 * result )
00257     {
00258 
00259         assert(msOptions->lit && "No normals present");
00260 
00261         Vector3 here, left, down;
00262         here.x = x;
00263         here.y = getHeightAt( x, z );
00264         here.z = z;
00265 
00266         left.x = x - 1;
00267         left.y = getHeightAt( x - 1, z );
00268         left.z = z;
00269 
00270         down.x = x;
00271         down.y = getHeightAt( x, z + 1 );
00272         down.z = z + 1;
00273 
00274         left = left - here;
00275 
00276         down = down - here;
00277 
00278         left.normalise();
00279         down.normalise();
00280 
00281         *result = left.crossProduct( down );
00282         result -> normalise();
00283 
00284         // result->x = - result->x;
00285         // result->y = - result->y;
00286         // result->z = - result->z;
00287     }
00288     //-----------------------------------------------------------------------
00289     void TerrainRenderable::_calculateNormals()
00290     {
00291         Vector3 norm;
00292 
00293         assert (msOptions->lit && "No normals present");
00294 
00295         HardwareVertexBufferSharedPtr vbuf = 
00296             mTerrain->vertexBufferBinding->getBuffer(MAIN_BINDING);
00297         const VertexElement* elem = mTerrain->vertexDeclaration->findElementBySemantic(VES_NORMAL);
00298         unsigned char* pBase = static_cast<unsigned char*>( vbuf->lock(HardwareBuffer::HBL_DISCARD) );
00299         Real* pNorm;
00300 
00301         for ( size_t j = 0; j < msOptions->tileSize; j++ )
00302         {
00303             for ( size_t i = 0; i < msOptions->tileSize; i++ )
00304             {
00305 
00306                 _getNormalAt( _vertex( i, j, 0 ), _vertex( i, j, 2 ), &norm );
00307 
00308                 //  printf( "Normal = %5f,%5f,%5f\n", norm.x, norm.y, norm.z );
00309                 elem->baseVertexPointerToElement(pBase, &pNorm);
00310                 *pNorm++ = norm.x;
00311                 *pNorm++ = norm.y;
00312                 *pNorm++ = norm.z;
00313                 pBase += vbuf->getVertexSize();
00314             }
00315 
00316         }
00317         vbuf->unlock();
00318     }
00319     //-----------------------------------------------------------------------
00320     void TerrainRenderable::_notifyCurrentCamera( Camera* cam )
00321     {
00322 
00323         if ( mForcedRenderLevel >= 0 )
00324         {
00325             mRenderLevel = mForcedRenderLevel;
00326             return ;
00327         }
00328 
00329 
00330         Vector3 cpos = cam -> getDerivedPosition();
00331         Vector3 diff = mCenter - cpos;
00332 
00333         Real L = diff.squaredLength();
00334 
00335         mRenderLevel = -1;
00336 
00337         for ( int i = 0; i < msOptions->maxGeoMipMapLevel; i++ )
00338         {
00339             if ( mMinLevelDistSqr[ i ] > L )
00340             {
00341                 mRenderLevel = i - 1;
00342                 break;
00343             }
00344         }
00345 
00346         if ( mRenderLevel < 0 )
00347             mRenderLevel = msOptions->maxGeoMipMapLevel - 1;
00348 
00349         if (msOptions->lodMorph)
00350         {
00351             // Get the next LOD level down
00352             int nextLevel = mNextLevelDown[mRenderLevel];
00353             if (nextLevel == 0)
00354             {
00355                 // No next level, so never morph
00356                 mLODMorphFactor = 0;
00357             }
00358             else
00359             {
00360                 // Set the morph such that the morph happens in the last 0.25 of
00361                 // the distance range
00362                 Real range = mMinLevelDistSqr[nextLevel] - mMinLevelDistSqr[mRenderLevel];
00363                 if (range)
00364                 {
00365                     Real percent = (L - mMinLevelDistSqr[mRenderLevel]) / range;
00366                     // scale result so that msLODMorphStart == 0, 1 == 1, clamp to 0 below that
00367                     Real rescale = 1.0f / (1.0f - msOptions->lodMorphStart);
00368                     mLODMorphFactor = std::max((percent - msOptions->lodMorphStart) * rescale, 0.0f);
00369                 }
00370                 else
00371                 {
00372                     // Identical ranges
00373                     mLODMorphFactor = 0.0f;
00374                 }
00375 
00376                 assert(mLODMorphFactor >= 0 && mLODMorphFactor <= 1);
00377             }
00378 
00379             // Bind the correct delta buffer if it has changed
00380             // nextLevel - 1 since the first entry is for LOD 1 (since LOD 0 never needs it)
00381             if (mLastNextLevel != nextLevel)
00382             {
00383                 if (nextLevel > 0)
00384                 {
00385                     mTerrain->vertexBufferBinding->setBinding(DELTA_BINDING, 
00386                         mDeltaBuffers[nextLevel - 1]);
00387                 }
00388                 else
00389                 {
00390                     // bind dummy (incase bindings checked)
00391                     mTerrain->vertexBufferBinding->setBinding(DELTA_BINDING, 
00392                         mDeltaBuffers[0]);
00393                 }
00394             }
00395             mLastNextLevel = nextLevel;
00396 
00397         }
00398 
00399     }
00400     //-----------------------------------------------------------------------
00401     void TerrainRenderable::_updateRenderQueue( RenderQueue* queue )
00402     {
00403         queue->addRenderable( this );
00404     }
00405     //-----------------------------------------------------------------------
00406     void TerrainRenderable::getRenderOperation( RenderOperation& op )
00407     {
00408         //setup indexes for vertices and uvs...
00409 
00410         assert( mInit && "Uninitialized" );
00411 
00412         op.useIndexes = true;
00413         op.operationType = msOptions->useTriStrips ? 
00414             RenderOperation::OT_TRIANGLE_STRIP : RenderOperation::OT_TRIANGLE_LIST;
00415         op.vertexData = mTerrain;
00416         op.indexData = getIndexData();
00417 
00418 
00419     }
00420     //-----------------------------------------------------------------------
00421     void TerrainRenderable::getWorldTransforms( Matrix4* xform ) const
00422     {
00423         *xform = mParentNode->_getFullTransform();
00424     }
00425     //-----------------------------------------------------------------------
00426     const Quaternion& TerrainRenderable::getWorldOrientation(void) const
00427     {
00428         return mParentNode->_getDerivedOrientation();
00429     }
00430     //-----------------------------------------------------------------------
00431     const Vector3& TerrainRenderable::getWorldPosition(void) const
00432     {
00433         return mParentNode->_getDerivedPosition();
00434     }
00435     //-----------------------------------------------------------------------
00436     bool TerrainRenderable::_checkSize( int n )
00437     {
00438         for ( int i = 0; i < 10; i++ )
00439         {
00440             if ( ( ( 1 << i ) + 1 ) == n )
00441                 return true;
00442         }
00443 
00444         return false;
00445     }
00446     //-----------------------------------------------------------------------
00447     void TerrainRenderable::_calculateMinLevelDist2( Real C )
00448     {
00449         //level 0 has no delta.
00450         mMinLevelDistSqr[ 0 ] = 0;
00451 
00452         int i, j;
00453 
00454         for ( int level = 1; level < msOptions->maxGeoMipMapLevel; level++ )
00455         {
00456             mMinLevelDistSqr[ level ] = 0;
00457 
00458             int step = 1 << level;
00459             // The step of the next higher LOD
00460             int higherstep = step >> 1;
00461 
00462             Real* pDeltas = 0;
00463             if (msOptions->lodMorph)
00464             {
00465                 // Create a set of delta values (store at index - 1 since 0 has none)
00466                 mDeltaBuffers[level - 1]  = createDeltaBuffer();
00467                 // Lock, but don't discard (we want the pre-initialised zeros)
00468                 pDeltas = static_cast<Real*>(
00469                     mDeltaBuffers[level - 1]->lock(HardwareBuffer::HBL_NORMAL));
00470             }
00471 
00472             for ( j = 0; j < msOptions->tileSize - step; j += step )
00473             {
00474                 for ( i = 0; i < msOptions->tileSize - step; i += step )
00475                 {
00476                     /* Form planes relating to the lower detail tris to be produced
00477                     For tri lists and even tri strip rows, they are this shape:
00478                     x---x
00479                     | / |
00480                     x---x
00481                     For odd tri strip rows, they are this shape:
00482                     x---x
00483                     | \ |
00484                     x---x
00485                     */
00486 
00487                     Vector3 v1(_vertex( i, j, 0 ), _vertex( i, j, 1 ), _vertex( i, j, 2 ));
00488                     Vector3 v2(_vertex( i + step, j, 0 ), _vertex( i + step, j, 1 ), _vertex( i + step, j, 2 ));
00489                     Vector3 v3(_vertex( i, j + step, 0 ), _vertex( i, j + step, 1 ), _vertex( i, j + step, 2 ));
00490                     Vector3 v4(_vertex( i + step, j + step, 0 ), _vertex( i + step, j + step, 1 ), _vertex( i + step, j + step, 2 ));
00491 
00492                     Plane t1, t2;
00493                     bool backwardTri = false;
00494                     if (!msOptions->useTriStrips || j % 2 == 0)
00495                     {
00496                         t1.redefine(v1, v3, v2);
00497                         t2.redefine(v2, v3, v4);
00498                     }
00499                     else
00500                     {
00501                         t1.redefine(v1, v3, v4);
00502                         t2.redefine(v1, v4, v2);
00503                         backwardTri = true;
00504                     }
00505 
00506                     // include the bottommost row of vertices if this is the last row
00507                     int zubound = (j == (msOptions->tileSize - step)? step : step - 1);
00508                     for ( int z = 0; z <= zubound; z++ )
00509                     {
00510                         // include the rightmost col of vertices if this is the last col
00511                         int xubound = (i == (msOptions->tileSize - step)? step : step - 1);
00512                         for ( int x = 0; x <= xubound; x++ )
00513                         {
00514                             int fulldetailx = i + x;
00515                             int fulldetailz = j + z;
00516                             if ( fulldetailx % step == 0 && 
00517                                 fulldetailz % step == 0 )
00518                             {
00519                                 // Skip, this one is a vertex at this level
00520                                 continue;
00521                             }
00522 
00523                             Real zpct = (Real)z / (Real)step;
00524                             Real xpct = (Real)x / (Real)step;
00525 
00526                             //interpolated height
00527                             Vector3 actualPos(
00528                                 _vertex( fulldetailx, fulldetailz, 0 ), 
00529                                 _vertex( fulldetailx, fulldetailz, 1 ), 
00530                                 _vertex( fulldetailx, fulldetailz, 2 ));
00531                             Real interp_h;
00532                             // Determine which tri we're on 
00533                             if ((xpct + zpct <= 1.0f && !backwardTri) ||
00534                                 (xpct + (1-zpct) <= 1.0f && backwardTri))
00535                             {
00536                                 // Solve for x/z
00537                                 interp_h = 
00538                                     (-(t1.normal.x * actualPos.x)
00539                                     - t1.normal.z * actualPos.z
00540                                     - t1.d) / t1.normal.y;
00541                             }
00542                             else
00543                             {
00544                                 // Second tri
00545                                 interp_h = 
00546                                     (-(t2.normal.x * actualPos.x)
00547                                     - t2.normal.z * actualPos.z
00548                                     - t2.d) / t2.normal.y;
00549                             }
00550 
00551                             Real actual_h = _vertex( fulldetailx, fulldetailz, 1 );
00552                             Real delta = fabs( interp_h - actual_h );
00553 
00554                             Real D2 = delta * delta * C * C;
00555 
00556                             if ( mMinLevelDistSqr[ level ] < D2 )
00557                                 mMinLevelDistSqr[ level ] = D2;
00558 
00559                             // Should be save height difference?
00560                             // Don't morph along edges
00561                             if (msOptions->lodMorph && 
00562                                 fulldetailx != 0  && fulldetailx != (msOptions->tileSize - 1) && 
00563                                 fulldetailz != 0  && fulldetailz != (msOptions->tileSize - 1) )
00564                             {
00565                                 // Save height difference 
00566                                 pDeltas[fulldetailx + (fulldetailz * msOptions->tileSize)] = 
00567                                     interp_h - actual_h;
00568                             }
00569 
00570                         }
00571 
00572                     }
00573                 }
00574             }
00575 
00576             // Unlock morph deltas if required
00577             if (msOptions->lodMorph)
00578             {
00579                 mDeltaBuffers[level - 1]->unlock();
00580             }
00581         }
00582 
00583 
00584 
00585         // Post validate the whole set
00586         for ( i = 1; i < msOptions->maxGeoMipMapLevel; i++ )
00587         {
00588 
00589             // Make sure no LOD transition within the tile
00590             // This is especially a problem when using large tiles with flat areas
00591             /* Hmm, this can look bad on some areas, disable for now
00592             Vector3 delta(_vertex(0,0,0), mCenter.y, _vertex(0,0,2));
00593             delta = delta - mCenter;
00594             Real minDist = delta.squaredLength();
00595             mMinLevelDistSqr[ i ] = std::max(mMinLevelDistSqr[ i ], minDist);
00596             */
00597 
00598             //make sure the levels are increasing...
00599             if ( mMinLevelDistSqr[ i ] < mMinLevelDistSqr[ i - 1 ] )
00600             {
00601                 mMinLevelDistSqr[ i ] = mMinLevelDistSqr[ i - 1 ];
00602             }
00603         }
00604 
00605         // Now reverse traverse the list setting the 'next level down'
00606         Real lastDist = -1;
00607         int lastIndex = 0;
00608         for (i = msOptions->maxGeoMipMapLevel - 1; i >= 0; --i)
00609         {
00610             if (i == msOptions->maxGeoMipMapLevel - 1)
00611             {
00612                 // Last one is always 0
00613                 lastIndex = i;
00614                 lastDist = mMinLevelDistSqr[i];
00615                 mNextLevelDown[i] = 0;
00616             }
00617             else
00618             {
00619                 mNextLevelDown[i] = lastIndex;
00620                 if (mMinLevelDistSqr[i] != lastDist)
00621                 {
00622                     lastIndex = i;
00623                     lastDist = mMinLevelDistSqr[i];
00624                 }
00625             }
00626 
00627         }
00628 
00629 
00630     }
00631     //-----------------------------------------------------------------------
00632     void TerrainRenderable::_initLevelIndexes()
00633     {
00634         if ( mLevelInit )
00635             return ;
00636 
00637 
00638         if ( mLevelIndex.size() == 0 )
00639         {
00640             for ( int i = 0; i < 16; i++ )
00641             {
00642 
00643                 mLevelIndex.push_back( new IndexMap() );
00644 
00645             }
00646 
00647         }
00648 
00649         mLevelInit = true;
00650     }
00651     //-----------------------------------------------------------------------
00652     void TerrainRenderable::_destroyLevelIndexes()
00653     {
00654         if ( mLevelInit )
00655         {
00656             for ( int i = 0; i < 16; i++ )
00657             {
00658                 delete mLevelIndex[i];
00659             }
00660             mLevelIndex.clear();
00661             mLevelInit = false;
00662         }
00663     }
00664     //-----------------------------------------------------------------------
00665     void TerrainRenderable::_adjustRenderLevel( int i )
00666     {
00667 
00668         mRenderLevel = i;
00669     }
00670     //-----------------------------------------------------------------------
00671     Real TerrainRenderable::_calculateCFactor()
00672     {
00673         Real A, T;
00674 
00675         const TerrainOptions& opts = TerrainSceneManager::getOptions();
00676         if (!opts.primaryCamera)
00677         {
00678             Except(Exception::ERR_ITEM_NOT_FOUND, 
00679                 "You have not created a camera yet!", 
00680                 "TerrainRenderable::_calculateCFactor");
00681         }
00682 
00683         //A = 1 / Math::Tan(Math::AngleUnitsToRadians(opts.primaryCamera->getFOVy()));
00684         // Turn off detail compression at higher FOVs
00685         A = 1.0f;
00686 
00687         int vertRes = opts.primaryCamera->getViewport()->getActualHeight();
00688 
00689         T = 2 * ( Real ) opts.maxPixelError / ( Real ) vertRes;
00690 
00691         return A / T;
00692     }
00693     //-----------------------------------------------------------------------
00694     float TerrainRenderable::getHeightAt( float x, float z )
00695     {
00696         Vector3 start;
00697         Vector3 end;
00698 
00699         start.x = _vertex( 0, 0, 0 );
00700         start.y = _vertex( 0, 0, 1 );
00701         start.z = _vertex( 0, 0, 2 );
00702 
00703         end.x = _vertex( msOptions->tileSize - 1, msOptions->tileSize - 1, 0 );
00704         end.y = _vertex( msOptions->tileSize - 1, msOptions->tileSize - 1, 1 );
00705         end.z = _vertex( msOptions->tileSize - 1, msOptions->tileSize - 1, 2 );
00706 
00707         /* Safety catch, if the point asked for is outside
00708         * of this tile, it will ask the appropriate tile
00709         */
00710 
00711         if ( x < start.x )
00712         {
00713             if ( mNeighbors[ WEST ] != 0 )
00714                 return mNeighbors[ WEST ] ->getHeightAt( x, z );
00715             else
00716                 x = start.x;
00717         }
00718 
00719         if ( x > end.x )
00720         {
00721             if ( mNeighbors[ EAST ] != 0 )
00722                 return mNeighbors[ EAST ] ->getHeightAt( x, z );
00723             else
00724                 x = end.x;
00725         }
00726 
00727         if ( z < start.z )
00728         {
00729             if ( mNeighbors[ NORTH ] != 0 )
00730                 return mNeighbors[ NORTH ] ->getHeightAt( x, z );
00731             else
00732                 z = start.z;
00733         }
00734 
00735         if ( z > end.z )
00736         {
00737             if ( mNeighbors[ SOUTH ] != 0 )
00738                 return mNeighbors[ SOUTH ] ->getHeightAt( x, z );
00739             else
00740                 z = end.z;
00741         }
00742 
00743 
00744 
00745         float x_pct = ( x - start.x ) / ( end.x - start.x );
00746         float z_pct = ( z - start.z ) / ( end.z - start.z );
00747 
00748         float x_pt = x_pct * ( float ) ( msOptions->tileSize - 1 );
00749         float z_pt = z_pct * ( float ) ( msOptions->tileSize - 1 );
00750 
00751         int x_index = ( int ) x_pt;
00752         int z_index = ( int ) z_pt;
00753 
00754         // If we got to the far right / bottom edge, move one back
00755         if (x_index == msOptions->tileSize - 1)
00756         {
00757             --x_index;
00758             x_pct = 1.0f;
00759         }
00760         else
00761         {
00762             // get remainder
00763             x_pct = x_pt - x_index;
00764         }
00765         if (z_index == msOptions->tileSize - 1)
00766         {
00767             --z_index;
00768             z_pct = 1.0f;
00769         }
00770         else
00771         {
00772             z_pct = z_pt - z_index;
00773         }
00774 
00775         //bilinear interpolate to find the height.
00776 
00777         float t1 = _vertex( x_index, z_index, 1 );
00778         float t2 = _vertex( x_index + 1, z_index, 1 );
00779         float b1 = _vertex( x_index, z_index + 1, 1 );
00780         float b2 = _vertex( x_index + 1, z_index + 1, 1 );
00781 
00782         float midpoint = (b1 + t2) / 2.0;
00783 
00784         if (x_pct + z_pct <= 1) {
00785             b2 = midpoint + (midpoint - t1);
00786         } else {
00787             t1 = midpoint + (midpoint - b2);
00788         }
00789 
00790         float t = ( t1 * ( 1 - x_pct ) ) + ( t2 * ( x_pct ) );
00791         float b = ( b1 * ( 1 - x_pct ) ) + ( b2 * ( x_pct ) );
00792 
00793         float h = ( t * ( 1 - z_pct ) ) + ( b * ( z_pct ) );
00794 
00795         return h;
00796     }
00797     //-----------------------------------------------------------------------
00798     bool TerrainRenderable::intersectSegment( const Vector3 & start, const Vector3 & end, Vector3 * result )
00799     {
00800         Vector3 dir = end - start;
00801         Vector3 ray = start;
00802 
00803         //special case...
00804         if ( dir.x == 0 && dir.z == 0 )
00805         {
00806             if ( ray.y <= getHeightAt( ray.x, ray.z ) )
00807             {
00808                 if ( result != 0 )
00809                     * result = start;
00810 
00811                 return true;
00812             }
00813         }
00814 
00815         dir.normalise();
00816 
00817         //dir.x *= mScale.x;
00818         //dir.y *= mScale.y;
00819         //dir.z *= mScale.z;
00820 
00821         const Vector3 * corners = getBoundingBox().getAllCorners();
00822 
00823         //start with the next one...
00824         ray += dir;
00825 
00826 
00827         while ( ! ( ( ray.x < corners[ 0 ].x ) ||
00828             ( ray.x > corners[ 4 ].x ) ||
00829             ( ray.z < corners[ 0 ].z ) ||
00830             ( ray.z > corners[ 4 ].z ) ) )
00831         {
00832 
00833 
00834             float h = getHeightAt( ray.x, ray.z );
00835 
00836             if ( ray.y <= h )
00837             {
00838                 if ( result != 0 )
00839                     * result = ray;
00840 
00841                 return true;
00842             }
00843 
00844             else
00845             {
00846                 ray += dir;
00847             }
00848 
00849         }
00850 
00851         if ( ray.x < corners[ 0 ].x && mNeighbors[ WEST ] != 0 )
00852             return mNeighbors[ WEST ] ->intersectSegment( ray, end, result );
00853         else if ( ray.z < corners[ 0 ].z && mNeighbors[ NORTH ] != 0 )
00854             return mNeighbors[ NORTH ] ->intersectSegment( ray, end, result );
00855         else if ( ray.x > corners[ 4 ].x && mNeighbors[ EAST ] != 0 )
00856             return mNeighbors[ EAST ] ->intersectSegment( ray, end, result );
00857         else if ( ray.z > corners[ 4 ].z && mNeighbors[ SOUTH ] != 0 )
00858             return mNeighbors[ SOUTH ] ->intersectSegment( ray, end, result );
00859         else
00860         {
00861             if ( result != 0 )
00862                 * result = Vector3( -1, -1, -1 );
00863 
00864             return false;
00865         }
00866     }
00867     //-----------------------------------------------------------------------
00868     void TerrainRenderable::_generateVertexLighting( const Vector3 &sun, ColourValue ambient )
00869     {
00870 
00871         Vector3 pt;
00872         Vector3 normal;
00873         Vector3 light;
00874 
00875         HardwareVertexBufferSharedPtr vbuf = 
00876             mTerrain->vertexBufferBinding->getBuffer(MAIN_BINDING);
00877         const VertexElement* elem = mTerrain->vertexDeclaration->findElementBySemantic(VES_DIFFUSE);
00878         //for each point in the terrain, see if it's in the line of sight for the sun.
00879         for ( size_t i = 0; i < msOptions->tileSize; i++ )
00880         {
00881             for ( size_t j = 0; j < msOptions->tileSize; j++ )
00882             {
00883                 //  printf( "Checking %f,%f,%f ", pt.x, pt.y, pt.z );
00884                 pt.x = _vertex( i, j, 0 );
00885                 pt.y = _vertex( i, j, 1 );
00886                 pt.z = _vertex( i, j, 2 );
00887 
00888                 light = sun - pt;
00889 
00890                 light.normalise();
00891 
00892                 if ( ! intersectSegment( pt, sun, 0 ) )
00893                 {
00894                     //
00895                     _getNormalAt( _vertex( i, j, 0 ), _vertex( i, j, 2 ), &normal );
00896 
00897                     float l = light.dotProduct( normal );
00898 
00899                     ColourValue v;
00900                     v.r = ambient.r + l;
00901                     v.g = ambient.g + l;
00902                     v.b = ambient.b + l;
00903 
00904                     if ( v.r > 1 ) v.r = 1;
00905 
00906                     if ( v.g > 1 ) v.g = 1;
00907 
00908                     if ( v.b > 1 ) v.b = 1;
00909 
00910                     if ( v.r < 0 ) v.r = 0;
00911 
00912                     if ( v.g < 0 ) v.g = 0;
00913 
00914                     if ( v.b < 0 ) v.b = 0;
00915 
00916                     RGBA colour;
00917                     Root::getSingleton().convertColourValue( v, &colour );
00918                     vbuf->writeData(
00919                         (_index( i, j ) * vbuf->getVertexSize()) + elem->getOffset(),
00920                         sizeof(RGBA), &colour);
00921                 }
00922 
00923                 else
00924                 {
00925                     RGBA colour;
00926                     Root::getSingleton().convertColourValue( ambient, &colour );
00927 
00928                     vbuf->writeData(
00929                         (_index( i, j ) * vbuf->getVertexSize()) + elem->getOffset(), 
00930                         sizeof(RGBA), &colour);
00931                 }
00932 
00933             }
00934 
00935         }
00936 
00937         printf( "." );
00938     }
00939     //-----------------------------------------------------------------------
00940     Real TerrainRenderable::getSquaredViewDepth(const Camera* cam) const
00941     {
00942         Vector3 diff = mCenter - cam->getDerivedPosition();
00943         // Use squared length to avoid square root
00944         return diff.squaredLength();
00945     }
00946 
00947     //-----------------------------------------------------------------------
00948     const LightList& TerrainRenderable::getLights(void) const
00949     {
00950         return getParentSceneNode()->findLights(this->getBoundingRadius());
00951     }
00952     //-----------------------------------------------------------------------
00953     IndexData* TerrainRenderable::getIndexData(void)
00954     {
00955         unsigned int stitchFlags = 0;
00956 
00957         if ( mNeighbors[ EAST ] != 0 && mNeighbors[ EAST ] -> mRenderLevel > mRenderLevel )
00958         {
00959             stitchFlags |= STITCH_EAST;
00960             stitchFlags |= 
00961                 (mNeighbors[ EAST ] -> mRenderLevel - mRenderLevel) << STITCH_EAST_SHIFT;
00962         }
00963 
00964         if ( mNeighbors[ WEST ] != 0 && mNeighbors[ WEST ] -> mRenderLevel > mRenderLevel )
00965         {
00966             stitchFlags |= STITCH_WEST;
00967             stitchFlags |= 
00968                 (mNeighbors[ WEST ] -> mRenderLevel - mRenderLevel) << STITCH_WEST_SHIFT;
00969         }
00970 
00971         if ( mNeighbors[ NORTH ] != 0 && mNeighbors[ NORTH ] -> mRenderLevel > mRenderLevel )
00972         {
00973             stitchFlags |= STITCH_NORTH;
00974             stitchFlags |= 
00975                 (mNeighbors[ NORTH ] -> mRenderLevel - mRenderLevel) << STITCH_NORTH_SHIFT;
00976         }
00977 
00978         if ( mNeighbors[ SOUTH ] != 0 && mNeighbors[ SOUTH ] -> mRenderLevel > mRenderLevel )
00979         {
00980             stitchFlags |= STITCH_SOUTH;
00981             stitchFlags |= 
00982                 (mNeighbors[ SOUTH ] -> mRenderLevel - mRenderLevel) << STITCH_SOUTH_SHIFT;
00983         }
00984 
00985         // Check preexisting
00986         IndexMap::iterator ii = mLevelIndex[ mRenderLevel ]->find( stitchFlags );
00987         IndexData* indexData;
00988         if ( ii == mLevelIndex[ mRenderLevel ]->end())
00989         {
00990             // Create
00991             if (msOptions->useTriStrips)
00992             {
00993                 indexData = generateTriStripIndexes(stitchFlags);
00994             }
00995             else
00996             {
00997                 indexData = generateTriListIndexes(stitchFlags);
00998             }
00999             mLevelIndex[ mRenderLevel ]->insert(
01000                 IndexMap::value_type(stitchFlags, indexData));
01001         }
01002         else
01003         {
01004             indexData = ii->second;
01005         }
01006 
01007 
01008         return indexData;
01009 
01010 
01011     }
01012     //-----------------------------------------------------------------------
01013     IndexData* TerrainRenderable::generateTriStripIndexes(unsigned int stitchFlags)
01014     {
01015         // The step used for the current level
01016         int step = 1 << mRenderLevel;
01017         // The step used for the lower level
01018         int lowstep = 1 << (mRenderLevel + 1);
01019 
01020         int numIndexes = 0;
01021 
01022         // Calculate the number of indexes required
01023         // This is the number of 'cells' at this detail level x 2
01024         // plus 3 degenerates to turn corners
01025         int numTrisAcross = (((msOptions->tileSize-1) / step) * 2) + 3;
01026         // Num indexes is number of tris + 2
01027         int new_length = numTrisAcross * ((msOptions->tileSize-1) / step) + 2;
01028         //this is the maximum for a level.  It wastes a little, but shouldn't be a problem.
01029 
01030         IndexData* indexData = new IndexData;
01031         indexData->indexBuffer = 
01032             HardwareBufferManager::getSingleton().createIndexBuffer(
01033             HardwareIndexBuffer::IT_16BIT,
01034             new_length, HardwareBuffer::HBU_STATIC_WRITE_ONLY);//, false);
01035 
01036         msIndexCache.mCache.push_back( indexData );
01037 
01038         unsigned short* pIdx = static_cast<unsigned short*>(
01039             indexData->indexBuffer->lock(0, 
01040             indexData->indexBuffer->getSizeInBytes(), 
01041             HardwareBuffer::HBL_DISCARD));
01042 
01043         // Stripified mesh
01044         for ( int j = 0; j < msOptions->tileSize - 1; j += step )
01045         {
01046             int i;
01047             // Forward strip
01048             // We just do the |/ here, final | done after
01049             for ( i = 0; i < msOptions->tileSize - 1; i += step )
01050             {
01051                 int x[4], y[4];
01052                 x[0] = x[1] = i;
01053                 x[2] = x[3] = i + step;
01054                 y[0] = y[2] = j;
01055                 y[1] = y[3] = j + step;
01056 
01057                 if (j == 0  && (stitchFlags & STITCH_NORTH))
01058                 {
01059                     // North reduction means rounding x[0] and x[2]
01060                     if (x[0] % lowstep != 0)
01061                     {
01062                         // Since we know we only drop down one level of LOD,
01063                         // removing 1 step of higher LOD should return to lower
01064                         x[0] -= step;
01065                     }
01066                     if (x[2] % lowstep != 0)
01067                     {
01068                         x[2] -= step;
01069                     }
01070                 }
01071 
01072                 // Never get a south tiling on a forward strip (always finish on 
01073                 // a backward strip)
01074 
01075                 if (i == 0  && (stitchFlags & STITCH_WEST))
01076                 {
01077                     // West reduction means rounding y[0] / y[1]
01078                     if (y[0] % lowstep != 0)
01079                     {
01080                         y[0] -= step;
01081                     }
01082                     if (y[1] % lowstep != 0)
01083                     {
01084                         y[1] -= step;
01085                     }
01086                 }
01087                 if (i == (msOptions->tileSize - 1 - step) && (stitchFlags & STITCH_EAST))
01088                 {
01089                     // East tiling means rounding y[2] & y[3]
01090                     if (y[2] % lowstep != 0)
01091                     {
01092                         y[2] -= step;
01093                     }
01094                     if (y[3] % lowstep != 0)
01095                     {
01096                         y[3] -= step;
01097                     }
01098                 }
01099 
01100                 //triangles
01101                 if (i == 0)
01102                 {
01103                     // Starter
01104                     *pIdx++ = _index( x[0], y[0] ); numIndexes++;
01105                 }
01106                 *pIdx++ = _index( x[1], y[1] ); numIndexes++;
01107                 *pIdx++ = _index( x[2], y[2] ); numIndexes++;
01108 
01109                 if (i == msOptions->tileSize - 1 - step)
01110                 {
01111                     // Emit extra index to finish row
01112                     *pIdx++ = _index( x[3], y[3] ); numIndexes++;
01113                     if (j < msOptions->tileSize - 1 - step)
01114                     {
01115                         // Emit this index twice more (this is to turn around without
01116                         // artefacts)
01117                         // ** Hmm, looks like we can drop this and it's unnoticeable
01118                         //*pIdx++ = _index( x[3], y[3] ); numIndexes++;
01119                         //*pIdx++ = _index( x[3], y[3] ); numIndexes++;
01120                     }
01121                 }
01122 
01123             }
01124             // Increment row
01125             j += step;
01126             // Backward strip
01127             for ( i = msOptions->tileSize - 1; i > 0 ; i -= step )
01128             {
01129                 int x[4], y[4];
01130                 x[0] = x[1] = i;
01131                 x[2] = x[3] = i - step;
01132                 y[0] = y[2] = j;
01133                 y[1] = y[3] = j + step;
01134 
01135                 // Never get a north tiling on a backward strip (always
01136                 // start on a forward strip)
01137                 if (j == (msOptions->tileSize - 1 - step) && (stitchFlags & STITCH_SOUTH))
01138                 {
01139                     // South reduction means rounding x[1] / x[3]
01140                     if (x[1] % lowstep != 0)
01141                     {
01142                         x[1] -= step;
01143                     }
01144                     if (x[3] % lowstep != 0)
01145                     {
01146                         x[3] -= step;
01147                     }
01148                 }
01149 
01150                 if (i == step  && (stitchFlags & STITCH_WEST))
01151                 {
01152                     // West tiling on backward strip is rounding of y[2] / y[3]
01153                     if (y[2] % lowstep != 0)
01154                     {
01155                         y[2] -= step;
01156                     }
01157                     if (y[3] % lowstep != 0)
01158                     {
01159                         y[3] -= step;
01160                     }
01161                 }
01162                 if (i == msOptions->tileSize - 1 && (stitchFlags & STITCH_EAST))
01163                 {
01164                     // East tiling means rounding y[0] and y[1] on backward strip
01165                     if (y[0] % lowstep != 0)
01166                     {
01167                         y[0] -= step;
01168                     }
01169                     if (y[1] % lowstep != 0)
01170                     {
01171                         y[1] -= step;
01172                     }
01173                 }
01174 
01175                 //triangles
01176                 if (i == msOptions->tileSize)
01177                 {
01178                     // Starter
01179                     *pIdx++ = _index( x[0], y[0] ); numIndexes++;
01180                 }
01181                 *pIdx++ = _index( x[1], y[1] ); numIndexes++;
01182                 *pIdx++ = _index( x[2], y[2] ); numIndexes++;
01183 
01184                 if (i == step)
01185                 {
01186                     // Emit extra index to finish row
01187                     *pIdx++ = _index( x[3], y[3] ); numIndexes++;
01188                     if (j < msOptions->tileSize - 1 - step)
01189                     {
01190                         // Emit this index once more (this is to turn around)
01191                         *pIdx++ = _index( x[3], y[3] ); numIndexes++;
01192                     }
01193                 }
01194             }
01195         }
01196 
01197 
01198         indexData->indexBuffer->unlock();
01199         indexData->indexCount = numIndexes;
01200         indexData->indexStart = 0;
01201 
01202         return indexData;
01203 
01204     }
01205     //-----------------------------------------------------------------------
01206     IndexData* TerrainRenderable::generateTriListIndexes(unsigned int stitchFlags)
01207     {
01208 
01209         int numIndexes = 0;
01210         int step = 1 << mRenderLevel;
01211 
01212         IndexData* indexData = 0;
01213 
01214         int north = stitchFlags & STITCH_NORTH ? step : 0;
01215         int south = stitchFlags & STITCH_SOUTH ? step : 0;
01216         int east = stitchFlags & STITCH_EAST ? step : 0;
01217         int west = stitchFlags & STITCH_WEST ? step : 0;
01218 
01219         int new_length = ( msOptions->tileSize / step ) * ( msOptions->tileSize / step ) * 2 * 2 * 2 ;
01220         //this is the maximum for a level.  It wastes a little, but shouldn't be a problem.
01221 
01222         indexData = new IndexData;
01223         indexData->indexBuffer = 
01224             HardwareBufferManager::getSingleton().createIndexBuffer(
01225             HardwareIndexBuffer::IT_16BIT,
01226             new_length, HardwareBuffer::HBU_STATIC_WRITE_ONLY);//, false);
01227 
01228         msIndexCache.mCache.push_back( indexData );
01229 
01230         unsigned short* pIdx = static_cast<unsigned short*>(
01231             indexData->indexBuffer->lock(0, 
01232             indexData->indexBuffer->getSizeInBytes(), 
01233             HardwareBuffer::HBL_DISCARD));
01234 
01235         // Do the core vertices, minus stitches
01236         for ( int j = north; j < msOptions->tileSize - 1 - south; j += step )
01237         {
01238             for ( int i = west; i < msOptions->tileSize - 1 - east; i += step )
01239             {
01240                 //triangles
01241                 *pIdx++ = _index( i, j ); numIndexes++;
01242                 *pIdx++ = _index( i, j + step ); numIndexes++;
01243                 *pIdx++ = _index( i + step, j ); numIndexes++;
01244 
01245                 *pIdx++ = _index( i, j + step ); numIndexes++;
01246                 *pIdx++ = _index( i + step, j + step ); numIndexes++;
01247                 *pIdx++ = _index( i + step, j ); numIndexes++;
01248             }
01249         }
01250 
01251         // North stitching
01252         if ( north > 0 )
01253         {
01254             numIndexes += stitchEdge(NORTH, mRenderLevel, mNeighbors[NORTH]->mRenderLevel,
01255                 west > 0, east > 0, &pIdx);
01256         }
01257         // East stitching
01258         if ( east > 0 )
01259         {
01260             numIndexes += stitchEdge(EAST, mRenderLevel, mNeighbors[EAST]->mRenderLevel,
01261                 north > 0, south > 0, &pIdx);
01262         }
01263         // South stitching
01264         if ( south > 0 )
01265         {
01266             numIndexes += stitchEdge(SOUTH, mRenderLevel, mNeighbors[SOUTH]->mRenderLevel,
01267                 east > 0, west > 0, &pIdx);
01268         }
01269         // West stitching
01270         if ( west > 0 )
01271         {
01272             numIndexes += stitchEdge(WEST, mRenderLevel, mNeighbors[WEST]->mRenderLevel,
01273                 south > 0, north > 0, &pIdx);
01274         }
01275 
01276 
01277         indexData->indexBuffer->unlock();
01278         indexData->indexCount = numIndexes;
01279         indexData->indexStart = 0;
01280 
01281         return indexData;
01282     }
01283     //-----------------------------------------------------------------------
01284     HardwareVertexBufferSharedPtr TerrainRenderable::createDeltaBuffer(void)
01285     {
01286         // Delta buffer is a 1D float buffer of height offsets
01287         HardwareVertexBufferSharedPtr buf = 
01288             HardwareBufferManager::getSingleton().createVertexBuffer(
01289             VertexElement::getTypeSize(VET_FLOAT1), 
01290             msOptions->tileSize * msOptions->tileSize,
01291             HardwareBuffer::HBU_STATIC_WRITE_ONLY);
01292         // Fill the buffer with zeros, we will only fill in delta
01293         void* pVoid = buf->lock(HardwareBuffer::HBL_DISCARD);
01294         memset(pVoid, 0, msOptions->tileSize * msOptions->tileSize * sizeof(Real));
01295         buf->unlock();
01296 
01297         return buf;
01298 
01299     }
01300     //-----------------------------------------------------------------------
01301     void TerrainRenderable::_updateCustomGpuParameter(
01302         const GpuProgramParameters::AutoConstantEntry& constantEntry, 
01303         GpuProgramParameters* params) const
01304     {
01305         if (constantEntry.data == MORPH_CUSTOM_PARAM_ID)
01306         {
01307             // Update morph LOD factor
01308             params->setConstant(constantEntry.index, mLODMorphFactor);
01309         }
01310         else
01311         {
01312             Renderable::_updateCustomGpuParameter(constantEntry, params);
01313         }
01314 
01315     }
01316     //-----------------------------------------------------------------------
01317     int TerrainRenderable::stitchEdge(Neighbor neighbor, int hiLOD, int loLOD, 
01318         bool omitFirstTri, bool omitLastTri, unsigned short** ppIdx)
01319     {
01320         assert(loLOD > hiLOD);
01321         /* 
01322         Now do the stitching; we can stitch from any level to any level.
01323         The stitch pattern is like this for each pair of vertices in the lower LOD
01324         (excuse the poor ascii art):
01325 
01326         lower LOD
01327         *-----------*
01328         |\  \ 3 /  /|
01329         |1\2 \ / 4/5|
01330         *--*--*--*--*
01331         higher LOD
01332 
01333         The algorithm is, for each pair of lower LOD vertices:
01334         1. Iterate over the higher LOD vertices, generating tris connected to the 
01335         first lower LOD vertex, up to and including 1/2 the span of the lower LOD 
01336         over the higher LOD (tris 1-2). Skip the first tri if it is on the edge 
01337         of the tile and that edge is to be stitched itself.
01338         2. Generate a single tri for the middle using the 2 lower LOD vertices and 
01339         the middle vertex of the higher LOD (tri 3). 
01340         3. Iterate over the higher LOD vertices from 1/2 the span of the lower LOD
01341         to the end, generating tris connected to the second lower LOD vertex 
01342         (tris 4-5). Skip the last tri if it is on the edge of a tile and that
01343         edge is to be stitched itself.
01344 
01345         The same algorithm works for all edges of the patch; stitching is done
01346         clockwise so that the origin and steps used change, but the general
01347         approach does not.
01348         */
01349 
01350         // Get pointer to be updated
01351         unsigned short* pIdx = *ppIdx;
01352 
01353         // Work out the steps ie how to increment indexes
01354         // Step from one vertex to another in the high detail version
01355         int step = 1 << hiLOD;
01356         // Step from one vertex to another in the low detail version
01357         int superstep = 1 << loLOD;
01358         // Step half way between low detail steps
01359         int halfsuperstep = superstep >> 1;
01360 
01361         // Work out the starting points and sign of increments
01362         // We always work the strip clockwise
01363         int startx, starty, endx, rowstep;
01364         bool horizontal;
01365         switch(neighbor)
01366         {
01367         case NORTH:
01368             startx = starty = 0;
01369             endx = msOptions->tileSize - 1;
01370             rowstep = step;
01371             horizontal = true;
01372             break;
01373         case SOUTH:
01374             // invert x AND y direction, helps to keep same winding
01375             startx = starty = msOptions->tileSize - 1;
01376             endx = 0;
01377             rowstep = -step;
01378             step = -step;
01379             superstep = -superstep;
01380             halfsuperstep = -halfsuperstep;
01381             horizontal = true;
01382             break;
01383         case EAST:
01384             startx = 0;
01385             endx = msOptions->tileSize - 1;
01386             starty = msOptions->tileSize - 1;
01387             rowstep = -step;
01388             horizontal = false;
01389             break;
01390         case WEST:
01391             startx = msOptions->tileSize - 1;
01392             endx = 0;
01393             starty = 0;
01394             rowstep = step;
01395             step = -step;
01396             superstep = -superstep;
01397             halfsuperstep = -halfsuperstep;
01398             horizontal = false;
01399             break;
01400         };
01401 
01402         int numIndexes = 0;
01403 
01404         for ( int j = startx; j != endx; j += superstep )
01405         {
01406             int k;
01407             for (k = 0; k != halfsuperstep; k += step)
01408             {
01409                 int jk = j + k;
01410                 //skip the first bit of the corner?
01411                 if ( j != startx || k != 0 || !omitFirstTri )
01412                 {
01413                     if (horizontal)
01414                     {
01415                         *pIdx++ = _index( j , starty ); numIndexes++;
01416                         *pIdx++ = _index( jk, starty + rowstep ); numIndexes++;
01417                         *pIdx++ = _index( jk + step, starty + rowstep ); numIndexes++;
01418                     }
01419                     else
01420                     {
01421                         *pIdx++ = _index( starty, j ); numIndexes++;
01422                         *pIdx++ = _index( starty + rowstep, jk ); numIndexes++;
01423                         *pIdx++ = _index( starty + rowstep, jk + step); numIndexes++;
01424                     }
01425                 }
01426             }
01427 
01428             // Middle tri
01429             if (horizontal)
01430             {
01431                 *pIdx++ = _index( j, starty ); numIndexes++;
01432                 *pIdx++ = _index( j + halfsuperstep, starty + rowstep); numIndexes++;
01433                 *pIdx++ = _index( j + superstep, starty ); numIndexes++;
01434             }
01435             else
01436             {
01437                 *pIdx++ = _index( starty, j ); numIndexes++;
01438                 *pIdx++ = _index( starty + rowstep, j + halfsuperstep ); numIndexes++;
01439                 *pIdx++ = _index( starty, j + superstep ); numIndexes++;
01440             }
01441 
01442             for (k = halfsuperstep; k != superstep; k += step)
01443             {
01444                 int jk = j + k;
01445                 if ( j != endx - superstep || k != superstep - step || !omitLastTri )
01446                 {
01447                     if (horizontal)
01448                     {
01449                         *pIdx++ = _index( j + superstep, starty ); numIndexes++;
01450                         *pIdx++ = _index( jk, starty + rowstep ); numIndexes++;
01451                         *pIdx++ = _index( jk + step, starty + rowstep ); numIndexes++;
01452                     }
01453                     else
01454                     {
01455                         *pIdx++ = _index( starty, j + superstep ); numIndexes++;
01456                         *pIdx++ = _index( starty + rowstep, jk ); numIndexes++;
01457                         *pIdx++ = _index( starty + rowstep, jk + step ); numIndexes++;
01458                     }
01459                 }
01460             }
01461         }
01462 
01463         *ppIdx = pIdx;
01464 
01465         return numIndexes;
01466 
01467     }
01468 
01469 
01470 } //namespace

Copyright © 2002-2003 by The OGRE Team
Last modified Sun Nov 28 19:48:48 2004