@ -73,18 +73,20 @@ namespace
* osg : : Quat ( xr , osg : : Vec3 ( - 1 , 0 , 0 ) ) ;
}
void set NodeRotation( const MWWorld : : Ptr & ptr , MWRender : : RenderingManager & rendering , RotationOrder order )
osg : : Quat make NodeRotation( const MWWorld : : Ptr & ptr , RotationOrder order )
{
if ( ! ptr . getRefData ( ) . getBaseNode ( ) )
return ;
const auto pos = ptr . getRefData ( ) . getPosition ( ) ;
const auto rot = ptr . getClass ( ) . isActor ( ) ? makeActorOsgQuat ( pos )
: ( order = = RotationOrder : : inverse ? makeInversedOrderObjectOsgQuat ( pos ) : makeObjectOsgQuat ( pos ) ) ;
rendering . rotateObject ( ptr ,
ptr . getClass ( ) . isActor ( )
? makeActorOsgQuat ( ptr . getRefData ( ) . getPosition ( ) )
: ( order = = RotationOrder : : inverse
? makeInversedOrderObjectOsgQuat ( ptr . getRefData ( ) . getPosition ( ) )
: makeObjectOsgQuat ( ptr . getRefData ( ) . getPosition ( ) ) )
) ;
return rot ;
}
void setNodeRotation ( const MWWorld : : Ptr & ptr , MWRender : : RenderingManager & rendering , osg : : Quat rotation )
{
if ( ptr . getRefData ( ) . getBaseNode ( ) )
rendering . rotateObject ( ptr , rotation ) ;
}
std : : string getModel ( const MWWorld : : Ptr & ptr , const VFS : : Manager * vfs )
@ -101,7 +103,7 @@ namespace
}
void addObject ( const MWWorld : : Ptr & ptr , MWPhysics : : PhysicsSystem & physics ,
MWRender : : RenderingManager & rendering , std : : set < ESM : : RefNum > & pagedRefs )
MWRender : : RenderingManager & rendering , std : : set < ESM : : RefNum > & pagedRefs , bool onlyPhysics )
{
if ( ptr . getRefData ( ) . getBaseNode ( ) | | physics . getActor ( ptr ) )
{
@ -109,19 +111,23 @@ namespace
return ;
}
bool useAnim = ptr . getClass ( ) . useAnim ( ) ;
std : : string model = getModel ( ptr , rendering . getResourceSystem ( ) - > getVFS ( ) ) ;
const auto rotation = makeNodeRotation ( ptr , RotationOrder : : direct ) ;
if ( onlyPhysics & & ! physics . getObject ( ptr ) & & ! ptr . getClass ( ) . isActor ( ) )
{
// When we preload physics object we need to skip animated objects. They are dependant on the scene graph which doesn't yet exist.
ptr . getClass ( ) . insertObject ( ptr , model , rotation , physics , true ) ;
return ;
}
const ESM : : RefNum & refnum = ptr . getCellRef ( ) . getRefNum ( ) ;
if ( ! refnum . hasContentFile ( ) | | pagedRefs . find ( refnum ) = = pagedRefs . end ( ) )
ptr . getClass ( ) . insertObjectRendering ( ptr , model , rendering ) ;
else
ptr . getRefData ( ) . setBaseNode ( new SceneUtil : : PositionAttitudeTransform ) ; // FIXME remove this when physics code is fixed not to depend on basenode
setNodeRotation ( ptr , rendering , RotationOrder : : direct ) ;
setNodeRotation ( ptr , rendering , rotation ) ;
ptr . getClass ( ) . insertObject ( ptr , model , physics ) ;
if ( useAnim )
if ( ptr . getClass ( ) . useAnim ( ) )
MWBase : : Environment : : get ( ) . getMechanicsManager ( ) - > add ( ptr ) ;
if ( ptr . getClass ( ) . isActor ( ) )
@ -129,6 +135,9 @@ namespace
// Restore effect particles
MWBase : : Environment : : get ( ) . getWorld ( ) - > applyLoopingParticles ( ptr ) ;
if ( ! physics . getObject ( ptr ) )
ptr . getClass ( ) . insertObject ( ptr , model , rotation , physics ) ;
}
void addObject ( const MWWorld : : Ptr & ptr , const MWPhysics : : PhysicsSystem & physics , DetourNavigator : : Navigator & navigator )
@ -199,11 +208,12 @@ namespace
{
MWWorld : : CellStore & mCell ;
Loading : : Listener & mLoadingListener ;
bool mOnlyObjects ;
bool mTest ;
std : : vector < MWWorld : : Ptr > mToInsert ;
InsertVisitor ( MWWorld : : CellStore & cell , Loading : : Listener & loadingListener , bool test) ;
InsertVisitor ( MWWorld : : CellStore & cell , Loading : : Listener & loadingListener , bool onlyObjects, bool test) ;
bool operator ( ) ( const MWWorld : : Ptr & ptr ) ;
@ -211,8 +221,8 @@ namespace
void insert ( AddObject & & addObject ) ;
} ;
InsertVisitor : : InsertVisitor ( MWWorld : : CellStore & cell , Loading : : Listener & loadingListener , bool test)
: mCell ( cell ) , mLoadingListener ( loadingListener ) , m Test( test )
InsertVisitor : : InsertVisitor ( MWWorld : : CellStore & cell , Loading : : Listener & loadingListener , bool onlyObjects, bool test)
: mCell ( cell ) , mLoadingListener ( loadingListener ) , m OnlyObjects( onlyObjects ) , m Test( test )
{ }
bool InsertVisitor : : operator ( ) ( const MWWorld : : Ptr & ptr )
@ -228,7 +238,7 @@ namespace
{
for ( MWWorld : : Ptr & ptr : mToInsert )
{
if ( ! ptr . getRefData ( ) . isDeleted ( ) & & ptr . getRefData ( ) . isEnabled ( ) )
if ( ! ptr . getRefData ( ) . isDeleted ( ) & & ptr . getRefData ( ) . isEnabled ( ) & & ( ! mOnlyObjects | | ! ptr . getClass ( ) . isActor ( ) ) )
{
try
{
@ -261,6 +271,16 @@ namespace
return std : : abs ( cellPosition . first ) + std : : abs ( cellPosition . second ) ;
}
bool isCellInCollection ( int x , int y , MWWorld : : Scene : : CellStoreCollection & collection )
{
for ( auto * cell : collection )
{
assert ( cell - > getCell ( ) - > isExterior ( ) ) ;
if ( x = = cell - > getCell ( ) - > getGridX ( ) & & y = = cell - > getCell ( ) - > getGridY ( ) )
return true ;
}
return false ;
}
}
@ -274,7 +294,7 @@ namespace MWWorld
{
if ( ! ptr . getRefData ( ) . getBaseNode ( ) ) return ;
ptr . getClass ( ) . insertObjectRendering ( ptr , getModel ( ptr , mRendering . getResourceSystem ( ) - > getVFS ( ) ) , mRendering ) ;
setNodeRotation ( ptr , mRendering , RotationOrder: : direct ) ;
setNodeRotation ( ptr , mRendering , makeNodeRotation( ptr , RotationOrder: : direct ) ) ;
reloadTerrain ( ) ;
}
}
@ -290,8 +310,9 @@ namespace MWWorld
void Scene : : updateObjectRotation ( const Ptr & ptr , RotationOrder order )
{
setNodeRotation ( ptr , mRendering , order ) ;
mPhysics - > updateRotation ( ptr ) ;
const auto rot = makeNodeRotation ( ptr , order ) ;
setNodeRotation ( ptr , mRendering , rot ) ;
mPhysics - > updateRotation ( ptr , rot ) ;
}
void Scene : : updateObjectScale ( const Ptr & ptr )
@ -311,165 +332,213 @@ namespace MWWorld
mRendering . update ( duration , paused ) ;
}
void Scene : : unload Cell ( CellStoreCollection : : iterator iter , bool test )
void Scene : : unload InactiveCell ( CellStore * cell , bool test )
{
assert ( mActiveCells . find ( cell ) = = mActiveCells . end ( ) ) ;
assert ( mInactiveCells . find ( cell ) ! = mInactiveCells . end ( ) ) ;
if ( ! test )
Log ( Debug : : Info ) < < " Unloading cell " < < ( * iter ) - > getCell ( ) - > getDescription ( ) ;
Log ( Debug : : Info ) < < " Unloading cell " < < cell - > getCell ( ) - > getDescription ( ) ;
ListObjectsVisitor visitor ;
cell - > forEach ( visitor ) ;
for ( const auto & ptr : visitor . mObjects )
mPhysics - > remove ( ptr ) ;
if ( cell - > getCell ( ) - > isExterior ( ) )
{
const auto cellX = cell - > getCell ( ) - > getGridX ( ) ;
const auto cellY = cell - > getCell ( ) - > getGridY ( ) ;
mPhysics - > removeHeightField ( cellX , cellY ) ;
}
mInactiveCells . erase ( cell ) ;
}
void Scene : : deactivateCell ( CellStore * cell , bool test )
{
assert ( mInactiveCells . find ( cell ) ! = mInactiveCells . end ( ) ) ;
if ( mActiveCells . find ( cell ) = = mActiveCells . end ( ) )
return ;
if ( ! test )
Log ( Debug : : Info ) < < " Deactivate cell " < < cell - > getCell ( ) - > getDescription ( ) ;
const auto navigator = MWBase : : Environment : : get ( ) . getWorld ( ) - > getNavigator ( ) ;
ListAndResetObjectsVisitor visitor ;
( * iter ) - > forEach ( visitor ) ;
cell - > forEach ( visitor ) ;
const auto world = MWBase : : Environment : : get ( ) . getWorld ( ) ;
for ( const auto & ptr : visitor . mObjects )
{
if ( const auto object = mPhysics - > getObject ( ptr ) )
{
navigator - > removeObject ( DetourNavigator : : ObjectId ( object ) ) ;
if ( object - > isAnimated ( ) )
mPhysics - > remove ( ptr ) ;
}
else if ( mPhysics - > getActor ( ptr ) )
{
navigator - > removeAgent ( world - > getPathfindingHalfExtents ( ptr ) ) ;
mRendering . removeActorPath ( ptr ) ;
mPhysics - > remove ( ptr ) ;
}
mPhysics - > remove ( ptr ) ;
}
const auto cellX = ( * iter ) - > getCell ( ) - > getGridX ( ) ;
const auto cellY = ( * iter ) - > getCell ( ) - > getGridY ( ) ;
const auto cellX = cell - > getCell ( ) - > getGridX ( ) ;
const auto cellY = cell - > getCell ( ) - > getGridY ( ) ;
if ( ( * iter ) - > getCell ( ) - > isExterior ( ) )
if ( cell - > getCell ( ) - > isExterior ( ) )
{
if ( const auto heightField = mPhysics - > getHeightField ( cellX , cellY ) )
navigator - > removeObject ( DetourNavigator : : ObjectId ( heightField ) ) ;
mPhysics - > removeHeightField ( cellX , cellY ) ;
}
if ( ( * iter ) - > getCell ( ) - > hasWater ( ) )
if ( cell - > getCell ( ) - > hasWater ( ) )
navigator - > removeWater ( osg : : Vec2i ( cellX , cellY ) ) ;
if ( const auto pathgrid = world - > getStore ( ) . get < ESM : : Pathgrid > ( ) . search ( * ( * iter ) - > getCell ( ) ) )
if ( const auto pathgrid = world - > getStore ( ) . get < ESM : : Pathgrid > ( ) . search ( * cell - > getCell ( ) ) )
navigator - > removePathgrid ( * pathgrid ) ;
const auto player = world - > getPlayerPtr ( ) ;
navigator - > update ( player . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) ;
MWBase : : Environment : : get ( ) . getMechanicsManager ( ) - > drop ( * iter ) ;
MWBase : : Environment : : get ( ) . getMechanicsManager ( ) - > drop ( cell ) ;
mRendering . removeCell ( * iter ) ;
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > removeCell ( * iter ) ;
mRendering . removeCell ( cell ) ;
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > removeCell ( cell ) ;
MWBase : : Environment : : get ( ) . getWorld ( ) - > getLocalScripts ( ) . clearCell ( * iter ) ;
MWBase : : Environment : : get ( ) . getWorld ( ) - > getLocalScripts ( ) . clearCell ( cell ) ;
MWBase : : Environment : : get ( ) . getSoundManager ( ) - > stopSound ( * iter ) ;
mActiveCells . erase ( * iter ) ;
MWBase : : Environment : : get ( ) . getSoundManager ( ) - > stopSound ( cell ) ;
mActiveCells . erase ( cell ) ;
}
void Scene : : load Cell ( CellStore * cell , Loading : : Listener * loadingListener , bool respawn , bool test )
void Scene : : activate Cell ( CellStore * cell , Loading : : Listener * loadingListener , bool respawn , bool test )
{
std : : pair < CellStoreCollection : : iterator , bool > result = mActiveCells . insert ( cell ) ;
assert ( mActiveCells . find ( cell ) = = mActiveCells . end ( ) ) ;
assert ( mInactiveCells . find ( cell ) ! = mInactiveCells . end ( ) ) ;
mActiveCells . insert ( cell ) ;
if ( test )
Log ( Debug : : Info ) < < " Testing cell " < < cell - > getCell ( ) - > getDescription ( ) ;
else
Log ( Debug : : Info ) < < " Loading cell " < < cell - > getCell ( ) - > getDescription ( ) ;
if ( result . second )
const auto world = MWBase : : Environment : : get ( ) . getWorld ( ) ;
const auto navigator = world - > getNavigator ( ) ;
const int cellX = cell - > getCell ( ) - > getGridX ( ) ;
const int cellY = cell - > getCell ( ) - > getGridY ( ) ;
if ( ! test & & cell - > getCell ( ) - > isExterior ( ) )
{
if ( test )
Log ( Debug : : Info ) < < " Testing cell " < < cell - > getCell ( ) - > getDescription ( ) ;
else
Log ( Debug : : Info ) < < " Loading cell " < < cell - > getCell ( ) - > getDescription ( ) ;
if ( const auto heigh tFi eld = mPhy sics- > ge tHeightField( cellX , cellY ) )
navigator- > addObject ( DetourNavigator : : ObjectId ( heightField ) , * heightField - > getShape ( ) ,
heightField - > getCollisionObject ( ) - > getWorldTransform ( ) ) ;
}
float verts = ESM : : Land : : LAND_SIZE ;
float worldsize = ESM : : Land : : REAL_SIZE ;
if ( const auto pathgrid = world - > getStore ( ) . get < ESM : : Pathgrid > ( ) . search ( * cell - > getCell ( ) ) )
navigator - > addPathgrid ( * cell - > getCell ( ) , * pathgrid ) ;
const auto world = MWBase : : Environment : : get ( ) . getWorld ( ) ;
const auto navigator = world - > getNavigator ( ) ;
// register local scripts
// do this before insertCell, to make sure we don't add scripts from levelled creature spawning twice
MWBase : : Environment : : get ( ) . getWorld ( ) - > getLocalScripts ( ) . addCell ( cell ) ;
const int cellX = cell - > getCell ( ) - > getGridX ( ) ;
const int cellY = cell - > getCell ( ) - > getGridY ( ) ;
if ( respawn )
cell - > respawn ( ) ;
// Load terrain physics first...
if ( ! test & & cell - > getCell ( ) - > isExterior ( ) )
insertCell ( * cell , loadingListener , false , test ) ;
mRendering . addCell ( cell ) ;
if ( ! test )
{
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > addCell ( cell ) ;
bool waterEnabled = cell - > getCell ( ) - > hasWater ( ) | | cell - > isExterior ( ) ;
float waterLevel = cell - > getWaterLevel ( ) ;
mRendering . setWaterEnabled ( waterEnabled ) ;
if ( waterEnabled )
{
osg : : ref_ptr < const ESMTerrain : : LandObject > land = mRendering . getLandManager ( ) - > getLand ( cellX , cellY ) ;
const ESM : : Land : : LandData * data = land ? land - > getData ( ESM : : Land : : DATA_VHGT ) : nullptr ;
if ( data )
mPhysics - > enableWater ( waterLevel ) ;
mRendering . setWaterHeight ( waterLevel ) ;
if ( cell - > getCell ( ) - > isExterior ( ) )
{
mPhysics - > addHeightField ( data - > mHeights , cellX , cellY , worldsize / ( verts - 1 ) , verts , data - > mMinHeight , data - > mMaxHeight , land . get ( ) ) ;
if ( const auto heightField = mPhysics - > getHeightField ( cellX , cellY ) )
navigator - > addWater ( osg : : Vec2i ( cellX , cellY ) , ESM : : Land : : REAL_SIZE ,
cell - > getWaterLevel ( ) , heightField - > getCollisionObject ( ) - > getWorldTransform ( ) ) ;
}
else
{
static std : : vector < float > defaultHeight ;
defaultHeight . resize ( verts * verts , ESM : : Land : : DEFAULT_HEIGHT ) ;
mPhysics - > addHeightField ( & defaultHeight [ 0 ] , cell - > getCell ( ) - > getGridX ( ) , cell - > getCell ( ) - > getGridY ( ) , worldsize / ( verts - 1 ) , verts , ESM : : Land : : DEFAULT_HEIGHT , ESM : : Land : : DEFAULT_HEIGHT , land . get ( ) ) ;
navigator - > addWater ( osg : : Vec2i ( cellX , cellY ) , std : : numeric_limits < int > : : max ( ) ,
cell - > getWaterLevel ( ) , btTransform : : getIdentity ( ) ) ;
}
if ( const auto heightField = mPhysics - > getHeightField ( cellX , cellY ) )
navigator - > addObject ( DetourNavigator : : ObjectId ( heightField ) , * heightField - > getShape ( ) ,
heightField - > getCollisionObject ( ) - > getWorldTransform ( ) ) ;
}
else
mPhysics - > disableWater ( ) ;
if ( const auto pathgrid = world - > getStore ( ) . get < ESM : : Pathgrid > ( ) . search ( * cell - > getCell ( ) ) )
navigator - > addPathgrid ( * cell - > getCell ( ) , * pathgrid ) ;
const auto player = MWBase : : Environment : : get ( ) . getWorld ( ) - > getPlayerPtr ( ) ;
// register local scripts
// do this before insertCell, to make sure we don't add scripts from levelled creature spawning twice
MWBase : : Environment : : get ( ) . getWorld ( ) - > getLocalScripts ( ) . addCell ( cell ) ;
// By default the player is grounded, with the scene fully loaded, we validate and correct this.
if ( player . mCell = = cell ) // Only run once, during initial cell load.
{
mPhysics - > traceDown ( player , player . getRefData ( ) . getPosition ( ) . asVec3 ( ) , 10.f ) ;
}
if ( respawn )
cell - > respawn ( ) ;
navigator - > update ( player . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) ;
// ... then references. This is important for adjustPosition to work correctly.
insertCell ( * cell , loadingListener , test ) ;
if ( ! cell - > isExterior ( ) & & ! ( cell - > getCell ( ) - > mData . mFlags & ESM : : Cell : : QuasiEx ) )
mRendering . configureAmbient ( cell - > getCell ( ) ) ;
}
mRendering . addCell ( cell ) ;
if ( ! test )
{
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > addCell ( cell ) ;
bool waterEnabled = cell - > getCell ( ) - > hasWater ( ) | | cell - > isExterior ( ) ;
float waterLevel = cell - > getWaterLevel ( ) ;
mRendering . setWaterEnabled ( waterEnabled ) ;
if ( waterEnabled )
{
mPhysics - > enableWater ( waterLevel ) ;
mRendering . setWaterHeight ( waterLevel ) ;
mPreloader - > notifyLoaded ( cell ) ;
}
if ( cell - > getCell ( ) - > isExterior ( ) )
{
if ( const auto heightField = mPhysics - > getHeightField ( cellX , cellY ) )
navigator - > addWater ( osg : : Vec2i ( cellX , cellY ) , ESM : : Land : : REAL_SIZE ,
cell - > getWaterLevel ( ) , heightField - > getCollisionObject ( ) - > getWorldTransform ( ) ) ;
}
else
{
navigator - > addWater ( osg : : Vec2i ( cellX , cellY ) , std : : numeric_limits < int > : : max ( ) ,
cell - > getWaterLevel ( ) , btTransform : : getIdentity ( ) ) ;
}
}
else
mPhysics - > disableWater ( ) ;
void Scene : : loadInactiveCell ( CellStore * cell , Loading : : Listener * loadingListener , bool test )
{
assert ( mActiveCells . find ( cell ) = = mActiveCells . end ( ) ) ;
assert ( mInactiveCells . find ( cell ) = = mInactiveCells . end ( ) ) ;
mInactiveCells . insert ( cell ) ;
const auto player = MWBase : : Environment : : get ( ) . getWorld ( ) - > getPlayerPtr ( ) ;
if ( test )
Log ( Debug : : Info ) < < " Testing inactive cell " < < cell - > getCell ( ) - > getDescription ( ) ;
else
Log ( Debug : : Info ) < < " Loading inactive cell " < < cell - > getCell ( ) - > getDescription ( ) ;
// By default the player is grounded, with the scene fully loaded, we validate and correct this.
if ( player . mCell = = cell ) // Only run once, during initial cell load.
{
mPhysics - > traceDown ( player , player . getRefData ( ) . getPosition ( ) . asVec3 ( ) , 10.f ) ;
}
if ( ! test & & cell - > getCell ( ) - > isExterior ( ) )
{
float verts = ESM : : Land : : LAND_SIZE ;
float worldsize = ESM : : Land : : REAL_SIZE ;
navigator - > update ( player . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) ;
const int cellX = cell - > getCell ( ) - > getGridX ( ) ;
const int cellY = cell - > getCell ( ) - > getGridY ( ) ;
if ( ! cell - > isExterior ( ) & & ! ( cell - > getCell ( ) - > mData . mFlags & ESM : : Cell : : QuasiEx ) )
{
mRendering . configureAmbient ( cell - > getCell ( ) ) ;
}
osg : : ref_ptr < const ESMTerrain : : LandObject > land = mRendering . getLandManager ( ) - > getLand ( cellX , cellY ) ;
const ESM : : Land : : LandData * data = land ? land - > getData ( ESM : : Land : : DATA_VHGT ) : nullptr ;
if ( data )
{
mPhysics - > addHeightField ( data - > mHeights , cellX , cellY , worldsize / ( verts - 1 ) , verts , data - > mMinHeight , data - > mMaxHeight , land . get ( ) ) ;
}
else
{
static std : : vector < float > defaultHeight ;
defaultHeight . resize ( verts * verts , ESM : : Land : : DEFAULT_HEIGHT ) ;
mPhysics - > addHeightField ( & defaultHeight [ 0 ] , cellX , cellY , worldsize / ( verts - 1 ) , verts , ESM : : Land : : DEFAULT_HEIGHT , ESM : : Land : : DEFAULT_HEIGHT , land . get ( ) ) ;
}
}
mPreloader - > notifyLoaded ( cell ) ;
insertCell ( * cell , loadingListener , true , test ) ;
}
void Scene : : clear ( )
{
CellStoreCollection : : iterator active = mActiveCells . begin ( ) ;
while ( active ! = mActiveCells . end ( ) )
unloadCell ( active + + ) ;
for ( auto iter = mInactiveCells . begin ( ) ; iter ! = mInactiveCells . end ( ) ; )
{
auto * cell = * iter + + ;
deactivateCell ( cell ) ;
unloadInactiveCell ( cell ) ;
}
assert ( mActiveCells . empty ( ) ) ;
assert ( mInactiveCells . empty ( ) ) ;
mCurrentCell = nullptr ;
mPreloader - > clear ( ) ;
@ -512,20 +581,24 @@ namespace MWWorld
void Scene : : changeCellGrid ( const osg : : Vec3f & pos , int playerCellX , int playerCellY , bool changeEvent )
{
CellStoreCollection : : iterator active = mActiveCells . begin ( ) ;
while ( active ! = mActiveCells . end ( ) )
for ( auto iter = mInactiveCells . begin ( ) ; iter ! = mInactiveCells . end ( ) ; )
{
if ( ( * active ) - > getCell ( ) - > isExterior ( ) )
auto * cell = * iter + + ;
if ( cell - > getCell ( ) - > isExterior ( ) )
{
if ( std : : abs ( playerCellX - ( * active ) - > getCell ( ) - > getGridX ( ) ) < = mHalfGridSize & &
std : : abs ( playerCellY - ( * active ) - > getCell ( ) - > getGridY ( ) ) < = mHalfGridSize )
{
// keep cells within the new grid
+ + active ;
continue ;
}
const auto dx = std : : abs ( playerCellX - cell - > getCell ( ) - > getGridX ( ) ) ;
const auto dy = std : : abs ( playerCellY - cell - > getCell ( ) - > getGridY ( ) ) ;
if ( dx > mHalfGridSize | | dy > mHalfGridSize )
deactivateCell ( cell ) ;
if ( dx > mHalfGridSize + 1 | | dy > mHalfGridSize + 1 )
unloadInactiveCell ( cell ) ;
}
else
{
deactivateCell ( cell ) ;
unloadInactiveCell ( cell ) ;
}
unloadCell ( active + + ) ;
}
mCurrentGridCenter = osg : : Vec2i ( playerCellX , playerCellY ) ;
@ -537,32 +610,24 @@ namespace MWWorld
mRendering . getPagedRefnums ( newGrid , mPagedRefs ) ;
std : : size_t refsToLoad = 0 ;
std : : vector < std : : pair < int , int > > cellsPositionsToLoad ;
// get the number of refs to load
for ( int x = playerCellX - mHalfGridSize ; x < = playerCellX + mHalfGridSize ; + + x )
const auto cellsToLoad = [ & playerCellX , & playerCellY , & refsToLoad ] ( CellStoreCollection & collection , int range ) - > std : : vector < std : : pair < int , int > >
{
for ( int y = playerCellY - mHalfGridSize ; y < = playerCellY + mHalfGridSize ; + + y )
std : : vector < std : : pair < int , int > > cellsPositionsToLoad ;
for ( int x = playerCellX - range ; x < = playerCellX + range ; + + x )
{
CellStoreCollection : : iterator iter = mActiveCells . begin ( ) ;
while ( iter ! = mActiveCells . end ( ) )
for ( int y = playerCellY - range ; y < = playerCellY + range ; + + y )
{
assert ( ( * iter ) - > getCell ( ) - > isExterior ( ) ) ;
if ( x = = ( * iter ) - > getCell ( ) - > getGridX ( ) & &
y = = ( * iter ) - > getCell ( ) - > getGridY ( ) )
break ;
+ + iter ;
}
if ( iter = = mActiveCells . end ( ) )
{
refsToLoad + = MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( x , y ) - > count ( ) ;
cellsPositionsToLoad . emplace_back ( x , y ) ;
if ( ! isCellInCollection ( x , y , collection ) )
{
refsToLoad + = MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( x , y ) - > count ( ) ;
cellsPositionsToLoad . emplace_back ( x , y ) ;
}
}
}
}
return cellsPositionsToLoad ;
} ;
auto cellsPositionsToLoad = cellsToLoad ( mActiveCells , mHalfGridSize ) ;
auto cellsPositionsToLoadInactive = cellsToLoad ( mInactiveCells , mHalfGridSize + 1 ) ;
Loading : : Listener * loadingListener = MWBase : : Environment : : get ( ) . getWindowManager ( ) - > getLoadingScreen ( ) ;
Loading : : ScopedLoad load ( loadingListener ) ;
@ -585,30 +650,26 @@ namespace MWWorld
return getCellPositionPriority ( lhs ) < getCellPositionPriority ( rhs ) ;
} ) ;
std : : sort ( cellsPositionsToLoadInactive . begin ( ) , cellsPositionsToLoadInactive . end ( ) ,
[ & ] ( const std : : pair < int , int > & lhs , const std : : pair < int , int > & rhs ) {
return getCellPositionPriority ( lhs ) < getCellPositionPriority ( rhs ) ;
} ) ;
// Load cells
for ( const auto & cellPosition : cellsPositionsToLoad )
for ( const auto & [ x , y ] : cellsPositionsToLoadInactive )
{
const auto x = cellPosition . first ;
const auto y = cellPosition . second ;
CellStoreCollection : : iterator iter = mActiveCells . begin ( ) ;
while ( iter ! = mActiveCells . end ( ) )
if ( ! isCellInCollection ( x , y , mInactiveCells ) )
{
assert ( ( * iter ) - > getCell ( ) - > isExterior ( ) ) ;
if ( x = = ( * iter ) - > getCell ( ) - > getGridX ( ) & &
y = = ( * iter ) - > getCell ( ) - > getGridY ( ) )
break ;
+ + iter ;
CellStore * cell = MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( x , y ) ;
loadInactiveCell ( cell , loadingListener ) ;
}
if ( iter = = mActiveCells . end ( ) )
}
for ( const auto & [ x , y ] : cellsPositionsToLoad )
{
if ( ! isCellInCollection ( x , y , mActiveCells ) )
{
CellStore * cell = MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( x , y ) ;
loadCell ( cell , loadingListener , changeEvent ) ;
activateCell ( cell , loadingListener , changeEvent ) ;
}
}
@ -643,7 +704,8 @@ namespace MWWorld
CellStoreCollection : : iterator iter = mActiveCells . begin ( ) ;
CellStore * cell = MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( it - > mData . mX , it - > mData . mY ) ;
loadCell ( cell , loadingListener , false , true ) ;
loadInactiveCell ( cell , loadingListener , true ) ;
activateCell ( cell , loadingListener , false , true ) ;
iter = mActiveCells . begin ( ) ;
while ( iter ! = mActiveCells . end ( ) )
@ -651,7 +713,8 @@ namespace MWWorld
if ( it - > isExterior ( ) & & it - > mData . mX = = ( * iter ) - > getCell ( ) - > getGridX ( ) & &
it - > mData . mY = = ( * iter ) - > getCell ( ) - > getGridY ( ) )
{
unloadCell ( iter , true ) ;
deactivateCell ( * iter , true ) ;
unloadInactiveCell ( * iter , true ) ;
break ;
}
@ -689,7 +752,8 @@ namespace MWWorld
loadingListener - > setLabel ( " Testing interior cells ( " + std : : to_string ( i ) + " / " + std : : to_string ( cells . getIntSize ( ) ) + " )... " ) ;
CellStore * cell = MWBase : : Environment : : get ( ) . getWorld ( ) - > getInterior ( it - > mName ) ;
loadCell ( cell , loadingListener , false , true ) ;
loadInactiveCell ( cell , loadingListener , true ) ;
activateCell ( cell , loadingListener , false , true ) ;
CellStoreCollection : : iterator iter = mActiveCells . begin ( ) ;
while ( iter ! = mActiveCells . end ( ) )
@ -698,7 +762,8 @@ namespace MWWorld
if ( it - > mName = = ( * iter ) - > getCell ( ) - > mName )
{
unloadCell ( iter , true ) ;
deactivateCell ( * iter , true ) ;
unloadInactiveCell ( * iter , true ) ;
break ;
}
@ -820,15 +885,21 @@ namespace MWWorld
Log ( Debug : : Info ) < < " Changing to interior " ;
// unload
CellStoreCollection : : iterator active = mActiveCells . begin ( ) ;
while ( active ! = mActiveCells . end ( ) )
unloadCell ( active + + ) ;
for ( auto iter = mInactiveCells . begin ( ) ; iter ! = mInactiveCells . end ( ) ; )
{
auto * cell = * iter + + ;
deactivateCell ( cell ) ;
unloadInactiveCell ( cell ) ;
}
assert ( mActiveCells . empty ( ) ) ;
assert ( mInactiveCells . empty ( ) ) ;
loadingListener - > setProgressRange ( cell - > count ( ) ) ;
// Load cell.
mPagedRefs . clear ( ) ;
loadCell ( cell , loadingListener , changeEvent ) ;
loadInactiveCell ( cell , loadingListener ) ;
activateCell ( cell , loadingListener , changeEvent ) ;
changePlayerCell ( cell , position , adjustPlayerPos ) ;
@ -878,23 +949,26 @@ namespace MWWorld
mCellChanged = false ;
}
void Scene : : insertCell ( CellStore & cell , Loading : : Listener * loadingListener , bool test)
void Scene : : insertCell ( CellStore & cell , Loading : : Listener * loadingListener , bool onlyObjects, bool test)
{
InsertVisitor insertVisitor ( cell , * loadingListener , test) ;
InsertVisitor insertVisitor ( cell , * loadingListener , onlyObjects, test) ;
cell . forEach ( insertVisitor ) ;
insertVisitor . insert ( [ & ] ( const MWWorld : : Ptr & ptr ) { addObject ( ptr , * mPhysics , mRendering , mPagedRefs ) ; } ) ;
insertVisitor . insert ( [ & ] ( const MWWorld : : Ptr & ptr ) { addObject ( ptr , * mPhysics , mNavigator ) ; } ) ;
insertVisitor . insert ( [ & ] ( const MWWorld : : Ptr & ptr ) { addObject ( ptr , * mPhysics , mRendering , mPagedRefs , onlyObjects ) ; } ) ;
if ( ! onlyObjects )
{
insertVisitor . insert ( [ & ] ( const MWWorld : : Ptr & ptr ) { addObject ( ptr , * mPhysics , mNavigator ) ; } ) ;
// do adjustPosition (snapping actors to ground) after objects are loaded, so we don't depend on the loading order
PositionVisitor posVisitor ;
cell . forEach ( posVisitor ) ;
// do adjustPosition (snapping actors to ground) after objects are loaded, so we don't depend on the loading order
PositionVisitor posVisitor ;
cell . forEach ( posVisitor ) ;
}
}
void Scene : : addObjectToScene ( const Ptr & ptr )
{
try
{
addObject ( ptr , * mPhysics , mRendering , mPagedRefs );
addObject ( ptr , * mPhysics , mRendering , mPagedRefs , false );
addObject ( ptr , * mPhysics , mNavigator ) ;
MWBase : : Environment : : get ( ) . getWorld ( ) - > scaleObject ( ptr , ptr . getCellRef ( ) . getScale ( ) ) ;
const auto navigator = MWBase : : Environment : : get ( ) . getWorld ( ) - > getNavigator ( ) ;