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