2011-07-31 17:07:11 +02:00
# include "scene.hpp"
2015-06-03 23:04:35 +02:00
# include <limits>
2020-06-25 21:46:07 +02:00
# include <chrono>
# include <thread>
2021-07-11 14:43:52 +02:00
# include <atomic>
2013-08-19 20:30:22 +02:00
2018-03-14 01:49:08 +03:00
# include <BulletCollision/CollisionDispatch/btCollisionObject.h>
2018-07-12 11:44:11 +03:00
# include <BulletCollision/CollisionShapes/btCompoundShape.h>
2018-03-14 01:49:08 +03:00
2018-08-14 23:05:43 +04:00
# include <components/debug/debuglog.hpp>
2015-07-09 19:22:04 +02:00
# include <components/loadinglistener/loadinglistener.hpp>
2015-01-12 11:29:56 +01:00
# include <components/misc/resourcehelpers.hpp>
2015-04-01 17:02:15 +02:00
# include <components/settings/settings.hpp>
2015-04-22 19:08:56 +02:00
# include <components/resource/resourcesystem.hpp>
2017-02-15 00:55:35 +01:00
# include <components/resource/scenemanager.hpp>
2018-03-14 01:49:08 +03:00
# include <components/resource/bulletshape.hpp>
2019-11-24 17:40:19 +04:00
# include <components/sceneutil/unrefqueue.hpp>
2020-05-10 13:37:00 +00:00
# include <components/sceneutil/positionattitudetransform.hpp>
2018-03-14 01:49:08 +03:00
# include <components/detournavigator/navigator.hpp>
2018-04-21 14:56:04 +03:00
# include <components/detournavigator/debug.hpp>
2019-02-28 20:03:42 +00:00
# include <components/misc/convert.hpp>
2021-07-14 20:57:52 +02:00
# include <components/detournavigator/heightfieldshape.hpp>
2015-04-12 15:34:50 +02:00
2012-04-23 15:27:03 +02:00
# include "../mwbase/environment.hpp"
2014-10-02 16:30:23 +02:00
# include "../mwbase/world.hpp"
2012-08-09 14:33:21 +02:00
# include "../mwbase/soundmanager.hpp"
2012-08-11 17:30:55 +02:00
# include "../mwbase/mechanicsmanager.hpp"
2012-08-12 18:11:09 +02:00
# include "../mwbase/windowmanager.hpp"
2020-12-19 00:02:31 +01:00
# include "../mwbase/luamanager.hpp"
2012-03-10 16:05:12 +01:00
2015-04-12 15:34:50 +02:00
# include "../mwrender/renderingmanager.hpp"
2017-03-06 19:04:17 +01:00
# include "../mwrender/landmanager.hpp"
2015-04-12 15:34:50 +02:00
2015-05-10 01:09:00 +02:00
# include "../mwphysics/physicssystem.hpp"
2018-03-14 01:49:08 +03:00
# include "../mwphysics/actor.hpp"
# include "../mwphysics/object.hpp"
# include "../mwphysics/heightfield.hpp"
2015-05-10 01:09:00 +02:00
2011-07-31 17:07:11 +02:00
# include "player.hpp"
2012-07-03 12:30:50 +02:00
# include "localscripts.hpp"
2012-10-01 19:17:04 +04:00
# include "esmstore.hpp"
2013-01-05 21:12:08 -08:00
# include "class.hpp"
2015-12-06 18:13:04 +01:00
# include "cellvisitors.hpp"
2014-02-23 20:11:05 +01:00
# include "cellstore.hpp"
2016-02-07 00:36:31 +01:00
# include "cellpreloader.hpp"
2011-07-31 17:07:11 +02:00
2012-05-14 17:41:17 +02:00
namespace
2011-08-09 00:05:16 +02:00
{
2019-11-30 12:29:31 +01:00
using MWWorld : : RotationOrder ;
2018-08-26 23:27:38 +03:00
osg : : Quat makeActorOsgQuat ( const ESM : : Position & position )
{
return osg : : Quat ( position . rot [ 2 ] , osg : : Vec3 ( 0 , 0 , - 1 ) ) ;
}
osg : : Quat makeInversedOrderObjectOsgQuat ( const ESM : : Position & position )
{
const float xr = position . rot [ 0 ] ;
const float yr = position . rot [ 1 ] ;
const float zr = position . rot [ 2 ] ;
return osg : : Quat ( xr , osg : : Vec3 ( - 1 , 0 , 0 ) )
* osg : : Quat ( yr , osg : : Vec3 ( 0 , - 1 , 0 ) )
* osg : : Quat ( zr , osg : : Vec3 ( 0 , 0 , - 1 ) ) ;
}
2015-01-13 17:14:54 +01:00
2018-08-26 23:27:38 +03:00
osg : : Quat makeObjectOsgQuat ( const ESM : : Position & position )
{
const float xr = position . rot [ 0 ] ;
const float yr = position . rot [ 1 ] ;
const float zr = position . rot [ 2 ] ;
return osg : : Quat ( zr , osg : : Vec3 ( 0 , 0 , - 1 ) )
* osg : : Quat ( yr , osg : : Vec3 ( 0 , - 1 , 0 ) )
* osg : : Quat ( xr , osg : : Vec3 ( - 1 , 0 , 0 ) ) ;
}
2021-02-05 14:55:42 +01:00
osg : : Quat makeNodeRotation ( const MWWorld : : Ptr & ptr , RotationOrder order )
2017-02-04 15:12:01 +01:00
{
2021-02-05 14:55:42 +01:00
const auto pos = ptr . getRefData ( ) . getPosition ( ) ;
const auto rot = ptr . getClass ( ) . isActor ( ) ? makeActorOsgQuat ( pos )
: ( order = = RotationOrder : : inverse ? makeInversedOrderObjectOsgQuat ( pos ) : makeObjectOsgQuat ( pos ) ) ;
return rot ;
}
2021-01-23 10:43:32 +01:00
2021-02-05 14:55:42 +01:00
void setNodeRotation ( const MWWorld : : Ptr & ptr , MWRender : : RenderingManager & rendering , osg : : Quat rotation )
{
if ( ptr . getRefData ( ) . getBaseNode ( ) )
rendering . rotateObject ( ptr , rotation ) ;
2017-02-04 15:12:01 +01:00
}
2020-05-11 13:37:00 +00:00
std : : string getModel ( const MWWorld : : Ptr & ptr , const VFS : : Manager * vfs )
{
bool useAnim = ptr . getClass ( ) . useAnim ( ) ;
std : : string model = ptr . getClass ( ) . getModel ( ptr ) ;
if ( useAnim )
model = Misc : : ResourceHelpers : : correctActorModelPath ( model , vfs ) ;
const std : : string & id = ptr . getCellRef ( ) . getRefId ( ) ;
if ( id = = " prisonmarker " | | id = = " divinemarker " | | id = = " templemarker " | | id = = " northmarker " )
model = " " ; // marker objects that have a hardcoded function in the game logic, should be hidden from the player
return model ;
}
2015-05-10 01:09:00 +02:00
void addObject ( const MWWorld : : Ptr & ptr , MWPhysics : : PhysicsSystem & physics ,
2021-02-05 14:55:42 +01:00
MWRender : : RenderingManager & rendering , std : : set < ESM : : RefNum > & pagedRefs , bool onlyPhysics )
2015-01-13 17:14:54 +01:00
{
2017-06-28 22:40:13 +02:00
if ( ptr . getRefData ( ) . getBaseNode ( ) | | physics . getActor ( ptr ) )
{
2018-08-14 23:05:43 +04:00
Log ( Debug : : Warning ) < < " Warning: Tried to add " < < ptr . getCellRef ( ) . getRefId ( ) < < " to the scene twice " ;
2017-06-28 22:40:13 +02:00
return ;
}
2020-05-11 13:37:00 +00:00
std : : string model = getModel ( ptr , rendering . getResourceSystem ( ) - > getVFS ( ) ) ;
2021-02-05 14:55:42 +01:00
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 ;
}
2017-02-20 19:04:02 +01:00
2021-01-29 16:51:05 +04:00
const ESM : : RefNum & refnum = ptr . getCellRef ( ) . getRefNum ( ) ;
if ( ! refnum . hasContentFile ( ) | | pagedRefs . find ( refnum ) = = pagedRefs . end ( ) )
ptr . getClass ( ) . insertObjectRendering ( ptr , model , rendering ) ;
2021-01-29 16:51:13 +04:00
else
ptr . getRefData ( ) . setBaseNode ( new SceneUtil : : PositionAttitudeTransform ) ; // FIXME remove this when physics code is fixed not to depend on basenode
2021-02-05 14:55:42 +01:00
setNodeRotation ( ptr , rendering , rotation ) ;
2015-06-16 20:36:48 +02:00
2021-02-05 14:55:42 +01:00
if ( ptr . getClass ( ) . useAnim ( ) )
2021-01-29 16:51:05 +04:00
MWBase : : Environment : : get ( ) . getMechanicsManager ( ) - > add ( ptr ) ;
2017-02-20 19:04:02 +01:00
2021-01-29 16:51:05 +04:00
if ( ptr . getClass ( ) . isActor ( ) )
rendering . addWaterRippleEmitter ( ptr ) ;
2018-03-17 13:41:13 +04:00
2021-01-29 16:51:05 +04:00
// Restore effect particles
MWBase : : Environment : : get ( ) . getWorld ( ) - > applyLoopingParticles ( ptr ) ;
2021-02-05 14:55:42 +01:00
if ( ! physics . getObject ( ptr ) )
ptr . getClass ( ) . insertObject ( ptr , model , rotation , physics ) ;
2020-12-19 00:02:31 +01:00
MWBase : : Environment : : get ( ) . getLuaManager ( ) - > objectAddedToScene ( ptr ) ;
2015-01-13 17:14:54 +01:00
}
2018-08-26 23:27:38 +03:00
void addObject ( const MWWorld : : Ptr & ptr , const MWPhysics : : PhysicsSystem & physics , DetourNavigator : : Navigator & navigator )
{
if ( const auto object = physics . getObject ( ptr ) )
{
if ( ptr . getClass ( ) . isDoor ( ) & & ! ptr . getCellRef ( ) . getTeleport ( ) )
{
btVector3 aabbMin ;
btVector3 aabbMax ;
2021-08-01 02:13:55 +02:00
object - > getShapeInstance ( ) - > getCollisionShape ( ) - > getAabb ( btTransform : : getIdentity ( ) , aabbMin , aabbMax ) ;
2018-08-26 23:27:38 +03:00
const auto center = ( aabbMax + aabbMin ) * 0.5f ;
const auto distanceFromDoor = MWBase : : Environment : : get ( ) . getWorld ( ) - > getMaxActivationDistance ( ) * 0.5f ;
const auto toPoint = aabbMax . x ( ) - aabbMin . x ( ) < aabbMax . y ( ) - aabbMin . y ( )
? btVector3 ( distanceFromDoor , 0 , 0 )
: btVector3 ( 0 , distanceFromDoor , 0 ) ;
2020-10-14 15:55:15 +02:00
const auto transform = object - > getTransform ( ) ;
2018-08-26 23:27:38 +03:00
const btTransform closedDoorTransform (
2019-02-28 20:03:42 +00:00
Misc : : Convert : : toBullet ( makeObjectOsgQuat ( ptr . getCellRef ( ) . getPosition ( ) ) ) ,
2018-08-26 23:27:38 +03:00
transform . getOrigin ( )
) ;
2019-02-28 20:03:42 +00:00
const auto start = Misc : : Convert : : makeOsgVec3f ( closedDoorTransform ( center + toPoint ) ) ;
2018-08-26 23:27:38 +03:00
const auto startPoint = physics . castRay ( start , start - osg : : Vec3f ( 0 , 0 , 1000 ) , ptr , { } ,
MWPhysics : : CollisionType_World | MWPhysics : : CollisionType_HeightMap | MWPhysics : : CollisionType_Water ) ;
const auto connectionStart = startPoint . mHit ? startPoint . mHitPos : start ;
2019-02-28 20:03:42 +00:00
const auto end = Misc : : Convert : : makeOsgVec3f ( closedDoorTransform ( center - toPoint ) ) ;
2018-08-26 23:27:38 +03:00
const auto endPoint = physics . castRay ( end , end - osg : : Vec3f ( 0 , 0 , 1000 ) , ptr , { } ,
MWPhysics : : CollisionType_World | MWPhysics : : CollisionType_HeightMap | MWPhysics : : CollisionType_Water ) ;
const auto connectionEnd = endPoint . mHit ? endPoint . mHitPos : end ;
navigator . addObject (
2018-09-22 18:36:57 +03:00
DetourNavigator : : ObjectId ( object ) ,
2021-08-01 02:13:55 +02:00
DetourNavigator : : DoorShapes ( object - > getShapeInstance ( ) , connectionStart , connectionEnd ) ,
2018-08-26 23:27:38 +03:00
transform
) ;
}
else
{
navigator . addObject (
2018-09-22 18:36:57 +03:00
DetourNavigator : : ObjectId ( object ) ,
2021-08-01 02:13:55 +02:00
DetourNavigator : : ObjectShapes ( object - > getShapeInstance ( ) ) ,
2020-10-14 15:55:15 +02:00
object - > getTransform ( )
2018-08-26 23:27:38 +03:00
) ;
}
}
2019-03-03 14:58:03 +03:00
else if ( physics . getActor ( ptr ) )
2018-08-26 23:27:38 +03:00
{
2019-03-03 14:58:03 +03:00
navigator . addAgent ( MWBase : : Environment : : get ( ) . getWorld ( ) - > getPathfindingHalfExtents ( ptr ) ) ;
2018-08-26 23:27:38 +03:00
}
}
2015-12-06 18:13:04 +01:00
struct InsertVisitor
2014-02-23 21:21:27 +01:00
{
MWWorld : : CellStore & mCell ;
Loading : : Listener & mLoadingListener ;
2021-02-05 14:55:42 +01:00
bool mOnlyObjects ;
2019-11-24 17:40:19 +04:00
bool mTest ;
2014-02-23 21:21:27 +01:00
2016-02-05 18:29:33 +01:00
std : : vector < MWWorld : : Ptr > mToInsert ;
2021-02-05 14:55:42 +01:00
InsertVisitor ( MWWorld : : CellStore & cell , Loading : : Listener & loadingListener , bool onlyObjects , bool test ) ;
2014-02-23 21:21:27 +01:00
bool operator ( ) ( const MWWorld : : Ptr & ptr ) ;
2018-08-26 23:27:38 +03:00
template < class AddObject >
void insert ( AddObject & & addObject ) ;
2014-02-23 21:21:27 +01:00
} ;
2021-02-05 14:55:42 +01:00
InsertVisitor : : InsertVisitor ( MWWorld : : CellStore & cell , Loading : : Listener & loadingListener , bool onlyObjects , bool test )
: mCell ( cell ) , mLoadingListener ( loadingListener ) , mOnlyObjects ( onlyObjects ) , mTest ( test )
2014-02-23 21:21:27 +01:00
{ }
2015-12-06 18:13:04 +01:00
bool InsertVisitor : : operator ( ) ( const MWWorld : : Ptr & ptr )
2014-02-23 21:21:27 +01:00
{
2016-02-05 18:29:33 +01:00
// do not insert directly as we can't modify the cell from within the visitation
// CreatureLevList::insertObjectRendering may spawn a new creature
mToInsert . push_back ( ptr ) ;
return true ;
}
2014-02-23 21:21:27 +01:00
2018-08-26 23:27:38 +03:00
template < class AddObject >
void InsertVisitor : : insert ( AddObject & & addObject )
2016-02-05 18:29:33 +01:00
{
2019-03-07 12:38:55 +04:00
for ( MWWorld : : Ptr & ptr : mToInsert )
2014-02-23 21:21:27 +01:00
{
2021-02-05 14:55:42 +01:00
if ( ! ptr . getRefData ( ) . isDeleted ( ) & & ptr . getRefData ( ) . isEnabled ( ) & & ( ! mOnlyObjects | | ! ptr . getClass ( ) . isActor ( ) ) )
2014-02-23 21:21:27 +01:00
{
2016-02-05 18:29:33 +01:00
try
{
2018-08-26 23:27:38 +03:00
addObject ( ptr ) ;
2016-02-05 18:29:33 +01:00
}
catch ( const std : : exception & e )
{
2017-03-02 22:07:43 +01:00
std : : string error ( " failed to render ' " + ptr . getCellRef ( ) . getRefId ( ) + " ': " ) ;
2018-08-14 23:05:43 +04:00
Log ( Debug : : Error ) < < error + e . what ( ) ;
2016-02-05 18:29:33 +01:00
}
2014-02-23 21:21:27 +01:00
}
2019-11-24 17:40:19 +04:00
if ( ! mTest )
mLoadingListener . increaseProgress ( 1 ) ;
2016-02-05 18:29:33 +01:00
}
2014-02-23 21:21:27 +01:00
}
2015-12-04 19:46:02 +01:00
2020-01-13 20:12:44 +03:00
struct PositionVisitor
2015-12-04 19:46:02 +01:00
{
bool operator ( ) ( const MWWorld : : Ptr & ptr )
{
if ( ! ptr . getRefData ( ) . isDeleted ( ) & & ptr . getRefData ( ) . isEnabled ( ) )
2020-12-12 18:02:46 +01:00
ptr . getClass ( ) . adjustPosition ( ptr , false ) ;
2015-12-04 19:46:02 +01:00
return true ;
}
} ;
2018-04-01 16:54:10 +03:00
int getCellPositionDistanceToOrigin ( const std : : pair < int , int > & cellPosition )
{
return std : : abs ( cellPosition . first ) + std : : abs ( cellPosition . second ) ;
}
2021-02-05 14:55:42 +01:00
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 ;
}
2011-08-09 00:05:16 +02:00
}
2011-07-31 17:07:11 +02:00
namespace MWWorld
{
2012-03-18 21:31:31 -04:00
2020-05-11 13:37:00 +00:00
void Scene : : removeFromPagedRefs ( const Ptr & ptr )
{
const ESM : : RefNum & refnum = ptr . getCellRef ( ) . getRefNum ( ) ;
if ( refnum . hasContentFile ( ) & & mPagedRefs . erase ( refnum ) )
{
if ( ! ptr . getRefData ( ) . getBaseNode ( ) ) return ;
ptr . getClass ( ) . insertObjectRendering ( ptr , getModel ( ptr , mRendering . getResourceSystem ( ) - > getVFS ( ) ) , mRendering ) ;
2021-02-05 14:55:42 +01:00
setNodeRotation ( ptr , mRendering , makeNodeRotation ( ptr , RotationOrder : : direct ) ) ;
2020-05-11 13:37:00 +00:00
reloadTerrain ( ) ;
}
}
void Scene : : updateObjectPosition ( const Ptr & ptr , const osg : : Vec3f & pos , bool movePhysics )
{
mRendering . moveObject ( ptr , pos ) ;
if ( movePhysics )
{
mPhysics - > updatePosition ( ptr ) ;
}
}
void Scene : : updateObjectRotation ( const Ptr & ptr , RotationOrder order )
2014-06-14 17:56:41 +02:00
{
2021-02-05 14:55:42 +01:00
const auto rot = makeNodeRotation ( ptr , order ) ;
setNodeRotation ( ptr , mRendering , rot ) ;
mPhysics - > updateRotation ( ptr , rot ) ;
2014-06-14 17:56:41 +02:00
}
2015-04-24 14:49:20 +02:00
void Scene : : updateObjectScale ( const Ptr & ptr )
{
2020-05-11 13:37:00 +00:00
float scale = ptr . getCellRef ( ) . getScale ( ) ;
osg : : Vec3f scaleVec ( scale , scale , scale ) ;
ptr . getClass ( ) . adjustScale ( ptr , scaleVec , true ) ;
mRendering . scaleObject ( ptr , scaleVec ) ;
mPhysics - > updateScale ( ptr ) ;
2015-04-24 14:49:20 +02:00
}
2014-05-11 15:17:25 +02:00
void Scene : : update ( float duration , bool paused )
{
2020-05-12 13:37:00 +00:00
mPreloader - > updateCache ( mRendering . getReferenceTime ( ) ) ;
2020-05-12 13:37:00 +00:00
preloadCells ( duration ) ;
2016-02-07 05:13:46 -08:00
2015-04-19 01:57:52 +02:00
mRendering . update ( duration , paused ) ;
2011-12-26 19:23:46 -05:00
}
2012-03-18 21:31:31 -04:00
2021-02-05 14:55:42 +01:00
void Scene : : unloadInactiveCell ( CellStore * cell , bool test )
{
assert ( mActiveCells . find ( cell ) = = mActiveCells . end ( ) ) ;
assert ( mInactiveCells . find ( cell ) ! = mInactiveCells . end ( ) ) ;
if ( ! test )
Log ( Debug : : Info ) < < " Unloading cell " < < cell - > getCell ( ) - > getDescription ( ) ;
ListObjectsVisitor visitor ;
cell - > forEach ( visitor ) ;
for ( const auto & ptr : visitor . mObjects )
2021-03-05 22:21:53 +01:00
{
2021-02-05 14:55:42 +01:00
mPhysics - > remove ( ptr ) ;
2021-03-05 22:21:53 +01:00
ptr . mRef - > mData . mPhysicsPostponed = false ;
}
2021-02-05 14:55:42 +01:00
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 )
2011-07-31 17:07:11 +02:00
{
2021-02-05 14:55:42 +01:00
assert ( mInactiveCells . find ( cell ) ! = mInactiveCells . end ( ) ) ;
if ( mActiveCells . find ( cell ) = = mActiveCells . end ( ) )
return ;
2019-11-24 17:40:19 +04:00
if ( ! test )
2021-02-05 14:55:42 +01:00
Log ( Debug : : Info ) < < " Deactivate cell " < < cell - > getCell ( ) - > getDescription ( ) ;
2018-03-14 01:49:08 +03:00
2015-12-06 18:13:04 +01:00
ListAndResetObjectsVisitor visitor ;
2013-03-10 10:00:20 +01:00
2021-02-05 14:55:42 +01:00
cell - > forEach ( visitor ) ;
2019-03-03 14:58:03 +03:00
const auto world = MWBase : : Environment : : get ( ) . getWorld ( ) ;
2018-03-14 01:49:08 +03:00
for ( const auto & ptr : visitor . mObjects )
2011-11-21 12:52:28 +01:00
{
2018-03-14 01:49:08 +03:00
if ( const auto object = mPhysics - > getObject ( ptr ) )
2021-02-05 14:55:42 +01:00
{
2021-06-29 20:12:22 +02:00
mNavigator . removeObject ( DetourNavigator : : ObjectId ( object ) ) ;
2021-02-05 14:55:42 +01:00
if ( object - > isAnimated ( ) )
mPhysics - > remove ( ptr ) ;
}
2019-03-10 14:24:03 +03:00
else if ( mPhysics - > getActor ( ptr ) )
2018-07-21 13:37:02 +03:00
{
2021-06-29 20:12:22 +02:00
mNavigator . removeAgent ( world - > getPathfindingHalfExtents ( ptr ) ) ;
2018-07-21 13:37:02 +03:00
mRendering . removeActorPath ( ptr ) ;
2021-02-05 14:55:42 +01:00
mPhysics - > remove ( ptr ) ;
2018-07-21 13:37:02 +03:00
}
2020-12-19 00:02:31 +01:00
MWBase : : Environment : : get ( ) . getLuaManager ( ) - > objectRemovedFromScene ( ptr ) ;
2013-04-17 17:05:54 +02:00
}
2012-03-13 17:09:50 +01:00
2021-02-05 14:55:42 +01:00
const auto cellX = cell - > getCell ( ) - > getGridX ( ) ;
const auto cellY = cell - > getCell ( ) - > getGridY ( ) ;
2018-07-20 22:11:34 +03:00
2021-02-05 14:55:42 +01:00
if ( cell - > getCell ( ) - > isExterior ( ) )
2013-04-17 17:05:54 +02:00
{
2021-07-27 20:08:36 +02:00
if ( mPhysics - > getHeightField ( cellX , cellY ) ! = nullptr )
mNavigator . removeHeightfield ( osg : : Vec2i ( cellX , cellY ) ) ;
2011-11-19 01:01:19 -05:00
}
2012-03-18 21:31:31 -04:00
2021-02-05 14:55:42 +01:00
if ( cell - > getCell ( ) - > hasWater ( ) )
2021-06-29 20:12:22 +02:00
mNavigator . removeWater ( osg : : Vec2i ( cellX , cellY ) ) ;
2018-07-20 22:11:34 +03:00
2021-02-05 14:55:42 +01:00
if ( const auto pathgrid = world - > getStore ( ) . get < ESM : : Pathgrid > ( ) . search ( * cell - > getCell ( ) ) )
2021-06-29 20:12:22 +02:00
mNavigator . removePathgrid ( * pathgrid ) ;
2020-06-11 23:23:30 +02:00
2019-03-03 14:58:03 +03:00
const auto player = world - > getPlayerPtr ( ) ;
2021-06-29 20:12:22 +02:00
mNavigator . update ( player . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) ;
2018-04-21 15:27:25 +03:00
2021-02-05 14:55:42 +01:00
MWBase : : Environment : : get ( ) . getMechanicsManager ( ) - > drop ( cell ) ;
2015-05-22 00:55:43 +02:00
2021-02-05 14:55:42 +01:00
mRendering . removeCell ( cell ) ;
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > removeCell ( cell ) ;
2012-01-23 14:33:06 +01:00
2021-02-05 14:55:42 +01:00
MWBase : : Environment : : get ( ) . getWorld ( ) - > getLocalScripts ( ) . clearCell ( cell ) ;
2013-11-30 10:50:02 +01:00
2021-02-05 14:55:42 +01:00
MWBase : : Environment : : get ( ) . getSoundManager ( ) - > stopSound ( cell ) ;
mActiveCells . erase ( cell ) ;
2011-07-31 17:07:11 +02:00
}
2011-08-01 03:33:02 +02:00
2021-02-05 14:55:42 +01:00
void Scene : : activateCell ( CellStore * cell , Loading : : Listener * loadingListener , bool respawn , bool test )
2011-07-31 17:07:11 +02:00
{
2021-07-14 20:57:52 +02:00
using DetourNavigator : : HeightfieldShape ;
2021-02-05 14:55:42 +01:00
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 ( ) ;
const auto world = MWBase : : Environment : : get ( ) . getWorld ( ) ;
const int cellX = cell - > getCell ( ) - > getGridX ( ) ;
const int cellY = cell - > getCell ( ) - > getGridY ( ) ;
2011-11-21 12:52:28 +01:00
2021-02-05 14:55:42 +01:00
if ( ! test & & cell - > getCell ( ) - > isExterior ( ) )
2012-03-13 17:09:50 +01:00
{
2021-02-05 14:55:42 +01:00
if ( const auto heightField = mPhysics - > getHeightField ( cellX , cellY ) )
2021-07-14 20:57:52 +02:00
{
const osg : : Vec2i cellPosition ( cellX , cellY ) ;
const btVector3 & origin = heightField - > getCollisionObject ( ) - > getWorldTransform ( ) . getOrigin ( ) ;
const osg : : Vec3f shift ( origin . x ( ) , origin . y ( ) , origin . z ( ) ) ;
const osg : : ref_ptr < const ESMTerrain : : LandObject > land = mRendering . getLandManager ( ) - > getLand ( cellX , cellY ) ;
const ESM : : Land : : LandData * const data = land = = nullptr ? nullptr : land - > getData ( ESM : : Land : : DATA_VHGT ) ;
const HeightfieldShape shape = [ & ] ( ) - > HeightfieldShape
{
if ( data = = nullptr )
{
return DetourNavigator : : HeightfieldPlane { static_cast < float > ( ESM : : Land : : DEFAULT_HEIGHT ) } ;
}
else
{
DetourNavigator : : HeightfieldSurface heights ;
heights . mHeights = data - > mHeights ;
heights . mSize = static_cast < std : : size_t > ( ESM : : Land : : LAND_SIZE ) ;
heights . mMinHeight = data - > mMinHeight ;
heights . mMaxHeight = data - > mMaxHeight ;
return heights ;
}
} ( ) ;
mNavigator . addHeightfield ( cellPosition , ESM : : Land : : REAL_SIZE , shift , shape ) ;
}
2021-02-05 14:55:42 +01:00
}
2012-03-13 17:09:50 +01:00
2021-02-05 14:55:42 +01:00
if ( const auto pathgrid = world - > getStore ( ) . get < ESM : : Pathgrid > ( ) . search ( * cell - > getCell ( ) ) )
2021-06-29 20:12:22 +02:00
mNavigator . addPathgrid ( * cell - > getCell ( ) , * pathgrid ) ;
2018-03-14 01:49:08 +03:00
2021-02-05 14:55:42 +01:00
// 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 ) ;
2018-07-20 22:11:34 +03:00
2021-02-05 14:55:42 +01:00
if ( respawn )
cell - > respawn ( ) ;
insertCell ( * cell , loadingListener , false , test ) ;
2021-01-23 20:59:24 +01:00
2021-02-05 14:55:42 +01:00
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 )
2012-03-28 22:46:29 +02:00
{
2021-02-05 14:55:42 +01:00
mPhysics - > enableWater ( waterLevel ) ;
mRendering . setWaterHeight ( waterLevel ) ;
if ( cell - > getCell ( ) - > isExterior ( ) )
2017-03-06 19:04:17 +01:00
{
2021-02-05 14:55:42 +01:00
if ( const auto heightField = mPhysics - > getHeightField ( cellX , cellY ) )
2021-07-14 21:54:41 +02:00
{
const btTransform & transform = heightField - > getCollisionObject ( ) - > getWorldTransform ( ) ;
2021-06-29 20:12:22 +02:00
mNavigator . addWater ( osg : : Vec2i ( cellX , cellY ) , ESM : : Land : : REAL_SIZE ,
2021-07-14 21:54:41 +02:00
osg : : Vec3f ( static_cast < float > ( transform . getOrigin ( ) . x ( ) ) ,
static_cast < float > ( transform . getOrigin ( ) . y ( ) ) ,
waterLevel ) ) ;
}
2012-11-05 16:07:59 +04:00
}
2016-02-28 16:47:41 +01:00
else
{
2021-06-29 20:12:22 +02:00
mNavigator . addWater ( osg : : Vec2i ( cellX , cellY ) , std : : numeric_limits < int > : : max ( ) ,
2021-07-14 21:54:41 +02:00
osg : : Vec3f ( 0 , 0 , waterLevel ) ) ;
2016-02-28 16:47:41 +01:00
}
2012-03-28 22:46:29 +02:00
}
2021-02-05 14:55:42 +01:00
else
mPhysics - > disableWater ( ) ;
2012-03-28 21:46:52 +02:00
2021-02-05 14:55:42 +01:00
const auto player = MWBase : : Environment : : get ( ) . getWorld ( ) - > getPlayerPtr ( ) ;
2016-02-05 18:29:33 +01:00
2021-06-29 20:12:22 +02:00
mNavigator . update ( player . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) ;
2013-04-04 16:51:22 +02:00
2021-02-05 14:55:42 +01:00
if ( ! cell - > isExterior ( ) & & ! ( cell - > getCell ( ) - > mData . mFlags & ESM : : Cell : : QuasiEx ) )
mRendering . configureAmbient ( cell - > getCell ( ) ) ;
}
2019-11-24 17:40:19 +04:00
2021-02-05 14:55:42 +01:00
mPreloader - > notifyLoaded ( cell ) ;
}
2019-11-24 17:40:19 +04:00
2021-02-05 14:55:42 +01:00
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 ) ;
2019-11-24 17:40:19 +04:00
2021-02-05 14:55:42 +01:00
if ( test )
Log ( Debug : : Info ) < < " Testing inactive cell " < < cell - > getCell ( ) - > getDescription ( ) ;
else
Log ( Debug : : Info ) < < " Loading inactive cell " < < cell - > getCell ( ) - > getDescription ( ) ;
2021-03-14 13:40:48 +01:00
2021-02-05 14:55:42 +01:00
if ( ! test & & cell - > getCell ( ) - > isExterior ( ) )
{
float verts = ESM : : Land : : LAND_SIZE ;
float worldsize = ESM : : Land : : REAL_SIZE ;
2021-03-14 02:39:18 +01:00
2021-02-05 14:55:42 +01:00
const int cellX = cell - > getCell ( ) - > getGridX ( ) ;
const int cellY = cell - > getCell ( ) - > getGridY ( ) ;
2019-11-24 17:40:19 +04:00
2021-02-05 14:55:42 +01:00
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 ( ) ) ;
2014-10-05 22:24:11 +02:00
}
2011-07-31 17:07:11 +02:00
}
2016-02-09 18:33:02 +01:00
2021-02-05 14:55:42 +01:00
insertCell ( * cell , loadingListener , true , test ) ;
2011-07-31 17:07:11 +02:00
}
2011-08-01 03:33:02 +02:00
2017-02-09 04:03:38 +01:00
void Scene : : clear ( )
2013-05-15 17:54:18 +02:00
{
2021-02-05 14:55:42 +01:00
for ( auto iter = mInactiveCells . begin ( ) ; iter ! = mInactiveCells . end ( ) ; )
{
auto * cell = * iter + + ;
deactivateCell ( cell ) ;
unloadInactiveCell ( cell ) ;
}
2013-05-15 17:54:18 +02:00
assert ( mActiveCells . empty ( ) ) ;
2021-02-05 14:55:42 +01:00
assert ( mInactiveCells . empty ( ) ) ;
2018-10-09 10:21:12 +04:00
mCurrentCell = nullptr ;
2017-02-09 04:03:38 +01:00
mPreloader - > clear ( ) ;
2013-05-15 17:54:18 +02:00
}
2019-06-13 13:37:00 +00:00
osg : : Vec4i Scene : : gridCenterToBounds ( const osg : : Vec2i & centerCell ) const
{
return osg : : Vec4i ( centerCell . x ( ) - mHalfGridSize , centerCell . y ( ) - mHalfGridSize , centerCell . x ( ) + mHalfGridSize + 1 , centerCell . y ( ) + mHalfGridSize + 1 ) ;
}
osg : : Vec2i Scene : : getNewGridCenter ( const osg : : Vec3f & pos , const osg : : Vec2i * currentGridCenter ) const
{
if ( currentGridCenter )
{
float centerX , centerY ;
MWBase : : Environment : : get ( ) . getWorld ( ) - > indexToPosition ( currentGridCenter - > x ( ) , currentGridCenter - > y ( ) , centerX , centerY , true ) ;
2020-04-30 13:37:00 +00:00
float distance = std : : max ( std : : abs ( centerX - pos . x ( ) ) , std : : abs ( centerY - pos . y ( ) ) ) ;
2019-06-13 13:37:00 +00:00
const float maxDistance = Constants : : CellSizeInUnits / 2 + mCellLoadingThreshold ; // 1/2 cell size + threshold
if ( distance < = maxDistance )
return * currentGridCenter ;
}
osg : : Vec2i newCenter ;
MWBase : : Environment : : get ( ) . getWorld ( ) - > positionToIndex ( pos . x ( ) , pos . y ( ) , newCenter . x ( ) , newCenter . y ( ) ) ;
return newCenter ;
}
2015-04-12 15:34:50 +02:00
void Scene : : playerMoved ( const osg : : Vec3f & pos )
2014-10-02 16:30:23 +02:00
{
2018-04-21 02:57:01 +03:00
const auto player = MWBase : : Environment : : get ( ) . getWorld ( ) - > getPlayerPtr ( ) ;
2021-06-29 20:12:22 +02:00
mNavigator . updatePlayerPosition ( player . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) ;
2018-04-21 02:57:01 +03:00
2014-10-02 16:30:23 +02:00
if ( ! mCurrentCell | | ! mCurrentCell - > isExterior ( ) )
return ;
2019-06-13 13:37:00 +00:00
osg : : Vec2i newCell = getNewGridCenter ( pos , & mCurrentGridCenter ) ;
if ( newCell ! = mCurrentGridCenter )
2020-05-12 13:37:00 +00:00
changeCellGrid ( pos , newCell . x ( ) , newCell . y ( ) ) ;
2014-10-02 16:30:23 +02:00
}
2020-05-12 13:37:00 +00:00
void Scene : : changeCellGrid ( const osg : : Vec3f & pos , int playerCellX , int playerCellY , bool changeEvent )
2011-07-31 17:07:11 +02:00
{
2021-02-05 14:55:42 +01:00
for ( auto iter = mInactiveCells . begin ( ) ; iter ! = mInactiveCells . end ( ) ; )
2011-07-31 17:07:11 +02:00
{
2021-02-05 14:55:42 +01:00
auto * cell = * iter + + ;
if ( cell - > getCell ( ) - > isExterior ( ) )
2021-01-23 20:59:24 +01:00
{
2021-02-05 14:55:42 +01:00
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 ) ;
2011-07-31 17:07:11 +02:00
}
}
2020-05-10 13:37:00 +00:00
mCurrentGridCenter = osg : : Vec2i ( playerCellX , playerCellY ) ;
osg : : Vec4i newGrid = gridCenterToBounds ( mCurrentGridCenter ) ;
mRendering . setActiveGrid ( newGrid ) ;
2020-05-12 13:37:00 +00:00
preloadTerrain ( pos , true ) ;
2020-05-10 13:37:00 +00:00
mPagedRefs . clear ( ) ;
mRendering . getPagedRefnums ( newGrid , mPagedRefs ) ;
2018-04-01 16:48:25 +03:00
std : : size_t refsToLoad = 0 ;
2021-02-05 14:55:42 +01:00
const auto cellsToLoad = [ & playerCellX , & playerCellY , & refsToLoad ] ( CellStoreCollection & collection , int range ) - > std : : vector < std : : pair < int , int > >
2014-10-02 16:30:23 +02:00
{
2021-02-05 14:55:42 +01:00
std : : vector < std : : pair < int , int > > cellsPositionsToLoad ;
for ( int x = playerCellX - range ; x < = playerCellX + range ; + + x )
2012-09-11 16:37:54 +02:00
{
2021-02-05 14:55:42 +01:00
for ( int y = playerCellY - range ; y < = playerCellY + range ; + + y )
2021-01-29 16:51:05 +04:00
{
2021-02-05 14:55:42 +01:00
if ( ! isCellInCollection ( x , y , collection ) )
{
refsToLoad + = MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( x , y ) - > count ( ) ;
cellsPositionsToLoad . emplace_back ( x , y ) ;
}
2018-04-01 16:54:10 +03:00
}
2012-09-11 16:37:54 +02:00
}
2021-02-05 14:55:42 +01:00
return cellsPositionsToLoad ;
} ;
2021-03-05 22:21:53 +01:00
for ( const auto & cell : mActiveCells )
{
cell - > forEach ( [ & ] ( const MWWorld : : Ptr & ptr )
{
if ( ptr . mRef - > mData . mPhysicsPostponed )
{
ptr . mRef - > mData . mPhysicsPostponed = false ;
if ( ptr . mRef - > mData . isEnabled ( ) & & ptr . mRef - > mData . getCount ( ) > 0 ) {
std : : string model = getModel ( ptr , MWBase : : Environment : : get ( ) . getResourceSystem ( ) - > getVFS ( ) ) ;
const auto rotation = makeNodeRotation ( ptr , RotationOrder : : direct ) ;
ptr . getClass ( ) . insertObjectPhysics ( ptr , model , rotation , * mPhysics ) ;
}
}
return true ;
} ) ;
}
2021-02-05 14:55:42 +01:00
auto cellsPositionsToLoad = cellsToLoad ( mActiveCells , mHalfGridSize ) ;
auto cellsPositionsToLoadInactive = cellsToLoad ( mInactiveCells , mHalfGridSize + 1 ) ;
2012-09-11 16:37:54 +02:00
2020-05-10 13:37:00 +00:00
Loading : : Listener * loadingListener = MWBase : : Environment : : get ( ) . getWindowManager ( ) - > getLoadingScreen ( ) ;
Loading : : ScopedLoad load ( loadingListener ) ;
std : : string loadingExteriorText = " #{sLoadingMessage3} " ;
2021-05-26 23:19:22 +02:00
loadingListener - > setLabel ( loadingExteriorText ) ;
2013-08-27 15:48:13 +02:00
loadingListener - > setProgressRange ( refsToLoad ) ;
2018-04-01 16:54:10 +03:00
const auto getDistanceToPlayerCell = [ & ] ( const std : : pair < int , int > & cellPosition )
{
return std : : abs ( cellPosition . first - playerCellX ) + std : : abs ( cellPosition . second - playerCellY ) ;
} ;
const auto getCellPositionPriority = [ & ] ( const std : : pair < int , int > & cellPosition )
{
return std : : make_pair ( getDistanceToPlayerCell ( cellPosition ) , getCellPositionDistanceToOrigin ( cellPosition ) ) ;
} ;
std : : sort ( cellsPositionsToLoad . begin ( ) , cellsPositionsToLoad . end ( ) ,
[ & ] ( const std : : pair < int , int > & lhs , const std : : pair < int , int > & rhs ) {
return getCellPositionPriority ( lhs ) < getCellPositionPriority ( rhs ) ;
} ) ;
2021-02-05 14:55:42 +01:00
std : : sort ( cellsPositionsToLoadInactive . begin ( ) , cellsPositionsToLoadInactive . end ( ) ,
[ & ] ( const std : : pair < int , int > & lhs , const std : : pair < int , int > & rhs ) {
return getCellPositionPriority ( lhs ) < getCellPositionPriority ( rhs ) ;
} ) ;
2011-07-31 17:07:11 +02:00
// Load cells
2021-02-05 14:55:42 +01:00
for ( const auto & [ x , y ] : cellsPositionsToLoadInactive )
2014-10-02 16:30:23 +02:00
{
2021-02-05 14:55:42 +01:00
if ( ! isCellInCollection ( x , y , mInactiveCells ) )
2018-04-01 16:54:10 +03:00
{
2021-02-05 14:55:42 +01:00
CellStore * cell = MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( x , y ) ;
loadInactiveCell ( cell , loadingListener ) ;
2018-04-01 16:54:10 +03:00
}
2021-02-05 14:55:42 +01:00
}
for ( const auto & [ x , y ] : cellsPositionsToLoad )
{
if ( ! isCellInCollection ( x , y , mActiveCells ) )
2018-04-01 16:54:10 +03:00
{
CellStore * cell = MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( x , y ) ;
2021-02-05 14:55:42 +01:00
activateCell ( cell , loadingListener , changeEvent ) ;
2011-07-31 17:07:11 +02:00
}
2014-10-02 16:30:23 +02:00
}
2011-07-31 17:07:11 +02:00
2018-04-01 16:54:10 +03:00
CellStore * current = MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( playerCellX , playerCellY ) ;
2014-10-02 16:30:23 +02:00
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > changeCell ( current ) ;
2011-07-31 17:07:11 +02:00
2016-02-27 12:53:07 +01:00
if ( changeEvent )
mCellChanged = true ;
2021-05-05 19:23:07 +02:00
2021-05-14 21:06:29 +02:00
mNavigator . wait ( * loadingListener , DetourNavigator : : WaitConditionType : : requiredTilesPresent ) ;
2014-10-02 16:30:23 +02:00
}
2011-07-31 17:07:11 +02:00
2019-11-24 17:40:19 +04:00
void Scene : : testExteriorCells ( )
{
// Note: temporary disable ICO to decrease memory usage
mRendering . getResourceSystem ( ) - > getSceneManager ( ) - > setIncrementalCompileOperation ( nullptr ) ;
mRendering . getResourceSystem ( ) - > setExpiryDelay ( 1.f ) ;
const MWWorld : : Store < ESM : : Cell > & cells = MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) . get < ESM : : Cell > ( ) ;
Loading : : Listener * loadingListener = MWBase : : Environment : : get ( ) . getWindowManager ( ) - > getLoadingScreen ( ) ;
Loading : : ScopedLoad load ( loadingListener ) ;
loadingListener - > setProgressRange ( cells . getExtSize ( ) ) ;
MWWorld : : Store < ESM : : Cell > : : iterator it = cells . extBegin ( ) ;
int i = 1 ;
for ( ; it ! = cells . extEnd ( ) ; + + it )
{
loadingListener - > setLabel ( " Testing exterior cells ( " + std : : to_string ( i ) + " / " + std : : to_string ( cells . getExtSize ( ) ) + " )... " ) ;
CellStoreCollection : : iterator iter = mActiveCells . begin ( ) ;
CellStore * cell = MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( it - > mData . mX , it - > mData . mY ) ;
2021-02-05 14:55:42 +01:00
loadInactiveCell ( cell , loadingListener , true ) ;
activateCell ( cell , loadingListener , false , true ) ;
2019-11-24 17:40:19 +04:00
iter = mActiveCells . begin ( ) ;
while ( iter ! = mActiveCells . end ( ) )
{
if ( it - > isExterior ( ) & & it - > mData . mX = = ( * iter ) - > getCell ( ) - > getGridX ( ) & &
it - > mData . mY = = ( * iter ) - > getCell ( ) - > getGridY ( ) )
{
2021-02-05 14:55:42 +01:00
deactivateCell ( * iter , true ) ;
unloadInactiveCell ( * iter , true ) ;
2019-11-24 17:40:19 +04:00
break ;
}
+ + iter ;
}
mRendering . getResourceSystem ( ) - > updateCache ( mRendering . getReferenceTime ( ) ) ;
mRendering . getUnrefQueue ( ) - > flush ( mRendering . getWorkQueue ( ) ) ;
loadingListener - > increaseProgress ( 1 ) ;
i + + ;
}
mRendering . getResourceSystem ( ) - > getSceneManager ( ) - > setIncrementalCompileOperation ( mRendering . getIncrementalCompileOperation ( ) ) ;
mRendering . getResourceSystem ( ) - > setExpiryDelay ( Settings : : Manager : : getFloat ( " cache expiry delay " , " Cells " ) ) ;
}
void Scene : : testInteriorCells ( )
{
// Note: temporary disable ICO to decrease memory usage
mRendering . getResourceSystem ( ) - > getSceneManager ( ) - > setIncrementalCompileOperation ( nullptr ) ;
mRendering . getResourceSystem ( ) - > setExpiryDelay ( 1.f ) ;
const MWWorld : : Store < ESM : : Cell > & cells = MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) . get < ESM : : Cell > ( ) ;
Loading : : Listener * loadingListener = MWBase : : Environment : : get ( ) . getWindowManager ( ) - > getLoadingScreen ( ) ;
Loading : : ScopedLoad load ( loadingListener ) ;
loadingListener - > setProgressRange ( cells . getIntSize ( ) ) ;
int i = 1 ;
MWWorld : : Store < ESM : : Cell > : : iterator it = cells . intBegin ( ) ;
for ( ; it ! = cells . intEnd ( ) ; + + it )
{
loadingListener - > setLabel ( " Testing interior cells ( " + std : : to_string ( i ) + " / " + std : : to_string ( cells . getIntSize ( ) ) + " )... " ) ;
CellStore * cell = MWBase : : Environment : : get ( ) . getWorld ( ) - > getInterior ( it - > mName ) ;
2021-02-05 14:55:42 +01:00
loadInactiveCell ( cell , loadingListener , true ) ;
activateCell ( cell , loadingListener , false , true ) ;
2019-11-24 17:40:19 +04:00
CellStoreCollection : : iterator iter = mActiveCells . begin ( ) ;
while ( iter ! = mActiveCells . end ( ) )
{
assert ( ! ( * iter ) - > getCell ( ) - > isExterior ( ) ) ;
if ( it - > mName = = ( * iter ) - > getCell ( ) - > mName )
{
2021-02-05 14:55:42 +01:00
deactivateCell ( * iter , true ) ;
unloadInactiveCell ( * iter , true ) ;
2019-11-24 17:40:19 +04:00
break ;
}
+ + iter ;
}
mRendering . getResourceSystem ( ) - > updateCache ( mRendering . getReferenceTime ( ) ) ;
mRendering . getUnrefQueue ( ) - > flush ( mRendering . getWorkQueue ( ) ) ;
loadingListener - > increaseProgress ( 1 ) ;
i + + ;
}
mRendering . getResourceSystem ( ) - > getSceneManager ( ) - > setIncrementalCompileOperation ( mRendering . getIncrementalCompileOperation ( ) ) ;
mRendering . getResourceSystem ( ) - > setExpiryDelay ( Settings : : Manager : : getFloat ( " cache expiry delay " , " Cells " ) ) ;
}
2014-10-02 16:30:23 +02:00
void Scene : : changePlayerCell ( CellStore * cell , const ESM : : Position & pos , bool adjustPlayerPos )
{
mCurrentCell = cell ;
2011-07-31 17:07:11 +02:00
2017-03-09 02:17:25 +01:00
mRendering . enableTerrain ( cell - > isExterior ( ) ) ;
2014-10-02 16:30:23 +02:00
MWBase : : World * world = MWBase : : Environment : : get ( ) . getWorld ( ) ;
MWWorld : : Ptr old = world - > getPlayerPtr ( ) ;
world - > getPlayer ( ) . setCell ( cell ) ;
2011-07-31 17:07:11 +02:00
2014-10-02 16:30:23 +02:00
MWWorld : : Ptr player = world - > getPlayerPtr ( ) ;
2015-05-21 23:54:39 +02:00
mRendering . updatePlayerPtr ( player ) ;
2011-07-31 17:07:11 +02:00
2014-10-02 16:30:23 +02:00
if ( adjustPlayerPos ) {
2021-04-11 18:18:10 +02:00
world - > moveObject ( player , pos . asVec3 ( ) ) ;
2021-04-11 19:17:17 +02:00
world - > rotateObject ( player , pos . asRotationVec3 ( ) ) ;
2011-07-31 17:07:11 +02:00
Some PVS-Studio and cppcheck fixes
cppcheck:
[apps/esmtool/record.cpp:697]: (performance) Prefer prefix ++/-- operators for non-primitive types.
[apps/esmtool/record.cpp:1126]: (performance) Prefer prefix ++/-- operators for non-primitive types.
[apps/esmtool/record.cpp:1138]: (performance) Prefer prefix ++/-- operators for non-primitive types.
[apps/niftest/niftest.cpp:36]: (performance) Function parameter 'filename' should be passed by reference.
[apps/niftest/niftest.cpp:41]: (performance) Function parameter 'filename' should be passed by reference.
[apps/opencs/model/prefs/boolsetting.cpp:25]: (warning) Possible leak in public function. The pointer 'mWidget' is not deallocated before it is allocated.
[apps/opencs/model/prefs/shortcuteventhandler.cpp:52]: (warning) Return value of std::remove() ignored. Elements remain in container.
[apps/openmw/mwstate/quicksavemanager.cpp:5]: (performance) Variable 'mSaveName' is assigned in constructor body. Consider performing initialization in initialization list.
PVS-Studio:
apps/opencs/model/filter/parser.cpp 582 warn V560 A part of conditional expression is always true: allowPredefined.
apps/opencs/view/world/referencecreator.cpp 67 warn V547 Expression '!errors.empty()' is always false.
apps/opencs/view/world/referencecreator.cpp 74 warn V547 Expression '!errors.empty()' is always false.
apps/opencs/view/doc/loader.cpp 170 warn V560 A part of conditional expression is always true: !completed.
apps/opencs/view/doc/loader.cpp 170 warn V560 A part of conditional expression is always true: !error.empty().
apps/opencs/model/tools/pathgridcheck.cpp 32 err V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 32, 34.
apps/opencs/model/world/refidadapterimp.cpp 1376 err V547 Expression 'subColIndex < 3' is always true.
apps/openmw/mwgui/widgets.hpp 318 warn V703 It is odd that the 'mEnableRepeat' field in derived class 'MWScrollBar' overwrites field in base class 'ScrollBar'. Check lines: widgets.hpp:318, MyGUI_ScrollBar.h:179.
apps/openmw/mwgui/widgets.hpp 319 warn V703 It is odd that the 'mRepeatTriggerTime' field in derived class 'MWScrollBar' overwrites field in base class 'ScrollBar'. Check lines: widgets.hpp:319, MyGUI_ScrollBar.h:180.
apps/openmw/mwgui/widgets.hpp 320 warn V703 It is odd that the 'mRepeatStepTime' field in derived class 'MWScrollBar' overwrites field in base class 'ScrollBar'. Check lines: widgets.hpp:320, MyGUI_ScrollBar.h:181
apps/openmw/mwmechanics/actors.cpp 1425 warn V547 Expression '!detected' is always true.
apps/openmw/mwmechanics/character.cpp 2155 err V547 Expression 'mode == 0' is always true.
apps/openmw/mwmechanics/character.cpp 1192 warn V592 The expression was enclosed by parentheses twice: ((expression)). One pair of parentheses is unnecessary or misprint is present.
apps/openmw/mwmechanics/character.cpp 521 warn V560 A part of conditional expression is always true: (idle == mIdleState).
apps/openmw/mwmechanics/pathfinding.cpp 317 err V547 Expression 'mPath.size() >= 2' is always true.
apps/openmw/mwscript/interpretercontext.cpp 409 warn V560 A part of conditional expression is always false: rank > 9.
apps/openmw/mwgui/windowbase.cpp 28 warn V560 A part of conditional expression is always true: !visible.
apps/openmw/mwgui/journalwindow.cpp 561 warn V547 Expression '!mAllQuests' is always false.
apps/openmw/mwgui/referenceinterface.cpp 18 warn V571 Recurring check. The '!mPtr.isEmpty()' condition was already verified in line 16.
apps/openmw/mwworld/scene.cpp 463 warn V547 Expression 'adjustPlayerPos' is always true.
apps/openmw/mwworld/worldimp.cpp 409 err V766 An item with the same key '"sCompanionShare"' has already been added.
apps/openmw/mwworld/cellstore.cpp 691 warn V519 The 'state.mWaterLevel' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 689, 691.
apps/openmw/mwworld/weather.cpp 1125 warn V519 The 'mResult.mParticleEffect' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 1123, 1125.
apps/openmw/mwworld/weather.cpp 1137 warn V519 The 'mResult.mParticleEffect' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 1135, 1137.
apps/wizard/unshield/unshieldworker.cpp 475 warn V728 An excessive check can be simplified. The '(A && B) || (!A && !B)' expression is equivalent to the 'bool(A) == bool(B)' expression.
apps/wizard/installationpage.cpp 163 warn V735 Possibly an incorrect HTML. The "</p" closing tag was encountered, while the "</span" tag was expected.
components/fontloader/fontloader.cpp 427 err V547 Expression 'i == 1' is always true.
components/nifosg/nifloader.cpp 282 warn V519 The 'created' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 278, 282.
components/esm/loadregn.cpp 119 err V586 The 'clear' function is called twice for deallocation of the same resource. Check lines: 112, 119.
components/esm/cellref.cpp 178 warn V581 The conditional expressions of the 'if' statements situated alongside each other are identical. Check lines: 175, 178.
components/esmterrain/storage.cpp 235 warn V560 A part of conditional expression is always true: colStart == 0.
components/esmterrain/storage.cpp 237 warn V560 A part of conditional expression is always true: rowStart == 0.
2018-04-09 18:55:16 +03:00
player . getClass ( ) . adjustPosition ( player , true ) ;
2014-10-02 16:30:23 +02:00
}
2020-06-05 18:22:53 +04:00
MWBase : : Environment : : get ( ) . getMechanicsManager ( ) - > updateCell ( old , player ) ;
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > watchActor ( player ) ;
2014-10-02 16:30:23 +02:00
2017-06-25 12:47:57 +02:00
mPhysics - > updatePtr ( old , player ) ;
2020-06-05 18:22:53 +04:00
world - > adjustSky ( ) ;
2017-02-09 01:24:13 +01:00
2020-05-12 13:37:00 +00:00
mLastPlayerPos = player . getRefData ( ) . getPosition ( ) . asVec3 ( ) ;
2011-07-31 17:07:11 +02:00
}
2011-08-01 03:33:02 +02:00
2018-08-26 23:27:38 +03:00
Scene : : Scene ( MWRender : : RenderingManager & rendering , MWPhysics : : PhysicsSystem * physics ,
DetourNavigator : : Navigator & navigator )
2020-11-13 11:39:47 +04:00
: mCurrentCell ( nullptr ) , mCellChanged ( false ) , mPhysics ( physics ) , mRendering ( rendering ) , mNavigator ( navigator )
2016-02-07 07:37:56 -08:00
, mCellLoadingThreshold ( 1024.f )
2016-02-07 18:01:14 +01:00
, mPreloadDistance ( Settings : : Manager : : getInt ( " preload distance " , " Cells " ) )
, mPreloadEnabled ( Settings : : Manager : : getBool ( " preload enabled " , " Cells " ) )
2016-02-09 01:58:07 +01:00
, mPreloadExteriorGrid ( Settings : : Manager : : getBool ( " preload exterior grid " , " Cells " ) )
, mPreloadDoors ( Settings : : Manager : : getBool ( " preload doors " , " Cells " ) )
, mPreloadFastTravel ( Settings : : Manager : : getBool ( " preload fast travel " , " Cells " ) )
2017-07-19 16:43:29 +02:00
, mPredictionTime ( Settings : : Manager : : getFloat ( " prediction time " , " Cells " ) )
2011-08-01 03:33:02 +02:00
{
2017-03-06 19:04:17 +01:00
mPreloader . reset ( new CellPreloader ( rendering . getResourceSystem ( ) , physics - > getShapeManager ( ) , rendering . getTerrain ( ) , rendering . getLandManager ( ) ) ) ;
2016-02-09 01:02:40 +01:00
mPreloader - > setWorkQueue ( mRendering . getWorkQueue ( ) ) ;
2016-02-07 19:05:55 +01:00
2017-02-04 02:36:44 +01:00
mPreloader - > setUnrefQueue ( rendering . getUnrefQueue ( ) ) ;
2016-02-09 19:04:59 +01:00
mPhysics - > setUnrefQueue ( rendering . getUnrefQueue ( ) ) ;
2016-02-18 17:47:10 +01:00
rendering . getResourceSystem ( ) - > setExpiryDelay ( Settings : : Manager : : getFloat ( " cache expiry delay " , " Cells " ) ) ;
mPreloader - > setExpiryDelay ( Settings : : Manager : : getFloat ( " preload cell expiry delay " , " Cells " ) ) ;
mPreloader - > setMinCacheSize ( Settings : : Manager : : getInt ( " preload cell cache min " , " Cells " ) ) ;
mPreloader - > setMaxCacheSize ( Settings : : Manager : : getInt ( " preload cell cache max " , " Cells " ) ) ;
2016-03-29 23:28:53 +02:00
mPreloader - > setPreloadInstances ( Settings : : Manager : : getBool ( " preload instances " , " Cells " ) ) ;
2011-08-01 03:33:02 +02:00
}
Scene : : ~ Scene ( )
{
2021-07-11 14:43:52 +02:00
for ( const osg : : ref_ptr < SceneUtil : : WorkItem > & v : mWorkItems )
v - > abort ( ) ;
for ( const osg : : ref_ptr < SceneUtil : : WorkItem > & v : mWorkItems )
v - > waitTillDone ( ) ;
2011-08-01 03:33:02 +02:00
}
bool Scene : : hasCellChanged ( ) const
{
return mCellChanged ;
}
2011-08-09 09:56:09 +02:00
2011-11-15 23:31:18 -05:00
const Scene : : CellStoreCollection & Scene : : getActiveCells ( ) const
2011-08-01 04:06:38 +02:00
{
return mActiveCells ;
}
2011-08-09 09:56:09 +02:00
2016-03-24 17:18:08 +01:00
void Scene : : changeToInteriorCell ( const std : : string & cellName , const ESM : : Position & position , bool adjustPlayerPos , bool changeEvent )
2011-07-31 17:07:11 +02:00
{
2014-08-07 16:37:03 +02:00
CellStore * cell = MWBase : : Environment : : get ( ) . getWorld ( ) - > getInterior ( cellName ) ;
2019-11-18 22:10:31 +04:00
bool useFading = ( mCurrentCell ! = nullptr ) ;
if ( useFading )
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > fadeScreenOut ( 0.5 ) ;
2013-02-28 17:54:42 +01:00
2013-08-27 15:48:13 +02:00
Loading : : Listener * loadingListener = MWBase : : Environment : : get ( ) . getWindowManager ( ) - > getLoadingScreen ( ) ;
std : : string loadingInteriorText = " #{sLoadingMessage2} " ;
2021-05-26 23:19:22 +02:00
loadingListener - > setLabel ( loadingInteriorText ) ;
2014-08-07 16:37:03 +02:00
Loading : : ScopedLoad load ( loadingListener ) ;
2013-02-28 17:54:42 +01:00
2019-11-18 22:10:31 +04:00
if ( mCurrentCell ! = nullptr & & * mCurrentCell = = * cell )
2012-09-11 16:37:54 +02:00
{
2012-11-04 23:22:30 +00:00
MWBase : : World * world = MWBase : : Environment : : get ( ) . getWorld ( ) ;
2021-04-11 18:18:10 +02:00
world - > moveObject ( world - > getPlayerPtr ( ) , position . asVec3 ( ) ) ;
2021-04-11 19:17:17 +02:00
world - > rotateObject ( world - > getPlayerPtr ( ) , position . asRotationVec3 ( ) ) ;
2013-04-03 23:55:57 +02:00
2016-03-24 17:18:08 +01:00
if ( adjustPlayerPos )
world - > getPlayerPtr ( ) . getClass ( ) . adjustPosition ( world - > getPlayerPtr ( ) , true ) ;
2014-08-01 16:25:41 +02:00
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > fadeScreenIn ( 0.5 ) ;
2012-11-04 23:22:30 +00:00
return ;
2012-09-11 16:37:54 +02:00
}
2013-03-10 10:00:20 +01:00
2018-08-14 23:05:43 +04:00
Log ( Debug : : Info ) < < " Changing to interior " ;
2011-07-31 17:07:11 +02:00
2012-11-04 23:22:30 +00:00
// unload
2021-02-05 14:55:42 +01:00
for ( auto iter = mInactiveCells . begin ( ) ; iter ! = mInactiveCells . end ( ) ; )
{
auto * cell = * iter + + ;
deactivateCell ( cell ) ;
unloadInactiveCell ( cell ) ;
}
assert ( mActiveCells . empty ( ) ) ;
assert ( mInactiveCells . empty ( ) ) ;
2012-04-23 15:27:03 +02:00
2018-04-01 16:48:25 +03:00
loadingListener - > setProgressRange ( cell - > count ( ) ) ;
2013-08-27 15:48:13 +02:00
2012-11-04 23:22:30 +00:00
// Load cell.
2020-05-10 13:37:00 +00:00
mPagedRefs . clear ( ) ;
2021-02-05 14:55:42 +01:00
loadInactiveCell ( cell , loadingListener ) ;
activateCell ( cell , loadingListener , changeEvent ) ;
2011-07-31 17:07:11 +02:00
2016-03-30 01:54:03 +02:00
changePlayerCell ( cell , position , adjustPlayerPos ) ;
2012-11-03 19:29:55 +00:00
2012-11-04 23:22:30 +00:00
// adjust fog
2015-04-21 23:27:26 +02:00
mRendering . configureFog ( mCurrentCell - > getCell ( ) ) ;
2013-03-10 10:00:20 +01:00
2011-07-31 17:07:11 +02:00
// Sky system
2012-07-03 12:30:50 +02:00
MWBase : : Environment : : get ( ) . getWorld ( ) - > adjustSky ( ) ;
2011-07-31 17:07:11 +02:00
2016-02-27 12:53:07 +01:00
if ( changeEvent )
mCellChanged = true ;
2019-11-18 22:10:31 +04:00
if ( useFading )
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > fadeScreenIn ( 0.5 ) ;
2014-10-02 16:30:23 +02:00
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > changeCell ( mCurrentCell ) ;
2021-05-05 18:13:17 +02:00
2021-05-14 21:06:29 +02:00
mNavigator . wait ( * loadingListener , DetourNavigator : : WaitConditionType : : requiredTilesPresent ) ;
2011-07-31 17:07:11 +02:00
}
2011-08-01 03:33:02 +02:00
2016-02-27 12:53:07 +01:00
void Scene : : changeToExteriorCell ( const ESM : : Position & position , bool adjustPlayerPos , bool changeEvent )
2011-07-31 17:07:11 +02:00
{
int x = 0 ;
int y = 0 ;
2012-07-03 12:30:50 +02:00
MWBase : : Environment : : get ( ) . getWorld ( ) - > positionToIndex ( position . pos [ 0 ] , position . pos [ 1 ] , x , y ) ;
2011-07-31 17:07:11 +02:00
2017-10-05 18:39:28 +02:00
if ( changeEvent )
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > fadeScreenOut ( 0.5 ) ;
2020-05-12 13:37:00 +00:00
changeCellGrid ( position . asVec3 ( ) , x , y , changeEvent ) ;
2014-10-02 16:30:23 +02:00
CellStore * current = MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( x , y ) ;
changePlayerCell ( current , position , adjustPlayerPos ) ;
2017-10-05 18:39:28 +02:00
if ( changeEvent )
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > fadeScreenIn ( 0.5 ) ;
2011-07-31 17:07:11 +02:00
}
2011-08-09 09:56:09 +02:00
2013-12-05 13:21:26 +01:00
CellStore * Scene : : getCurrentCell ( )
2011-08-01 04:06:38 +02:00
{
return mCurrentCell ;
}
2011-08-01 03:33:02 +02:00
void Scene : : markCellAsUnchanged ( )
{
mCellChanged = false ;
}
2011-08-27 10:30:38 +02:00
2021-02-05 14:55:42 +01:00
void Scene : : insertCell ( CellStore & cell , Loading : : Listener * loadingListener , bool onlyObjects , bool test )
2012-05-14 17:41:17 +02:00
{
2021-02-05 14:55:42 +01:00
InsertVisitor insertVisitor ( cell , * loadingListener , onlyObjects , test ) ;
2015-12-06 18:13:04 +01:00
cell . forEach ( insertVisitor ) ;
2021-02-05 14:55:42 +01:00
insertVisitor . insert ( [ & ] ( const MWWorld : : Ptr & ptr ) { addObject ( ptr , * mPhysics , mRendering , mPagedRefs , onlyObjects ) ; } ) ;
if ( ! onlyObjects )
{
insertVisitor . insert ( [ & ] ( const MWWorld : : Ptr & ptr ) { addObject ( ptr , * mPhysics , mNavigator ) ; } ) ;
2015-12-04 19:46:02 +01:00
2021-02-05 14:55:42 +01:00
// do adjustPosition (snapping actors to ground) after objects are loaded, so we don't depend on the loading order
PositionVisitor posVisitor ;
cell . forEach ( posVisitor ) ;
}
2012-05-14 17:41:17 +02:00
}
2011-08-09 00:05:16 +02:00
2012-05-25 17:28:27 +02:00
void Scene : : addObjectToScene ( const Ptr & ptr )
{
2015-01-31 19:21:16 +01:00
try
{
2021-02-05 14:55:42 +01:00
addObject ( ptr , * mPhysics , mRendering , mPagedRefs , false ) ;
2018-08-26 23:27:38 +03:00
addObject ( ptr , * mPhysics , mNavigator ) ;
2015-04-23 23:50:46 +02:00
MWBase : : Environment : : get ( ) . getWorld ( ) - > scaleObject ( ptr , ptr . getCellRef ( ) . getScale ( ) ) ;
2018-04-21 15:27:25 +03:00
const auto player = MWBase : : Environment : : get ( ) . getWorld ( ) - > getPlayerPtr ( ) ;
2021-06-29 20:12:22 +02:00
mNavigator . update ( player . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) ;
2015-01-31 19:21:16 +01:00
}
catch ( std : : exception & e )
{
2018-08-14 23:05:43 +04:00
Log ( Debug : : Error ) < < " failed to render ' " < < ptr . getCellRef ( ) . getRefId ( ) < < " ': " < < e . what ( ) ;
2015-01-31 19:21:16 +01:00
}
2012-05-25 17:28:27 +02:00
}
2012-08-09 14:33:21 +02:00
2012-05-25 17:28:27 +02:00
void Scene : : removeObjectFromScene ( const Ptr & ptr )
{
2013-01-28 23:39:11 -08:00
MWBase : : Environment : : get ( ) . getMechanicsManager ( ) - > remove ( ptr ) ;
2012-05-25 17:28:27 +02:00
MWBase : : Environment : : get ( ) . getSoundManager ( ) - > stopSound3D ( ptr ) ;
2020-12-19 00:02:31 +01:00
MWBase : : Environment : : get ( ) . getLuaManager ( ) - > objectRemovedFromScene ( ptr ) ;
2018-03-14 01:49:08 +03:00
if ( const auto object = mPhysics - > getObject ( ptr ) )
2018-04-21 15:27:25 +03:00
{
2021-06-29 20:12:22 +02:00
mNavigator . removeObject ( DetourNavigator : : ObjectId ( object ) ) ;
2018-04-21 15:27:25 +03:00
const auto player = MWBase : : Environment : : get ( ) . getWorld ( ) - > getPlayerPtr ( ) ;
2021-06-29 20:12:22 +02:00
mNavigator . update ( player . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) ;
2018-04-21 15:27:25 +03:00
}
2019-03-10 14:24:03 +03:00
else if ( mPhysics - > getActor ( ptr ) )
2018-04-22 19:22:00 +03:00
{
2021-06-29 20:12:22 +02:00
mNavigator . removeAgent ( MWBase : : Environment : : get ( ) . getWorld ( ) - > getPathfindingHalfExtents ( ptr ) ) ;
2018-04-22 19:22:00 +03:00
}
2015-05-12 03:02:15 +02:00
mPhysics - > remove ( ptr ) ;
2015-05-22 00:55:43 +02:00
mRendering . removeObject ( ptr ) ;
2015-06-16 20:36:48 +02:00
if ( ptr . getClass ( ) . isActor ( ) )
mRendering . removeWaterRippleEmitter ( ptr ) ;
2020-05-10 13:37:00 +00:00
ptr . getRefData ( ) . setBaseNode ( nullptr ) ;
2012-05-25 17:28:27 +02:00
}
2012-07-26 16:14:11 +04:00
bool Scene : : isCellActive ( const CellStore & cell )
{
CellStoreCollection : : iterator active = mActiveCells . begin ( ) ;
while ( active ! = mActiveCells . end ( ) ) {
2012-08-08 14:51:33 +04:00
if ( * * active = = cell ) {
2012-07-26 16:14:11 +04:00
return true ;
}
+ + active ;
}
return false ;
}
2014-04-29 15:27:49 +02:00
Ptr Scene : : searchPtrViaActorId ( int actorId )
{
for ( CellStoreCollection : : const_iterator iter ( mActiveCells . begin ( ) ) ;
iter ! = mActiveCells . end ( ) ; + + iter )
if ( Ptr ptr = ( * iter ) - > searchViaActorId ( actorId ) )
return ptr ;
return Ptr ( ) ;
}
2016-02-07 05:13:46 -08:00
2017-02-15 00:55:35 +01:00
class PreloadMeshItem : public SceneUtil : : WorkItem
{
public :
PreloadMeshItem ( const std : : string & mesh , Resource : : SceneManager * sceneManager )
: mMesh ( mesh ) , mSceneManager ( sceneManager )
{
}
2020-10-16 22:18:54 +04:00
void doWork ( ) override
2017-02-15 00:55:35 +01:00
{
2021-07-11 14:43:52 +02:00
if ( mAborted )
return ;
2017-02-15 00:55:35 +01:00
try
{
mSceneManager - > getTemplate ( mMesh ) ;
}
2021-04-19 15:43:00 +04:00
catch ( std : : exception & )
2017-02-15 00:55:35 +01:00
{
}
}
2021-07-11 14:43:52 +02:00
void abort ( ) override
{
mAborted = true ;
}
2017-02-15 00:55:35 +01:00
private :
std : : string mMesh ;
Resource : : SceneManager * mSceneManager ;
2021-07-11 14:43:52 +02:00
std : : atomic_bool mAborted { false } ;
2017-02-15 00:55:35 +01:00
} ;
2017-02-20 19:58:00 +01:00
void Scene : : preload ( const std : : string & mesh , bool useAnim )
2017-02-15 00:55:35 +01:00
{
2017-02-20 19:58:00 +01:00
std : : string mesh_ = mesh ;
if ( useAnim )
mesh_ = Misc : : ResourceHelpers : : correctActorModelPath ( mesh_ , mRendering . getResourceSystem ( ) - > getVFS ( ) ) ;
if ( ! mRendering . getResourceSystem ( ) - > getSceneManager ( ) - > checkLoaded ( mesh_ , mRendering . getReferenceTime ( ) ) )
2021-07-11 14:43:52 +02:00
{
osg : : ref_ptr < PreloadMeshItem > item ( new PreloadMeshItem ( mesh_ , mRendering . getResourceSystem ( ) - > getSceneManager ( ) ) ) ;
mRendering . getWorkQueue ( ) - > addWorkItem ( item ) ;
const auto isDone = [ ] ( const osg : : ref_ptr < SceneUtil : : WorkItem > & v ) { return v - > isDone ( ) ; } ;
mWorkItems . erase ( std : : remove_if ( mWorkItems . begin ( ) , mWorkItems . end ( ) , isDone ) , mWorkItems . end ( ) ) ;
mWorkItems . emplace_back ( std : : move ( item ) ) ;
}
2017-02-15 00:55:35 +01:00
}
2017-02-09 01:24:13 +01:00
void Scene : : preloadCells ( float dt )
2016-02-07 07:37:56 -08:00
{
2020-05-12 13:37:00 +00:00
if ( dt < = 1e-06 ) return ;
2019-06-13 13:37:00 +00:00
std : : vector < PositionCellGrid > exteriorPositions ;
2017-03-09 04:18:35 +01:00
2017-02-09 01:24:13 +01:00
const MWWorld : : ConstPtr player = MWBase : : Environment : : get ( ) . getWorld ( ) - > getPlayerPtr ( ) ;
osg : : Vec3f playerPos = player . getRefData ( ) . getPosition ( ) . asVec3 ( ) ;
osg : : Vec3f moved = playerPos - mLastPlayerPos ;
2017-07-19 16:43:29 +02:00
osg : : Vec3f predictedPos = playerPos + moved / dt * mPredictionTime ;
2017-02-09 01:24:13 +01:00
2017-03-09 04:18:35 +01:00
if ( mCurrentCell - > isExterior ( ) )
2019-06-13 13:37:00 +00:00
exteriorPositions . emplace_back ( predictedPos , gridCenterToBounds ( getNewGridCenter ( predictedPos , & mCurrentGridCenter ) ) ) ;
2017-03-09 04:18:35 +01:00
2017-02-09 01:24:13 +01:00
mLastPlayerPos = playerPos ;
2017-03-09 21:45:38 +01:00
if ( mPreloadEnabled )
{
if ( mPreloadDoors )
preloadTeleportDoorDestinations ( playerPos , predictedPos , exteriorPositions ) ;
if ( mPreloadExteriorGrid )
preloadExteriorGrid ( playerPos , predictedPos ) ;
if ( mPreloadFastTravel )
2017-03-12 00:47:06 +01:00
preloadFastTravelDestinations ( playerPos , predictedPos , exteriorPositions ) ;
2017-03-09 21:45:38 +01:00
}
2017-03-09 04:18:35 +01:00
mPreloader - > setTerrainPreloadPositions ( exteriorPositions ) ;
2016-02-07 07:37:56 -08:00
}
2019-06-13 13:37:00 +00:00
void Scene : : preloadTeleportDoorDestinations ( const osg : : Vec3f & playerPos , const osg : : Vec3f & predictedPos , std : : vector < PositionCellGrid > & exteriorPositions )
2016-02-07 05:13:46 -08:00
{
std : : vector < MWWorld : : ConstPtr > teleportDoors ;
2019-03-07 12:38:55 +04:00
for ( const MWWorld : : CellStore * cellStore : mActiveCells )
2016-02-07 05:13:46 -08:00
{
typedef MWWorld : : CellRefList < ESM : : Door > : : List DoorList ;
const DoorList & doors = cellStore - > getReadOnlyDoors ( ) . mList ;
2019-03-07 12:38:55 +04:00
for ( auto & door : doors )
2016-02-07 05:13:46 -08:00
{
2019-03-07 12:38:55 +04:00
if ( ! door . mRef . getTeleport ( ) )
{
2016-02-07 05:13:46 -08:00
continue ;
}
2020-10-17 12:26:35 +04:00
teleportDoors . emplace_back ( & door , cellStore ) ;
2016-02-07 05:13:46 -08:00
}
}
2019-03-07 12:38:55 +04:00
for ( const MWWorld : : ConstPtr & door : teleportDoors )
2016-02-07 05:13:46 -08:00
{
2017-02-09 01:24:13 +01:00
float sqrDistToPlayer = ( playerPos - door . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) . length2 ( ) ;
sqrDistToPlayer = std : : min ( sqrDistToPlayer , ( predictedPos - door . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) . length2 ( ) ) ;
2016-02-07 05:13:46 -08:00
2016-02-07 07:37:56 -08:00
if ( sqrDistToPlayer < mPreloadDistance * mPreloadDistance )
2016-02-07 05:13:46 -08:00
{
try
{
if ( ! door . getCellRef ( ) . getDestCell ( ) . empty ( ) )
2016-02-09 01:51:23 +01:00
preloadCell ( MWBase : : Environment : : get ( ) . getWorld ( ) - > getInterior ( door . getCellRef ( ) . getDestCell ( ) ) ) ;
2016-02-07 05:13:46 -08:00
else
{
2017-03-09 04:18:35 +01:00
osg : : Vec3f pos = door . getCellRef ( ) . getDoorDest ( ) . asVec3 ( ) ;
2016-02-07 05:13:46 -08:00
int x , y ;
2017-03-09 04:18:35 +01:00
MWBase : : Environment : : get ( ) . getWorld ( ) - > positionToIndex ( pos . x ( ) , pos . y ( ) , x , y ) ;
2016-02-09 01:51:23 +01:00
preloadCell ( MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( x , y ) , true ) ;
2019-06-13 13:37:00 +00:00
exteriorPositions . emplace_back ( pos , gridCenterToBounds ( getNewGridCenter ( pos ) ) ) ;
2016-02-07 05:13:46 -08:00
}
}
2021-04-19 15:43:00 +04:00
catch ( std : : exception & )
2016-02-07 05:13:46 -08:00
{
// ignore error for now, would spam the log too much
}
}
}
}
2016-02-07 07:37:56 -08:00
2017-02-09 01:24:13 +01:00
void Scene : : preloadExteriorGrid ( const osg : : Vec3f & playerPos , const osg : : Vec3f & predictedPos )
2016-02-07 07:37:56 -08:00
{
if ( ! MWBase : : Environment : : get ( ) . getWorld ( ) - > isCellExterior ( ) )
return ;
int halfGridSizePlusOne = mHalfGridSize + 1 ;
int cellX , cellY ;
2019-06-13 13:37:00 +00:00
cellX = mCurrentGridCenter . x ( ) ; cellY = mCurrentGridCenter . y ( ) ;
2016-02-07 07:37:56 -08:00
float centerX , centerY ;
MWBase : : Environment : : get ( ) . getWorld ( ) - > indexToPosition ( cellX , cellY , centerX , centerY , true ) ;
for ( int dx = - halfGridSizePlusOne ; dx < = halfGridSizePlusOne ; + + dx )
{
for ( int dy = - halfGridSizePlusOne ; dy < = halfGridSizePlusOne ; + + dy )
{
if ( dy ! = halfGridSizePlusOne & & dy ! = - halfGridSizePlusOne & & dx ! = halfGridSizePlusOne & & dx ! = - halfGridSizePlusOne )
continue ; // only care about the outer (not yet loaded) part of the grid
float thisCellCenterX , thisCellCenterY ;
MWBase : : Environment : : get ( ) . getWorld ( ) - > indexToPosition ( cellX + dx , cellY + dy , thisCellCenterX , thisCellCenterY , true ) ;
float dist = std : : max ( std : : abs ( thisCellCenterX - playerPos . x ( ) ) , std : : abs ( thisCellCenterY - playerPos . y ( ) ) ) ;
2017-02-09 01:24:13 +01:00
dist = std : : min ( dist , std : : max ( std : : abs ( thisCellCenterX - predictedPos . x ( ) ) , std : : abs ( thisCellCenterY - predictedPos . y ( ) ) ) ) ;
2018-09-17 14:52:43 +04:00
float loadDist = Constants : : CellSizeInUnits / 2 + Constants : : CellSizeInUnits - mCellLoadingThreshold + mPreloadDistance ;
2016-02-07 07:37:56 -08:00
if ( dist < loadDist )
2016-02-09 01:51:23 +01:00
preloadCell ( MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( cellX + dx , cellY + dy ) ) ;
}
}
}
void Scene : : preloadCell ( CellStore * cell , bool preloadSurrounding )
{
if ( preloadSurrounding & & cell - > isExterior ( ) )
{
int x = cell - > getCell ( ) - > getGridX ( ) ;
int y = cell - > getCell ( ) - > getGridY ( ) ;
2016-03-29 00:48:47 +02:00
unsigned int numpreloaded = 0 ;
2016-02-09 01:51:23 +01:00
for ( int dx = - mHalfGridSize ; dx < = mHalfGridSize ; + + dx )
{
for ( int dy = - mHalfGridSize ; dy < = mHalfGridSize ; + + dy )
{
mPreloader - > preload ( MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( x + dx , y + dy ) , mRendering . getReferenceTime ( ) ) ;
2016-03-29 00:48:47 +02:00
if ( + + numpreloaded > = mPreloader - > getMaxCacheSize ( ) )
break ;
2016-02-09 01:51:23 +01:00
}
}
}
else
mPreloader - > preload ( cell , mRendering . getReferenceTime ( ) ) ;
}
2020-05-12 13:37:00 +00:00
void Scene : : preloadTerrain ( const osg : : Vec3f & pos , bool sync )
2017-03-12 22:38:50 +01:00
{
2019-06-13 13:37:00 +00:00
std : : vector < PositionCellGrid > vec ;
vec . emplace_back ( pos , gridCenterToBounds ( getNewGridCenter ( pos ) ) ) ;
2020-05-12 13:37:00 +00:00
if ( sync & & mRendering . pagingUnlockCache ( ) )
mPreloader - > abortTerrainPreloadExcept ( nullptr ) ;
else
mPreloader - > abortTerrainPreloadExcept ( & vec [ 0 ] ) ;
2017-03-12 22:38:50 +01:00
mPreloader - > setTerrainPreloadPositions ( vec ) ;
2020-05-12 13:37:00 +00:00
if ( ! sync ) return ;
Loading : : Listener * loadingListener = MWBase : : Environment : : get ( ) . getWindowManager ( ) - > getLoadingScreen ( ) ;
Loading : : ScopedLoad load ( loadingListener ) ;
int progress = 0 , initialProgress = - 1 , progressRange = 0 ;
while ( ! mPreloader - > syncTerrainLoad ( vec , progress , progressRange , mRendering . getReferenceTime ( ) ) )
{
if ( initialProgress = = - 1 )
{
loadingListener - > setLabel ( " #{sLoadingMessage4} " ) ;
initialProgress = progress ;
}
if ( progress )
{
loadingListener - > setProgressRange ( std : : max ( 0 , progressRange - initialProgress ) ) ;
loadingListener - > setProgress ( progress - initialProgress ) ;
}
else
loadingListener - > setProgress ( 0 ) ;
2020-06-25 21:46:07 +02:00
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 5 ) ) ;
2020-05-12 13:37:00 +00:00
}
2017-03-12 22:38:50 +01:00
}
2020-05-08 13:37:00 +00:00
void Scene : : reloadTerrain ( )
{
mPreloader - > setTerrainPreloadPositions ( std : : vector < PositionCellGrid > ( ) ) ;
}
2016-02-09 01:51:23 +01:00
struct ListFastTravelDestinationsVisitor
{
ListFastTravelDestinationsVisitor ( float preloadDist , const osg : : Vec3f & playerPos )
: mPreloadDist ( preloadDist )
, mPlayerPos ( playerPos )
{
}
bool operator ( ) ( const MWWorld : : Ptr & ptr )
{
if ( ( ptr . getRefData ( ) . getPosition ( ) . asVec3 ( ) - mPlayerPos ) . length2 ( ) > mPreloadDist * mPreloadDist )
return true ;
if ( ptr . getClass ( ) . isNpc ( ) )
{
const std : : vector < ESM : : Transport : : Dest > & transport = ptr . get < ESM : : NPC > ( ) - > mBase - > mTransport . mList ;
mList . insert ( mList . begin ( ) , transport . begin ( ) , transport . end ( ) ) ;
}
else
{
const std : : vector < ESM : : Transport : : Dest > & transport = ptr . get < ESM : : Creature > ( ) - > mBase - > mTransport . mList ;
mList . insert ( mList . begin ( ) , transport . begin ( ) , transport . end ( ) ) ;
}
return true ;
}
float mPreloadDist ;
osg : : Vec3f mPlayerPos ;
std : : vector < ESM : : Transport : : Dest > mList ;
} ;
2019-06-13 13:37:00 +00:00
void Scene : : preloadFastTravelDestinations ( const osg : : Vec3f & playerPos , const osg : : Vec3f & /*predictedPos*/ , std : : vector < PositionCellGrid > & exteriorPositions ) // ignore predictedPos here since opening dialogue with travel service takes extra time
2016-02-09 01:51:23 +01:00
{
const MWWorld : : ConstPtr player = MWBase : : Environment : : get ( ) . getWorld ( ) - > getPlayerPtr ( ) ;
ListFastTravelDestinationsVisitor listVisitor ( mPreloadDistance , player . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) ;
2019-03-07 12:38:55 +04:00
for ( MWWorld : : CellStore * cellStore : mActiveCells )
2016-02-09 01:51:23 +01:00
{
cellStore - > forEachType < ESM : : NPC > ( listVisitor ) ;
cellStore - > forEachType < ESM : : Creature > ( listVisitor ) ;
}
2019-03-07 12:38:55 +04:00
for ( ESM : : Transport : : Dest & dest : listVisitor . mList )
2016-02-09 01:51:23 +01:00
{
2019-03-07 12:38:55 +04:00
if ( ! dest . mCellName . empty ( ) )
preloadCell ( MWBase : : Environment : : get ( ) . getWorld ( ) - > getInterior ( dest . mCellName ) ) ;
2016-02-09 01:51:23 +01:00
else
{
2019-03-07 12:38:55 +04:00
osg : : Vec3f pos = dest . mPos . asVec3 ( ) ;
2016-02-09 01:51:23 +01:00
int x , y ;
2017-03-12 00:47:06 +01:00
MWBase : : Environment : : get ( ) . getWorld ( ) - > positionToIndex ( pos . x ( ) , pos . y ( ) , x , y ) ;
2016-02-09 01:51:23 +01:00
preloadCell ( MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( x , y ) , true ) ;
2019-06-13 13:37:00 +00:00
exteriorPositions . emplace_back ( pos , gridCenterToBounds ( getNewGridCenter ( pos ) ) ) ;
2016-02-07 07:37:56 -08:00
}
}
}
2011-07-31 17:07:11 +02:00
}