From 91b3926a49fbc3285c4b354764060f9243a1e419 Mon Sep 17 00:00:00 2001 From: fredzio Date: Thu, 15 Oct 2020 06:11:00 +0200 Subject: [PATCH] We need to update the collision world after each step. Change order of traversal simulation step to make it rare enough to be parallelizable Before: for actor in actors: repeat numstep: solve(actor) After: repeat numstep: for actor in actors: solve(actor) Introduce struct ActorFrameData to pack all data that is necessary for the solver --- apps/openmw/mwphysics/movementsolver.cpp | 90 ++++------ apps/openmw/mwphysics/movementsolver.hpp | 13 +- apps/openmw/mwphysics/physicssystem.cpp | 203 ++++++++++++++++++----- apps/openmw/mwphysics/physicssystem.hpp | 50 ++++++ 4 files changed, 255 insertions(+), 101 deletions(-) diff --git a/apps/openmw/mwphysics/movementsolver.cpp b/apps/openmw/mwphysics/movementsolver.cpp index 6345a76d97..3c78104dc7 100644 --- a/apps/openmw/mwphysics/movementsolver.cpp +++ b/apps/openmw/mwphysics/movementsolver.cpp @@ -10,18 +10,14 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" -#include "../mwmechanics/actorutil.hpp" -#include "../mwmechanics/creaturestats.hpp" -#include "../mwmechanics/movement.hpp" - #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/player.hpp" #include "../mwworld/refdata.hpp" #include "actor.hpp" #include "collisiontype.hpp" #include "constants.hpp" +#include "physicssystem.hpp" #include "stepper.hpp" #include "trace.h" @@ -78,24 +74,26 @@ namespace MWPhysics return tracer.mEndPos-offset + osg::Vec3f(0.f, 0.f, sGroundOffset); } - osg::Vec3f MovementSolver::move(osg::Vec3f position, const MWWorld::Ptr &ptr, Actor* physicActor, const osg::Vec3f &movement, float time, - bool isFlying, float waterlevel, float slowFall, const btCollisionWorld* collisionWorld, - std::map& standingCollisionTracker) + void MovementSolver::move(ActorFrameData& actor, float time, const btCollisionWorld* collisionWorld, + WorldFrameData& worldData) { - const ESM::Position& refpos = ptr.getRefData().getPosition(); + auto* physicActor = actor.mActorRaw; + auto ptr = actor.mPtr; + const ESM::Position& refpos = actor.mRefpos; // Early-out for totally static creatures // (Not sure if gravity should still apply?) if (!ptr.getClass().isMobile(ptr)) - return position; + return; // Reset per-frame data physicActor->setWalkingOnWater(false); // Anything to collide with? if(!physicActor->getCollisionMode()) { - return position + (osg::Quat(refpos.rot[0], osg::Vec3f(-1, 0, 0)) * + actor.mPosition += (osg::Quat(refpos.rot[0], osg::Vec3f(-1, 0, 0)) * osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1)) - ) * movement * time; + ) * actor.mMovement * time; + return; } const btCollisionObject *colobj = physicActor->getCollisionObject(); @@ -105,23 +103,23 @@ namespace MWPhysics // 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(); + actor.mPosition.z() += halfExtents.z(); static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get().find("fSwimHeightScale")->mValue.getFloat(); - float swimlevel = waterlevel + halfExtents.z() - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); + float swimlevel = actor.mWaterlevel + halfExtents.z() - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); ActorTracer tracer; osg::Vec3f inertia = physicActor->getInertialForce(); osg::Vec3f velocity; - if (position.z() < swimlevel || isFlying) + if (actor.mPosition.z() < swimlevel || actor.mFlying) { - velocity = (osg::Quat(refpos.rot[0], osg::Vec3f(-1, 0, 0)) * osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * movement; + velocity = (osg::Quat(refpos.rot[0], osg::Vec3f(-1, 0, 0)) * osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * actor.mMovement; } else { - velocity = (osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * movement; + velocity = (osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * actor.mMovement; if ((velocity.z() > 0.f && physicActor->getOnGround() && !physicActor->getOnSlope()) || (velocity.z() > 0.f && velocity.z() + inertia.z() <= -velocity.z() && physicActor->getOnSlope())) @@ -131,38 +129,16 @@ namespace MWPhysics } // 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) + if (actor.mMovement.z() > 0 && actor.mIsDead && actor.mPosition.z() < swimlevel) velocity = osg::Vec3f(0,0,1) * 25; - if (ptr.getClass().getMovementSettings(ptr).mPosition[2]) - { - const bool isPlayer = (ptr == MWMechanics::getPlayer()); - // Advance acrobatics and set flag for GetPCJumping - if (isPlayer) - { - ptr.getClass().skillUsageSucceeded(ptr, ESM::Skill::Acrobatics, 0); - MWBase::Environment::get().getWorld()->getPlayer().setJumping(true); - } - - // Decrease fatigue - if (!isPlayer || !MWBase::Environment::get().getWorld()->getGodModeState()) - { - const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - const float fFatigueJumpBase = gmst.find("fFatigueJumpBase")->mValue.getFloat(); - const float fFatigueJumpMult = gmst.find("fFatigueJumpMult")->mValue.getFloat(); - const float normalizedEncumbrance = std::min(1.f, ptr.getClass().getNormalizedEncumbrance(ptr)); - const float fatigueDecrease = fFatigueJumpBase + normalizedEncumbrance * fFatigueJumpMult; - MWMechanics::DynamicStat fatigue = ptr.getClass().getCreatureStats(ptr).getFatigue(); - fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease); - ptr.getClass().getCreatureStats(ptr).setFatigue(fatigue); - } - ptr.getClass().getMovementSettings(ptr).mPosition[2] = 0; - } + if (actor.mWantJump) + actor.mDidJump = true; // Now that we have the effective movement vector, apply wind forces to it - if (MWBase::Environment::get().getWorld()->isInStorm()) + if (worldData.mIsInStorm) { - osg::Vec3f stormDirection = MWBase::Environment::get().getWorld()->getStormDirection(); + osg::Vec3f stormDirection = worldData.mStormDirection; float angleDegrees = osg::RadiansToDegrees(std::acos(stormDirection * velocity / (stormDirection.length() * velocity.length()))); static const float fStromWalkMult = MWBase::Environment::get().getWorld()->getStore().get().find("fStromWalkMult")->mValue.getFloat(); velocity *= 1.f-(fStromWalkMult * (angleDegrees/180.f)); @@ -170,7 +146,7 @@ namespace MWPhysics Stepper stepper(collisionWorld, colobj); osg::Vec3f origVelocity = velocity; - osg::Vec3f newPosition = position; + osg::Vec3f newPosition = actor.mPosition; /* * 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 @@ -182,7 +158,7 @@ namespace MWPhysics osg::Vec3f nextpos = newPosition + velocity * remainingTime; // If not able to fly, don't allow to swim up into the air - if(!isFlying && nextpos.z() > swimlevel && newPosition.z() < swimlevel) + if(!actor.mFlying && nextpos.z() > swimlevel && newPosition.z() < swimlevel) { const osg::Vec3f down(0,0,-1); velocity = slide(velocity, down); @@ -235,7 +211,7 @@ namespace MWPhysics if (result) { // don't let pure water creatures move out of water after stepMove - if (ptr.getClass().isPureWaterCreature(ptr) && newPosition.z() + halfExtents.z() > waterlevel) + if (ptr.getClass().isPureWaterCreature(ptr) && newPosition.z() + halfExtents.z() > actor.mWaterlevel) newPosition = oldPosition; } else @@ -245,7 +221,7 @@ namespace MWPhysics // Do not allow sliding upward if there is gravity. // Stepping will have taken care of that. - if(!(newPosition.z() < swimlevel || isFlying)) + if(!(newPosition.z() < swimlevel || actor.mFlying)) newVelocity.z() = std::min(newVelocity.z(), 0.0f); if ((newVelocity-velocity).length2() < 0.01) @@ -269,11 +245,11 @@ namespace MWPhysics const btCollisionObject* standingOn = tracer.mHitObject; PtrHolder* ptrHolder = static_cast(standingOn->getUserPointer()); if (ptrHolder) - standingCollisionTracker[ptr] = ptrHolder->getPtr(); + actor.mStandingOn = ptrHolder->getPtr(); if (standingOn->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Water) physicActor->setWalkingOnWater(true); - if (!isFlying) + if (!actor.mFlying) newPosition.z() = tracer.mEndPos.z() + sGroundOffset; isOnGround = true; @@ -292,7 +268,7 @@ namespace MWPhysics btVector3 aabbMin, aabbMax; tracer.mHitObject->getCollisionShape()->getAabb(tracer.mHitObject->getWorldTransform(), aabbMin, aabbMax); btVector3 center = (aabbMin + aabbMax) / 2.f; - inertia = osg::Vec3f(position.x() - center.x(), position.y() - center.y(), 0); + inertia = osg::Vec3f(actor.mPosition.x() - center.x(), actor.mPosition.y() - center.y(), 0); inertia.normalize(); inertia *= 100; } @@ -302,16 +278,16 @@ namespace MWPhysics } } - if((isOnGround && !isOnSlope) || newPosition.z() < swimlevel || isFlying) + if((isOnGround && !isOnSlope) || newPosition.z() < swimlevel || actor.mFlying) physicActor->setInertialForce(osg::Vec3f(0.f, 0.f, 0.f)); else { inertia.z() -= time * Constants::GravityConst * Constants::UnitsPerMeter; if (inertia.z() < 0) - inertia.z() *= slowFall; - if (slowFall < 1.f) { - inertia.x() *= slowFall; - inertia.y() *= slowFall; + inertia.z() *= actor.mSlowFall; + if (actor.mSlowFall < 1.f) { + inertia.x() *= actor.mSlowFall; + inertia.y() *= actor.mSlowFall; } physicActor->setInertialForce(inertia); } @@ -319,6 +295,6 @@ namespace MWPhysics physicActor->setOnSlope(isOnSlope); newPosition.z() -= halfExtents.z(); // remove what was added at the beginning - return newPosition; + actor.mPosition = newPosition; } } diff --git a/apps/openmw/mwphysics/movementsolver.hpp b/apps/openmw/mwphysics/movementsolver.hpp index 54a417fa75..75fba1cf0e 100644 --- a/apps/openmw/mwphysics/movementsolver.hpp +++ b/apps/openmw/mwphysics/movementsolver.hpp @@ -5,13 +5,18 @@ #include -#include "../mwworld/ptr.hpp" - class btCollisionWorld; +namespace MWWorld +{ + class Ptr; +} + namespace MWPhysics { class Actor; + struct ActorFrameData; + struct WorldFrameData; class MovementSolver { @@ -31,9 +36,7 @@ namespace MWPhysics public: static osg::Vec3f traceDown(const MWWorld::Ptr &ptr, const osg::Vec3f& position, Actor* actor, btCollisionWorld* collisionWorld, float maxHeight); - static osg::Vec3f move(osg::Vec3f position, const MWWorld::Ptr &ptr, Actor* physicActor, const osg::Vec3f &movement, float time, - bool isFlying, float waterlevel, float slowFall, const btCollisionWorld* collisionWorld, - std::map& standingCollisionTracker); + static void move(ActorFrameData& actor, float time, const btCollisionWorld* collisionWorld, WorldFrameData& worldData); }; } diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 97be7c39ec..2fb556522e 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -31,9 +31,11 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/actorutil.hpp" +#include "../mwmechanics/movement.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwworld/player.hpp" #include "../mwrender/bulletdebugdraw.hpp" @@ -687,14 +689,106 @@ namespace MWPhysics numSteps = std::min(numSteps, maxAllowedSteps); mTimeAccum -= numSteps * mPhysicsDt; + mActorsFrameData = prepareFrameData(); + bool advanceSimulation = (numSteps != 0); + if (advanceSimulation) + mWorldFrameData = std::make_unique(); - if (numSteps) + // update each actor position based on latest data + for (auto& data : mActorsFrameData) + data.updatePosition(); + + mMovementResults.clear(); + while (numSteps--) { - // Collision events should be available on every frame - mStandingCollisions.clear(); + for (auto& actorData : mActorsFrameData) + MovementSolver::move(actorData, mPhysicsDt, mCollisionWorld.get(), *mWorldFrameData); + + // update actors position + for (auto& actorData : mActorsFrameData) + { + if(const auto actor = actorData.mActor.lock()) + { + if (actorData.mPosition != actorData.mActorRaw->getPosition()) + actorData.mPositionChanged = true; + actorData.mActorRaw->setPosition(actorData.mPosition); + } + } } - const MWWorld::Ptr player = MWMechanics::getPlayer(); + for (auto& actorData : mActorsFrameData) + { + // handle fall of actor + const float heightDiff = actorData.mPosition.z() - actorData.mOldHeight; + + const bool isStillOnGround = (advanceSimulation && actorData.mWasOnGround && actorData.mActorRaw->getOnGround()); + + if (isStillOnGround || actorData.mFlying || actorData.mSwimming || actorData.mSlowFall < 1) + actorData.mNeedLand = true; + else if (heightDiff < 0) + actorData.mFallHeight += heightDiff; + + // interpolate position + const float interpolationFactor = mTimeAccum / mPhysicsDt; + mMovementResults[actorData.mPtr] = actorData.mPosition * interpolationFactor + actorData.mActorRaw->getPreviousPosition() * (1.f - interpolationFactor); + + // update mechanics if actor jumped + if (actorData.mDidJump) + { + const bool isPlayer = (actorData.mPtr == MWMechanics::getPlayer()); + // Advance acrobatics and set flag for GetPCJumping + if (isPlayer) + { + actorData.mPtr.getClass().skillUsageSucceeded(actorData.mPtr, ESM::Skill::Acrobatics, 0); + MWBase::Environment::get().getWorld()->getPlayer().setJumping(true); + } + + // Decrease fatigue + if (!isPlayer || !MWBase::Environment::get().getWorld()->getGodModeState()) + { + const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); + const float fFatigueJumpBase = gmst.find("fFatigueJumpBase")->mValue.getFloat(); + const float fFatigueJumpMult = gmst.find("fFatigueJumpMult")->mValue.getFloat(); + const float normalizedEncumbrance = std::min(1.f, actorData.mPtr.getClass().getNormalizedEncumbrance(actorData.mPtr)); + const float fatigueDecrease = fFatigueJumpBase + normalizedEncumbrance * fFatigueJumpMult; + MWMechanics::DynamicStat fatigue = actorData.mPtr.getClass().getCreatureStats(actorData.mPtr).getFatigue(); + fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease); + actorData.mPtr.getClass().getCreatureStats(actorData.mPtr).setFatigue(fatigue); + } + actorData.mPtr.getClass().getMovementSettings(actorData.mPtr).mPosition[2] = 0; + } + + MWMechanics::CreatureStats& stats = actorData.mPtr.getClass().getCreatureStats(actorData.mPtr); + if (actorData.mNeedLand) + stats.land(actorData.mPtr == MWMechanics::getPlayer() && (actorData.mFlying || actorData.mSwimming)); + else if (actorData.mFallHeight < 0) + stats.addToFallHeight(-actorData.mFallHeight); + } + + // update actors aabb + for (const auto& actorData : mActorsFrameData) + if (actorData.mPositionChanged) + mCollisionWorld->updateSingleAabb(actorData.mActorRaw->getCollisionObject()); + + // update standing collisions map + if (advanceSimulation) + { + mStandingCollisions.clear(); + for (auto& actorData : mActorsFrameData) + { + if (!actorData.mStandingOn.isEmpty()) + mStandingCollisions[actorData.mPtr] = actorData.mStandingOn; + else + mStandingCollisions.erase(actorData.mPtr); + } + } + return mMovementResults; + } + + std::vector PhysicsSystem::prepareFrameData() + { + std::vector actorsFrameData; + actorsFrameData.reserve(mMovementQueue.size()); const MWBase::World *world = MWBase::Environment::get().getWorld(); for (const auto& m : mMovementQueue) { @@ -702,7 +796,10 @@ namespace MWPhysics const auto& movement = m.second; const auto foundActor = mActors.find(character); if (foundActor == mActors.end()) // actor was already removed from the scene + { + mStandingCollisions.erase(character); continue; + } auto physicActor = foundActor->second; float waterlevel = -std::numeric_limits::max(); @@ -713,56 +810,27 @@ namespace MWPhysics const MWMechanics::MagicEffects& effects = character.getClass().getCreatureStats(character).getMagicEffects(); bool waterCollision = false; + bool moveToWaterSurface = false; if (cell->getCell()->hasWater() && effects.get(ESM::MagicEffect::WaterWalking).getMagnitude()) { if (!world->isUnderwater(character.getCell(), osg::Vec3f(character.getRefData().getPosition().asVec3()))) waterCollision = true; else if (physicActor->getCollisionMode() && canMoveToWaterSurface(character, waterlevel)) { - const osg::Vec3f actorPosition = physicActor->getPosition(); - physicActor->setPosition(osg::Vec3f(actorPosition.x(), actorPosition.y(), waterlevel)); + moveToWaterSurface = true; waterCollision = true; } } + physicActor->setCanWaterWalk(waterCollision); // Slow fall reduces fall speed by a factor of (effect magnitude / 200) - float slowFall = 1.f - std::max(0.f, std::min(1.f, effects.get(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f)); + const float slowFall = 1.f - std::max(0.f, std::min(1.f, effects.get(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f)); - bool flying = world->isFlying(character); - bool swimming = world->isSwimming(character); - - bool wasOnGround = physicActor->getOnGround(); - osg::Vec3f position = physicActor->getPosition(); - float oldHeight = position.z(); - bool positionChanged = false; - for (int i=0; igetPtr(), physicActor.get(), movement, mPhysicsDt, - flying, waterlevel, slowFall, mCollisionWorld.get(), mStandingCollisions); - if (position != physicActor->getPosition()) - positionChanged = true; - physicActor->setPosition(position); // always set even if unchanged to make sure interpolation is correct - } - if (positionChanged) - mCollisionWorld->updateSingleAabb(physicActor->getCollisionObject()); - - float interpolationFactor = mTimeAccum / mPhysicsDt; - osg::Vec3f interpolated = position * interpolationFactor + physicActor->getPreviousPosition() * (1.f - interpolationFactor); - - float heightDiff = position.z() - oldHeight; - - MWMechanics::CreatureStats& stats = character.getClass().getCreatureStats(character); - bool isStillOnGround = (numSteps > 0 && wasOnGround && physicActor->getOnGround()); - if (isStillOnGround || flying || swimming || slowFall < 1) - stats.land(character == player && (flying || swimming)); - else if (heightDiff < 0) - stats.addToFallHeight(-heightDiff); - - mMovementResults.emplace(character, interpolated); + actorsFrameData.emplace_back(std::move(physicActor), character, mStandingCollisions[character], moveToWaterSurface, movement, slowFall, waterlevel); } mMovementQueue.clear(); - return mMovementResults; + return actorsFrameData; } void PhysicsSystem::stepSimulation() @@ -896,4 +964,61 @@ namespace MWPhysics stats.setAttribute(frameNumber, "Physics Objects", mObjects.size()); stats.setAttribute(frameNumber, "Physics HeightFields", mHeightFields.size()); } + + ActorFrameData::ActorFrameData(const std::shared_ptr& actor, const MWWorld::Ptr character, const MWWorld::Ptr standingOn, + bool moveToWaterSurface, osg::Vec3f movement, float slowFall, float waterlevel) + : mActor(actor), mActorRaw(actor.get()), mStandingOn(standingOn), + mPositionChanged(false), mDidJump(false), mNeedLand(false), mMoveToWaterSurface(moveToWaterSurface), + mWaterlevel(waterlevel), mSlowFall(slowFall), mOldHeight(0), mFallHeight(0), mMovement(movement), mPosition(), mRefpos() + { + const MWBase::World *world = MWBase::Environment::get().getWorld(); + mPtr = actor->getPtr(); + mFlying = world->isFlying(character); + mSwimming = world->isSwimming(character); + mWantJump = mPtr.getClass().getMovementSettings(mPtr).mPosition[2] != 0; + mIsDead = mPtr.getClass().getCreatureStats(mPtr).isDead(); + mWasOnGround = actor->getOnGround(); + } + + void ActorFrameData::updatePosition() + { + mPosition = mActorRaw->getPosition(); + if (mMoveToWaterSurface) + { + mPosition.z() = mWaterlevel; + mActorRaw->setPosition(mPosition); + } + mOldHeight = mPosition.z(); + mRefpos = mPtr.getRefData().getPosition(); + } + + WorldFrameData::WorldFrameData() + : mIsInStorm(MWBase::Environment::get().getWorld()->isInStorm()) + , mStormDirection(MWBase::Environment::get().getWorld()->getStormDirection()) + {} + + LOSRequest::LOSRequest(const std::weak_ptr& a1, const std::weak_ptr& a2) + : mResult(false), mStale(false), mAge(0) + { + // we use raw actor pointer pair to uniquely identify request + // sort the pointer value in ascending order to not duplicate equivalent requests, eg. getLOS(A, B) and getLOS(B, A) + auto* raw1 = a1.lock().get(); + auto* raw2 = a2.lock().get(); + assert(raw1 != raw2); + if (raw1 < raw2) + { + mActors = {a1, a2}; + mRawActors = {raw1, raw2}; + } + else + { + mActors = {a2, a1}; + mRawActors = {raw2, raw1}; + } + } + + bool operator==(const LOSRequest& lhs, const LOSRequest& rhs) noexcept + { + return lhs.mRawActors == rhs.mRawActors; + } } diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index fd9b52cb6b..b9390e9de1 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -1,6 +1,7 @@ #ifndef OPENMW_MWPHYSICS_PHYSICSSYSTEM_H #define OPENMW_MWPHYSICS_PHYSICSSYSTEM_H +#include #include #include #include @@ -53,6 +54,51 @@ namespace MWPhysics class HeightField; class Object; class Actor; + class PhysicsTaskScheduler; + + struct LOSRequest + { + LOSRequest(const std::weak_ptr& a1, const std::weak_ptr& a2); + std::array, 2> mActors; + std::array mRawActors; + bool mResult; + bool mStale; + int mAge; + }; + bool operator==(const LOSRequest& lhs, const LOSRequest& rhs) noexcept; + + struct ActorFrameData + { + ActorFrameData(const std::shared_ptr& actor, const MWWorld::Ptr character, const MWWorld::Ptr standingOn, bool moveToWaterSurface, osg::Vec3f movement, float slowFall, float waterlevel); + void updatePosition(); + std::weak_ptr mActor; + Actor* mActorRaw; + MWWorld::Ptr mPtr; + MWWorld::Ptr mStandingOn; + bool mFlying; + bool mSwimming; + bool mPositionChanged; + bool mWasOnGround; + bool mWantJump; + bool mDidJump; + bool mIsDead; + bool mNeedLand; + bool mMoveToWaterSurface; + float mWaterlevel; + float mSlowFall; + float mOldHeight; + float mFallHeight; + osg::Vec3f mMovement; + osg::Vec3f mPosition; + ESM::Position mRefpos; + }; + + struct WorldFrameData + { + WorldFrameData(); + bool mIsInStorm; + osg::Vec3f mStormDirection; + }; class PhysicsSystem : public RayCastingInterface { @@ -191,6 +237,8 @@ namespace MWPhysics void updateWater(); + std::vector prepareFrameData(); + osg::ref_ptr mUnrefQueue; std::unique_ptr mBroadphase; @@ -224,6 +272,8 @@ namespace MWPhysics using PtrVelocityList = std::vector>; PtrVelocityList mMovementQueue; PtrPositionList mMovementResults; + std::unique_ptr mWorldFrameData; + std::vector mActorsFrameData; float mTimeAccum;