diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index a23a2e56f4..6c7345c031 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -22,7 +22,8 @@ namespace MWPhysics Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, PhysicsTaskScheduler* scheduler, bool canWaterWalk, DetourNavigator::CollisionShapeType collisionShapeType) - : mStandingOnPtr(nullptr), mCanWaterWalk(canWaterWalk), mWalkingOnWater(false) + : PtrHolder(ptr, ptr.getRefData().getPosition().asVec3()) + , mStandingOnPtr(nullptr), mCanWaterWalk(canWaterWalk), mWalkingOnWater(false) , mMeshTranslation(shape->mCollisionBox.mCenter), mOriginalHalfExtents(shape->mCollisionBox.mExtents) , mStuckFrames(0), mLastStuckPosition{0, 0, 0} , mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false) @@ -31,8 +32,6 @@ Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, Physic , mActive(false) , mTaskScheduler(scheduler) { - mPtr = ptr; - // 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 // (NPCs have bodyparts and use a different approach) @@ -94,14 +93,13 @@ Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, Physic mCollisionObject->setCollisionShape(mShape.get()); mCollisionObject->setUserPointer(this); - updateScale(); + updateScaleUnsafe(); if(!mRotationallyInvariant) - setRotation(mPtr.getRefData().getBaseNode()->getAttitude()); + mRotation = mPtr.getRefData().getBaseNode()->getAttitude(); - updatePosition(); addCollisionMask(getCollisionMask()); - updateCollisionObjectPosition(); + updateCollisionObjectPositionUnsafe(); } Actor::~Actor() @@ -169,6 +167,11 @@ osg::Vec3f Actor::getScaledMeshTranslation() const void Actor::updateCollisionObjectPosition() { std::scoped_lock lock(mPositionMutex); + updateCollisionObjectPositionUnsafe(); +} + +void Actor::updateCollisionObjectPositionUnsafe() +{ mShape->setLocalScaling(Misc::Convert::toBullet(mScale)); osg::Vec3f newPosition = getScaledMeshTranslation() + mPosition; @@ -230,6 +233,11 @@ bool Actor::isRotationallyInvariant() const void Actor::updateScale() { std::scoped_lock lock(mPositionMutex); + updateScaleUnsafe(); +} + +void Actor::updateScaleUnsafe() +{ float scale = mPtr.getCellRef().getScale(); osg::Vec3f scaleVec(scale,scale,scale); diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 146a065063..4d7412e88b 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -33,6 +33,10 @@ namespace MWPhysics bool canWaterWalk, DetourNavigator::CollisionShapeType collisionShapeType); ~Actor() override; + Actor(const Actor&) = delete; + + Actor& operator=(const Actor&) = delete; + /** * Sets the collisionMode for this actor. If disabled, the actor can fly and clip geometry. */ @@ -189,8 +193,8 @@ namespace MWPhysics osg::Vec3f mScale; osg::Vec3f mPositionOffset; - bool mWorldPositionChanged; - bool mSkipSimulation; + bool mWorldPositionChanged = false; + bool mSkipSimulation = true; mutable std::mutex mPositionMutex; unsigned int mStuckFrames; @@ -205,8 +209,9 @@ namespace MWPhysics PhysicsTaskScheduler* mTaskScheduler; - Actor(const Actor&); - Actor& operator=(const Actor&); + inline void updateScaleUnsafe(); + + inline void updateCollisionObjectPositionUnsafe(); }; } diff --git a/apps/openmw/mwphysics/object.cpp b/apps/openmw/mwphysics/object.cpp index f222a38340..b646925ab1 100644 --- a/apps/openmw/mwphysics/object.cpp +++ b/apps/openmw/mwphysics/object.cpp @@ -15,14 +15,14 @@ namespace MWPhysics { Object::Object(const MWWorld::Ptr& ptr, osg::ref_ptr shapeInstance, osg::Quat rotation, int collisionType, PhysicsTaskScheduler* scheduler) - : mShapeInstance(std::move(shapeInstance)) + : PtrHolder(ptr, osg::Vec3f()) + , mShapeInstance(std::move(shapeInstance)) , mSolid(true) , mScale(ptr.getCellRef().getScale(), ptr.getCellRef().getScale(), ptr.getCellRef().getScale()) , mPosition(ptr.getRefData().getPosition().asVec3()) , mRotation(rotation) , mTaskScheduler(scheduler) { - mPtr = ptr; mCollisionObject = BulletHelpers::makeCollisionObject(mShapeInstance->mCollisionShape.get(), Misc::Convert::toBullet(mPosition), Misc::Convert::toBullet(rotation)); mCollisionObject->setUserPointer(this); diff --git a/apps/openmw/mwphysics/projectile.cpp b/apps/openmw/mwphysics/projectile.cpp index 29ec4387b1..d9bfd74bf5 100644 --- a/apps/openmw/mwphysics/projectile.cpp +++ b/apps/openmw/mwphysics/projectile.cpp @@ -15,7 +15,8 @@ namespace MWPhysics { Projectile::Projectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, float radius, PhysicsTaskScheduler* scheduler, PhysicsSystem* physicssystem) - : mHitWater(false) + : PtrHolder(MWWorld::Ptr(), position) + , mHitWater(false) , mActive(true) , mHitTarget(nullptr) , mPhysics(physicssystem) diff --git a/apps/openmw/mwphysics/ptrholder.hpp b/apps/openmw/mwphysics/ptrholder.hpp index c4141d14bc..e2ba60518c 100644 --- a/apps/openmw/mwphysics/ptrholder.hpp +++ b/apps/openmw/mwphysics/ptrholder.hpp @@ -16,6 +16,14 @@ namespace MWPhysics class PtrHolder { public: + explicit PtrHolder(const MWWorld::Ptr& ptr, const osg::Vec3f& position) + : mPtr(ptr) + , mSimulationPosition(position) + , mPosition(position) + , mPreviousPosition(position) + { + } + virtual ~PtrHolder() = default; void updatePtr(const MWWorld::Ptr& updated) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 2c5850e4d2..451102c50e 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -286,15 +286,6 @@ namespace MWWorld } } - void Scene::updateObjectPosition(const Ptr &ptr, const osg::Vec3f &pos, bool movePhysics) - { - mRendering.moveObject(ptr, pos); - if (movePhysics) - { - mPhysics->updatePosition(ptr); - } - } - void Scene::updateObjectRotation(const Ptr &ptr, RotationOrder order) { const auto rot = makeNodeRotation(ptr, order); diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index f0246f0882..d1f8611ea4 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -188,7 +188,6 @@ namespace MWWorld void updateObjectRotation(const Ptr& ptr, RotationOrder order); void updateObjectScale(const Ptr& ptr); - void updateObjectPosition(const Ptr &ptr, const osg::Vec3f &pos, bool movePhysics); bool isCellActive(const CellStore &cell); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e0d89acf40..e82153c39b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1260,10 +1260,11 @@ namespace MWWorld } if (haveToMove && newPtr.getRefData().getBaseNode()) { - mWorldScene->updateObjectPosition(newPtr, position, movePhysics); + mRendering->moveObject(newPtr, position); if (movePhysics) { - if (const auto object = mPhysics->getObject(ptr)) + mPhysics->updatePosition(newPtr); + if (const MWPhysics::Object* object = mPhysics->getObject(newPtr)) updateNavigatorObject(*object); } }