2012-07-03 10:30:50 +00:00
# include "physicssystem.hpp"
2011-10-29 07:50:11 +00:00
# include <stdexcept>
2015-05-02 22:39:01 +00:00
# include <osg/Group>
2015-05-10 00:08:25 +00:00
# include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
2015-05-27 20:32:11 +00:00
# include <BulletCollision/CollisionShapes/btConeShape.h>
2015-06-01 13:34:46 +00:00
# include <BulletCollision/CollisionShapes/btSphereShape.h>
2015-05-27 20:32:11 +00:00
# include <BulletCollision/CollisionShapes/btStaticPlaneShape.h>
# include <BulletCollision/CollisionShapes/btCompoundShape.h>
# include <BulletCollision/CollisionDispatch/btCollisionObject.h>
# include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
# include <BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h>
2015-05-27 21:09:38 +00:00
# include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
2015-05-27 20:32:11 +00:00
# include <BulletCollision/BroadphaseCollision/btDbvtBroadphase.h>
2016-10-14 18:59:55 +00:00
2015-05-27 21:09:38 +00:00
# include <LinearMath/btQuickprof.h>
2015-05-10 00:08:25 +00:00
2013-02-24 21:52:23 +00:00
# include <components/nifbullet/bulletnifloader.hpp>
2015-05-12 14:24:53 +00:00
# include <components/resource/resourcesystem.hpp>
2015-11-16 22:30:10 +00:00
# include <components/resource/bulletshapemanager.hpp>
2011-08-01 13:55:36 +00:00
2014-02-23 19:11:05 +00:00
# include <components/esm/loadgmst.hpp>
2015-11-20 20:57:04 +00:00
# include <components/sceneutil/positionattitudetransform.hpp>
2016-02-09 18:04:59 +00:00
# include <components/sceneutil/unrefqueue.hpp>
2014-02-23 19:11:05 +00:00
2015-05-12 14:24:53 +00:00
# include <components/nifosg/particle.hpp> // FindRecIndexVisitor
2015-05-12 01:02:15 +00:00
# include "../mwbase/world.hpp"
2012-11-05 18:40:02 +00:00
# include "../mwbase/environment.hpp"
2011-08-01 13:55:36 +00:00
2013-12-27 20:21:18 +00:00
# include "../mwmechanics/creaturestats.hpp"
2014-09-17 00:20:46 +00:00
# include "../mwmechanics/movement.hpp"
2015-08-21 09:12:39 +00:00
# include "../mwmechanics/actorutil.hpp"
2013-12-27 20:21:18 +00:00
2013-08-03 10:16:51 +00:00
# include "../mwworld/esmstore.hpp"
2014-02-23 19:11:05 +00:00
# include "../mwworld/cellstore.hpp"
2013-08-03 10:16:51 +00:00
2015-05-02 22:39:01 +00:00
# include "../mwrender/bulletdebugdraw.hpp"
2015-05-09 22:28:51 +00:00
# include "../mwbase/world.hpp"
# include "../mwbase/environment.hpp"
2014-06-23 18:43:24 +00:00
2015-05-09 23:09:00 +00:00
# include "../mwworld/class.hpp"
2012-03-20 00:03:48 +00:00
2015-05-12 01:02:15 +00:00
# include "collisiontype.hpp"
# include "actor.hpp"
# include "convert.hpp"
# include "trace.h"
2015-05-09 23:09:00 +00:00
namespace MWPhysics
2011-08-01 13:55:36 +00:00
{
2014-05-18 02:05:08 +00:00
static const float sMaxSlope = 49.0f ;
2014-12-21 15:56:14 +00:00
static const float sStepSizeUp = 34.0f ;
static const float sStepSizeDown = 62.0f ;
2013-02-07 21:18:16 +00:00
// Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared.
2013-08-20 11:41:52 +00:00
static const int sMaxIterations = 8 ;
2013-02-05 20:45:10 +00:00
2015-05-12 01:02:15 +00:00
// FIXME: move to a separate file
2013-02-05 20:45:10 +00:00
class MovementSolver
{
private :
2015-05-31 16:04:14 +00:00
static float getSlope ( osg : : Vec3f normal )
2013-08-17 08:11:57 +00:00
{
2015-05-31 16:04:14 +00:00
normal . normalize ( ) ;
2015-05-12 01:02:15 +00:00
return osg : : RadiansToDegrees ( std : : acos ( normal * osg : : Vec3f ( 0.f , 0.f , 1.f ) ) ) ;
2013-08-17 08:11:57 +00:00
}
2016-12-02 01:25:05 +00:00
enum StepMoveResult
{
Result_Blocked , // unable to move over obstacle
Result_MaxSlope , // unable to end movement on this slope
Result_Success
} ;
static StepMoveResult stepMove ( const btCollisionObject * colobj , osg : : Vec3f & position ,
2016-03-05 15:09:56 +00:00
const osg : : Vec3f & toMove , float & remainingTime , const btCollisionWorld * collisionWorld )
2013-02-05 20:45:10 +00:00
{
2014-03-23 02:24:04 +00:00
/*
* Slide up an incline or set of stairs . Should be called only after a
* collision detection otherwise unnecessary tracing will be performed .
*
* NOTE : with a small change this method can be used to step over an obstacle
* of height sStepSize .
*
* If successful return ' true ' and update ' position ' to the new possible
* location and adjust ' remainingTime ' .
*
* If not successful return ' false ' . May fail for these reasons :
* - can ' t move directly up from current position
* - having moved up by between epsilon ( ) and sStepSize , can ' t move forward
2015-01-01 23:34:16 +00:00
* - having moved forward by between epsilon ( ) and toMove ,
2014-03-23 02:24:04 +00:00
* = moved down between 0 and just under sStepSize but slope was too steep , or
* = moved the full sStepSize down ( FIXME : this could be a bug )
*
*
*
* Starting position . Obstacle or stairs with height upto sStepSize in front .
*
* + - - + + - - + | XX
2015-01-01 23:34:16 +00:00
* | | - - - - - - - > toMove | | + - - + XX
2014-03-23 02:24:04 +00:00
* | | | | | XXXXX
* | | + - - + | | + - - + XXXXX
* | | | XX | | | | XXXXXXXX
* + - - + + - - + + - - + + - - - - - - - -
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
* Try moving up sStepSize using stepper .
* FIXME : does not work in case there is no front obstacle but there is one above
*
* + - - + + - - +
* | | | |
* | | | | | XX
* | | | | + - - + XX
* | | | | | XXXXX
* + - - + + - - + + - - + + - - + XXXXX
* | XX | | XXXXXXXX
* + - - + + - - - - - - - -
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2015-05-12 01:02:15 +00:00
ActorTracer tracer , stepper ;
2013-08-18 15:24:39 +00:00
2015-05-27 21:09:38 +00:00
stepper . doTrace ( colobj , position , position + osg : : Vec3f ( 0.0f , 0.0f , sStepSizeUp ) , collisionWorld ) ;
2013-08-25 18:04:55 +00:00
if ( stepper . mFraction < std : : numeric_limits < float > : : epsilon ( ) )
2016-12-02 01:25:05 +00:00
return Result_Blocked ; // didn't even move the smallest representable amount
2014-03-23 02:24:04 +00:00
// (TODO: shouldn't this be larger? Why bother with such a small amount?)
2013-02-20 15:51:36 +00:00
2014-03-23 02:24:04 +00:00
/*
* Try moving from the elevated position using tracer .
*
* + - - + + - - +
* | | | YY | FIXME : collision with object YY
* | | + - - +
* | |
* < - - - - - - - - - - - - - - - - - - - > | |
* + - - + + - - +
2015-01-01 23:34:16 +00:00
* | XX | the moved amount is toMove * tracer . mFraction
2014-03-23 02:24:04 +00:00
* + - - +
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2015-05-27 21:09:38 +00:00
tracer . doTrace ( colobj , stepper . mEndPos , stepper . mEndPos + toMove , collisionWorld ) ;
2013-08-25 18:04:55 +00:00
if ( tracer . mFraction < std : : numeric_limits < float > : : epsilon ( ) )
2016-12-02 01:25:05 +00:00
return Result_Blocked ; // didn't even move the smallest representable amount
2013-02-05 20:45:10 +00:00
2014-03-23 02:24:04 +00:00
/*
2014-12-21 15:56:14 +00:00
* Try moving back down sStepSizeDown using stepper .
2014-03-23 02:24:04 +00:00
* NOTE : if there is an obstacle below ( e . g . stairs ) , we ' ll be " stepping up " .
* Below diagram is the case where we " stepped over " an obstacle in front .
*
* + - - +
* | YY |
* + - - + + - - +
* | |
* | |
* + - - + | |
* | XX | | |
* + - - + + - - +
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2015-05-27 21:09:38 +00:00
stepper . doTrace ( colobj , tracer . mEndPos , tracer . mEndPos - osg : : Vec3f ( 0.0f , 0.0f , sStepSizeDown ) , collisionWorld ) ;
2016-12-02 01:25:05 +00:00
if ( getSlope ( stepper . mPlaneNormal ) > sMaxSlope )
return Result_MaxSlope ;
if ( stepper . mFraction < 1.0f )
2013-02-05 20:45:10 +00:00
{
2014-12-16 19:44:42 +00:00
// don't allow stepping up other actors
2015-05-10 00:08:25 +00:00
if ( stepper . mHitObject - > getBroadphaseHandle ( ) - > m_collisionFilterGroup = = CollisionType_Actor )
2016-12-02 01:25:05 +00:00
return Result_Blocked ;
2013-02-05 20:45:10 +00:00
// only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall.
2014-03-23 02:24:04 +00:00
// TODO: stepper.mPlaneNormal does not appear to be reliable - needs more testing
// NOTE: caller's variables 'position' & 'remainingTime' are modified here
2013-08-18 15:24:39 +00:00
position = stepper . mEndPos ;
2014-03-23 02:24:04 +00:00
remainingTime * = ( 1.0f - tracer . mFraction ) ; // remaining time is proportional to remaining distance
2016-12-02 01:25:05 +00:00
return Result_Success ;
2013-02-05 20:45:10 +00:00
}
2016-12-02 01:25:05 +00:00
return Result_Blocked ;
2013-02-05 20:45:10 +00:00
}
2013-08-17 08:11:57 +00:00
///Project a vector u on another vector v
2015-05-12 01:02:15 +00:00
static inline osg : : Vec3f project ( const osg : : Vec3f & u , const osg : : Vec3f & v )
2013-02-05 20:45:10 +00:00
{
2015-05-12 01:02:15 +00:00
return v * ( u * v ) ;
// ^ dot product
2013-02-05 20:45:10 +00:00
}
2013-08-17 08:11:57 +00:00
///Helper for computing the character sliding
2015-05-12 01:02:15 +00:00
static inline osg : : Vec3f slide ( const osg : : Vec3f & direction , const osg : : Vec3f & planeNormal )
2013-02-05 20:45:10 +00:00
{
2013-08-17 08:11:57 +00:00
return direction - project ( direction , planeNormal ) ;
2013-02-05 20:45:10 +00:00
}
2015-05-12 01:02:15 +00:00
static inline osg : : Vec3f reflect ( const osg : : Vec3 & velocity , const osg : : Vec3f & normal )
{
2015-05-21 19:04:48 +00:00
return velocity - ( normal * ( normal * velocity ) ) * 2 ;
// ^ dot product
2015-05-12 01:02:15 +00:00
}
2013-08-17 08:11:57 +00:00
2013-02-05 20:45:10 +00:00
public :
2015-05-27 21:09:38 +00:00
static osg : : Vec3f traceDown ( const MWWorld : : Ptr & ptr , Actor * actor , btCollisionWorld * collisionWorld , float maxHeight )
2013-04-03 21:55:57 +00:00
{
2015-05-12 01:02:15 +00:00
osg : : Vec3f position ( ptr . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) ;
2013-04-03 21:55:57 +00:00
2015-05-12 01:02:15 +00:00
ActorTracer tracer ;
2015-05-27 21:09:38 +00:00
tracer . findGround ( actor , position , position - osg : : Vec3f ( 0 , 0 , maxHeight ) , collisionWorld ) ;
2013-08-17 11:42:35 +00:00
if ( tracer . mFraction > = 1.0f )
2013-08-19 11:56:02 +00:00
{
2015-05-12 01:02:15 +00:00
actor - > setOnGround ( false ) ;
2013-08-17 10:55:04 +00:00
return position ;
2013-08-19 11:56:02 +00:00
}
2014-10-03 16:32:46 +00:00
else
{
// Check if we actually found a valid spawn point (use an infinitely thin ray this time).
// Required for some broken door destinations in Morrowind.esm, where the spawn point
// intersects with other geometry if the actor's base is taken into account
2015-05-12 01:02:15 +00:00
btVector3 from = toBullet ( position ) ;
2014-10-03 16:32:46 +00:00
btVector3 to = from - btVector3 ( 0 , 0 , maxHeight ) ;
btCollisionWorld : : ClosestRayResultCallback resultCallback1 ( from , to ) ;
resultCallback1 . m_collisionFilterGroup = 0xff ;
2015-05-10 00:08:25 +00:00
resultCallback1 . m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap ;
2014-10-03 16:32:46 +00:00
2015-05-27 21:09:38 +00:00
collisionWorld - > rayTest ( from , to , resultCallback1 ) ;
2015-11-18 18:00:43 +00:00
2014-10-03 16:32:46 +00:00
if ( resultCallback1 . hasHit ( ) & &
2016-03-11 21:29:50 +00:00
( ( toOsg ( resultCallback1 . m_hitPointWorld ) - tracer . mEndPos ) . length ( ) > 35
2014-10-03 16:32:46 +00:00
| | getSlope ( tracer . mPlaneNormal ) > sMaxSlope ) )
{
2015-05-12 01:02:15 +00:00
actor - > setOnGround ( getSlope ( toOsg ( resultCallback1 . m_hitNormalWorld ) ) < = sMaxSlope ) ;
return toOsg ( resultCallback1 . m_hitPointWorld ) + osg : : Vec3f ( 0.f , 0.f , 1.f ) ;
2014-10-03 16:32:46 +00:00
}
2015-05-12 01:02:15 +00:00
actor - > setOnGround ( getSlope ( tracer . mPlaneNormal ) < = sMaxSlope ) ;
2014-10-03 16:32:46 +00:00
return tracer . mEndPos ;
}
2013-04-03 21:55:57 +00:00
}
2016-02-13 01:56:41 +00:00
static osg : : Vec3f move ( osg : : Vec3f position , const MWWorld : : Ptr & ptr , Actor * physicActor , const osg : : Vec3f & movement , float time ,
2016-03-05 15:09:56 +00:00
bool isFlying , float waterlevel , float slowFall , const btCollisionWorld * collisionWorld ,
2015-11-18 20:20:12 +00:00
std : : map < MWWorld : : Ptr , MWWorld : : Ptr > & standingCollisionTracker )
2013-02-05 20:45:10 +00:00
{
2015-05-12 01:02:15 +00:00
const ESM : : Position & refpos = ptr . getRefData ( ) . getPosition ( ) ;
2014-06-10 00:15:09 +00:00
// Early-out for totally static creatures
// (Not sure if gravity should still apply?)
2015-01-09 08:40:53 +00:00
if ( ! ptr . getClass ( ) . isMobile ( ptr ) )
2014-06-10 00:15:09 +00:00
return position ;
2014-10-05 20:24:11 +00:00
// Reset per-frame data
physicActor - > setWalkingOnWater ( false ) ;
2015-01-13 02:11:29 +00:00
// Anything to collide with?
2014-12-18 02:24:10 +00:00
if ( ! physicActor - > getCollisionMode ( ) )
2013-02-06 20:39:26 +00:00
{
2015-05-12 01:02:15 +00:00
return position + ( osg : : Quat ( refpos . rot [ 0 ] , osg : : Vec3f ( - 1 , 0 , 0 ) ) *
osg : : Quat ( refpos . rot [ 2 ] , osg : : Vec3f ( 0 , 0 , - 1 ) )
) * movement * time ;
2013-02-06 20:39:26 +00:00
}
2013-02-05 20:45:10 +00:00
2016-03-05 15:09:56 +00:00
const btCollisionObject * colobj = physicActor - > getCollisionObject ( ) ;
2015-11-08 18:59:33 +00:00
osg : : Vec3f halfExtents = physicActor - > getHalfExtents ( ) ;
// NOTE: here we don't account for the collision box translation (i.e. physicActor->getPosition() - refpos.pos).
// That means the collision shape used for moving this actor is in a different spot than the collision shape
// other actors are using to collide against this actor.
// While this is strictly speaking wrong, it's needed for MW compatibility.
position . z ( ) + = halfExtents . z ( ) ;
2014-03-16 09:56:11 +00:00
2015-01-31 19:54:08 +00:00
static const float fSwimHeightScale = MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) . get < ESM : : GameSetting > ( )
. find ( " fSwimHeightScale " ) - > getFloat ( ) ;
2015-11-08 18:59:33 +00:00
float swimlevel = waterlevel + halfExtents . z ( ) - ( physicActor - > getRenderingHalfExtents ( ) . z ( ) * 2 * fSwimHeightScale ) ;
2013-08-21 14:06:07 +00:00
2015-05-12 01:02:15 +00:00
ActorTracer tracer ;
osg : : Vec3f inertia = physicActor - > getInertialForce ( ) ;
osg : : Vec3f velocity ;
2014-03-15 21:09:14 +00:00
2015-05-12 01:02:15 +00:00
if ( position . z ( ) < swimlevel | | isFlying )
2013-02-06 20:39:26 +00:00
{
2015-05-12 01:02:15 +00:00
velocity = ( osg : : Quat ( refpos . rot [ 0 ] , osg : : Vec3f ( - 1 , 0 , 0 ) ) *
osg : : Quat ( refpos . rot [ 2 ] , osg : : Vec3f ( 0 , 0 , - 1 ) ) ) * movement ;
2013-02-06 20:39:26 +00:00
}
else
{
2015-05-12 01:02:15 +00:00
velocity = ( osg : : Quat ( refpos . rot [ 2 ] , osg : : Vec3f ( 0 , 0 , - 1 ) ) ) * movement ;
2014-09-17 00:20:46 +00:00
2016-06-15 17:38:04 +00:00
if ( velocity . z ( ) > 0.f & & physicActor - > getOnGround ( ) )
2015-01-13 02:11:29 +00:00
inertia = velocity ;
2016-06-15 17:38:04 +00:00
else if ( ! physicActor - > getOnGround ( ) )
2013-08-19 15:09:23 +00:00
{
2015-01-13 02:11:29 +00:00
velocity = velocity + physicActor - > getInertialForce ( ) ;
2013-08-19 15:09:23 +00:00
}
2013-02-06 20:39:26 +00:00
}
2015-11-08 19:58:00 +00:00
2016-02-01 22:13:43 +00:00
// dead actors underwater will float to the surface, if the CharacterController tells us to do so
if ( movement . z ( ) > 0 & & ptr . getClass ( ) . getCreatureStats ( ptr ) . isDead ( ) & & position . z ( ) < swimlevel )
2015-11-08 19:58:00 +00:00
velocity = osg : : Vec3f ( 0 , 0 , 1 ) * 25 ;
2014-09-17 00:20:46 +00:00
ptr . getClass ( ) . getMovementSettings ( ptr ) . mPosition [ 2 ] = 0 ;
2013-02-06 20:39:26 +00:00
2014-06-26 18:26:46 +00:00
// Now that we have the effective movement vector, apply wind forces to it
if ( MWBase : : Environment : : get ( ) . getWorld ( ) - > isInStorm ( ) )
2013-02-05 20:45:10 +00:00
{
2015-05-12 01:02:15 +00:00
osg : : Vec3f stormDirection = MWBase : : Environment : : get ( ) . getWorld ( ) - > getStormDirection ( ) ;
2015-06-05 01:35:59 +00:00
float angleDegrees = osg : : RadiansToDegrees ( std : : acos ( stormDirection * velocity / ( stormDirection . length ( ) * velocity . length ( ) ) ) ) ;
2014-06-26 18:26:46 +00:00
static const float fStromWalkMult = MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) . get < ESM : : GameSetting > ( )
. find ( " fStromWalkMult " ) - > getFloat ( ) ;
2015-05-12 01:02:15 +00:00
velocity * = 1.f - ( fStromWalkMult * ( angleDegrees / 180.f ) ) ;
2013-02-05 20:45:10 +00:00
}
2015-05-12 01:02:15 +00:00
osg : : Vec3f origVelocity = velocity ;
2015-01-14 23:58:12 +00:00
2015-05-12 01:02:15 +00:00
osg : : Vec3f newPosition = position ;
2014-03-15 21:09:14 +00:00
/*
* A loop to find newPosition using tracer , if successful different from the starting position .
* nextpos is the local variable used to find potential newPosition , using velocity and remainingTime
* The initial velocity was set earlier ( see above ) .
*/
2013-08-17 08:11:57 +00:00
float remainingTime = time ;
2014-03-15 21:09:14 +00:00
for ( int iterations = 0 ; iterations < sMaxIterations & & remainingTime > 0.01f ; + + iterations )
2013-08-17 08:11:57 +00:00
{
2015-05-12 01:02:15 +00:00
osg : : Vec3f nextpos = newPosition + velocity * remainingTime ;
2014-03-15 21:09:14 +00:00
2014-05-03 09:33:20 +00:00
// If not able to fly, don't allow to swim up into the air
2015-05-12 01:02:15 +00:00
if ( newPosition . z ( ) < swimlevel & &
2014-03-15 21:09:14 +00:00
! isFlying & & // can't fly
2015-05-12 01:02:15 +00:00
nextpos . z ( ) > swimlevel & & // but about to go above water
newPosition . z ( ) < = swimlevel )
2013-08-21 14:06:07 +00:00
{
2015-05-12 01:02:15 +00:00
const osg : : Vec3f down ( 0 , 0 , - 1 ) ;
float movelen = velocity . normalize ( ) ;
osg : : Vec3f reflectdir = reflect ( velocity , down ) ;
reflectdir . normalize ( ) ;
2013-08-21 14:06:07 +00:00
velocity = slide ( reflectdir , down ) * movelen ;
2014-03-16 09:56:11 +00:00
// NOTE: remainingTime is unchanged before the loop continues
2014-03-15 21:09:14 +00:00
continue ; // velocity updated, calculate nextpos again
2013-08-21 14:06:07 +00:00
}
2015-05-12 01:02:15 +00:00
if ( ( newPosition - nextpos ) . length2 ( ) > 0.0001 )
2014-06-08 00:26:12 +00:00
{
// trace to where character would go if there were no obstructions
2015-05-27 21:09:38 +00:00
tracer . doTrace ( colobj , newPosition , nextpos , collisionWorld ) ;
2013-02-05 20:45:10 +00:00
2014-06-08 00:26:12 +00:00
// check for obstructions
if ( tracer . mFraction > = 1.0f )
{
newPosition = tracer . mEndPos ; // ok to move, so set newPosition
break ;
}
}
else
2013-02-05 20:45:10 +00:00
{
2014-06-08 00:26:12 +00:00
// The current position and next position are nearly the same, so just exit.
// Note: Bullet can trigger an assert in debug modes if the positions
// are the same, since that causes it to attempt to normalize a zero
// length vector (which can also happen with nearly identical vectors, since
// precision can be lost due to any math Bullet does internally). Since we
// aren't performing any collision detection, we want to reject the next
// position, so that we don't slowly move inside another object.
2013-08-17 08:11:57 +00:00
break ;
2013-02-05 20:45:10 +00:00
}
2014-06-08 00:26:12 +00:00
2015-05-12 01:02:15 +00:00
osg : : Vec3f oldPosition = newPosition ;
2014-03-23 02:24:04 +00:00
// We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over)
2014-04-11 11:24:00 +00:00
// NOTE: stepMove modifies newPosition if successful
2016-12-02 01:25:05 +00:00
const float minStep = 10.f ;
StepMoveResult result = stepMove ( colobj , newPosition , velocity * remainingTime , remainingTime , collisionWorld ) ;
if ( result = = Result_MaxSlope & & ( velocity * remainingTime ) . length ( ) < minStep ) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent
2015-05-12 01:02:15 +00:00
{
osg : : Vec3f normalizedVelocity = velocity ;
normalizedVelocity . normalize ( ) ;
2016-12-02 01:25:05 +00:00
result = stepMove ( colobj , newPosition , normalizedVelocity * minStep , remainingTime , collisionWorld ) ;
2015-05-12 01:02:15 +00:00
}
2016-12-02 01:25:05 +00:00
if ( result = = Result_Success )
2014-04-11 11:24:00 +00:00
{
2014-04-27 12:59:21 +00:00
// don't let pure water creatures move out of water after stepMove
2015-01-09 08:40:53 +00:00
if ( ptr . getClass ( ) . isPureWaterCreature ( ptr )
2015-11-08 18:59:33 +00:00
& & newPosition . z ( ) + halfExtents . z ( ) > waterlevel )
2014-04-11 11:24:00 +00:00
newPosition = oldPosition ;
}
2013-08-17 08:11:57 +00:00
else
{
// Can't move this way, try to find another spot along the plane
2015-05-12 01:02:15 +00:00
osg : : Vec3f direction = velocity ;
float movelen = direction . normalize ( ) ;
osg : : Vec3f reflectdir = reflect ( velocity , tracer . mPlaneNormal ) ;
reflectdir . normalize ( ) ;
2015-01-14 23:58:12 +00:00
2015-05-12 01:02:15 +00:00
osg : : Vec3f newVelocity = slide ( reflectdir , tracer . mPlaneNormal ) * movelen ;
if ( ( newVelocity - velocity ) . length2 ( ) < 0.01 )
2015-01-14 23:58:12 +00:00
break ;
2015-05-12 01:02:15 +00:00
if ( ( velocity * origVelocity ) < = 0.f )
break ; // ^ dot product
2015-01-14 23:58:12 +00:00
velocity = newVelocity ;
2013-08-17 08:11:57 +00:00
// Do not allow sliding upward if there is gravity. Stepping will have taken
// care of that.
2015-05-12 01:02:15 +00:00
if ( ! ( newPosition . z ( ) < swimlevel | | isFlying ) )
velocity . z ( ) = std : : min ( velocity . z ( ) , 0.0f ) ;
2013-08-17 08:11:57 +00:00
}
}
2013-02-05 20:45:10 +00:00
2014-10-05 20:59:24 +00:00
bool isOnGround = false ;
2015-05-12 01:02:15 +00:00
if ( ! ( inertia . z ( ) > 0.f ) & & ! ( newPosition . z ( ) < swimlevel ) )
2013-02-15 02:34:51 +00:00
{
2015-05-12 01:02:15 +00:00
osg : : Vec3f from = newPosition ;
osg : : Vec3f to = newPosition - ( physicActor - > getOnGround ( ) ?
osg : : Vec3f ( 0 , 0 , sStepSizeDown + 2.f ) : osg : : Vec3f ( 0 , 0 , 2.f ) ) ;
2015-05-27 21:09:38 +00:00
tracer . doTrace ( colobj , from , to , collisionWorld ) ;
2014-12-16 22:18:41 +00:00
if ( tracer . mFraction < 1.0f & & getSlope ( tracer . mPlaneNormal ) < = sMaxSlope
2015-05-10 00:08:25 +00:00
& & tracer . mHitObject - > getBroadphaseHandle ( ) - > m_collisionFilterGroup ! = CollisionType_Actor )
2013-08-19 15:09:23 +00:00
{
2014-09-29 20:30:21 +00:00
const btCollisionObject * standingOn = tracer . mHitObject ;
2015-12-18 16:30:39 +00:00
PtrHolder * ptrHolder = static_cast < PtrHolder * > ( standingOn - > getUserPointer ( ) ) ;
2015-05-29 23:32:00 +00:00
if ( ptrHolder )
standingCollisionTracker [ ptr ] = ptrHolder - > getPtr ( ) ;
2015-05-21 23:43:45 +00:00
2015-05-10 00:08:25 +00:00
if ( standingOn - > getBroadphaseHandle ( ) - > m_collisionFilterGroup = = CollisionType_Water )
2014-10-05 20:24:11 +00:00
physicActor - > setWalkingOnWater ( true ) ;
2014-10-05 20:59:24 +00:00
if ( ! isFlying )
2015-05-12 01:02:15 +00:00
newPosition . z ( ) = tracer . mEndPos . z ( ) + 1.0f ;
2014-09-29 20:30:21 +00:00
2013-08-19 15:09:23 +00:00
isOnGround = true ;
}
2013-02-15 02:34:51 +00:00
else
2014-12-16 22:18:41 +00:00
{
// standing on actors is not allowed (see above).
// in addition to that, apply a sliding effect away from the center of the actor,
// so that we do not stay suspended in air indefinitely.
2015-05-10 00:08:25 +00:00
if ( tracer . mFraction < 1.0f & & tracer . mHitObject - > getBroadphaseHandle ( ) - > m_collisionFilterGroup = = CollisionType_Actor )
2014-12-16 22:18:41 +00:00
{
2015-05-12 01:02:15 +00:00
if ( osg : : Vec3f ( velocity . x ( ) , velocity . y ( ) , 0 ) . length2 ( ) < 100.f * 100.f )
2014-12-16 22:18:41 +00:00
{
btVector3 aabbMin , aabbMax ;
tracer . mHitObject - > getCollisionShape ( ) - > getAabb ( tracer . mHitObject - > getWorldTransform ( ) , aabbMin , aabbMax ) ;
btVector3 center = ( aabbMin + aabbMax ) / 2.f ;
2015-05-12 01:02:15 +00:00
inertia = osg : : Vec3f ( position . x ( ) - center . x ( ) , position . y ( ) - center . y ( ) , 0 ) ;
inertia . normalize ( ) ;
2014-12-16 22:18:41 +00:00
inertia * = 100 ;
}
}
2013-08-18 12:38:50 +00:00
isOnGround = false ;
2014-12-16 22:18:41 +00:00
}
2013-02-15 02:34:51 +00:00
}
2013-08-17 08:11:57 +00:00
2015-05-12 01:02:15 +00:00
if ( isOnGround | | newPosition . z ( ) < swimlevel | | isFlying )
physicActor - > setInertialForce ( osg : : Vec3f ( 0.f , 0.f , 0.f ) ) ;
2013-08-18 12:38:50 +00:00
else
{
2015-05-12 01:02:15 +00:00
inertia . z ( ) + = time * - 627.2f ;
if ( inertia . z ( ) < 0 )
inertia . z ( ) * = slowFall ;
2016-06-10 13:22:12 +00:00
if ( slowFall < 1.f ) {
2016-11-26 11:27:11 +00:00
inertia . x ( ) * = slowFall ;
inertia . y ( ) * = slowFall ;
2016-06-10 13:22:12 +00:00
}
2013-08-18 12:38:50 +00:00
physicActor - > setInertialForce ( inertia ) ;
}
2013-08-18 15:24:39 +00:00
physicActor - > setOnGround ( isOnGround ) ;
2013-08-17 08:11:57 +00:00
2015-11-08 18:59:33 +00:00
newPosition . z ( ) - = halfExtents . z ( ) ; // remove what was added at the beginning
2013-02-05 20:45:10 +00:00
return newPosition ;
}
} ;
2015-05-10 00:08:25 +00:00
// ---------------------------------------------------------------
class HeightField
{
public :
2015-08-31 14:08:19 +00:00
HeightField ( const float * heights , int x , int y , float triSize , float sqrtVerts )
2015-05-10 00:08:25 +00:00
{
// find the minimum and maximum heights (needed for bullet)
float minh = heights [ 0 ] ;
float maxh = heights [ 0 ] ;
for ( int i = 1 ; i < sqrtVerts * sqrtVerts ; + + i )
{
float h = heights [ i ] ;
if ( h > maxh ) maxh = h ;
if ( h < minh ) minh = h ;
}
mShape = new btHeightfieldTerrainShape (
sqrtVerts , sqrtVerts , heights , 1 ,
minh , maxh , 2 ,
PHY_FLOAT , true
) ;
mShape - > setUseDiamondSubdivision ( true ) ;
mShape - > setLocalScaling ( btVector3 ( triSize , triSize , 1 ) ) ;
btTransform transform ( btQuaternion : : getIdentity ( ) ,
btVector3 ( ( x + 0.5f ) * triSize * ( sqrtVerts - 1 ) ,
( y + 0.5f ) * triSize * ( sqrtVerts - 1 ) ,
( maxh + minh ) * 0.5f ) ) ;
mCollisionObject = new btCollisionObject ;
mCollisionObject - > setCollisionShape ( mShape ) ;
mCollisionObject - > setWorldTransform ( transform ) ;
}
~ HeightField ( )
{
delete mCollisionObject ;
delete mShape ;
}
btCollisionObject * getCollisionObject ( )
{
return mCollisionObject ;
}
private :
btHeightfieldTerrainShape * mShape ;
btCollisionObject * mCollisionObject ;
2016-01-03 17:20:34 +00:00
void operator = ( const HeightField & ) ;
HeightField ( const HeightField & ) ;
2015-05-10 00:08:25 +00:00
} ;
2015-05-12 01:02:15 +00:00
// --------------------------------------------------------------
class Object : public PtrHolder
{
public :
2015-11-16 22:30:10 +00:00
Object ( const MWWorld : : Ptr & ptr , osg : : ref_ptr < Resource : : BulletShapeInstance > shapeInstance )
2015-05-12 01:02:15 +00:00
: mShapeInstance ( shapeInstance )
2015-11-20 18:22:31 +00:00
, mSolid ( true )
2015-05-12 01:02:15 +00:00
{
mPtr = ptr ;
mCollisionObject . reset ( new btCollisionObject ) ;
mCollisionObject - > setCollisionShape ( shapeInstance - > getCollisionShape ( ) ) ;
2015-05-10 00:08:25 +00:00
2015-05-12 01:02:15 +00:00
mCollisionObject - > setUserPointer ( static_cast < PtrHolder * > ( this ) ) ;
2015-05-10 00:08:25 +00:00
2015-05-12 01:02:15 +00:00
setScale ( ptr . getCellRef ( ) . getScale ( ) ) ;
setRotation ( toBullet ( ptr . getRefData ( ) . getBaseNode ( ) - > getAttitude ( ) ) ) ;
const float * pos = ptr . getRefData ( ) . getPosition ( ) . pos ;
setOrigin ( btVector3 ( pos [ 0 ] , pos [ 1 ] , pos [ 2 ] ) ) ;
}
2016-02-09 18:04:59 +00:00
const Resource : : BulletShapeInstance * getShapeInstance ( ) const
{
return mShapeInstance . get ( ) ;
}
2015-05-12 01:02:15 +00:00
void setScale ( float scale )
{
mShapeInstance - > getCollisionShape ( ) - > setLocalScaling ( btVector3 ( scale , scale , scale ) ) ;
}
void setRotation ( const btQuaternion & quat )
{
mCollisionObject - > getWorldTransform ( ) . setRotation ( quat ) ;
}
void setOrigin ( const btVector3 & vec )
{
mCollisionObject - > getWorldTransform ( ) . setOrigin ( vec ) ;
}
btCollisionObject * getCollisionObject ( )
{
return mCollisionObject . get ( ) ;
}
2016-03-05 14:56:19 +00:00
const btCollisionObject * getCollisionObject ( ) const
{
return mCollisionObject . get ( ) ;
}
2015-11-20 18:22:31 +00:00
/// Return solid flag. Not used by the object itself, true by default.
bool isSolid ( ) const
{
return mSolid ;
}
void setSolid ( bool solid )
{
mSolid = solid ;
}
2015-11-19 22:33:08 +00:00
bool isAnimated ( ) const
{
return ! mShapeInstance - > mAnimatedShapes . empty ( ) ;
}
2015-05-27 21:09:38 +00:00
void animateCollisionShapes ( btCollisionWorld * collisionWorld )
2015-05-12 14:24:53 +00:00
{
if ( mShapeInstance - > mAnimatedShapes . empty ( ) )
return ;
assert ( mShapeInstance - > getCollisionShape ( ) - > isCompound ( ) ) ;
2016-03-05 18:41:45 +00:00
btCompoundShape * compound = static_cast < btCompoundShape * > ( mShapeInstance - > getCollisionShape ( ) ) ;
2015-05-12 14:24:53 +00:00
2016-08-16 15:42:07 +00:00
for ( std : : map < int , int > : : const_iterator it = mShapeInstance - > mAnimatedShapes . begin ( ) ; it ! = mShapeInstance - > mAnimatedShapes . end ( ) ; + + it )
2015-05-12 14:24:53 +00:00
{
int recIndex = it - > first ;
int shapeIndex = it - > second ;
2016-08-16 15:49:47 +00:00
std : : map < int , osg : : NodePath > : : iterator nodePathFound = mRecIndexToNodePath . find ( recIndex ) ;
if ( nodePathFound = = mRecIndexToNodePath . end ( ) )
2015-05-12 14:24:53 +00:00
{
2016-08-16 15:49:47 +00:00
NifOsg : : FindGroupByRecIndex visitor ( recIndex ) ;
mPtr . getRefData ( ) . getBaseNode ( ) - > accept ( visitor ) ;
if ( ! visitor . mFound )
{
std : : cerr < < " animateCollisionShapes: Can't find node " < < recIndex < < std : : endl ;
return ;
}
osg : : NodePath nodePath = visitor . mFoundPath ;
nodePath . erase ( nodePath . begin ( ) ) ;
nodePathFound = mRecIndexToNodePath . insert ( std : : make_pair ( recIndex , nodePath ) ) . first ;
2015-05-12 14:24:53 +00:00
}
2016-08-16 15:49:47 +00:00
osg : : NodePath & nodePath = nodePathFound - > second ;
osg : : Matrixf matrix = osg : : computeLocalToWorld ( nodePath ) ;
2015-05-12 14:24:53 +00:00
osg : : Vec3f scale = matrix . getScale ( ) ;
matrix . orthoNormalize ( matrix ) ;
btTransform transform ;
transform . setOrigin ( toBullet ( matrix . getTrans ( ) ) * compound - > getLocalScaling ( ) ) ;
for ( int i = 0 ; i < 3 ; + + i )
for ( int j = 0 ; j < 3 ; + + j )
transform . getBasis ( ) [ i ] [ j ] = matrix ( j , i ) ; // NB column/row major difference
2016-08-16 15:50:16 +00:00
if ( compound - > getLocalScaling ( ) * toBullet ( scale ) ! = compound - > getChildShape ( shapeIndex ) - > getLocalScaling ( ) )
compound - > getChildShape ( shapeIndex ) - > setLocalScaling ( compound - > getLocalScaling ( ) * toBullet ( scale ) ) ;
if ( ! ( transform = = compound - > getChildTransform ( shapeIndex ) ) )
compound - > updateChildTransform ( shapeIndex , transform ) ;
2015-05-12 14:24:53 +00:00
}
2015-05-27 21:09:38 +00:00
collisionWorld - > updateSingleAabb ( mCollisionObject . get ( ) ) ;
2015-05-12 14:24:53 +00:00
}
2015-05-12 01:02:15 +00:00
private :
std : : auto_ptr < btCollisionObject > mCollisionObject ;
2015-11-16 22:30:10 +00:00
osg : : ref_ptr < Resource : : BulletShapeInstance > mShapeInstance ;
2016-08-16 15:49:47 +00:00
std : : map < int , osg : : NodePath > mRecIndexToNodePath ;
2015-11-20 18:22:31 +00:00
bool mSolid ;
2015-05-12 01:02:15 +00:00
} ;
// ---------------------------------------------------------------
2015-05-12 14:24:53 +00:00
PhysicsSystem : : PhysicsSystem ( Resource : : ResourceSystem * resourceSystem , osg : : ref_ptr < osg : : Group > parentNode )
2015-12-01 22:04:02 +00:00
: mShapeManager ( new Resource : : BulletShapeManager ( resourceSystem - > getVFS ( ) , resourceSystem - > getSceneManager ( ) , resourceSystem - > getNifFileManager ( ) ) )
2016-02-06 15:57:54 +00:00
, mResourceSystem ( resourceSystem )
2015-05-23 20:44:00 +00:00
, mDebugDrawEnabled ( false )
2015-05-12 01:02:15 +00:00
, mTimeAccum ( 0.0f )
2015-05-10 00:08:25 +00:00
, mWaterHeight ( 0 )
2015-05-23 20:44:00 +00:00
, mWaterEnabled ( false )
2015-05-10 00:08:25 +00:00
, mParentNode ( parentNode )
2011-08-01 13:55:36 +00:00
{
2016-02-06 15:57:54 +00:00
mResourceSystem - > addResourceManager ( mShapeManager . get ( ) ) ;
2015-05-10 00:08:25 +00:00
mCollisionConfiguration = new btDefaultCollisionConfiguration ( ) ;
mDispatcher = new btCollisionDispatcher ( mCollisionConfiguration ) ;
mBroadphase = new btDbvtBroadphase ( ) ;
2015-05-27 20:32:11 +00:00
2015-05-27 21:09:38 +00:00
mCollisionWorld = new btCollisionWorld ( mDispatcher , mBroadphase , mCollisionConfiguration ) ;
2015-05-10 00:08:25 +00:00
// 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.
2015-05-27 21:09:38 +00:00
mCollisionWorld - > setForceUpdateAllAabbs ( false ) ;
2011-08-01 13:55:36 +00:00
}
2011-08-22 19:34:51 +00:00
2011-08-01 13:55:36 +00:00
PhysicsSystem : : ~ PhysicsSystem ( )
{
2016-02-06 15:57:54 +00:00
mResourceSystem - > removeResourceManager ( mShapeManager . get ( ) ) ;
2015-05-10 00:08:25 +00:00
if ( mWaterCollisionObject . get ( ) )
2015-05-27 21:09:38 +00:00
mCollisionWorld - > removeCollisionObject ( mWaterCollisionObject . get ( ) ) ;
2015-05-10 00:08:25 +00:00
for ( HeightFieldMap : : iterator it = mHeightFields . begin ( ) ; it ! = mHeightFields . end ( ) ; + + it )
{
2015-05-27 21:09:38 +00:00
mCollisionWorld - > removeCollisionObject ( it - > second - > getCollisionObject ( ) ) ;
2015-05-10 00:08:25 +00:00
delete it - > second ;
}
2015-05-12 01:02:15 +00:00
for ( ObjectMap : : iterator it = mObjects . begin ( ) ; it ! = mObjects . end ( ) ; + + it )
{
2015-05-27 21:09:38 +00:00
mCollisionWorld - > removeCollisionObject ( it - > second - > getCollisionObject ( ) ) ;
2015-05-12 01:02:15 +00:00
delete it - > second ;
}
for ( ActorMap : : iterator it = mActors . begin ( ) ; it ! = mActors . end ( ) ; + + it )
{
delete it - > second ;
}
2015-05-27 21:09:38 +00:00
delete mCollisionWorld ;
2015-05-10 00:08:25 +00:00
delete mCollisionConfiguration ;
delete mDispatcher ;
delete mBroadphase ;
2012-01-29 15:31:18 +00:00
}
2013-02-07 20:11:10 +00:00
2016-02-09 18:04:59 +00:00
void PhysicsSystem : : setUnrefQueue ( SceneUtil : : UnrefQueue * unrefQueue )
{
mUnrefQueue = unrefQueue ;
}
2016-02-06 23:07:02 +00:00
Resource : : BulletShapeManager * PhysicsSystem : : getShapeManager ( )
{
return mShapeManager . get ( ) ;
}
2015-05-02 22:39:01 +00:00
bool PhysicsSystem : : toggleDebugRendering ( )
{
mDebugDrawEnabled = ! mDebugDrawEnabled ;
if ( mDebugDrawEnabled & & ! mDebugDrawer . get ( ) )
{
2015-05-27 21:09:38 +00:00
mDebugDrawer . reset ( new MWRender : : DebugDrawer ( mParentNode , mCollisionWorld ) ) ;
mCollisionWorld - > setDebugDrawer ( mDebugDrawer . get ( ) ) ;
2015-05-10 00:08:25 +00:00
mDebugDrawer - > setDebugMode ( mDebugDrawEnabled ) ;
2015-05-02 22:39:01 +00:00
}
else if ( mDebugDrawer . get ( ) )
mDebugDrawer - > setDebugMode ( mDebugDrawEnabled ) ;
return mDebugDrawEnabled ;
}
2015-12-18 16:56:48 +00:00
void PhysicsSystem : : markAsNonSolid ( const MWWorld : : ConstPtr & ptr )
2015-11-20 18:22:31 +00:00
{
ObjectMap : : iterator found = mObjects . find ( ptr ) ;
if ( found = = mObjects . end ( ) )
return ;
found - > second - > setSolid ( false ) ;
}
bool PhysicsSystem : : isOnSolidGround ( const MWWorld : : Ptr & actor ) const
{
const Actor * physactor = getActor ( actor ) ;
2015-12-08 20:12:05 +00:00
if ( ! physactor | | ! physactor - > getOnGround ( ) )
2015-11-20 18:22:31 +00:00
return false ;
CollisionMap : : const_iterator found = mStandingCollisions . find ( actor ) ;
if ( found = = mStandingCollisions . end ( ) )
return true ; // assume standing on terrain (which is a non-object, so not collision tracked)
ObjectMap : : const_iterator foundObj = mObjects . find ( found - > second ) ;
if ( foundObj = = mObjects . end ( ) )
return false ;
if ( ! foundObj - > second - > isSolid ( ) )
return false ;
return true ;
}
2015-05-22 02:36:17 +00:00
class DeepestNotMeContactTestResultCallback : public btCollisionWorld : : ContactResultCallback
{
const btCollisionObject * mMe ;
// Store the real origin, since the shape's origin is its center
btVector3 mOrigin ;
public :
const btCollisionObject * mObject ;
btVector3 mContactPoint ;
btScalar mLeastDistSqr ;
DeepestNotMeContactTestResultCallback ( const btCollisionObject * me , const btVector3 & origin )
: mMe ( me ) , mOrigin ( origin ) , mObject ( NULL ) , mContactPoint ( 0 , 0 , 0 ) ,
mLeastDistSqr ( std : : numeric_limits < float > : : max ( ) )
{ }
virtual btScalar addSingleResult ( btManifoldPoint & cp ,
const btCollisionObjectWrapper * col0Wrap , int partId0 , int index0 ,
const btCollisionObjectWrapper * col1Wrap , int partId1 , int index1 )
{
2015-06-08 18:37:01 +00:00
const btCollisionObject * collisionObject = col1Wrap - > m_collisionObject ;
if ( collisionObject ! = mMe )
2015-05-22 02:36:17 +00:00
{
btScalar distsqr = mOrigin . distance2 ( cp . getPositionWorldOnA ( ) ) ;
if ( ! mObject | | distsqr < mLeastDistSqr )
{
2015-06-08 18:37:01 +00:00
mObject = collisionObject ;
2015-05-22 02:36:17 +00:00
mLeastDistSqr = distsqr ;
mContactPoint = cp . getPositionWorldOnA ( ) ;
}
}
return 0.f ;
}
} ;
2015-12-18 16:38:21 +00:00
std : : pair < MWWorld : : Ptr , osg : : Vec3f > PhysicsSystem : : getHitContact ( const MWWorld : : ConstPtr & actor ,
2015-05-22 02:36:17 +00:00
const osg : : Vec3f & origin ,
const osg : : Quat & orient ,
2013-08-23 14:01:30 +00:00
float queryDistance )
2013-07-25 19:58:43 +00:00
{
2013-08-23 19:25:57 +00:00
const MWWorld : : Store < ESM : : GameSetting > & store = MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) . get < ESM : : GameSetting > ( ) ;
2015-05-22 02:36:17 +00:00
btConeShape shape ( osg : : DegreesToRadians ( store . find ( " fCombatAngleXY " ) - > getFloat ( ) / 2.0f ) , queryDistance ) ;
shape . setLocalScaling ( btVector3 ( 1 , 1 , osg : : DegreesToRadians ( store . find ( " fCombatAngleZ " ) - > getFloat ( ) / 2.0f ) /
2013-08-23 19:25:57 +00:00
shape . getRadius ( ) ) ) ;
// The shape origin is its center, so we have to move it forward by half the length. The
// real origin will be provided to getFilteredContact to find the closest.
2015-05-22 02:36:17 +00:00
osg : : Vec3f center = origin + ( orient * osg : : Vec3f ( 0.0f , queryDistance * 0.5f , 0.0f ) ) ;
2013-08-23 19:25:57 +00:00
btCollisionObject object ;
object . setCollisionShape ( & shape ) ;
2015-05-22 02:36:17 +00:00
object . setWorldTransform ( btTransform ( toBullet ( orient ) , toBullet ( center ) ) ) ;
const btCollisionObject * me = NULL ;
2015-12-18 16:38:21 +00:00
const Actor * physactor = getActor ( actor ) ;
2015-05-22 02:36:17 +00:00
if ( physactor )
me = physactor - > getCollisionObject ( ) ;
DeepestNotMeContactTestResultCallback resultCallback ( me , toBullet ( origin ) ) ;
resultCallback . m_collisionFilterGroup = CollisionType_Actor ;
2015-12-19 16:02:57 +00:00
resultCallback . m_collisionFilterMask = CollisionType_World | CollisionType_Door | CollisionType_HeightMap | CollisionType_Actor ;
2015-05-27 21:09:38 +00:00
mCollisionWorld - > contactTest ( & object , resultCallback ) ;
2015-05-22 02:36:17 +00:00
if ( resultCallback . mObject )
{
2015-12-18 16:30:39 +00:00
PtrHolder * holder = static_cast < PtrHolder * > ( resultCallback . mObject - > getUserPointer ( ) ) ;
2015-05-22 02:36:17 +00:00
if ( holder )
return std : : make_pair ( holder - > getPtr ( ) , toOsg ( resultCallback . mContactPoint ) ) ;
}
return std : : make_pair ( MWWorld : : Ptr ( ) , osg : : Vec3f ( ) ) ;
2013-07-25 19:58:43 +00:00
}
2015-12-18 16:36:14 +00:00
float PhysicsSystem : : getHitDistance ( const osg : : Vec3f & point , const MWWorld : : ConstPtr & target ) const
2015-11-18 18:00:43 +00:00
{
btCollisionObject * targetCollisionObj = NULL ;
const Actor * actor = getActor ( target ) ;
if ( actor )
targetCollisionObj = actor - > getCollisionObject ( ) ;
if ( ! targetCollisionObj )
return 0.f ;
btTransform rayFrom ;
rayFrom . setIdentity ( ) ;
rayFrom . setOrigin ( 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 ( ) ) ;
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 - toOsg ( cb . m_hitPointWorld ) ) . length ( ) ;
}
2015-05-31 23:57:15 +00:00
class ClosestNotMeRayResultCallback : public btCollisionWorld : : ClosestRayResultCallback
2012-02-24 15:12:43 +00:00
{
2015-05-31 23:57:15 +00:00
public :
ClosestNotMeRayResultCallback ( const btCollisionObject * me , const btVector3 & from , const btVector3 & to )
: btCollisionWorld : : ClosestRayResultCallback ( from , to )
, mMe ( me )
{
}
2015-09-16 18:45:37 +00:00
virtual btScalar addSingleResult ( btCollisionWorld : : LocalRayResult & rayResult , bool normalInWorldSpace )
2015-05-31 23:57:15 +00:00
{
if ( rayResult . m_collisionObject = = mMe )
return 1.f ;
return btCollisionWorld : : ClosestRayResultCallback : : addSingleResult ( rayResult , normalInWorldSpace ) ;
}
private :
const btCollisionObject * mMe ;
} ;
2011-10-20 22:15:30 +00:00
2015-12-18 17:32:42 +00:00
PhysicsSystem : : RayResult PhysicsSystem : : castRay ( const osg : : Vec3f & from , const osg : : Vec3f & to , MWWorld : : ConstPtr ignore , int mask , int group ) const
2012-07-25 16:25:53 +00:00
{
2015-05-21 23:43:45 +00:00
btVector3 btFrom = toBullet ( from ) ;
btVector3 btTo = toBullet ( to ) ;
2012-07-25 16:25:53 +00:00
2015-05-31 23:57:15 +00:00
const btCollisionObject * me = NULL ;
if ( ! ignore . isEmpty ( ) )
{
2015-12-18 17:02:57 +00:00
const Actor * actor = getActor ( ignore ) ;
2015-05-31 23:57:15 +00:00
if ( actor )
me = actor - > getCollisionObject ( ) ;
2016-03-05 14:56:19 +00:00
else
{
const Object * object = getObject ( ignore ) ;
if ( object )
me = object - > getCollisionObject ( ) ;
}
2015-05-31 23:57:15 +00:00
}
ClosestNotMeRayResultCallback resultCallback ( me , btFrom , btTo ) ;
2015-06-01 19:41:13 +00:00
resultCallback . m_collisionFilterGroup = group ;
2015-05-31 23:57:15 +00:00
resultCallback . m_collisionFilterMask = mask ;
2012-07-25 16:25:53 +00:00
2015-05-27 21:09:38 +00:00
mCollisionWorld - > rayTest ( btFrom , btTo , resultCallback ) ;
2015-05-31 23:57:15 +00:00
RayResult result ;
result . mHit = resultCallback . hasHit ( ) ;
2015-05-21 23:43:45 +00:00
if ( resultCallback . hasHit ( ) )
{
2015-05-31 23:57:15 +00:00
result . mHitPos = toOsg ( resultCallback . m_hitPointWorld ) ;
result . mHitNormal = toOsg ( resultCallback . m_hitNormalWorld ) ;
if ( PtrHolder * ptrHolder = static_cast < PtrHolder * > ( resultCallback . m_collisionObject - > getUserPointer ( ) ) )
result . mHitObject = ptrHolder - > getPtr ( ) ;
2012-07-25 16:25:53 +00:00
}
2015-05-31 23:57:15 +00:00
return result ;
}
2015-06-01 13:34:46 +00:00
PhysicsSystem : : RayResult PhysicsSystem : : castSphere ( const osg : : Vec3f & from , const osg : : Vec3f & to , float radius )
{
btCollisionWorld : : ClosestConvexResultCallback callback ( toBullet ( from ) , toBullet ( to ) ) ;
callback . m_collisionFilterGroup = 0xff ;
2015-12-19 15:18:12 +00:00
callback . m_collisionFilterMask = CollisionType_World | CollisionType_HeightMap | CollisionType_Door ;
2015-06-01 13:34:46 +00:00
btSphereShape shape ( radius ) ;
const btQuaternion btrot = btQuaternion : : getIdentity ( ) ;
btTransform from_ ( btrot , toBullet ( from ) ) ;
btTransform to_ ( btrot , toBullet ( to ) ) ;
mCollisionWorld - > convexSweepTest ( & shape , from_ , to_ , callback ) ;
RayResult result ;
result . mHit = callback . hasHit ( ) ;
if ( result . mHit )
{
result . mHitPos = toOsg ( callback . m_hitPointWorld ) ;
result . mHitNormal = toOsg ( callback . m_hitNormalWorld ) ;
}
return result ;
}
2015-12-18 17:02:57 +00:00
bool PhysicsSystem : : getLineOfSight ( const MWWorld : : ConstPtr & actor1 , const MWWorld : : ConstPtr & actor2 ) const
2015-05-31 23:57:15 +00:00
{
2015-12-18 17:02:57 +00:00
const Actor * physactor1 = getActor ( actor1 ) ;
const Actor * physactor2 = getActor ( actor2 ) ;
2015-05-31 23:57:15 +00:00
if ( ! physactor1 | | ! physactor2 )
return false ;
2016-05-27 15:42:17 +00:00
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 ) ) ;
2015-12-18 17:32:42 +00:00
RayResult result = castRay ( pos1 , pos2 , MWWorld : : Ptr ( ) , CollisionType_World | CollisionType_HeightMap | CollisionType_Door ) ;
2015-05-31 23:57:15 +00:00
return ! result . mHit ;
2012-07-25 16:25:53 +00:00
}
2015-06-01 00:40:42 +00:00
// physactor->getOnGround() is not a reliable indicator of whether the actor
// is on the ground (defaults to false, which means code blocks such as
// CharacterController::update() may falsely detect "falling").
//
// Also, collisions can move z position slightly off zero, giving a false
// indication. In order to reduce false detection of jumping, small distance
// below the actor is detected and ignored. A value of 1.5 is used here, but
// something larger may be more suitable. This change should resolve Bug#1271.
//
// TODO: There might be better places to update PhysicActor::mOnGround.
bool PhysicsSystem : : isOnGround ( const MWWorld : : Ptr & actor )
{
Actor * physactor = getActor ( actor ) ;
if ( ! physactor )
return false ;
if ( physactor - > getOnGround ( ) )
return true ;
else
{
osg : : Vec3f pos ( actor . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) ;
ActorTracer tracer ;
// a small distance above collision object is considered "on ground"
tracer . findGround ( physactor ,
pos ,
pos - osg : : Vec3f ( 0 , 0 , 1.5f ) , // trace a small amount down
mCollisionWorld ) ;
if ( tracer . mFraction < 1.0f ) // collision, must be close to something below
{
physactor - > setOnGround ( true ) ;
return true ;
}
else
return false ;
}
}
2016-11-14 15:20:17 +00:00
bool PhysicsSystem : : canMoveToWaterSurface ( const MWWorld : : ConstPtr & actor , const float waterlevel )
{
const Actor * physicActor = getActor ( actor ) ;
2016-12-22 13:39:03 +00:00
if ( ! physicActor )
return false ;
2016-11-14 15:20:17 +00:00
const float halfZ = physicActor - > getHalfExtents ( ) . z ( ) ;
const osg : : Vec3f actorPosition = physicActor - > getPosition ( ) ;
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 ) ;
return ( tracer . mFraction > = 1.0f ) ;
}
2015-12-18 16:36:14 +00:00
osg : : Vec3f PhysicsSystem : : getHalfExtents ( const MWWorld : : ConstPtr & actor ) const
2015-06-01 19:41:13 +00:00
{
2015-11-03 17:15:47 +00:00
const Actor * physactor = getActor ( actor ) ;
2015-06-01 19:41:13 +00:00
if ( physactor )
return physactor - > getHalfExtents ( ) ;
else
return osg : : Vec3f ( ) ;
}
2015-12-18 16:36:14 +00:00
osg : : Vec3f PhysicsSystem : : getRenderingHalfExtents ( const MWWorld : : ConstPtr & actor ) const
2015-11-01 20:45:58 +00:00
{
2015-11-03 17:15:47 +00:00
const Actor * physactor = getActor ( actor ) ;
2015-11-01 20:45:58 +00:00
if ( physactor )
return physactor - > getRenderingHalfExtents ( ) ;
else
return osg : : Vec3f ( ) ;
}
2016-02-13 01:56:41 +00:00
osg : : Vec3f PhysicsSystem : : getCollisionObjectPosition ( const MWWorld : : ConstPtr & actor ) const
2015-11-03 17:15:47 +00:00
{
const Actor * physactor = getActor ( actor ) ;
if ( physactor )
2016-02-13 01:56:41 +00:00
return physactor - > getCollisionObjectPosition ( ) ;
2015-11-03 17:15:47 +00:00
else
return osg : : Vec3f ( ) ;
}
2015-05-24 01:59:22 +00:00
class ContactTestResultCallback : public btCollisionWorld : : ContactResultCallback
2013-04-28 12:59:15 +00:00
{
2015-05-24 01:59:22 +00:00
public :
2015-11-18 19:41:49 +00:00
ContactTestResultCallback ( const btCollisionObject * testedAgainst )
: mTestedAgainst ( testedAgainst )
{
}
const btCollisionObject * mTestedAgainst ;
2015-05-24 01:59:22 +00:00
std : : vector < MWWorld : : Ptr > mResult ;
2015-06-08 18:37:01 +00:00
virtual btScalar addSingleResult ( btManifoldPoint & cp ,
const btCollisionObjectWrapper * col0Wrap , int partId0 , int index0 ,
const btCollisionObjectWrapper * col1Wrap , int partId1 , int index1 )
{
2015-06-26 04:40:28 +00:00
const btCollisionObject * collisionObject = col0Wrap - > m_collisionObject ;
2015-11-18 19:41:49 +00:00
if ( collisionObject = = mTestedAgainst )
collisionObject = col1Wrap - > m_collisionObject ;
2015-12-18 16:30:39 +00:00
PtrHolder * holder = static_cast < PtrHolder * > ( collisionObject - > getUserPointer ( ) ) ;
2015-05-24 01:59:22 +00:00
if ( holder )
mResult . push_back ( holder - > getPtr ( ) ) ;
return 0.f ;
}
} ;
2015-12-18 16:56:48 +00:00
std : : vector < MWWorld : : Ptr > PhysicsSystem : : getCollisions ( const MWWorld : : ConstPtr & ptr , int collisionGroup , int collisionMask ) const
2015-05-24 01:59:22 +00:00
{
btCollisionObject * me = NULL ;
2015-11-18 20:20:12 +00:00
ObjectMap : : const_iterator found = mObjects . find ( ptr ) ;
2015-05-24 01:59:22 +00:00
if ( found ! = mObjects . end ( ) )
me = found - > second - > getCollisionObject ( ) ;
else
return std : : vector < MWWorld : : Ptr > ( ) ;
2015-11-18 19:41:49 +00:00
ContactTestResultCallback resultCallback ( me ) ;
2015-05-24 01:59:22 +00:00
resultCallback . m_collisionFilterGroup = collisionGroup ;
resultCallback . m_collisionFilterMask = collisionMask ;
2015-05-27 21:09:38 +00:00
mCollisionWorld - > contactTest ( me , resultCallback ) ;
2015-05-24 01:59:22 +00:00
return resultCallback . mResult ;
2013-04-28 12:59:15 +00:00
}
2015-05-12 01:02:15 +00:00
osg : : Vec3f PhysicsSystem : : traceDown ( const MWWorld : : Ptr & ptr , float maxHeight )
2013-04-03 21:55:57 +00:00
{
2015-05-12 01:02:15 +00:00
ActorMap : : iterator found = mActors . find ( ptr ) ;
if ( found = = mActors . end ( ) )
return ptr . getRefData ( ) . getPosition ( ) . asVec3 ( ) ;
else
2015-05-27 21:09:38 +00:00
return MovementSolver : : traceDown ( ptr , found - > second , mCollisionWorld , maxHeight ) ;
2013-04-03 21:55:57 +00:00
}
2011-08-01 13:55:36 +00:00
2015-08-31 14:08:19 +00:00
void PhysicsSystem : : addHeightField ( const float * heights , int x , int y , float triSize , float sqrtVerts )
2012-03-13 16:09:50 +00:00
{
2015-05-10 00:08:25 +00:00
HeightField * heightfield = new HeightField ( heights , x , y , triSize , sqrtVerts ) ;
mHeightFields [ std : : make_pair ( x , y ) ] = heightfield ;
2015-05-27 21:09:38 +00:00
mCollisionWorld - > addCollisionObject ( heightfield - > getCollisionObject ( ) , CollisionType_HeightMap ,
2015-05-10 00:08:25 +00:00
CollisionType_Actor | CollisionType_Projectile ) ;
2012-03-13 16:09:50 +00:00
}
void PhysicsSystem : : removeHeightField ( int x , int y )
{
2015-05-10 00:08:25 +00:00
HeightFieldMap : : iterator heightfield = mHeightFields . find ( std : : make_pair ( x , y ) ) ;
if ( heightfield ! = mHeightFields . end ( ) )
{
2015-05-27 21:09:38 +00:00
mCollisionWorld - > removeCollisionObject ( heightfield - > second - > getCollisionObject ( ) ) ;
2015-05-10 00:08:25 +00:00
delete heightfield - > second ;
mHeightFields . erase ( heightfield ) ;
}
2012-03-13 16:09:50 +00:00
}
2015-12-18 17:32:42 +00:00
void PhysicsSystem : : addObject ( const MWWorld : : Ptr & ptr , const std : : string & mesh , int collisionType )
2011-08-01 13:55:36 +00:00
{
2016-02-09 17:48:49 +00:00
osg : : ref_ptr < Resource : : BulletShapeInstance > shapeInstance = mShapeManager - > getInstance ( mesh ) ;
2015-11-16 22:26:43 +00:00
if ( ! shapeInstance | | ! shapeInstance - > getCollisionShape ( ) )
2015-05-12 01:02:15 +00:00
return ;
Object * obj = new Object ( ptr , shapeInstance ) ;
mObjects . insert ( std : : make_pair ( ptr , obj ) ) ;
2014-06-21 21:32:58 +00:00
2015-11-19 22:33:08 +00:00
if ( obj - > isAnimated ( ) )
mAnimatedObjects . insert ( obj ) ;
2015-12-18 17:32:42 +00:00
mCollisionWorld - > addCollisionObject ( obj - > getCollisionObject ( ) , collisionType ,
2015-05-12 01:02:15 +00:00
CollisionType_Actor | CollisionType_HeightMap | CollisionType_Projectile ) ;
}
void PhysicsSystem : : remove ( const MWWorld : : Ptr & ptr )
{
ObjectMap : : iterator found = mObjects . find ( ptr ) ;
if ( found ! = mObjects . end ( ) )
{
2015-05-27 21:09:38 +00:00
mCollisionWorld - > removeCollisionObject ( found - > second - > getCollisionObject ( ) ) ;
2015-11-19 22:33:08 +00:00
2016-02-09 18:04:59 +00:00
if ( mUnrefQueue . get ( ) )
mUnrefQueue - > push ( found - > second - > getShapeInstance ( ) ) ;
2015-11-19 22:33:08 +00:00
mAnimatedObjects . erase ( found - > second ) ;
2015-05-12 01:02:15 +00:00
delete found - > second ;
mObjects . erase ( found ) ;
}
ActorMap : : iterator foundActor = mActors . find ( ptr ) ;
if ( foundActor ! = mActors . end ( ) )
{
delete foundActor - > second ;
mActors . erase ( foundActor ) ;
}
}
2015-05-29 23:32:00 +00:00
void PhysicsSystem : : updateCollisionMapPtr ( CollisionMap & map , const MWWorld : : Ptr & old , const MWWorld : : Ptr & updated )
{
CollisionMap : : iterator found = map . find ( old ) ;
if ( found ! = map . end ( ) )
{
map [ updated ] = found - > second ;
map . erase ( found ) ;
}
for ( CollisionMap : : iterator it = map . begin ( ) ; it ! = map . end ( ) ; + + it )
{
if ( it - > second = = old )
it - > second = updated ;
}
}
2015-05-12 14:24:53 +00:00
void PhysicsSystem : : updatePtr ( const MWWorld : : Ptr & old , const MWWorld : : Ptr & updated )
{
ObjectMap : : iterator found = mObjects . find ( old ) ;
if ( found ! = mObjects . end ( ) )
{
Object * obj = found - > second ;
obj - > updatePtr ( updated ) ;
mObjects . erase ( found ) ;
mObjects . insert ( std : : make_pair ( updated , obj ) ) ;
}
ActorMap : : iterator foundActor = mActors . find ( old ) ;
if ( foundActor ! = mActors . end ( ) )
{
Actor * actor = foundActor - > second ;
actor - > updatePtr ( updated ) ;
mActors . erase ( foundActor ) ;
mActors . insert ( std : : make_pair ( updated , actor ) ) ;
}
2015-05-29 23:32:00 +00:00
updateCollisionMapPtr ( mStandingCollisions , old , updated ) ;
2015-05-12 14:24:53 +00:00
}
2015-05-12 17:02:56 +00:00
Actor * PhysicsSystem : : getActor ( const MWWorld : : Ptr & ptr )
{
ActorMap : : iterator found = mActors . find ( ptr ) ;
if ( found ! = mActors . end ( ) )
return found - > second ;
return NULL ;
}
2015-12-18 16:36:14 +00:00
const Actor * PhysicsSystem : : getActor ( const MWWorld : : ConstPtr & ptr ) const
2015-11-03 17:15:47 +00:00
{
ActorMap : : const_iterator found = mActors . find ( ptr ) ;
if ( found ! = mActors . end ( ) )
return found - > second ;
return NULL ;
}
2016-03-05 14:56:19 +00:00
const Object * PhysicsSystem : : getObject ( const MWWorld : : ConstPtr & ptr ) const
{
ObjectMap : : const_iterator found = mObjects . find ( ptr ) ;
if ( found ! = mObjects . end ( ) )
return found - > second ;
return NULL ;
}
2015-05-12 01:02:15 +00:00
void PhysicsSystem : : updateScale ( const MWWorld : : Ptr & ptr )
{
ObjectMap : : iterator found = mObjects . find ( ptr ) ;
if ( found ! = mObjects . end ( ) )
{
2015-11-20 02:29:58 +00:00
float scale = ptr . getCellRef ( ) . getScale ( ) ;
2015-05-12 01:02:15 +00:00
found - > second - > setScale ( scale ) ;
2015-05-27 21:09:38 +00:00
mCollisionWorld - > updateSingleAabb ( found - > second - > getCollisionObject ( ) ) ;
2015-05-12 01:02:15 +00:00
return ;
}
ActorMap : : iterator foundActor = mActors . find ( ptr ) ;
if ( foundActor ! = mActors . end ( ) )
{
foundActor - > second - > updateScale ( ) ;
2015-05-27 21:09:38 +00:00
mCollisionWorld - > updateSingleAabb ( foundActor - > second - > getCollisionObject ( ) ) ;
2015-05-12 01:02:15 +00:00
return ;
}
}
void PhysicsSystem : : updateRotation ( const MWWorld : : Ptr & ptr )
{
ObjectMap : : iterator found = mObjects . find ( ptr ) ;
if ( found ! = mObjects . end ( ) )
{
found - > second - > setRotation ( toBullet ( ptr . getRefData ( ) . getBaseNode ( ) - > getAttitude ( ) ) ) ;
2015-05-27 21:09:38 +00:00
mCollisionWorld - > updateSingleAabb ( found - > second - > getCollisionObject ( ) ) ;
2015-05-12 01:02:15 +00:00
return ;
}
ActorMap : : iterator foundActor = mActors . find ( ptr ) ;
if ( foundActor ! = mActors . end ( ) )
{
foundActor - > second - > updateRotation ( ) ;
2015-05-27 21:09:38 +00:00
mCollisionWorld - > updateSingleAabb ( foundActor - > second - > getCollisionObject ( ) ) ;
2015-05-12 01:02:15 +00:00
return ;
}
}
void PhysicsSystem : : updatePosition ( const MWWorld : : Ptr & ptr )
{
ObjectMap : : iterator found = mObjects . find ( ptr ) ;
if ( found ! = mObjects . end ( ) )
{
found - > second - > setOrigin ( toBullet ( ptr . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) ) ;
2015-05-27 21:09:38 +00:00
mCollisionWorld - > updateSingleAabb ( found - > second - > getCollisionObject ( ) ) ;
2015-05-12 01:02:15 +00:00
return ;
}
ActorMap : : iterator foundActor = mActors . find ( ptr ) ;
if ( foundActor ! = mActors . end ( ) )
{
foundActor - > second - > updatePosition ( ) ;
2015-05-27 21:09:38 +00:00
mCollisionWorld - > updateSingleAabb ( foundActor - > second - > getCollisionObject ( ) ) ;
2015-05-12 01:02:15 +00:00
return ;
}
2011-08-01 13:55:36 +00:00
}
2015-11-16 22:26:43 +00:00
void PhysicsSystem : : addActor ( const MWWorld : : Ptr & ptr , const std : : string & mesh ) {
2016-02-09 17:51:17 +00:00
osg : : ref_ptr < const Resource : : BulletShape > shape = mShapeManager - > getShape ( mesh ) ;
if ( ! shape )
2015-11-16 22:26:43 +00:00
return ;
2012-09-12 22:30:32 +00:00
2016-02-09 17:51:17 +00:00
Actor * actor = new Actor ( ptr , shape , mCollisionWorld ) ;
2015-05-12 01:02:15 +00:00
mActors . insert ( std : : make_pair ( ptr , actor ) ) ;
2011-08-01 13:55:36 +00:00
}
bool PhysicsSystem : : toggleCollisionMode ( )
{
2015-08-21 09:12:39 +00:00
ActorMap : : iterator found = mActors . find ( MWMechanics : : getPlayer ( ) ) ;
2015-05-12 01:02:15 +00:00
if ( found ! = mActors . end ( ) )
2011-08-01 13:55:36 +00:00
{
2015-05-12 01:02:15 +00:00
bool cmode = found - > second - > getCollisionMode ( ) ;
cmode = ! cmode ;
found - > second - > enableCollisionMode ( cmode ) ;
return cmode ;
2011-08-01 13:55:36 +00:00
}
2015-05-09 22:28:51 +00:00
return false ;
2011-08-01 13:55:36 +00:00
}
2015-05-12 01:02:15 +00:00
void PhysicsSystem : : queueObjectMovement ( const MWWorld : : Ptr & ptr , const osg : : Vec3f & movement )
2013-08-17 14:48:45 +00:00
{
PtrVelocityList : : iterator iter = mMovementQueue . begin ( ) ;
2014-04-27 17:03:33 +00:00
for ( ; iter ! = mMovementQueue . end ( ) ; + + iter )
2013-08-17 14:48:45 +00:00
{
if ( iter - > first = = ptr )
{
iter - > second = movement ;
return ;
}
}
mMovementQueue . push_back ( std : : make_pair ( ptr , movement ) ) ;
}
2014-08-13 14:23:34 +00:00
void PhysicsSystem : : clearQueuedMovement ( )
{
mMovementQueue . clear ( ) ;
mStandingCollisions . clear ( ) ;
}
2013-08-17 14:48:45 +00:00
const PtrVelocityList & PhysicsSystem : : applyQueuedMovement ( float dt )
{
mMovementResults . clear ( ) ;
2013-08-20 18:31:49 +00:00
mTimeAccum + = dt ;
2016-02-13 01:56:41 +00:00
const float physicsDt = 1.f / 60.0f ;
2016-02-13 02:09:28 +00:00
const int maxAllowedSteps = 20 ;
2016-02-13 01:56:41 +00:00
int numSteps = mTimeAccum / ( physicsDt ) ;
2016-02-13 02:09:28 +00:00
numSteps = std : : min ( numSteps , maxAllowedSteps ) ;
2016-02-13 01:56:41 +00:00
mTimeAccum - = numSteps * physicsDt ;
if ( numSteps )
2013-08-17 14:48:45 +00:00
{
2014-10-11 22:13:24 +00:00
// Collision events should be available on every frame
mStandingCollisions . clear ( ) ;
2016-02-13 01:56:41 +00:00
}
2014-10-11 22:13:24 +00:00
2016-02-13 01:56:41 +00:00
const MWBase : : World * world = MWBase : : Environment : : get ( ) . getWorld ( ) ;
PtrVelocityList : : iterator iter = mMovementQueue . begin ( ) ;
for ( ; iter ! = mMovementQueue . end ( ) ; + + iter )
{
2016-10-26 09:04:54 +00:00
ActorMap : : iterator foundActor = mActors . find ( iter - > first ) ;
if ( foundActor = = mActors . end ( ) ) // actor was already removed from the scene
continue ;
Actor * physicActor = foundActor - > second ;
2016-02-13 01:56:41 +00:00
float waterlevel = - std : : numeric_limits < float > : : max ( ) ;
const MWWorld : : CellStore * cell = iter - > first . getCell ( ) ;
if ( cell - > getCell ( ) - > hasWater ( ) )
waterlevel = cell - > getWaterLevel ( ) ;
2013-08-23 20:38:26 +00:00
2016-02-13 01:56:41 +00:00
const MWMechanics : : MagicEffects & effects = iter - > first . getClass ( ) . getCreatureStats ( iter - > first ) . getMagicEffects ( ) ;
2014-01-17 14:47:34 +00:00
2016-02-13 01:56:41 +00:00
bool waterCollision = false ;
2016-10-25 17:26:17 +00:00
if ( cell - > getCell ( ) - > hasWater ( ) & & effects . get ( ESM : : MagicEffect : : WaterWalking ) . getMagnitude ( ) )
{
if ( ! world - > isUnderwater ( iter - > first . getCell ( ) , osg : : Vec3f ( iter - > first . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) ) )
waterCollision = true ;
2016-11-14 15:20:17 +00:00
else if ( physicActor - > getCollisionMode ( ) & & canMoveToWaterSurface ( iter - > first , waterlevel ) )
2016-10-25 17:26:17 +00:00
{
2016-10-26 09:04:54 +00:00
const osg : : Vec3f actorPosition = physicActor - > getPosition ( ) ;
2016-12-17 22:21:33 +00:00
physicActor - > setPosition ( osg : : Vec3f ( actorPosition . x ( ) , actorPosition . y ( ) , waterlevel ) ) ;
waterCollision = true ;
2016-10-25 17:26:17 +00:00
}
}
2016-02-13 01:56:41 +00:00
physicActor - > setCanWaterWalk ( waterCollision ) ;
2014-01-02 01:03:11 +00:00
2016-02-13 01:56:41 +00:00
// 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 ) ) ;
2014-01-17 14:47:34 +00:00
2016-02-13 01:56:41 +00:00
osg : : Vec3f position = physicActor - > getPosition ( ) ;
float oldHeight = position . z ( ) ;
for ( int i = 0 ; i < numSteps ; + + i )
{
position = MovementSolver : : move ( position , physicActor - > getPtr ( ) , physicActor , iter - > second , physicsDt ,
world - > isFlying ( iter - > first ) ,
waterlevel , slowFall , mCollisionWorld , mStandingCollisions ) ;
physicActor - > setPosition ( position ) ;
}
2013-12-27 20:21:18 +00:00
2016-02-13 01:56:41 +00:00
float interpolationFactor = mTimeAccum / physicsDt ;
osg : : Vec3f interpolated = position * interpolationFactor + physicActor - > getPreviousPosition ( ) * ( 1.f - interpolationFactor ) ;
2013-12-27 20:21:18 +00:00
2016-02-13 01:56:41 +00:00
float heightDiff = position . z ( ) - oldHeight ;
2013-12-27 20:21:18 +00:00
2016-02-13 01:56:41 +00:00
if ( heightDiff < 0 )
iter - > first . getClass ( ) . getCreatureStats ( iter - > first ) . addToFallHeight ( - heightDiff ) ;
2013-08-17 14:48:45 +00:00
2016-02-13 01:56:41 +00:00
mMovementResults . push_back ( std : : make_pair ( iter - > first , interpolated ) ) ;
2013-08-20 18:31:49 +00:00
}
2016-02-13 01:56:41 +00:00
2013-08-17 14:48:45 +00:00
mMovementQueue . clear ( ) ;
return mMovementResults ;
}
2014-06-23 18:43:24 +00:00
void PhysicsSystem : : stepSimulation ( float dt )
{
2015-11-19 22:33:08 +00:00
for ( std : : set < Object * > : : iterator it = mAnimatedObjects . begin ( ) ; it ! = mAnimatedObjects . end ( ) ; + + it )
( * it ) - > animateCollisionShapes ( mCollisionWorld ) ;
2014-06-23 18:43:24 +00:00
2016-10-14 18:59:55 +00:00
# ifndef BT_NO_PROFILE
2015-05-27 21:09:38 +00:00
CProfileManager : : Reset ( ) ;
CProfileManager : : Increment_Frame_Counter ( ) ;
2016-10-14 18:59:55 +00:00
# endif
2015-06-07 15:00:00 +00:00
}
2015-05-02 22:39:01 +00:00
2015-06-07 15:00:00 +00:00
void PhysicsSystem : : debugDraw ( )
{
2015-05-02 22:39:01 +00:00
if ( mDebugDrawer . get ( ) )
mDebugDrawer - > step ( ) ;
2014-06-23 18:43:24 +00:00
}
2014-07-29 17:01:40 +00:00
2015-12-18 16:56:48 +00:00
bool PhysicsSystem : : isActorStandingOn ( const MWWorld : : Ptr & actor , const MWWorld : : ConstPtr & object ) const
2014-07-29 17:01:40 +00:00
{
2015-05-29 23:32:00 +00:00
for ( CollisionMap : : const_iterator it = mStandingCollisions . begin ( ) ; it ! = mStandingCollisions . end ( ) ; + + it )
2014-07-29 17:01:40 +00:00
{
2015-05-29 23:32:00 +00:00
if ( it - > first = = actor & & it - > second = = object )
2014-07-29 17:01:40 +00:00
return true ;
}
return false ;
}
2015-12-18 16:56:48 +00:00
void PhysicsSystem : : getActorsStandingOn ( const MWWorld : : ConstPtr & object , std : : vector < MWWorld : : Ptr > & out ) const
2014-07-29 17:01:40 +00:00
{
2015-05-29 23:32:00 +00:00
for ( CollisionMap : : const_iterator it = mStandingCollisions . begin ( ) ; it ! = mStandingCollisions . end ( ) ; + + it )
2014-07-29 17:01:40 +00:00
{
2015-05-29 23:32:00 +00:00
if ( it - > second = = object )
2014-07-29 17:01:40 +00:00
out . push_back ( it - > first ) ;
}
}
2015-12-18 16:56:48 +00:00
bool PhysicsSystem : : isActorCollidingWith ( const MWWorld : : Ptr & actor , const MWWorld : : ConstPtr & object ) const
2014-07-29 17:01:40 +00:00
{
2015-11-18 20:20:12 +00:00
std : : vector < MWWorld : : Ptr > collisions = getCollisions ( object , CollisionType_World , CollisionType_Actor ) ;
return ( std : : find ( collisions . begin ( ) , collisions . end ( ) , actor ) ! = collisions . end ( ) ) ;
2014-07-29 17:01:40 +00:00
}
2015-12-18 16:56:48 +00:00
void PhysicsSystem : : getActorsCollidingWith ( const MWWorld : : ConstPtr & object , std : : vector < MWWorld : : Ptr > & out ) const
2014-07-29 17:01:40 +00:00
{
2015-11-18 20:20:12 +00:00
std : : vector < MWWorld : : Ptr > collisions = getCollisions ( object , CollisionType_World , CollisionType_Actor ) ;
out . insert ( out . end ( ) , collisions . begin ( ) , collisions . end ( ) ) ;
2014-07-29 17:01:40 +00:00
}
2014-10-05 20:24:11 +00:00
void PhysicsSystem : : disableWater ( )
{
if ( mWaterEnabled )
{
mWaterEnabled = false ;
updateWater ( ) ;
}
}
void PhysicsSystem : : enableWater ( float height )
{
if ( ! mWaterEnabled | | mWaterHeight ! = height )
{
mWaterEnabled = true ;
mWaterHeight = height ;
updateWater ( ) ;
}
}
void PhysicsSystem : : setWaterHeight ( float height )
{
if ( mWaterHeight ! = height )
{
mWaterHeight = height ;
updateWater ( ) ;
}
}
void PhysicsSystem : : updateWater ( )
{
if ( mWaterCollisionObject . get ( ) )
{
2016-12-16 19:22:07 +00:00
mCollisionWorld - > removeCollisionObject ( mWaterCollisionObject . get ( ) ) ;
2014-10-05 20:24:11 +00:00
}
if ( ! mWaterEnabled )
2016-12-16 19:22:07 +00:00
{
mWaterCollisionObject . reset ( ) ;
2014-10-05 20:24:11 +00:00
return ;
2016-12-16 19:22:07 +00:00
}
2014-10-05 20:24:11 +00:00
mWaterCollisionObject . reset ( new btCollisionObject ( ) ) ;
mWaterCollisionShape . reset ( new btStaticPlaneShape ( btVector3 ( 0 , 0 , 1 ) , mWaterHeight ) ) ;
mWaterCollisionObject - > setCollisionShape ( mWaterCollisionShape . get ( ) ) ;
2015-05-27 21:09:38 +00:00
mCollisionWorld - > addCollisionObject ( mWaterCollisionObject . get ( ) , CollisionType_Water ,
2015-05-10 00:08:25 +00:00
CollisionType_Actor ) ;
2014-10-05 20:24:11 +00:00
}
2011-08-01 13:55:36 +00:00
}