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