2019-12-26 21:32:58 +01:00
/*-------------------------------------------------------------------------------------
Copyright ( c ) 2006 John Judnich
This software is provided ' as - is ' , without any express or implied warranty . In no event will the authors be held liable for any damages arising from the use of this software .
Permission is granted to anyone to use this software for any purpose , including commercial applications , and to alter it and redistribute it freely , subject to the following restrictions :
1. The origin of this software must not be misrepresented ; you must not claim that you wrote the original software . If you use this software in a product , an acknowledgment in the product documentation would be appreciated but is not required .
2. Altered source versions must be plainly marked as such , and must not be misrepresented as being the original software .
3. This notice may not be removed or altered from any source distribution .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//PagedGeometry.h
//Main source file for the PagedGeometry engine.
//-------------------------------------------------------------------------------------
# include "PagedGeometry.h"
# include "StaticBillboardSet.h"
# include <OgreRoot.h>
# include <OgreTimer.h>
# include <OgreCamera.h>
# include <OgreVector.h>
using namespace Ogre ;
using namespace std ;
namespace Forests {
//-------------------------------------------------------------------------------------
PagedGeometry : : PagedGeometry ( Camera * cam , const Real pageSize , Ogre : : RenderQueueGroupID queue ) : mRenderQueue ( queue )
{
//Setup camera, scene manager, and scene node
if ( cam )
{
sceneCam = cam ;
sceneMgr = sceneCam - > getSceneManager ( ) ;
oldCamPos = sceneCam - > getDerivedPosition ( ) ;
# ifdef PAGEDGEOMETRY_ALTERNATE_COORDSYSTEM
rootNode = sceneMgr - > getRootSceneNode ( ) - > createChildSceneNode ( ) ; //Create PagedGeometry's root node
# else
rootNode = sceneMgr - > getRootSceneNode ( ) ;
# endif
} else {
sceneCam = NULL ;
sceneMgr = NULL ;
rootNode = NULL ;
oldCamPos = Vector3 : : ZERO ;
}
lastSceneCam = NULL ;
lastOldCamPos = Vector3 : : ZERO ;
# ifdef PAGEDGEOMETRY_ALTERNATE_COORDSYSTEM
//Setup default coordinate system
coordinateSystemQuat = Quaternion : : IDENTITY ;
# endif
//Init. timer
timer . reset ( ) ;
lastTime = 0 ;
//Setup page size / bounds
PagedGeometry : : pageSize = pageSize ;
m_bounds = TBounds ( 0 , 0 , 0 , 0 ) ;
//Misc.
pageLoader = NULL ;
geometryAllowedVisible = true ;
tempdir = " " ; // empty for current working directory
shadersEnabled = true ; // enable shaders by default
}
PagedGeometry : : ~ PagedGeometry ( )
{
# ifdef PAGEDGEOMETRY_ALTERNATE_COORDSYSTEM
//Remove PagedGeometry's coordinate system node
if ( rootNode )
sceneMgr - > destroySceneNode ( rootNode ) ;
# endif
//Remove all page managers and the geometry associated with them
removeDetailLevels ( ) ;
}
void PagedGeometry : : setTempDir ( Ogre : : String dir )
{
tempdir = dir ;
}
void PagedGeometry : : setPageLoader ( PageLoader * loader )
{
pageLoader = loader ;
}
void PagedGeometry : : setCamera ( Camera * cam )
{
if ( cam = = NULL ) {
//Simply set camera to null
sceneCam = NULL ;
} else {
if ( sceneMgr & & cam - > getSceneManager ( ) ! = sceneMgr )
OGRE_EXCEPT ( Exception : : ERR_INVALIDPARAMS , " The specified camera is from the wrong SceneManager " , " PagedGeometry::setCamera() " ) ;
if ( cam = = lastSceneCam ) {
//If the cache values for this camera are preserved, use them
std : : swap ( oldCamPos , lastOldCamPos ) ;
std : : swap ( sceneCam , lastSceneCam ) ;
} else {
lastSceneCam = sceneCam ;
lastOldCamPos = oldCamPos ;
sceneCam = cam ;
}
//If sceneMgre is NULL (this only occurs the first time a camera is set),
//then set the scene manager (it won't change after this point).
if ( sceneMgr = = NULL )
sceneMgr = sceneCam - > getSceneManager ( ) ;
//If rootNode is NULL (this also only occurs the first time a camera is set),
//the create a scene node (it won't change after this point) for the coordinate
//system translations.
if ( rootNode = = NULL ) {
# ifdef PAGEDGEOMETRY_ALTERNATE_COORDSYSTEM
rootNode = sceneMgr - > getRootSceneNode ( ) - > createChildSceneNode ( ) ;
rootNode - > setOrientation ( coordinateSystemQuat ) ;
# else
rootNode = sceneMgr - > getRootSceneNode ( ) ;
# endif
}
}
}
# ifdef PAGEDGEOMETRY_ALTERNATE_COORDSYSTEM
void PagedGeometry : : setCoordinateSystem ( Vector3 up , Vector3 right )
{
up . z = - up . z ;
Vector3 forward = right . crossProduct ( up ) ;
coordinateSystemQuat = Quaternion ( right , up , forward ) ;
if ( rootNode )
rootNode - > setOrientation ( coordinateSystemQuat ) ;
}
# endif
# ifdef PAGEDGEOMETRY_ALTERNATE_COORDSYSTEM
Vector3 PagedGeometry : : _convertToLocal ( const Vector3 & globalVec ) const
{
assert ( getSceneNode ( ) ) ;
//Convert from the given global position to the local coordinate system of PagedGeometry's root scene node.
return ( getSceneNode ( ) - > getOrientation ( ) . Inverse ( ) * globalVec ) ;
}
# else
//Default coordinate system - no conversion
Vector3 PagedGeometry : : _convertToLocal ( const Vector3 & globalVec ) const
{
return globalVec ;
}
# endif
void PagedGeometry : : setPageSize ( Real size )
{
if ( ! managerList . empty ( ) )
OGRE_EXCEPT ( Exception : : ERR_INVALIDPARAMS , " PagedGeometry::setPageSize() cannot be called after detail levels have been added. Call removeDetailLevels() first. " , " PagedGeometry::setPageSize() " ) ;
pageSize = size ;
}
void PagedGeometry : : setInfinite ( )
{
if ( ! managerList . empty ( ) )
OGRE_EXCEPT ( Exception : : ERR_INVALIDPARAMS , " PagedGeometry::setInfinite() cannot be called after detail levels have been added. Call removeDetailLevels() first. " , " PagedGeometry::setInfinite() " ) ;
m_bounds = TBounds ( 0 , 0 , 0 , 0 ) ;
}
void PagedGeometry : : setBounds ( TBounds bounds )
{
if ( ! managerList . empty ( ) )
OGRE_EXCEPT ( Exception : : ERR_INVALIDPARAMS , " PagedGeometry::setBounds() cannot be called after detail levels have been added. Call removeDetailLevels() first. " , " PagedGeometry::setBounds() " ) ;
if ( ! Math : : RealEqual ( bounds . width ( ) , bounds . height ( ) , 0.01f ) )
OGRE_EXCEPT ( Exception : : ERR_INVALIDPARAMS , " Bounds must be square " , " PagedGeometry::setBounds() " ) ;
if ( bounds . width ( ) < = 0 | | bounds . height ( ) < = 0 )
OGRE_EXCEPT ( Exception : : ERR_INVALIDPARAMS , " Bounds must have positive width and height " , " PagedGeometry::setBounds() " ) ;
m_bounds = bounds ;
}
TBounds PagedGeometry : : convertAABToTBounds ( const Ogre : : AxisAlignedBox & aab ) const
{
Vector3 minimum = _convertToLocal ( aab . getMinimum ( ) ) ;
Vector3 maximum = _convertToLocal ( aab . getMaximum ( ) ) ;
return TBounds ( minimum . x , minimum . z , maximum . x , maximum . z ) ;
}
void PagedGeometry : : removeDetailLevels ( )
{
std : : list < GeometryPageManager * > : : iterator it ;
//Delete all the page managers
for ( it = managerList . begin ( ) ; it ! = managerList . end ( ) ; + + it ) {
GeometryPageManager * mgr = * it ;
delete mgr ;
}
//Clear the page manager list
managerList . clear ( ) ;
}
void PagedGeometry : : update ( )
{
//If no camera has been set, then return without doing anything
if ( sceneCam = = NULL )
return ;
//Calculate time since last update
unsigned long deltaTime , tmp ;
tmp = timer . getMilliseconds ( ) ;
deltaTime = tmp - lastTime ;
lastTime = tmp ;
//Get camera position and speed
Vector3 camPos = _convertToLocal ( sceneCam - > getDerivedPosition ( ) ) ;
Vector3 camSpeed ; //Speed in units-per-millisecond
if ( deltaTime = = 0 ) {
camSpeed . x = 0 ;
camSpeed . y = 0 ;
camSpeed . z = 0 ;
} else {
camSpeed = ( camPos - oldCamPos ) / deltaTime ;
}
oldCamPos = camPos ;
if ( pageLoader ! = 0 ) {
//Update the PageLoader
pageLoader - > frameUpdate ( ) ;
//Update all the page managers
bool enableCache = true ;
std : : list < GeometryPageManager * > : : iterator it ;
GeometryPageManager * prevMgr = NULL ;
for ( it = managerList . begin ( ) ; it ! = managerList . end ( ) ; + + it ) {
GeometryPageManager * mgr = * it ;
mgr - > update ( deltaTime , camPos , camSpeed , enableCache , prevMgr ) ;
prevMgr = mgr ;
}
}
//Update misc. subsystems
StaticBillboardSet : : updateAll ( _convertToLocal ( getCamera ( ) - > getDerivedDirection ( ) ) ) ;
}
void PagedGeometry : : reloadGeometry ( )
{
assert ( pageLoader ) ;
std : : list < GeometryPageManager * > : : iterator it ;
for ( it = managerList . begin ( ) ; it ! = managerList . end ( ) ; + + it ) {
GeometryPageManager * mgr = * it ;
mgr - > reloadGeometry ( ) ;
}
}
void PagedGeometry : : reloadGeometryPage ( const Vector3 & point , bool forceLoadImmediately )
{
if ( ! pageLoader )
return ;
# ifdef PAGEDGEOMETRY_ALTERNATE_COORDSYSTEM
point = _convertToLocal ( point ) ;
# endif
std : : list < GeometryPageManager * > : : iterator it ;
for ( it = managerList . begin ( ) ; it ! = managerList . end ( ) ; + + it )
{
GeometryPageManager * mgr = * it ;
mgr - > reloadGeometryPage (
# ifdef PAGEDGEOMETRY_ALTERNATE_COORDSYSTEM
_convertToLocal ( point )
# else
point
# endif
, forceLoadImmediately
) ;
}
}
void PagedGeometry : : reloadGeometryPages ( const Ogre : : Vector3 & center , Real radius )
{
if ( ! pageLoader )
return ;
std : : list < GeometryPageManager * > : : iterator it ;
for ( it = managerList . begin ( ) ; it ! = managerList . end ( ) ; + + it )
{
GeometryPageManager * mgr = * it ;
mgr - > reloadGeometryPages (
# ifdef PAGEDGEOMETRY_ALTERNATE_COORDSYSTEM
_convertToLocal ( center )
# else
center
# endif
, radius ) ;
}
}
void PagedGeometry : : reloadGeometryPages ( const TBounds & area )
{
if ( ! pageLoader )
return ;
TBounds localArea = area ;
if ( localArea . left > localArea . right ) std : : swap ( localArea . left , localArea . right ) ;
if ( localArea . top > localArea . bottom ) std : : swap ( localArea . top , localArea . bottom ) ;
std : : list < GeometryPageManager * > : : iterator it ;
for ( it = managerList . begin ( ) ; it ! = managerList . end ( ) ; + + it ) {
GeometryPageManager * mgr = * it ;
mgr - > reloadGeometryPages ( localArea ) ;
}
}
void PagedGeometry : : preloadGeometry ( const TBounds & area )
{
if ( ! pageLoader )
return ;
TBounds localArea = area ;
if ( localArea . left > localArea . right ) std : : swap ( localArea . left , localArea . right ) ;
if ( localArea . top > localArea . bottom ) std : : swap ( localArea . top , localArea . bottom ) ;
std : : list < GeometryPageManager * > : : iterator it ;
for ( it = managerList . begin ( ) ; it ! = managerList . end ( ) ; + + it ) {
GeometryPageManager * mgr = * it ;
mgr - > preloadGeometry ( localArea ) ;
}
}
void PagedGeometry : : resetPreloadedGeometry ( )
{
if ( ! pageLoader )
return ;
std : : list < GeometryPageManager * > : : iterator it ;
for ( it = managerList . begin ( ) ; it ! = managerList . end ( ) ; + + it ) {
GeometryPageManager * mgr = * it ;
mgr - > resetPreloadedGeometry ( ) ;
}
}
void PagedGeometry : : _addDetailLevel ( GeometryPageManager * mgr , Real maxRange , Real transitionLength )
{
//Calculate the near range
Real minRange = 0 ;
if ( ! managerList . empty ( ) ) {
GeometryPageManager * lastMgr = managerList . back ( ) ;
minRange = lastMgr - > getFarRange ( ) ;
}
//Error check
if ( maxRange < = minRange ) {
OGRE_EXCEPT ( Exception : : ERR_INVALID_STATE , " Closer detail levels must be added before farther ones " , " PagedGeometry::addDetailLevel() " ) ;
}
//Setup the new manager
mgr - > setNearRange ( minRange ) ;
mgr - > setFarRange ( maxRange ) ;
mgr - > setTransition ( transitionLength ) ;
managerList . push_back ( mgr ) ;
}
void PagedGeometry : : setCustomParam ( string entity , string paramName , float paramValue )
{
setCustomParam ( entity + " . " + paramName , paramValue ) ;
}
void PagedGeometry : : setCustomParam ( string paramName , float paramValue )
{
customParam [ paramName ] = paramValue ;
}
float PagedGeometry : : getCustomParam ( string entity , string paramName , float defaultParamValue ) const
{
return getCustomParam ( entity + " . " + paramName , defaultParamValue ) ;
}
float PagedGeometry : : getCustomParam ( string paramName , float defaultParamValue ) const
{
std : : map < string , float > : : const_iterator it ;
it = customParam . find ( paramName ) ;
if ( it ! = customParam . end ( ) ) {
float x = it - > second ;
return x ;
}
else
return defaultParamValue ;
}
Ogre : : RenderQueueGroupID PagedGeometry : : getRenderQueue ( ) const
{
return mRenderQueue ;
}
//-------------------------------------------------------------------------------------
GeometryPageManager : : GeometryPageManager ( PagedGeometry * mainGeom )
: mainGeom ( mainGeom )
, geomGrid ( NULL )
2022-08-05 21:24:23 +02:00
, scrollBuffer ( NULL )
2019-12-26 21:32:58 +01:00
, geomGridX ( 0 )
, geomGridZ ( 0 )
2022-08-05 21:24:23 +02:00
, cacheTimer ( 0 ) // Reset the cache timer
2019-12-26 21:32:58 +01:00
{
//Use default cache speeds
setCacheSpeed ( ) ;
//No transition default
setTransition ( 0 ) ;
}
GeometryPageManager : : ~ GeometryPageManager ( )
{
//Delete GeometryPage's
for ( int x = 0 ; x < geomGridX ; + + x )
for ( int z = 0 ; z < geomGridZ ; + + z )
delete _getGridPage ( x , z ) ;
//Deallocate arrays
if ( geomGrid )
delete [ ] geomGrid ;
if ( scrollBuffer )
delete [ ] scrollBuffer ;
}
void GeometryPageManager : : update ( unsigned long deltaTime , Vector3 & camPos , Vector3 & camSpeed , bool & enableCache , GeometryPageManager * prevManager )
{
//-- Cache new geometry pages --
//Cache 1 page ahead of the view ranges
const Real cacheDist = farTransDist + mainGeom - > getPageSize ( ) ;
const Real cacheDistSq = cacheDist * cacheDist ;
//First calculate the general area where the pages will be processed
// 0,0 is the left top corner of the bounding box
int x1 = Math : : Floor ( ( ( camPos . x - cacheDist ) - gridBounds . left ) / mainGeom - > getPageSize ( ) ) ;
int x2 = Math : : Floor ( ( ( camPos . x + cacheDist ) - gridBounds . left ) / mainGeom - > getPageSize ( ) ) ;
int z1 = Math : : Floor ( ( ( camPos . z - cacheDist ) - gridBounds . top ) / mainGeom - > getPageSize ( ) ) ;
int z2 = Math : : Floor ( ( ( camPos . z + cacheDist ) - gridBounds . top ) / mainGeom - > getPageSize ( ) ) ;
if ( scrollBuffer )
{
//Check if the page grid needs to be scrolled
int shiftX = 0 , shiftZ = 0 ;
if ( x1 < 0 ) shiftX = x1 ; else if ( x2 > = geomGridX - 1 ) shiftX = x2 - ( geomGridX - 1 ) ;
if ( z1 < 0 ) shiftZ = z1 ; else if ( z2 > = geomGridZ - 1 ) shiftZ = z2 - ( geomGridZ - 1 ) ;
if ( shiftX ! = 0 | | shiftZ ! = 0 )
{
//Scroll grid
_scrollGridPages ( shiftX , shiftZ ) ;
//Update grid bounds and processing area
gridBounds . left + = shiftX * mainGeom - > getPageSize ( ) ;
gridBounds . right + = shiftX * mainGeom - > getPageSize ( ) ;
gridBounds . top + = shiftZ * mainGeom - > getPageSize ( ) ;
gridBounds . bottom + = shiftZ * mainGeom - > getPageSize ( ) ;
x1 - = shiftX ; x2 - = shiftX ;
z1 - = shiftZ ; z2 - = shiftZ ;
}
}
else
{
// make sure that values are inbounds
if ( x2 > = geomGridX )
x2 = geomGridX - 1 ;
if ( z2 > = geomGridZ )
z2 = geomGridZ - 1 ;
if ( x1 < 0 )
x1 = 0 ;
if ( z1 < 0 )
z1 = 0 ;
}
//Now, in that general area, find what pages are within the cacheDist radius
//Pages within the cacheDist radius will be added to the pending block list
//to be loaded later, and pages within farDist will be loaded immediately.
for ( int x = x1 ; x < = x2 ; + + x ) {
for ( int z = z1 ; z < = z2 ; + + z ) {
GeometryPage * blk = _getGridPage ( x , z ) ;
Real dx = camPos . x - blk - > _centerPoint . x ;
Real dz = camPos . z - blk - > _centerPoint . z ;
Real distSq = dx * dx + dz * dz ;
//If the page is in the cache radius...
if ( distSq < = cacheDistSq ) {
//If the block hasn't been loaded yet, it should be
if ( blk - > _loaded = = false ) {
//Test if the block's distance is between nearDist and farDist
if ( distSq > = nearDistSq & & distSq < farTransDistSq ) {
//If so, load the geometry immediately
_loadPage ( blk ) ;
loadedList . insert ( blk ) ;
//And remove it from the pending list if necessary
if ( blk - > _pending ) {
pendingList . erase ( blk ) ;
blk - > _pending = false ;
}
} else {
//Otherwise, add it to the pending geometry list (if not already)
//Pages in then pending list will be loaded later (see below)
if ( ! blk - > _pending ) {
pendingList . insert ( blk ) ;
blk - > _pending = true ;
}
}
} else {
//Set the inactive time to 0 (since the page is active). This
//must be done in order to keep it from expiring (and deleted).
//This way, blocks not in the cache radius won't have their
//inactivity clock reset, and they will expire in a few seconds.
blk - > _inactiveTime = 0 ;
}
}
}
}
//Calculate cache speeds based on camera speed. This is important to keep the cache
//process running smooth, because if the cache can't keep up with the camera, the
//immediately visible pages will be forced to load instantly, which can cause
//noticeable and sudden stuttering. The cache system results in smoother performance
//because it smooths the loading tasks out across multiple frames. For example,
//instead of loading 10+ blocks every 2 seconds, the cache would load 1 block every
//200 milliseconds.
Real speed = Math : : Sqrt ( camSpeed . x * camSpeed . x + camSpeed . z * camSpeed . z ) ;
unsigned long cacheInterval ;
if ( speed = = 0 )
cacheInterval = maxCacheInterval ;
else {
cacheInterval = ( mainGeom - > getPageSize ( ) * 0.8f ) / ( speed * pendingList . size ( ) ) ;
if ( cacheInterval > maxCacheInterval )
cacheInterval = maxCacheInterval ;
}
TPGeometryPages : : iterator i1 , i2 ;
//Now load a single geometry page periodically, based on the cacheInterval
cacheTimer + = deltaTime ;
if ( cacheTimer > = cacheInterval & & enableCache ) {
//Find a block to be loaded from the pending list
i1 = pendingList . begin ( ) ;
i2 = pendingList . end ( ) ;
while ( i1 ! = i2 )
{
GeometryPage * blk = * i1 ;
//Remove it from the pending list
i1 = pendingList . erase ( i1 ) ;
blk - > _pending = false ;
//If it's within the geometry cache radius, load it and break out of the loop
Real dx = camPos . x - blk - > _centerPoint . x ;
Real dz = camPos . z - blk - > _centerPoint . z ;
Real distSq = dx * dx + dz * dz ;
if ( distSq < = cacheDistSq ) {
_loadPage ( blk ) ;
loadedList . insert ( blk ) ;
enableCache = false ;
break ;
}
//Otherwise this will keep looping until an unloaded page is found
}
//Reset the cache timer
cacheTimer = 0 ;
}
//-- Update existing geometry and impostors --
//Loop through each loaded geometry block
i1 = loadedList . begin ( ) ;
i2 = loadedList . end ( ) ;
//Real fadeBeginDistSq = farDistSq - Math::Sqr(mainGeom->getPageSize() * 1.4142f);
Real halfPageSize = mainGeom - > getPageSize ( ) * 0.5f ;
while ( i1 ! = i2 )
{
GeometryPage * blk = * i1 ;
//If the geometry has expired...
if ( blk - > _inactiveTime > = inactivePageLife ) {
if ( ! blk - > _keepLoaded ) {
//Unload it
_unloadPage ( blk ) ;
i1 = loadedList . erase ( i1 ) ;
} else {
//This page needs to be kept loaded indefinitely, so don't unload it
blk - > _inactiveTime = 0 ;
+ + i1 ;
}
} else {
//Update it's visibility/fade status based on it's distance from the camera
bool visible = false ;
Real dx = camPos . x - blk - > _centerPoint . x ;
Real dz = camPos . z - blk - > _centerPoint . z ;
Real distSq = dx * dx + dz * dz ;
Real overlap = 0 , tmp ;
tmp = blk - > _trueBounds . getMaximum ( ) . x - halfPageSize ;
if ( tmp > overlap ) overlap = tmp ;
tmp = blk - > _trueBounds . getMaximum ( ) . z - halfPageSize ;
if ( tmp > overlap ) overlap = tmp ;
tmp = blk - > _trueBounds . getMinimum ( ) . x + halfPageSize ;
if ( tmp > overlap ) overlap = tmp ;
tmp = blk - > _trueBounds . getMinimum ( ) . z + halfPageSize ;
if ( tmp > overlap ) overlap = tmp ;
Real pageLengthSq = Math : : Sqr ( ( mainGeom - > getPageSize ( ) + overlap ) * 1.41421356f ) ;
if ( distSq + pageLengthSq > = nearDistSq & & distSq - pageLengthSq < farTransDistSq ) {
//Fade the page when transitioning
bool enable = false ;
Real fadeNear = 0 ;
Real fadeFar = 0 ;
if ( fadeEnabled & & distSq + pageLengthSq > = farDistSq ) {
//Fade in
visible = true ;
enable = true ;
fadeNear = farDist ;
fadeFar = farTransDist ;
}
else if ( prevManager & & prevManager - > fadeEnabled & & ( distSq - pageLengthSq < prevManager - > farTransDistSq ) ) {
//Fade out
visible = true ;
enable = true ;
fadeNear = prevManager - > farDist + ( prevManager - > farTransDist - prevManager - > farDist ) * 0.5f ; //This causes geometry to fade out faster than it fades in, avoiding a state where a transition appears semitransparent
fadeFar = prevManager - > farDist ;
}
//Apply fade settings
if ( enable ! = blk - > _fadeEnable ) {
blk - > setFade ( enable , fadeNear , fadeFar ) ;
blk - > _fadeEnable = enable ;
}
}
//Non-fade visibility
if ( distSq > = nearDistSq & & distSq < farDistSq )
visible = true ;
//Hide all?
if ( ! mainGeom - > getVisible ( ) )
visible = false ;
//Update visibility
if ( visible ) {
//Show the page if it isn't visible
if ( blk - > _visible ! = true ) {
blk - > setVisible ( true ) ;
blk - > _visible = true ;
}
} else {
//Hide the page if it's not already
if ( blk - > _visible ! = false ) {
blk - > setVisible ( false ) ;
blk - > _visible = false ;
}
}
//And update it
blk - > update ( ) ;
+ + i1 ;
}
//Increment the inactivity timer for the geometry
blk - > _inactiveTime + = deltaTime ;
}
}
//Clears all GeometryPage's
void GeometryPageManager : : reloadGeometry ( )
{
TPGeometryPages : : iterator it ;
for ( it = loadedList . begin ( ) ; it ! = loadedList . end ( ) ; + + it )
{
GeometryPage * page = * it ;
_unloadPageDelayed ( page ) ;
page - > _pending = true ;
pendingList . insert ( page ) ;
}
loadedList . clear ( ) ;
}
//Clears a single page (which contains the given point)
void GeometryPageManager : : reloadGeometryPage ( const Vector3 & point , bool forceLoadImmediately )
{
//Determine which grid block contains the given points
const int x = Math : : Floor ( geomGridX * ( point . x - gridBounds . left ) / gridBounds . width ( ) ) ;
const int z = Math : : Floor ( geomGridZ * ( point . z - gridBounds . top ) / gridBounds . height ( ) ) ;
//Unload the grid block if it's in the grid area, and is loaded
if ( x > = 0 & & z > = 0 & & x < geomGridX & & z < geomGridZ ) {
GeometryPage * page = _getGridPage ( x , z ) ;
if ( page - > _loaded ) {
_unloadPageDelayed ( page ) ;
page - > _pending = true ;
pendingList . insert ( page ) ;
}
if ( forceLoadImmediately ) {
//Load the geometry immediately
_loadPage ( page ) ;
loadedList . insert ( page ) ;
//And remove it from the pending list if necessary
if ( page - > _pending ) {
pendingList . erase ( page ) ;
page - > _pending = false ;
}
}
}
}
//Clears pages within the radius
void GeometryPageManager : : reloadGeometryPages ( const Vector3 & center , Real radius )
{
//First calculate a square boundary to eliminate the search space
TBounds area ( center . x - radius , center . z - radius , center . x + radius , center . z + radius ) ;
//Determine which grid block contains the top-left corner
int x1 = Math : : Floor ( geomGridX * ( area . left - gridBounds . left ) / gridBounds . width ( ) ) ;
int z1 = Math : : Floor ( geomGridZ * ( area . top - gridBounds . top ) / gridBounds . height ( ) ) ;
if ( x1 < 0 ) x1 = 0 ; else if ( x1 > geomGridX - 1 ) x1 = geomGridX - 1 ;
if ( z1 < 0 ) z1 = 0 ; else if ( z1 > geomGridZ - 1 ) z1 = geomGridZ - 1 ;
//...and the bottom right
int x2 = Math : : Floor ( geomGridX * ( area . right - gridBounds . left ) / gridBounds . width ( ) ) ;
int z2 = Math : : Floor ( geomGridZ * ( area . bottom - gridBounds . top ) / gridBounds . height ( ) ) ;
if ( x2 < 0 ) x2 = 0 ; else if ( x2 > geomGridX - 1 ) x2 = geomGridX - 1 ;
if ( z2 < 0 ) z2 = 0 ; else if ( z2 > geomGridZ - 1 ) z2 = geomGridZ - 1 ;
//Scan all the grid blocks in the region
2022-08-05 21:24:23 +02:00
//Real radiusSq = radius * radius;
2019-12-26 21:32:58 +01:00
for ( int x = x1 ; x < = x2 ; + + x ) {
for ( int z = z1 ; z < = z2 ; + + z ) {
GeometryPage * page = _getGridPage ( x , z ) ;
if ( page - > _loaded ) {
Vector3 pos = page - > getCenterPoint ( ) ;
Real distX = ( pos . x - center . x ) , distZ = ( pos . z - center . z ) ;
Real distSq = distX * distX + distZ * distZ ;
if ( distSq < = radius ) {
_unloadPageDelayed ( page ) ;
page - > _pending = true ;
pendingList . insert ( page ) ;
}
}
}
}
}
//Clears pages within the bounds
void GeometryPageManager : : reloadGeometryPages ( const TBounds & area )
{
//Determine which grid block contains the top-left corner
int x1 = Math : : Floor ( geomGridX * ( area . left - gridBounds . left ) / gridBounds . width ( ) ) ;
int z1 = Math : : Floor ( geomGridZ * ( area . top - gridBounds . top ) / gridBounds . height ( ) ) ;
if ( x1 < 0 ) x1 = 0 ; else if ( x1 > geomGridX - 1 ) x1 = geomGridX - 1 ;
if ( z1 < 0 ) z1 = 0 ; else if ( z1 > geomGridZ - 1 ) z1 = geomGridZ - 1 ;
//...and the bottom right
int x2 = Math : : Floor ( geomGridX * ( area . right - gridBounds . left ) / gridBounds . width ( ) ) ;
int z2 = Math : : Floor ( geomGridZ * ( area . bottom - gridBounds . top ) / gridBounds . height ( ) ) ;
if ( x2 < 0 ) x2 = 0 ; else if ( x2 > geomGridX - 1 ) x2 = geomGridX - 1 ;
if ( z2 < 0 ) z2 = 0 ; else if ( z2 > geomGridZ - 1 ) z2 = geomGridZ - 1 ;
//Unload the grid blocks
for ( int x = x1 ; x < = x2 ; + + x ) {
for ( int z = z1 ; z < = z2 ; + + z ) {
GeometryPage * page = _getGridPage ( x , z ) ;
if ( page - > _loaded ) {
_unloadPageDelayed ( page ) ;
page - > _pending = true ;
pendingList . insert ( page ) ;
}
}
}
}
//Loads pages within viewing range of the bounds and keeps them loaded
void GeometryPageManager : : preloadGeometry ( const TBounds & area )
{
TBounds loadarea ;
loadarea . left = area . left - farDist ;
loadarea . right = area . right + farDist ;
loadarea . top = area . top - farDist ;
loadarea . bottom = area . bottom + farDist ;
//Determine which grid block contains the top-left corner
int x1 = Math : : Floor ( geomGridX * ( loadarea . left - gridBounds . left ) / gridBounds . width ( ) ) ;
int z1 = Math : : Floor ( geomGridZ * ( loadarea . top - gridBounds . top ) / gridBounds . height ( ) ) ;
if ( x1 < 0 ) x1 = 0 ; else if ( x1 > geomGridX - 1 ) x1 = geomGridX - 1 ;
if ( z1 < 0 ) z1 = 0 ; else if ( z1 > geomGridZ - 1 ) z1 = geomGridZ - 1 ;
//...and the bottom right
int x2 = Math : : Floor ( geomGridX * ( loadarea . right - gridBounds . left ) / gridBounds . width ( ) ) ;
int z2 = Math : : Floor ( geomGridZ * ( loadarea . bottom - gridBounds . top ) / gridBounds . height ( ) ) ;
if ( x2 < 0 ) x2 = 0 ; else if ( x2 > geomGridX - 1 ) x2 = geomGridX - 1 ;
if ( z2 < 0 ) z2 = 0 ; else if ( z2 > geomGridZ - 1 ) z2 = geomGridZ - 1 ;
//Preload the grid blocks
for ( int x = x1 ; x < = x2 ; + + x ) {
for ( int z = z1 ; z < = z2 ; + + z ) {
GeometryPage * page = _getGridPage ( x , z ) ;
//If the page isn't loaded
if ( ! page - > _loaded ) {
//Load the geometry immediately
_loadPage ( page ) ;
loadedList . insert ( page ) ;
//And remove it from the pending list if necessary
if ( page - > _pending ) {
pendingList . erase ( page ) ;
page - > _pending = false ;
}
}
//Flag the page so it won't expire and be deleted in a few seconds if
//it's currently not in the viewing range.
page - > _keepLoaded = true ;
}
}
}
void GeometryPageManager : : resetPreloadedGeometry ( )
{
//Set all grid blocks' _keepLoaded flag to false
for ( int x = 0 ; x < geomGridX ; + + x ) {
for ( int z = 0 ; z < geomGridZ ; + + z ) {
GeometryPage * page = _getGridPage ( x , z ) ;
page - > _keepLoaded = true ;
}
}
}
//Loads the given page of geometry immediately
//Note: _loadPage() does add the page to loadedList, so that will have to be done manually
void GeometryPageManager : : _loadPage ( GeometryPage * page )
{
//Calculate page info
PageInfo info ;
Real halfPageSize = mainGeom - > getPageSize ( ) * 0.5f ;
info . bounds . left = page - > _centerPoint . x - halfPageSize ;
info . bounds . right = page - > _centerPoint . x + halfPageSize ;
info . bounds . top = page - > _centerPoint . z - halfPageSize ;
info . bounds . bottom = page - > _centerPoint . z + halfPageSize ;
info . centerPoint = page - > _centerPoint ;
info . xIndex = page - > _xIndex ;
info . zIndex = page - > _zIndex ;
info . userData = page - > _userData ;
//Check if the page is prepared. If not, should stop now (and rely on the page being loaded again when the background data has been prepared).
if ( ! mainGeom - > getPageLoader ( ) - > preparePage ( info ) ) {
page - > _inactiveTime = 0 ;
page - > _loaded = true ;
return ;
}
//Check if page needs unloading (if a delayed unload has been issued)
if ( page - > _needsUnload ) {
page - > removeEntities ( ) ;
mainGeom - > getPageLoader ( ) - > unloadPage ( info ) ;
page - > _userData = 0 ;
page - > _needsUnload = false ;
page - > clearBoundingBox ( ) ;
}
//Load the page
page - > setRegion ( info . bounds . left , info . bounds . top , info . bounds . right , info . bounds . bottom ) ;
mainGeom - > getPageLoader ( ) - > geomPage = page ;
mainGeom - > getPageLoader ( ) - > loadPage ( info ) ;
page - > _userData = info . userData ;
page - > build ( ) ;
page - > setVisible ( page - > _visible ) ;
page - > _inactiveTime = 0 ;
page - > _loaded = true ;
page - > _fadeEnable = false ;
}
//Unloads the given page of geometry immediately
//Note: _unloadPage() does not remove the page from loadedList, so that will have to be done manually
void GeometryPageManager : : _unloadPage ( GeometryPage * page )
{
//Calculate boundaries to unload
PageInfo info ;
Real halfPageSize = mainGeom - > getPageSize ( ) * 0.5f ;
info . bounds . left = page - > _centerPoint . x - halfPageSize ;
info . bounds . right = page - > _centerPoint . x + halfPageSize ;
info . bounds . top = page - > _centerPoint . z - halfPageSize ;
info . bounds . bottom = page - > _centerPoint . z + halfPageSize ;
info . centerPoint = page - > _centerPoint ;
info . xIndex = page - > _xIndex ;
info . zIndex = page - > _zIndex ;
info . userData = page - > _userData ;
//Unload the page
page - > removeEntities ( ) ;
mainGeom - > getPageLoader ( ) - > unloadPage ( info ) ;
page - > _userData = 0 ;
page - > _needsUnload = false ;
page - > clearBoundingBox ( ) ;
page - > _inactiveTime = 0 ;
page - > _loaded = false ;
page - > _fadeEnable = false ;
}
//"Virtually" unloads the given page of geometry. In reality it is unloaded during the next load.
//Note: _unloadPageDelayed() does not remove the page from loadedList, so that will have to be done manually
void GeometryPageManager : : _unloadPageDelayed ( GeometryPage * page )
{
page - > _needsUnload = true ;
page - > _loaded = false ;
}
//Scrolls pages in the grid by the given amount
void GeometryPageManager : : _scrollGridPages ( int shiftX , int shiftZ )
{
//Check if the camera moved completely out of the grid
if ( shiftX > geomGridX | | shiftX < - geomGridX | | shiftZ > geomGridZ | | shiftZ < - geomGridZ ) {
//If so, just reload all the tiles (reloading is accomplished by unloading - loading is automatic)
for ( int x = 0 ; x < geomGridX ; + + x ) {
for ( int z = 0 ; z < geomGridZ ; + + z ) {
GeometryPage * page = _getGridPage ( x , z ) ;
if ( page - > _loaded ) {
page - > _keepLoaded = false ;
_unloadPage ( page ) ;
loadedList . erase ( page ) ;
}
page - > _centerPoint . x + = shiftX * mainGeom - > getPageSize ( ) ;
page - > _centerPoint . z + = shiftZ * mainGeom - > getPageSize ( ) ;
page - > _xIndex + = shiftX ;
page - > _zIndex + = shiftZ ;
}
}
} else { //If not, scroll the grid by the X and Y values
//Scroll horizontally (X)
if ( shiftX > 0 ) {
for ( int z = 0 ; z < geomGridZ ; + + z ) {
//Temporarily store off-shifted pages first
for ( int x = 0 ; x < shiftX ; + + x ) {
GeometryPage * page = _getGridPage ( x , z ) ;
if ( page - > _loaded ) {
page - > _keepLoaded = false ;
_unloadPageDelayed ( page ) ;
loadedList . erase ( page ) ;
}
scrollBuffer [ x ] = page ;
}
//Shift left
int shiftedMidpoint = geomGridX - shiftX ;
for ( int x = 0 ; x < shiftedMidpoint ; + + x )
_setGridPage ( x , z , _getGridPage ( x + shiftX , z ) ) ;
//Rotate temporary pages around to other side of grid
for ( int x = 0 ; x < shiftX ; + + x ) {
scrollBuffer [ x ] - > _centerPoint . x + = geomGridX * mainGeom - > getPageSize ( ) ;
scrollBuffer [ x ] - > _xIndex + = geomGridX ;
_setGridPage ( x + shiftedMidpoint , z , scrollBuffer [ x ] ) ;
}
}
}
else if ( shiftX < 0 ) {
for ( int z = 0 ; z < geomGridZ ; + + z ) {
//Temporarily store off-shifted pages first
int initialMidpoint = geomGridX + shiftX ;
for ( int x = initialMidpoint ; x < geomGridX ; + + x ) {
GeometryPage * page = _getGridPage ( x , z ) ;
if ( page - > _loaded ) {
page - > _keepLoaded = false ;
_unloadPageDelayed ( page ) ;
loadedList . erase ( page ) ;
}
scrollBuffer [ x - initialMidpoint ] = page ;
}
//Shift right
for ( int x = geomGridX - 1 ; x > = - shiftX ; x - - )
_setGridPage ( x , z , _getGridPage ( x + shiftX , z ) ) ;
//Rotate temporary pages around to other side of grid
for ( int x = 0 ; x < - shiftX ; + + x ) {
scrollBuffer [ x ] - > _centerPoint . x - = geomGridX * mainGeom - > getPageSize ( ) ;
scrollBuffer [ x ] - > _xIndex - = geomGridX ;
_setGridPage ( x , z , scrollBuffer [ x ] ) ;
}
}
}
//Scroll vertically (Z)
if ( shiftZ > 0 ) {
for ( int x = 0 ; x < geomGridX ; + + x ) {
//Temporarily store off-shifted pages first
for ( int z = 0 ; z < shiftZ ; + + z ) {
GeometryPage * page = _getGridPage ( x , z ) ;
if ( page - > _loaded ) {
page - > _keepLoaded = false ;
_unloadPageDelayed ( page ) ;
loadedList . erase ( page ) ;
}
scrollBuffer [ z ] = page ;
}
//Shift left
int shiftedMidpoint = geomGridZ - shiftZ ;
for ( int z = 0 ; z < shiftedMidpoint ; + + z )
_setGridPage ( x , z , _getGridPage ( x , z + shiftZ ) ) ;
//Rotate temporary pages around to other side of grid
for ( int z = 0 ; z < shiftZ ; + + z ) {
scrollBuffer [ z ] - > _centerPoint . z + = geomGridZ * mainGeom - > getPageSize ( ) ;
scrollBuffer [ z ] - > _zIndex + = geomGridZ ;
_setGridPage ( x , z + shiftedMidpoint , scrollBuffer [ z ] ) ;
}
}
}
else if ( shiftZ < 0 ) {
for ( int x = 0 ; x < geomGridX ; + + x ) {
//Temporarily store off-shifted pages first
int initialMidpoint = geomGridZ + shiftZ ;
for ( int z = initialMidpoint ; z < geomGridZ ; + + z ) {
GeometryPage * page = _getGridPage ( x , z ) ;
if ( page - > _loaded ) {
page - > _keepLoaded = false ;
_unloadPageDelayed ( page ) ;
loadedList . erase ( page ) ;
}
scrollBuffer [ z - initialMidpoint ] = page ;
}
//Shift right
for ( int z = geomGridZ - 1 ; z > = - shiftZ ; z - - )
_setGridPage ( x , z , _getGridPage ( x , z + shiftZ ) ) ;
//Rotate temporary pages around to other side of grid
for ( int z = 0 ; z < - shiftZ ; + + z ) {
scrollBuffer [ z ] - > _centerPoint . z - = geomGridZ * mainGeom - > getPageSize ( ) ;
scrollBuffer [ z ] - > _zIndex - = geomGridZ ;
_setGridPage ( x , z , scrollBuffer [ z ] ) ;
}
}
}
}
}
GeometryPage : : GeometryPage ( )
{
_visible = _fadeEnable = _pending = _loaded = _needsUnload = _keepLoaded = false ;
_trueBoundsUndefined = true ;
_inactiveTime = 0 ; _xIndex = _zIndex = 0 ;
_centerPoint = Ogre : : Vector3 : : ZERO ;
_userData = NULL ;
mHasQueryFlag = false ;
mQueryFlag = 0 ;
}
void GeometryPage : : addEntityToBoundingBox ( Ogre : : MovableObject * ent , const Ogre : : Vector3 & position , const Ogre : : Quaternion & rotation , const Ogre : : Vector3 & scale )
{
//Update bounding box
Ogre : : Matrix4 mat ( rotation ) ;
mat . setScale ( scale ) ;
Ogre : : AxisAlignedBox entBounds = ent - > getBoundingBox ( ) ;
entBounds . transform ( mat ) ;
Ogre : : Vector3 relPosition = position - _centerPoint ;
if ( _trueBoundsUndefined ) {
_trueBounds . setMinimum ( entBounds . getMinimum ( ) + relPosition ) ;
_trueBounds . setMaximum ( entBounds . getMaximum ( ) + relPosition ) ;
_trueBoundsUndefined = false ;
} else {
Ogre : : Vector3 min = _trueBounds . getMinimum ( ) ;
Ogre : : Vector3 max = _trueBounds . getMaximum ( ) ;
min . makeFloor ( entBounds . getMinimum ( ) + relPosition ) ;
max . makeCeil ( entBounds . getMaximum ( ) + relPosition ) ;
_trueBounds . setMinimum ( min ) ;
_trueBounds . setMaximum ( max ) ;
}
}
const AxisAlignedBox & GeometryPage : : getBoundingBox ( )
{
return _trueBounds ;
}
void GeometryPage : : clearBoundingBox ( )
{
_trueBounds = AxisAlignedBox ( 0 , 0 , 0 , 0 , 0 , 0 ) ;
_trueBoundsUndefined = true ;
}
}