1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-21 23:09:42 +00:00

Non functionnal changes in preparation for async physics feature

This commit is contained in:
fredzio 2020-10-14 11:32:12 +02:00
parent 72549651e0
commit 82da2045a9
7 changed files with 101 additions and 111 deletions

View file

@ -17,32 +17,29 @@ namespace MWPhysics
{ {
Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr<const Resource::BulletShape> shape, btCollisionWorld* world) Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, btCollisionWorld* world)
: mCanWaterWalk(false), mWalkingOnWater(false) : mCanWaterWalk(false), mWalkingOnWater(false)
, mCollisionObject(nullptr), mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false) , mCollisionObject(nullptr), mMeshTranslation(shape->mCollisionBoxTranslate), mHalfExtents(shape->mCollisionBoxHalfExtents)
, mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false)
, mInternalCollisionMode(true) , mInternalCollisionMode(true)
, mExternalCollisionMode(true) , mExternalCollisionMode(true)
, mCollisionWorld(world) , mCollisionWorld(world)
{ {
mPtr = ptr; mPtr = ptr;
mHalfExtents = shape->mCollisionBoxHalfExtents;
mMeshTranslation = shape->mCollisionBoxTranslate;
// We can not create actor without collisions - he will fall through the ground. // We can not create actor without collisions - he will fall through the ground.
// In this case we should autogenerate collision box based on mesh shape // In this case we should autogenerate collision box based on mesh shape
// (NPCs have bodyparts and use a different approach) // (NPCs have bodyparts and use a different approach)
if (!ptr.getClass().isNpc() && mHalfExtents.length2() == 0.f) if (!ptr.getClass().isNpc() && mHalfExtents.length2() == 0.f)
{ {
const Resource::BulletShape* collisionShape = shape.get(); if (shape->mCollisionShape)
if (collisionShape && collisionShape->mCollisionShape)
{ {
btTransform transform; btTransform transform;
transform.setIdentity(); transform.setIdentity();
btVector3 min; btVector3 min;
btVector3 max; btVector3 max;
collisionShape->mCollisionShape->getAabb(transform, min, max); shape->mCollisionShape->getAabb(transform, min, max);
mHalfExtents.x() = (max[0] - min[0])/2.f; mHalfExtents.x() = (max[0] - min[0])/2.f;
mHalfExtents.y() = (max[1] - min[1])/2.f; mHalfExtents.y() = (max[1] - min[1])/2.f;
mHalfExtents.z() = (max[2] - min[2])/2.f; mHalfExtents.z() = (max[2] - min[2])/2.f;
@ -83,7 +80,7 @@ Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr<const Resource::BulletShape>
Actor::~Actor() Actor::~Actor()
{ {
if (mCollisionObject.get()) if (mCollisionObject)
mCollisionWorld->removeCollisionObject(mCollisionObject.get()); mCollisionWorld->removeCollisionObject(mCollisionObject.get());
} }
@ -112,7 +109,7 @@ void Actor::updateCollisionMask()
addCollisionMask(getCollisionMask()); addCollisionMask(getCollisionMask());
} }
int Actor::getCollisionMask() int Actor::getCollisionMask() const
{ {
int collisionMask = CollisionType_World | CollisionType_HeightMap; int collisionMask = CollisionType_World | CollisionType_HeightMap;
if (mExternalCollisionMode) if (mExternalCollisionMode)
@ -120,7 +117,6 @@ int Actor::getCollisionMask()
if (mCanWaterWalk) if (mCanWaterWalk)
collisionMask |= CollisionType_Water; collisionMask |= CollisionType_Water;
return collisionMask; return collisionMask;
} }
void Actor::updatePosition() void Actor::updatePosition()

View file

@ -21,12 +21,13 @@ namespace Resource
namespace MWPhysics namespace MWPhysics
{ {
class PhysicsTaskScheduler;
class Actor : public PtrHolder class Actor final : public PtrHolder
{ {
public: public:
Actor(const MWWorld::Ptr& ptr, osg::ref_ptr<const Resource::BulletShape> shape, btCollisionWorld* world); Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, btCollisionWorld* world);
~Actor(); ~Actor() override;
/** /**
* Sets the collisionMode for this actor. If disabled, the actor can fly and clip geometry. * Sets the collisionMode for this actor. If disabled, the actor can fly and clip geometry.
@ -136,7 +137,7 @@ namespace MWPhysics
/// Removes then re-adds the collision object to the dynamics world /// Removes then re-adds the collision object to the dynamics world
void updateCollisionMask(); void updateCollisionMask();
void addCollisionMask(int collisionMask); void addCollisionMask(int collisionMask);
int getCollisionMask(); int getCollisionMask() const;
bool mCanWaterWalk; bool mCanWaterWalk;
bool mWalkingOnWater; bool mWalkingOnWater;

View file

@ -14,9 +14,10 @@
namespace MWPhysics namespace MWPhysics
{ {
Object::Object(const MWWorld::Ptr& ptr, osg::ref_ptr<Resource::BulletShapeInstance> shapeInstance) Object::Object(const MWWorld::Ptr& ptr, osg::ref_ptr<Resource::BulletShapeInstance> shapeInstance, btCollisionWorld* world)
: mShapeInstance(shapeInstance) : mShapeInstance(shapeInstance)
, mSolid(true) , mSolid(true)
, mCollisionWorld(world)
{ {
mPtr = ptr; mPtr = ptr;
@ -31,6 +32,12 @@ namespace MWPhysics
setOrigin(btVector3(pos[0], pos[1], pos[2])); setOrigin(btVector3(pos[0], pos[1], pos[2]));
} }
Object::~Object()
{
if (mCollisionObject)
mCollisionWorld->removeCollisionObject(mCollisionObject.get());
}
const Resource::BulletShapeInstance* Object::getShapeInstance() const const Resource::BulletShapeInstance* Object::getShapeInstance() const
{ {
return mShapeInstance.get(); return mShapeInstance.get();

View file

@ -20,10 +20,11 @@ class btVector3;
namespace MWPhysics namespace MWPhysics
{ {
class Object : public PtrHolder class Object final : public PtrHolder
{ {
public: public:
Object(const MWWorld::Ptr& ptr, osg::ref_ptr<Resource::BulletShapeInstance> shapeInstance); Object(const MWWorld::Ptr& ptr, osg::ref_ptr<Resource::BulletShapeInstance> shapeInstance, btCollisionWorld* world);
~Object() override;
const Resource::BulletShapeInstance* getShapeInstance() const; const Resource::BulletShapeInstance* getShapeInstance() const;
void setScale(float scale); void setScale(float scale);
@ -42,6 +43,7 @@ namespace MWPhysics
osg::ref_ptr<Resource::BulletShapeInstance> mShapeInstance; osg::ref_ptr<Resource::BulletShapeInstance> mShapeInstance;
std::map<int, osg::NodePath> mRecIndexToNodePath; std::map<int, osg::NodePath> mRecIndexToNodePath;
bool mSolid; bool mSolid;
btCollisionWorld* mCollisionWorld;
}; };
} }

View file

@ -65,11 +65,11 @@ namespace MWPhysics
{ {
mResourceSystem->addResourceManager(mShapeManager.get()); mResourceSystem->addResourceManager(mShapeManager.get());
mCollisionConfiguration = new btDefaultCollisionConfiguration(); mCollisionConfiguration = std::make_unique<btDefaultCollisionConfiguration>();
mDispatcher = new btCollisionDispatcher(mCollisionConfiguration); mDispatcher = std::make_unique<btCollisionDispatcher>(mCollisionConfiguration.get());
mBroadphase = new btDbvtBroadphase(); 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. // 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. // Should a "static" object ever be moved, we have to update its AABB manually using DynamicsWorld::updateSingleAabb.
@ -92,7 +92,7 @@ namespace MWPhysics
{ {
mResourceSystem->removeResourceManager(mShapeManager.get()); mResourceSystem->removeResourceManager(mShapeManager.get());
if (mWaterCollisionObject.get()) if (mWaterCollisionObject)
mCollisionWorld->removeCollisionObject(mWaterCollisionObject.get()); mCollisionWorld->removeCollisionObject(mWaterCollisionObject.get());
for (auto& heightField : mHeightFields) for (auto& heightField : mHeightFields)
@ -101,21 +101,9 @@ namespace MWPhysics
delete heightField.second; delete heightField.second;
} }
for (auto& object : mObjects) mObjects.clear();
{ mActors.clear();
mCollisionWorld->removeCollisionObject(object.second->getCollisionObject());
delete object.second;
}
for (auto& actor : mActors)
{
delete actor.second;
}
delete mCollisionWorld;
delete mCollisionConfiguration;
delete mDispatcher;
delete mBroadphase;
} }
void PhysicsSystem::setUnrefQueue(SceneUtil::UnrefQueue *unrefQueue) void PhysicsSystem::setUnrefQueue(SceneUtil::UnrefQueue *unrefQueue)
@ -132,13 +120,13 @@ namespace MWPhysics
{ {
mDebugDrawEnabled = !mDebugDrawEnabled; 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()); mCollisionWorld->setDebugDrawer(mDebugDrawer.get());
mDebugDrawer->setDebugMode(mDebugDrawEnabled); mDebugDrawer->setDebugMode(mDebugDrawEnabled);
} }
else if (mDebugDrawer.get()) else if (mDebugDrawer)
mDebugDrawer->setDebugMode(mDebugDrawEnabled); mDebugDrawer->setDebugMode(mDebugDrawEnabled);
return mDebugDrawEnabled; return mDebugDrawEnabled;
} }
@ -175,7 +163,7 @@ namespace MWPhysics
std::pair<MWWorld::Ptr, osg::Vec3f> PhysicsSystem::getHitContact(const MWWorld::ConstPtr& actor, std::pair<MWWorld::Ptr, osg::Vec3f> PhysicsSystem::getHitContact(const MWWorld::ConstPtr& actor,
const osg::Vec3f &origin, const osg::Vec3f &origin,
const osg::Quat &orient, 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 // First of all, try to hit where you aim to
int hitmask = CollisionType_World | CollisionType_Door | CollisionType_HeightMap | CollisionType_Actor; int hitmask = CollisionType_World | CollisionType_Door | CollisionType_HeightMap | CollisionType_Actor;
@ -373,7 +361,7 @@ namespace MWPhysics
const osg::Vec3f startingPosition(actorPosition.x(), actorPosition.y(), actorPosition.z() + halfZ); const osg::Vec3f startingPosition(actorPosition.x(), actorPosition.y(), actorPosition.z() + halfZ);
const osg::Vec3f destinationPosition(actorPosition.x(), actorPosition.y(), waterlevel + halfZ); const osg::Vec3f destinationPosition(actorPosition.x(), actorPosition.y(), waterlevel + halfZ);
ActorTracer tracer; ActorTracer tracer;
tracer.doTrace(physicActor->getCollisionObject(), startingPosition, destinationPosition, mCollisionWorld); tracer.doTrace(physicActor->getCollisionObject(), startingPosition, destinationPosition, mCollisionWorld.get());
return (tracer.mFraction >= 1.0f); return (tracer.mFraction >= 1.0f);
} }
@ -444,7 +432,7 @@ namespace MWPhysics
if (found == mActors.end()) if (found == mActors.end())
return ptr.getRefData().getPosition().asVec3(); return ptr.getRefData().getPosition().asVec3();
else 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) void PhysicsSystem::addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts, float minH, float maxH, const osg::Object* holdObject)
@ -481,11 +469,11 @@ namespace MWPhysics
if (!shapeInstance || !shapeInstance->getCollisionShape()) if (!shapeInstance || !shapeInstance->getCollisionShape())
return; return;
Object *obj = new Object(ptr, shapeInstance); auto obj = std::make_shared<Object>(ptr, shapeInstance, mCollisionWorld.get());
mObjects.emplace(ptr, obj); mObjects.emplace(ptr, obj);
if (obj->isAnimated()) if (obj->isAnimated())
mAnimatedObjects.insert(obj); mAnimatedObjects.insert(obj.get());
mCollisionWorld->addCollisionObject(obj->getCollisionObject(), collisionType, mCollisionWorld->addCollisionObject(obj->getCollisionObject(), collisionType,
CollisionType_Actor|CollisionType_HeightMap|CollisionType_Projectile); CollisionType_Actor|CollisionType_HeightMap|CollisionType_Projectile);
@ -496,21 +484,17 @@ namespace MWPhysics
ObjectMap::iterator found = mObjects.find(ptr); ObjectMap::iterator found = mObjects.find(ptr);
if (found != mObjects.end()) if (found != mObjects.end())
{ {
mCollisionWorld->removeCollisionObject(found->second->getCollisionObject());
if (mUnrefQueue.get()) if (mUnrefQueue.get())
mUnrefQueue->push(found->second->getShapeInstance()); mUnrefQueue->push(found->second->getShapeInstance());
mAnimatedObjects.erase(found->second); mAnimatedObjects.erase(found->second.get());
delete found->second;
mObjects.erase(found); mObjects.erase(found);
} }
ActorMap::iterator foundActor = mActors.find(ptr); ActorMap::iterator foundActor = mActors.find(ptr);
if (foundActor != mActors.end()) if (foundActor != mActors.end())
{ {
delete foundActor->second;
mActors.erase(foundActor); mActors.erase(foundActor);
} }
} }
@ -536,19 +520,19 @@ namespace MWPhysics
ObjectMap::iterator found = mObjects.find(old); ObjectMap::iterator found = mObjects.find(old);
if (found != mObjects.end()) if (found != mObjects.end())
{ {
Object* obj = found->second; auto obj = found->second;
obj->updatePtr(updated); obj->updatePtr(updated);
mObjects.erase(found); mObjects.erase(found);
mObjects.emplace(updated, obj); mObjects.emplace(updated, std::move(obj));
} }
ActorMap::iterator foundActor = mActors.find(old); ActorMap::iterator foundActor = mActors.find(old);
if (foundActor != mActors.end()) if (foundActor != mActors.end())
{ {
Actor* actor = foundActor->second; auto actor = foundActor->second;
actor->updatePtr(updated); actor->updatePtr(updated);
mActors.erase(foundActor); mActors.erase(foundActor);
mActors.emplace(updated, actor); mActors.emplace(updated, std::move(actor));
} }
updateCollisionMapPtr(mStandingCollisions, old, updated); updateCollisionMapPtr(mStandingCollisions, old, updated);
@ -558,7 +542,7 @@ namespace MWPhysics
{ {
ActorMap::iterator found = mActors.find(ptr); ActorMap::iterator found = mActors.find(ptr);
if (found != mActors.end()) if (found != mActors.end())
return found->second; return found->second.get();
return nullptr; return nullptr;
} }
@ -566,7 +550,7 @@ namespace MWPhysics
{ {
ActorMap::const_iterator found = mActors.find(ptr); ActorMap::const_iterator found = mActors.find(ptr);
if (found != mActors.end()) if (found != mActors.end())
return found->second; return found->second.get();
return nullptr; return nullptr;
} }
@ -574,7 +558,7 @@ namespace MWPhysics
{ {
ObjectMap::const_iterator found = mObjects.find(ptr); ObjectMap::const_iterator found = mObjects.find(ptr);
if (found != mObjects.end()) if (found != mObjects.end())
return found->second; return found->second.get();
return nullptr; return nullptr;
} }
@ -639,11 +623,9 @@ namespace MWPhysics
void PhysicsSystem::addActor (const MWWorld::Ptr& ptr, const std::string& mesh) void PhysicsSystem::addActor (const MWWorld::Ptr& ptr, const std::string& mesh)
{ {
osg::ref_ptr<const Resource::BulletShape> shape = mShapeManager->getShape(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 // 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); const std::string fallbackModel = ptr.getClass().getModel(ptr);
if (fallbackModel != mesh) if (fallbackModel != mesh)
@ -652,8 +634,11 @@ namespace MWPhysics
} }
} }
Actor* actor = new Actor(ptr, shape, mCollisionWorld); if (!shape)
mActors.emplace(ptr, actor); return;
auto actor = std::make_shared<Actor>(ptr, shape, mCollisionWorld.get());
mActors.emplace(ptr, std::move(actor));
} }
bool PhysicsSystem::toggleCollisionMode() bool PhysicsSystem::toggleCollisionMode()
@ -691,14 +676,14 @@ namespace MWPhysics
mStandingCollisions.clear(); mStandingCollisions.clear();
} }
const PtrVelocityList& PhysicsSystem::applyQueuedMovement(float dt) const PtrPositionList& PhysicsSystem::applyQueuedMovement(float dt)
{ {
mMovementResults.clear(); mMovementResults.clear();
mTimeAccum += dt; mTimeAccum += dt;
const int maxAllowedSteps = 20; const int maxAllowedSteps = 20;
int numSteps = mTimeAccum / (mPhysicsDt); int numSteps = mTimeAccum / mPhysicsDt;
numSteps = std::min(numSteps, maxAllowedSteps); numSteps = std::min(numSteps, maxAllowedSteps);
mTimeAccum -= numSteps * mPhysicsDt; mTimeAccum -= numSteps * mPhysicsDt;
@ -711,26 +696,28 @@ namespace MWPhysics
const MWWorld::Ptr player = MWMechanics::getPlayer(); const MWWorld::Ptr player = MWMechanics::getPlayer();
const MWBase::World *world = MWBase::Environment::get().getWorld(); 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 if (foundActor == mActors.end()) // actor was already removed from the scene
continue; continue;
Actor* physicActor = foundActor->second; auto physicActor = foundActor->second;
float waterlevel = -std::numeric_limits<float>::max(); float waterlevel = -std::numeric_limits<float>::max();
const MWWorld::CellStore *cell = movementItem.first.getCell(); const MWWorld::CellStore *cell = character.getCell();
if(cell->getCell()->hasWater()) if(cell->getCell()->hasWater())
waterlevel = cell->getWaterLevel(); 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 waterCollision = false;
if (cell->getCell()->hasWater() && effects.get(ESM::MagicEffect::WaterWalking).getMagnitude()) 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; waterCollision = true;
else if (physicActor->getCollisionMode() && canMoveToWaterSurface(movementItem.first, waterlevel)) else if (physicActor->getCollisionMode() && canMoveToWaterSurface(character, waterlevel))
{ {
const osg::Vec3f actorPosition = physicActor->getPosition(); const osg::Vec3f actorPosition = physicActor->getPosition();
physicActor->setPosition(osg::Vec3f(actorPosition.x(), actorPosition.y(), waterlevel)); physicActor->setPosition(osg::Vec3f(actorPosition.x(), actorPosition.y(), waterlevel));
@ -742,8 +729,8 @@ namespace MWPhysics
// Slow fall reduces fall speed by a factor of (effect magnitude / 200) // 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)); 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 flying = world->isFlying(character);
bool swimming = world->isSwimming(movementItem.first); bool swimming = world->isSwimming(character);
bool wasOnGround = physicActor->getOnGround(); bool wasOnGround = physicActor->getOnGround();
osg::Vec3f position = physicActor->getPosition(); osg::Vec3f position = physicActor->getPosition();
@ -751,8 +738,8 @@ namespace MWPhysics
bool positionChanged = false; bool positionChanged = false;
for (int i=0; i<numSteps; ++i) for (int i=0; i<numSteps; ++i)
{ {
position = MovementSolver::move(position, physicActor->getPtr(), physicActor, movementItem.second, mPhysicsDt, position = MovementSolver::move(position, physicActor->getPtr(), physicActor.get(), movement, mPhysicsDt,
flying, waterlevel, slowFall, mCollisionWorld, mStandingCollisions); flying, waterlevel, slowFall, mCollisionWorld.get(), mStandingCollisions);
if (position != physicActor->getPosition()) if (position != physicActor->getPosition())
positionChanged = true; positionChanged = true;
physicActor->setPosition(position); // always set even if unchanged to make sure interpolation is correct physicActor->setPosition(position); // always set even if unchanged to make sure interpolation is correct
@ -765,25 +752,23 @@ namespace MWPhysics
float heightDiff = position.z() - oldHeight; float heightDiff = position.z() - oldHeight;
MWMechanics::CreatureStats& stats = movementItem.first.getClass().getCreatureStats(movementItem.first); MWMechanics::CreatureStats& stats = character.getClass().getCreatureStats(character);
bool isStillOnGround = (numSteps > 0 && wasOnGround && physicActor->getOnGround()); bool isStillOnGround = (numSteps > 0 && wasOnGround && physicActor->getOnGround());
if (isStillOnGround || flying || swimming || slowFall < 1) if (isStillOnGround || flying || swimming || slowFall < 1)
stats.land(movementItem.first == player && (flying || swimming)); stats.land(character == player && (flying || swimming));
else if (heightDiff < 0) else if (heightDiff < 0)
stats.addToFallHeight(-heightDiff); stats.addToFallHeight(-heightDiff);
mMovementResults.emplace_back(movementItem.first, interpolated); mMovementResults.emplace(character, interpolated);
} }
mMovementQueue.clear(); mMovementQueue.clear();
return mMovementResults; return mMovementResults;
} }
void PhysicsSystem::stepSimulation(float dt) void PhysicsSystem::stepSimulation()
{ {
for (Object* animatedObject : mAnimatedObjects) for (Object* animatedObject : mAnimatedObjects)
animatedObject->animateCollisionShapes(mCollisionWorld); animatedObject->animateCollisionShapes(mCollisionWorld.get());
#ifndef BT_NO_PROFILE #ifndef BT_NO_PROFILE
CProfileManager::Reset(); CProfileManager::Reset();
@ -795,12 +780,12 @@ namespace MWPhysics
{ {
ObjectMap::iterator found = mObjects.find(object); ObjectMap::iterator found = mObjects.find(object);
if (found != mObjects.end()) if (found != mObjects.end())
found->second->animateCollisionShapes(mCollisionWorld); found->second->animateCollisionShapes(mCollisionWorld.get());
} }
void PhysicsSystem::debugDraw() void PhysicsSystem::debugDraw()
{ {
if (mDebugDrawer.get()) if (mDebugDrawer)
mDebugDrawer->step(); mDebugDrawer->step();
} }
@ -865,7 +850,7 @@ namespace MWPhysics
void PhysicsSystem::updateWater() void PhysicsSystem::updateWater()
{ {
if (mWaterCollisionObject.get()) if (mWaterCollisionObject)
{ {
mCollisionWorld->removeCollisionObject(mWaterCollisionObject.get()); mCollisionWorld->removeCollisionObject(mWaterCollisionObject.get());
} }

View file

@ -47,7 +47,8 @@ class btCollisionShape;
namespace MWPhysics namespace MWPhysics
{ {
typedef std::vector<std::pair<MWWorld::Ptr,osg::Vec3f> > PtrVelocityList; using PtrPositionList = std::map<MWWorld::Ptr, osg::Vec3f>;
using CollisionMap = std::map<MWWorld::Ptr, MWWorld::Ptr>;
class HeightField; class HeightField;
class Object; class Object;
@ -93,7 +94,7 @@ namespace MWPhysics
bool toggleCollisionMode(); bool toggleCollisionMode();
void stepSimulation(float dt); void stepSimulation();
void debugDraw(); void debugDraw();
std::vector<MWWorld::Ptr> getCollisions(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const; ///< get handles this object collides with std::vector<MWWorld::Ptr> getCollisions(const MWWorld::ConstPtr &ptr, int collisionGroup, int collisionMask) const; ///< get handles this object collides with
@ -102,7 +103,7 @@ namespace MWPhysics
std::pair<MWWorld::Ptr, osg::Vec3f> getHitContact(const MWWorld::ConstPtr& actor, std::pair<MWWorld::Ptr, osg::Vec3f> getHitContact(const MWWorld::ConstPtr& actor,
const osg::Vec3f &origin, const osg::Vec3f &origin,
const osg::Quat &orientation, const osg::Quat &orientation,
float queryDistance, std::vector<MWWorld::Ptr> targets = std::vector<MWWorld::Ptr>()); float queryDistance, std::vector<MWWorld::Ptr>& targets);
/// Get distance from \a point to the collision shape of \a target. Uses a raycast to find where the /// Get distance from \a point to the collision shape of \a target. Uses a raycast to find where the
@ -146,7 +147,7 @@ namespace MWPhysics
void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity); void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity);
/// Apply all queued movements, then clear the list. /// Apply all queued movements, then clear the list.
const PtrVelocityList& applyQueuedMovement(float dt); const PtrPositionList& applyQueuedMovement(float dt);
/// Clear the queued movements list without applying. /// Clear the queued movements list without applying.
void clearQueuedMovement(); void clearQueuedMovement();
@ -192,37 +193,37 @@ namespace MWPhysics
osg::ref_ptr<SceneUtil::UnrefQueue> mUnrefQueue; osg::ref_ptr<SceneUtil::UnrefQueue> mUnrefQueue;
btBroadphaseInterface* mBroadphase; std::unique_ptr<btBroadphaseInterface> mBroadphase;
btDefaultCollisionConfiguration* mCollisionConfiguration; std::unique_ptr<btDefaultCollisionConfiguration> mCollisionConfiguration;
btCollisionDispatcher* mDispatcher; std::unique_ptr<btCollisionDispatcher> mDispatcher;
btCollisionWorld* mCollisionWorld; std::shared_ptr<btCollisionWorld> mCollisionWorld;
std::unique_ptr<Resource::BulletShapeManager> mShapeManager; std::unique_ptr<Resource::BulletShapeManager> mShapeManager;
Resource::ResourceSystem* mResourceSystem; Resource::ResourceSystem* mResourceSystem;
typedef std::map<MWWorld::ConstPtr, Object*> ObjectMap; using ObjectMap = std::map<MWWorld::ConstPtr, std::shared_ptr<Object>>;
ObjectMap mObjects; ObjectMap mObjects;
std::set<Object*> mAnimatedObjects; // stores pointers to elements in mObjects std::set<Object*> mAnimatedObjects; // stores pointers to elements in mObjects
typedef std::map<MWWorld::ConstPtr, Actor*> ActorMap; using ActorMap = std::map<MWWorld::ConstPtr, std::shared_ptr<Actor>>;
ActorMap mActors; ActorMap mActors;
typedef std::map<std::pair<int, int>, HeightField*> HeightFieldMap; using HeightFieldMap = std::map<std::pair<int, int>, HeightField *>;
HeightFieldMap mHeightFields; HeightFieldMap mHeightFields;
bool mDebugDrawEnabled; bool mDebugDrawEnabled;
// Tracks standing collisions happening during a single frame. <actor handle, collided handle> // Tracks standing collisions happening during a single frame. <actor handle, collided handle>
// This will detect standing on an object, but won't detect running e.g. against a wall. // This will detect standing on an object, but won't detect running e.g. against a wall.
typedef std::map<MWWorld::Ptr, MWWorld::Ptr> CollisionMap;
CollisionMap mStandingCollisions; CollisionMap mStandingCollisions;
// replaces all occurrences of 'old' in the map by 'updated', no matter if it's a key or value // replaces all occurrences of 'old' in the map by 'updated', no matter if it's a key or value
void updateCollisionMapPtr(CollisionMap& map, const MWWorld::Ptr &old, const MWWorld::Ptr &updated); void updateCollisionMapPtr(CollisionMap& map, const MWWorld::Ptr &old, const MWWorld::Ptr &updated);
using PtrVelocityList = std::vector<std::pair<MWWorld::Ptr, osg::Vec3f>>;
PtrVelocityList mMovementQueue; PtrVelocityList mMovementQueue;
PtrVelocityList mMovementResults; PtrPositionList mMovementResults;
float mTimeAccum; float mTimeAccum;

View file

@ -1494,24 +1494,22 @@ namespace MWWorld
void World::doPhysics(float duration) void World::doPhysics(float duration)
{ {
mPhysics->stepSimulation(duration); mPhysics->stepSimulation();
processDoors(duration); processDoors(duration);
mProjectileManager->update(duration); mProjectileManager->update(duration);
const MWPhysics::PtrVelocityList &results = mPhysics->applyQueuedMovement(duration); const auto results = mPhysics->applyQueuedMovement(duration);
MWPhysics::PtrVelocityList::const_iterator player(results.end());
for(MWPhysics::PtrVelocityList::const_iterator iter(results.begin());iter != results.end();++iter) for(const auto& result : results)
{ {
if(iter->first == getPlayerPtr()) // Handle player last, in case a cell transition occurs
{ if(result.first != getPlayerPtr())
// Handle player last, in case a cell transition occurs moveObjectImp(result.first, result.second.x(), result.second.y(), result.second.z(), false);
player = iter;
continue;
}
moveObjectImp(iter->first, iter->second.x(), iter->second.y(), iter->second.z(), false);
} }
if(player != results.end())
const auto player = results.find(getPlayerPtr());
if (player != results.end())
moveObjectImp(player->first, player->second.x(), player->second.y(), player->second.z(), false); moveObjectImp(player->first, player->second.x(), player->second.y(), player->second.z(), false);
} }