@ -31,6 +31,7 @@
# include "../mwmechanics/creaturestats.hpp"
# include "../mwmechanics/actorutil.hpp"
# include "../mwmechanics/movement.hpp"
# include "../mwworld/esmstore.hpp"
# include "../mwworld/cellstore.hpp"
@ -50,6 +51,7 @@
# include "contacttestresultcallback.hpp"
# include "constants.hpp"
# include "movementsolver.hpp"
# include "mtphysics.hpp"
namespace MWPhysics
{
@ -65,11 +67,11 @@ namespace MWPhysics
{
mResourceSystem - > addResourceManager ( mShapeManager . get ( ) ) ;
mCollisionConfiguration = new btDefaultCollisionConfiguration ( ) ;
mDispatcher = new btCollisionDispatcher ( mCollisionConfiguration ) ;
mBroadphase = new btDbvtBroadphase ( ) ;
mCollisionConfiguration = std : : make_unique < btDefaultCollisionConfiguration > ( ) ;
mDispatcher = std : : make_unique < btCollisionDispatcher > ( mCollisionConfiguration . get ( ) ) ;
mBroadphase = std : : make_unique < btDbvtBroadphase > ( ) ;
mCollisionWorld = new btCollisionWorld ( mDispatcher , mBroadphase , mCollisionConfiguration ) ;
mCollisionWorld = std : : make_shared < btCollisionWorld > ( mDispatcher . get ( ) , mBroadphase . get ( ) , mCollisionConfiguration . get ( ) ) ;
// Don't update AABBs of all objects every frame. Most objects in MW are static, so we don't need this.
// Should a "static" object ever be moved, we have to update its AABB manually using DynamicsWorld::updateSingleAabb.
@ -86,36 +88,26 @@ namespace MWPhysics
Log ( Debug : : Warning ) < < " Warning: using custom physics framerate ( " < < physFramerate < < " FPS). " ;
}
}
mTaskScheduler = std : : make_unique < PhysicsTaskScheduler > ( mPhysicsDt , mCollisionWorld ) ;
}
PhysicsSystem : : ~ PhysicsSystem ( )
{
mResourceSystem - > removeResourceManager ( mShapeManager . get ( ) ) ;
if ( mWaterCollisionObject .get ( ) )
m CollisionWorld - > removeCollisionObject ( mWaterCollisionObject . get ( ) ) ;
if ( mWaterCollisionObject )
m TaskScheduler - > removeCollisionObject ( mWaterCollisionObject . get ( ) ) ;
for ( auto & heightField : mHeightFields )
{
m CollisionWorld - > removeCollisionObject ( heightField . second - > getCollisionObject ( ) ) ;
m TaskScheduler - > removeCollisionObject ( heightField . second - > getCollisionObject ( ) ) ;
delete heightField . second ;
}
for ( auto & object : mObjects )
{
mCollisionWorld - > removeCollisionObject ( object . second - > getCollisionObject ( ) ) ;
delete object . second ;
}
for ( auto & actor : mActors )
{
delete actor . second ;
}
mObjects . clear ( ) ;
mActors . clear ( ) ;
delete mCollisionWorld ;
delete mCollisionConfiguration ;
delete mDispatcher ;
delete mBroadphase ;
}
void PhysicsSystem : : setUnrefQueue ( SceneUtil : : UnrefQueue * unrefQueue )
@ -132,13 +124,13 @@ namespace MWPhysics
{
mDebugDrawEnabled = ! mDebugDrawEnabled ;
if ( mDebugDrawEnabled & & ! mDebugDrawer .get ( ) )
if ( mDebugDrawEnabled & & ! mDebugDrawer )
{
mDebugDrawer . reset ( new MWRender : : DebugDrawer ( mParentNode , mCollisionWorld )) ;
mDebugDrawer . reset ( new MWRender : : DebugDrawer ( mParentNode , mCollisionWorld .get ( ) )) ;
mCollisionWorld - > setDebugDrawer ( mDebugDrawer . get ( ) ) ;
mDebugDrawer - > setDebugMode ( mDebugDrawEnabled ) ;
}
else if ( mDebugDrawer .get ( ) )
else if ( mDebugDrawer )
mDebugDrawer - > setDebugMode ( mDebugDrawEnabled ) ;
return mDebugDrawEnabled ;
}
@ -175,7 +167,7 @@ namespace MWPhysics
std : : pair < MWWorld : : Ptr , osg : : Vec3f > PhysicsSystem : : getHitContact ( const MWWorld : : ConstPtr & actor ,
const osg : : Vec3f & origin ,
const osg : : Quat & orient ,
float queryDistance , std : : vector < MWWorld : : Ptr > targets )
float queryDistance , std : : vector < MWWorld : : Ptr > & targets )
{
// First of all, try to hit where you aim to
int hitmask = CollisionType_World | CollisionType_Door | CollisionType_HeightMap | CollisionType_Actor ;
@ -221,7 +213,7 @@ namespace MWPhysics
DeepestNotMeContactTestResultCallback resultCallback ( me , targetCollisionObjects , Misc : : Convert : : toBullet ( origin ) ) ;
resultCallback . m_collisionFilterGroup = CollisionType_Actor ;
resultCallback . m_collisionFilterMask = CollisionType_World | CollisionType_Door | CollisionType_HeightMap | CollisionType_Actor ;
m CollisionWorld - > contactTest ( & object , resultCallback ) ;
m TaskScheduler - > contactTest ( & object , resultCallback ) ;
if ( resultCallback . mObject )
{
@ -245,21 +237,12 @@ namespace MWPhysics
rayFrom . setIdentity ( ) ;
rayFrom . setOrigin ( Misc : : Convert : : toBullet ( point ) ) ;
// target the collision object's world origin, this should be the center of the collision object
btTransform rayTo ;
rayTo . setIdentity ( ) ;
rayTo . setOrigin ( targetCollisionObj - > getWorldTransform ( ) . getOrigin ( ) ) ;
auto hitpoint = mTaskScheduler - > getHitPoint ( rayFrom , targetCollisionObj ) ;
if ( hitpoint )
return ( point - Misc : : Convert : : toOsg ( hitpoint . get ( ) ) ) . length ( ) ;
btCollisionWorld : : ClosestRayResultCallback cb ( rayFrom . getOrigin ( ) , rayTo . getOrigin ( ) ) ;
btCollisionWorld : : rayTestSingle ( rayFrom , rayTo , targetCollisionObj , targetCollisionObj - > getCollisionShape ( ) , targetCollisionObj - > getWorldTransform ( ) , cb ) ;
if ( ! cb . hasHit ( ) )
{
// didn't hit the target. this could happen if point is already inside the collision box
return 0.f ;
}
else
return ( point - Misc : : Convert : : toOsg ( cb . m_hitPointWorld ) ) . length ( ) ;
// didn't hit the target. this could happen if point is already inside the collision box
return 0.f ;
}
RayCastingResult PhysicsSystem : : castRay ( const osg : : Vec3f & from , const osg : : Vec3f & to , const MWWorld : : ConstPtr & ignore , std : : vector < MWWorld : : Ptr > targets , int mask , int group ) const
@ -303,7 +286,7 @@ namespace MWPhysics
resultCallback . m_collisionFilterGroup = group ;
resultCallback . m_collisionFilterMask = mask ;
m CollisionWorld - > rayTest ( btFrom , btTo , resultCallback ) ;
m TaskScheduler - > rayTest ( btFrom , btTo , resultCallback ) ;
RayCastingResult result ;
result . mHit = resultCallback . hasHit ( ) ;
@ -329,7 +312,7 @@ namespace MWPhysics
btTransform from_ ( btrot , Misc : : Convert : : toBullet ( from ) ) ;
btTransform to_ ( btrot , Misc : : Convert : : toBullet ( to ) ) ;
m CollisionWorld - > convexSweepTest ( & shape , from_ , to_ , callback ) ;
m TaskScheduler - > convexSweepTest ( & shape , from_ , to_ , callback ) ;
RayCastingResult result ;
result . mHit = callback . hasHit ( ) ;
@ -343,18 +326,15 @@ namespace MWPhysics
bool PhysicsSystem : : getLineOfSight ( const MWWorld : : ConstPtr & actor1 , const MWWorld : : ConstPtr & actor2 ) const
{
const Actor * physactor1 = getActor ( actor1 ) ;
const Actor * physactor2 = getActor ( actor2 ) ;
if ( ! physactor1 | | ! physactor2 )
return false ;
osg : : Vec3f pos1 ( physactor1 - > getCollisionObjectPosition ( ) + osg : : Vec3f ( 0 , 0 , physactor1 - > getHalfExtents ( ) . z ( ) * 0.9 ) ) ; // eye level
osg : : Vec3f pos2 ( physactor2 - > getCollisionObjectPosition ( ) + osg : : Vec3f ( 0 , 0 , physactor2 - > getHalfExtents ( ) . z ( ) * 0.9 ) ) ;
RayCastingResult result = castRay ( pos1 , pos2 , MWWorld : : ConstPtr ( ) , std : : vector < MWWorld : : Ptr > ( ) , CollisionType_World | CollisionType_HeightMap | CollisionType_Door ) ;
const auto getWeakPtr = [ & ] ( const MWWorld : : ConstPtr & ptr ) - > std : : weak_ptr < Actor >
{
const auto found = mActors . find ( ptr ) ;
if ( found ! = mActors . end ( ) )
return { found - > second } ;
return { } ;
} ;
return ! result . mHit ;
return mTaskScheduler - > getLineOfSight ( getWeakPtr ( actor1 ) , getWeakPtr ( actor2 ) ) ;
}
bool PhysicsSystem : : isOnGround ( const MWWorld : : Ptr & actor )
@ -373,7 +353,7 @@ namespace MWPhysics
const osg : : Vec3f startingPosition ( actorPosition . x ( ) , actorPosition . y ( ) , actorPosition . z ( ) + halfZ ) ;
const osg : : Vec3f destinationPosition ( actorPosition . x ( ) , actorPosition . y ( ) , waterlevel + halfZ ) ;
ActorTracer tracer ;
tracer . doTrace ( physicActor - > getCollisionObject ( ) , startingPosition , destinationPosition , mCollisionWorld );
tracer . doTrace ( physicActor - > getCollisionObject ( ) , startingPosition , destinationPosition , mCollisionWorld .get ( ) );
return ( tracer . mFraction > = 1.0f ) ;
}
@ -408,7 +388,7 @@ namespace MWPhysics
const Object * physobject = getObject ( object ) ;
if ( ! physobject ) return osg : : BoundingBox ( ) ;
btVector3 min , max ;
physobject- > getCollisionObject ( ) - > getCollisionShape ( ) - > getAabb ( physobject - > getCollisionObject ( ) - > getWorldTransform ( ) , min , max ) ;
mTaskScheduler - > getAabb ( physobject - > getCollisionObject ( ) , min , max ) ;
return osg : : BoundingBox ( Misc : : Convert : : toOsg ( min ) , Misc : : Convert : : toOsg ( max ) ) ;
}
@ -434,7 +414,7 @@ namespace MWPhysics
ContactTestResultCallback resultCallback ( me ) ;
resultCallback . m_collisionFilterGroup = collisionGroup ;
resultCallback . m_collisionFilterMask = collisionMask ;
m CollisionWorld - > contactTest ( me , resultCallback ) ;
m TaskScheduler - > contactTest ( me , resultCallback ) ;
return resultCallback . mResult ;
}
@ -444,7 +424,7 @@ namespace MWPhysics
if ( found = = mActors . end ( ) )
return ptr . getRefData ( ) . getPosition ( ) . asVec3 ( ) ;
else
return MovementSolver : : traceDown ( ptr , position , found - > second , mCollisionWorld , maxHeight ) ;
return MovementSolver : : traceDown ( ptr , position , found - > second .get ( ) , mCollisionWorld . get ( ) , maxHeight ) ;
}
void PhysicsSystem : : addHeightField ( const float * heights , int x , int y , float triSize , float sqrtVerts , float minH , float maxH , const osg : : Object * holdObject )
@ -452,7 +432,7 @@ namespace MWPhysics
HeightField * heightfield = new HeightField ( heights , x , y , triSize , sqrtVerts , minH , maxH , holdObject ) ;
mHeightFields [ std : : make_pair ( x , y ) ] = heightfield ;
m CollisionWorld - > addCollisionObject ( heightfield - > getCollisionObject ( ) , CollisionType_HeightMap ,
m TaskScheduler - > addCollisionObject ( heightfield - > getCollisionObject ( ) , CollisionType_HeightMap ,
CollisionType_Actor | CollisionType_Projectile ) ;
}
@ -461,7 +441,7 @@ namespace MWPhysics
HeightFieldMap : : iterator heightfield = mHeightFields . find ( std : : make_pair ( x , y ) ) ;
if ( heightfield ! = mHeightFields . end ( ) )
{
m CollisionWorld - > removeCollisionObject ( heightfield - > second - > getCollisionObject ( ) ) ;
m TaskScheduler - > removeCollisionObject ( heightfield - > second - > getCollisionObject ( ) ) ;
delete heightfield - > second ;
mHeightFields . erase ( heightfield ) ;
}
@ -481,13 +461,13 @@ namespace MWPhysics
if ( ! shapeInstance | | ! shapeInstance - > getCollisionShape ( ) )
return ;
Object * obj = new Object ( ptr , shapeInstance ) ;
auto obj = std : : make_shared < Object > ( ptr , shapeInstance , mTaskScheduler . get ( ) ) ;
mObjects . emplace ( ptr , obj ) ;
if ( obj - > isAnimated ( ) )
mAnimatedObjects . insert ( obj );
mAnimatedObjects . insert ( obj .get ( ) );
m CollisionWorld - > addCollisionObject ( obj - > getCollisionObject ( ) , collisionType ,
m TaskScheduler - > addCollisionObject ( obj - > getCollisionObject ( ) , collisionType ,
CollisionType_Actor | CollisionType_HeightMap | CollisionType_Projectile ) ;
}
@ -496,21 +476,17 @@ namespace MWPhysics
ObjectMap : : iterator found = mObjects . find ( ptr ) ;
if ( found ! = mObjects . end ( ) )
{
mCollisionWorld - > removeCollisionObject ( found - > second - > getCollisionObject ( ) ) ;
if ( mUnrefQueue . get ( ) )
mUnrefQueue - > push ( found - > second - > getShapeInstance ( ) ) ;
mAnimatedObjects . erase ( found - > second );
mAnimatedObjects . erase ( found - > second .get ( ) );
delete found - > second ;
mObjects . erase ( found ) ;
}
ActorMap : : iterator foundActor = mActors . find ( ptr ) ;
if ( foundActor ! = mActors . end ( ) )
{
delete foundActor - > second ;
mActors . erase ( foundActor ) ;
}
}
@ -536,19 +512,19 @@ namespace MWPhysics
ObjectMap : : iterator found = mObjects . find ( old ) ;
if ( found ! = mObjects . end ( ) )
{
Object * obj = found - > second ;
auto obj = found - > second ;
obj - > updatePtr ( updated ) ;
mObjects . erase ( found ) ;
mObjects . emplace ( updated , obj) ;
mObjects . emplace ( updated , std: : move ( obj) ) ;
}
ActorMap : : iterator foundActor = mActors . find ( old ) ;
if ( foundActor ! = mActors . end ( ) )
{
Actor * actor = foundActor - > second ;
auto actor = foundActor - > second ;
actor - > updatePtr ( updated ) ;
mActors . erase ( foundActor ) ;
mActors . emplace ( updated , actor) ;
mActors . emplace ( updated , std: : move ( actor) ) ;
}
updateCollisionMapPtr ( mStandingCollisions , old , updated ) ;
@ -558,7 +534,7 @@ namespace MWPhysics
{
ActorMap : : iterator found = mActors . find ( ptr ) ;
if ( found ! = mActors . end ( ) )
return found - > second ;
return found - > second .get ( ) ;
return nullptr ;
}
@ -566,7 +542,7 @@ namespace MWPhysics
{
ActorMap : : const_iterator found = mActors . find ( ptr ) ;
if ( found ! = mActors . end ( ) )
return found - > second ;
return found - > second .get ( ) ;
return nullptr ;
}
@ -574,7 +550,7 @@ namespace MWPhysics
{
ObjectMap : : const_iterator found = mObjects . find ( ptr ) ;
if ( found ! = mObjects . end ( ) )
return found - > second ;
return found - > second .get ( ) ;
return nullptr ;
}
@ -585,14 +561,14 @@ namespace MWPhysics
{
float scale = ptr . getCellRef ( ) . getScale ( ) ;
found - > second - > setScale ( scale ) ;
m CollisionWorld - > updateSingleAabb ( found - > second - > getCollisionObject ( ) ) ;
m TaskScheduler - > updateSingleAabb ( found - > second ) ;
return ;
}
ActorMap : : iterator foundActor = mActors . find ( ptr ) ;
if ( foundActor ! = mActors . end ( ) )
{
foundActor - > second - > updateScale ( ) ;
m CollisionWorld - > updateSingleAabb ( foundActor - > second - > getCollisionObject ( ) ) ;
m TaskScheduler - > updateSingleAabb ( foundActor - > second ) ;
return ;
}
}
@ -603,7 +579,7 @@ namespace MWPhysics
if ( found ! = mObjects . end ( ) )
{
found - > second - > setRotation ( Misc : : Convert : : toBullet ( ptr . getRefData ( ) . getBaseNode ( ) - > getAttitude ( ) ) ) ;
m CollisionWorld - > updateSingleAabb ( found - > second - > getCollisionObject ( ) ) ;
m TaskScheduler - > updateSingleAabb ( found - > second ) ;
return ;
}
ActorMap : : iterator foundActor = mActors . find ( ptr ) ;
@ -612,7 +588,7 @@ namespace MWPhysics
if ( ! foundActor - > second - > isRotationallyInvariant ( ) )
{
foundActor - > second - > updateRotation ( ) ;
m CollisionWorld - > updateSingleAabb ( foundActor - > second - > getCollisionObject ( ) ) ;
m TaskScheduler - > updateSingleAabb ( foundActor - > second ) ;
}
return ;
}
@ -624,14 +600,14 @@ namespace MWPhysics
if ( found ! = mObjects . end ( ) )
{
found - > second - > setOrigin ( Misc : : Convert : : toBullet ( ptr . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) ) ;
m CollisionWorld - > updateSingleAabb ( found - > second - > getCollisionObject ( ) ) ;
m TaskScheduler - > updateSingleAabb ( found - > second ) ;
return ;
}
ActorMap : : iterator foundActor = mActors . find ( ptr ) ;
if ( foundActor ! = mActors . end ( ) )
{
foundActor - > second - > updatePosition ( ) ;
m CollisionWorld - > updateSingleAabb ( foundActor - > second - > getCollisionObject ( ) ) ;
m TaskScheduler - > updateSingleAabb ( foundActor - > second ) ;
return ;
}
}
@ -639,11 +615,9 @@ namespace MWPhysics
void PhysicsSystem : : addActor ( const MWWorld : : Ptr & ptr , const std : : string & mesh )
{
osg : : ref_ptr < const Resource : : BulletShape > shape = mShapeManager - > getShape ( mesh ) ;
if ( ! shape )
return ;
// Try to get shape from basic model as fallback for creatures
if ( ! ptr . getClass ( ) . isNpc ( ) & & shape - > mCollisionBoxHalfExtents . length2 ( ) = = 0 )
if ( ! ptr . getClass ( ) . isNpc ( ) & & shape & & shape - > mCollisionBoxHalfExtents . length2 ( ) = = 0 )
{
const std : : string fallbackModel = ptr . getClass ( ) . getModel ( ptr ) ;
if ( fallbackModel ! = mesh )
@ -652,8 +626,11 @@ namespace MWPhysics
}
}
Actor * actor = new Actor ( ptr , shape , mCollisionWorld ) ;
mActors . emplace ( ptr , actor ) ;
if ( ! shape )
return ;
auto actor = std : : make_shared < Actor > ( ptr , shape , mTaskScheduler . get ( ) ) ;
mActors . emplace ( ptr , std : : move ( actor ) ) ;
}
bool PhysicsSystem : : toggleCollisionMode ( )
@ -691,99 +668,76 @@ namespace MWPhysics
mStandingCollisions . clear ( ) ;
}
const Ptr Velocity List& PhysicsSystem : : applyQueuedMovement ( float dt )
const Ptr Position List& PhysicsSystem : : applyQueuedMovement ( float dt , bool skipSimulation )
{
mMovementResults . clear ( ) ;
mTimeAccum + = dt ;
const int maxAllowedSteps = 20 ;
int numSteps = mTimeAccum / ( mPhysicsDt ) ;
int numSteps = mTimeAccum / mPhysicsDt ;
numSteps = std : : min ( numSteps , maxAllowedSteps ) ;
mTimeAccum - = numSteps * mPhysicsDt ;
if ( numSteps )
{
// Collision events should be available on every frame
mStandingCollisions . clear ( ) ;
}
return mTaskScheduler - > moveActors ( numSteps , mTimeAccum , prepareFrameData ( ) , mStandingCollisions , skipSimulation ) ;
}
const MWWorld : : Ptr player = MWMechanics : : getPlayer ( ) ;
std : : vector < ActorFrameData > PhysicsSystem : : prepareFrameData ( )
{
std : : vector < ActorFrameData > actorsFrameData ;
actorsFrameData . reserve ( mMovementQueue . size ( ) ) ;
const MWBase : : World * world = MWBase : : Environment : : get ( ) . getWorld ( ) ;
for ( auto & movementItem : mMovementQueue )
for ( const auto& m : mMovementQueue )
{
ActorMap : : iterator foundActor = mActors . find ( movementItem . first ) ;
const auto & character = m . first ;
const auto & movement = m . second ;
const auto foundActor = mActors . find ( character ) ;
if ( foundActor = = mActors . end ( ) ) // actor was already removed from the scene
{
mStandingCollisions . erase ( character ) ;
continue ;
Actor * physicActor = foundActor - > second ;
}
auto physicActor = foundActor - > second ;
float waterlevel = - std : : numeric_limits < float > : : max ( ) ;
const MWWorld : : CellStore * cell = movementItem. first . getCell ( ) ;
const MWWorld : : CellStore * cell = character . getCell ( ) ;
if ( cell - > getCell ( ) - > hasWater ( ) )
waterlevel = cell - > getWaterLevel ( ) ;
const MWMechanics : : MagicEffects & effects = movementItem. first . getClass ( ) . getCreatureStats ( movementItem . first ) . getMagicEffects ( ) ;
const MWMechanics : : MagicEffects & effects = character. getClass ( ) . getCreatureStats ( character ) . getMagicEffects ( ) ;
bool waterCollision = false ;
bool moveToWaterSurface = false ;
if ( cell - > getCell ( ) - > hasWater ( ) & & effects . get ( ESM : : MagicEffect : : WaterWalking ) . getMagnitude ( ) )
{
if ( ! world - > isUnderwater ( movementItem. first . getCell ( ) , osg : : Vec3f ( movementItem. first . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) ) )
if ( ! world - > isUnderwater ( character . getCell ( ) , osg : : Vec3f ( character . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) ) )
waterCollision = true ;
else if ( physicActor - > getCollisionMode ( ) & & canMoveToWaterSurface ( movementItem. first , waterlevel ) )
else if ( physicActor - > getCollisionMode ( ) & & canMoveToWaterSurface ( character , waterlevel ) )
{
const osg : : Vec3f actorPosition = physicActor - > getPosition ( ) ;
physicActor - > setPosition ( osg : : Vec3f ( actorPosition . x ( ) , actorPosition . y ( ) , waterlevel ) ) ;
moveToWaterSurface = true ;
waterCollision = true ;
}
}
physicActor - > setCanWaterWalk ( waterCollision ) ;
// Slow fall reduces fall speed by a factor of (effect magnitude / 200)
float slowFall = 1.f - std : : max ( 0.f , std : : min ( 1.f , effects . get ( ESM : : MagicEffect : : SlowFall ) . getMagnitude ( ) * 0.005f ) ) ;
bool flying = world - > isFlying ( movementItem . first ) ;
bool swimming = world - > isSwimming ( movementItem . first ) ;
const float slowFall = 1.f - std : : max ( 0.f , std : : min ( 1.f , effects . get ( ESM : : MagicEffect : : SlowFall ) . getMagnitude ( ) * 0.005f ) ) ;
bool wasOnGround = physicActor - > getOnGround ( ) ;
osg : : Vec3f position = physicActor - > getPosition ( ) ;
float oldHeight = position . z ( ) ;
bool positionChanged = false ;
for ( int i = 0 ; i < numSteps ; + + i )
{
position = MovementSolver : : move ( position , physicActor - > getPtr ( ) , physicActor , movementItem . second , mPhysicsDt ,
flying , waterlevel , slowFall , mCollisionWorld , mStandingCollisions ) ;
if ( position ! = physicActor - > getPosition ( ) )
positionChanged = true ;
physicActor - > setPosition ( position ) ; // always set even if unchanged to make sure interpolation is correct
}
if ( positionChanged )
mCollisionWorld - > updateSingleAabb ( physicActor - > getCollisionObject ( ) ) ;
float interpolationFactor = mTimeAccum / mPhysicsDt ;
osg : : Vec3f interpolated = position * interpolationFactor + physicActor - > getPreviousPosition ( ) * ( 1.f - interpolationFactor ) ;
float heightDiff = position . z ( ) - oldHeight ;
MWMechanics : : CreatureStats & stats = movementItem . first . getClass ( ) . getCreatureStats ( movementItem . first ) ;
bool isStillOnGround = ( numSteps > 0 & & wasOnGround & & physicActor - > getOnGround ( ) ) ;
if ( isStillOnGround | | flying | | swimming | | slowFall < 1 )
stats . land ( movementItem . first = = player & & ( flying | | swimming ) ) ;
else if ( heightDiff < 0 )
stats . addToFallHeight ( - heightDiff ) ;
mMovementResults . emplace_back ( movementItem . first , interpolated ) ;
actorsFrameData . emplace_back ( std : : move ( physicActor ) , character , mStandingCollisions [ character ] , moveToWaterSurface , movement , slowFall , waterlevel ) ;
}
mMovementQueue . clear ( ) ;
return mMovementResults ;
return actorsFrameData ;
}
void PhysicsSystem : : stepSimulation ( float dt )
void PhysicsSystem : : stepSimulation ( )
{
for ( Object * animatedObject : mAnimatedObjects )
animatedObject - > animateCollisionShapes ( mCollisionWorld ) ;
for ( Object * animatedObject : mAnimatedObjects )
if ( animatedObject - > animateCollisionShapes ( ) )
{
auto obj = mObjects . find ( animatedObject - > getPtr ( ) ) ;
assert ( obj ! = mObjects . end ( ) ) ;
mTaskScheduler - > updateSingleAabb ( obj - > second ) ;
}
# ifndef BT_NO_PROFILE
CProfileManager : : Reset ( ) ;
@ -795,12 +749,13 @@ namespace MWPhysics
{
ObjectMap : : iterator found = mObjects . find ( object ) ;
if ( found ! = mObjects . end ( ) )
found - > second - > animateCollisionShapes ( mCollisionWorld ) ;
if ( found - > second - > animateCollisionShapes ( ) )
mTaskScheduler - > updateSingleAabb ( found - > second ) ;
}
void PhysicsSystem : : debugDraw ( )
{
if ( mDebugDrawer .get ( ) )
if ( mDebugDrawer )
mDebugDrawer - > step ( ) ;
}
@ -865,9 +820,9 @@ namespace MWPhysics
void PhysicsSystem : : updateWater ( )
{
if ( mWaterCollisionObject .get ( ) )
if ( mWaterCollisionObject )
{
m CollisionWorld - > removeCollisionObject ( mWaterCollisionObject . get ( ) ) ;
m TaskScheduler - > removeCollisionObject ( mWaterCollisionObject . get ( ) ) ;
}
if ( ! mWaterEnabled )
@ -879,7 +834,7 @@ namespace MWPhysics
mWaterCollisionObject . reset ( new btCollisionObject ( ) ) ;
mWaterCollisionShape . reset ( new btStaticPlaneShape ( btVector3 ( 0 , 0 , 1 ) , mWaterHeight ) ) ;
mWaterCollisionObject - > setCollisionShape ( mWaterCollisionShape . get ( ) ) ;
m CollisionWorld - > addCollisionObject ( mWaterCollisionObject . get ( ) , CollisionType_Water ,
m TaskScheduler - > addCollisionObject ( mWaterCollisionObject . get ( ) , CollisionType_Water ,
CollisionType_Actor ) ;
}
@ -895,7 +850,7 @@ namespace MWPhysics
const int mask = MWPhysics : : CollisionType_Actor ;
const int group = 0xff ;
HasSphereCollisionCallback callback ( bulletPosition , radius , object , mask , group ) ;
m CollisionWorld- > getBroadphase ( ) - > aabbTest ( aabbMin , aabbMax , callback ) ;
m TaskScheduler - > aabbTest ( aabbMin , aabbMax , callback ) ;
return callback . getResult ( ) ;
}
@ -905,4 +860,61 @@ namespace MWPhysics
stats . setAttribute ( frameNumber , " Physics Objects " , mObjects . size ( ) ) ;
stats . setAttribute ( frameNumber , " Physics HeightFields " , mHeightFields . size ( ) ) ;
}
ActorFrameData : : ActorFrameData ( const std : : shared_ptr < Actor > & actor , const MWWorld : : Ptr character , const MWWorld : : Ptr standingOn ,
bool moveToWaterSurface , osg : : Vec3f movement , float slowFall , float waterlevel )
: mActor ( actor ) , mActorRaw ( actor . get ( ) ) , mStandingOn ( standingOn ) ,
mPositionChanged ( false ) , mDidJump ( false ) , mNeedLand ( false ) , mMoveToWaterSurface ( moveToWaterSurface ) ,
mWaterlevel ( waterlevel ) , mSlowFall ( slowFall ) , mOldHeight ( 0 ) , mFallHeight ( 0 ) , mMovement ( movement ) , mPosition ( ) , mRefpos ( )
{
const MWBase : : World * world = MWBase : : Environment : : get ( ) . getWorld ( ) ;
mPtr = actor - > getPtr ( ) ;
mFlying = world - > isFlying ( character ) ;
mSwimming = world - > isSwimming ( character ) ;
mWantJump = mPtr . getClass ( ) . getMovementSettings ( mPtr ) . mPosition [ 2 ] ! = 0 ;
mIsDead = mPtr . getClass ( ) . getCreatureStats ( mPtr ) . isDead ( ) ;
mWasOnGround = actor - > getOnGround ( ) ;
}
void ActorFrameData : : updatePosition ( )
{
mPosition = mActorRaw - > getPosition ( ) ;
if ( mMoveToWaterSurface )
{
mPosition . z ( ) = mWaterlevel ;
mActorRaw - > setPosition ( mPosition ) ;
}
mOldHeight = mPosition . z ( ) ;
mRefpos = mPtr . getRefData ( ) . getPosition ( ) ;
}
WorldFrameData : : WorldFrameData ( )
: mIsInStorm ( MWBase : : Environment : : get ( ) . getWorld ( ) - > isInStorm ( ) )
, mStormDirection ( MWBase : : Environment : : get ( ) . getWorld ( ) - > getStormDirection ( ) )
{ }
LOSRequest : : LOSRequest ( const std : : weak_ptr < Actor > & a1 , const std : : weak_ptr < Actor > & a2 )
: mResult ( false ) , mStale ( false ) , mAge ( 0 )
{
// we use raw actor pointer pair to uniquely identify request
// sort the pointer value in ascending order to not duplicate equivalent requests, eg. getLOS(A, B) and getLOS(B, A)
auto * raw1 = a1 . lock ( ) . get ( ) ;
auto * raw2 = a2 . lock ( ) . get ( ) ;
assert ( raw1 ! = raw2 ) ;
if ( raw1 < raw2 )
{
mActors = { a1 , a2 } ;
mRawActors = { raw1 , raw2 } ;
}
else
{
mActors = { a2 , a1 } ;
mRawActors = { raw2 , raw1 } ;
}
}
bool operator = = ( const LOSRequest & lhs , const LOSRequest & rhs ) noexcept
{
return lhs . mRawActors = = rhs . mRawActors ;
}
}