diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index d4f1d2f8a..619bbbdf5 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -286,6 +286,9 @@ namespace MWBase virtual MWWorld::Ptr moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore* newCell, float x, float y, float z, bool movePhysics=true) = 0; ///< @return an updated Ptr + virtual MWWorld::Ptr moveObjectBy(const MWWorld::Ptr &ptr, osg::Vec3f vec) = 0; + ///< @return an updated Ptr + virtual void scaleObject (const MWWorld::Ptr& ptr, float scale) = 0; virtual void rotateObject(const MWWorld::Ptr& ptr, float x, float y, float z, diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index b1f219e33..e7fe93b35 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -120,6 +120,8 @@ int Actor::getCollisionMask() const void Actor::updatePositionUnsafe() { + if (!mWorldPositionChanged && mWorldPosition != mPtr.getRefData().getPosition().asVec3()) + mWorldPositionChanged = true; mWorldPosition = mPtr.getRefData().getPosition().asVec3(); } @@ -153,6 +155,7 @@ void Actor::updateCollisionObjectPositionUnsafe() mLocalTransform.setOrigin(Misc::Convert::toBullet(newPosition)); mLocalTransform.setRotation(Misc::Convert::toBullet(mRotation)); mCollisionObject->setWorldTransform(mLocalTransform); + mWorldPositionChanged = false; } void Actor::updateCollisionObjectPosition() @@ -167,18 +170,20 @@ osg::Vec3f Actor::getCollisionObjectPosition() const return Misc::Convert::toOsg(mLocalTransform.getOrigin()); } -void Actor::setPosition(const osg::Vec3f& position) +bool Actor::setPosition(const osg::Vec3f& position) { std::scoped_lock lock(mPositionMutex); - mPreviousPosition = mPosition; - mPosition = position; + bool hasChanged = mPosition != position || mPositionOffset.length() != 0 || mWorldPositionChanged; + mPreviousPosition = mPosition + mPositionOffset; + mPosition = position + mPositionOffset; + mPositionOffset = osg::Vec3f(); + return hasChanged; } void Actor::adjustPosition(const osg::Vec3f& offset) { std::scoped_lock lock(mPositionMutex); - mPosition += offset; - mPreviousPosition += offset; + mPositionOffset += offset; } void Actor::resetPosition() @@ -189,6 +194,8 @@ void Actor::resetPosition() mPosition = mWorldPosition; mSimulationPosition = mWorldPosition; updateCollisionObjectPositionUnsafe(); + mStandingOnPtr = nullptr; + mWorldPositionChanged = false; } osg::Vec3f Actor::getPosition() const diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 07a9bebd2..7c8ea0b73 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -90,8 +90,9 @@ namespace MWPhysics /** * Store the current position into mPreviousPosition, then move to this position. + * Returns true if the new position is different. */ - void setPosition(const osg::Vec3f& position); + bool setPosition(const osg::Vec3f& position); void resetPosition(); void adjustPosition(const osg::Vec3f& offset); @@ -177,6 +178,8 @@ namespace MWPhysics osg::Vec3f mSimulationPosition; osg::Vec3f mPosition; osg::Vec3f mPreviousPosition; + osg::Vec3f mPositionOffset; + bool mWorldPositionChanged; btTransform mLocalTransform; mutable std::mutex mPositionMutex; diff --git a/apps/openmw/mwphysics/mtphysics.cpp b/apps/openmw/mwphysics/mtphysics.cpp index a78a30788..95c61edc7 100644 --- a/apps/openmw/mwphysics/mtphysics.cpp +++ b/apps/openmw/mwphysics/mtphysics.cpp @@ -100,15 +100,6 @@ namespace osg::Vec3f interpolateMovements(MWPhysics::ActorFrameData& actorData, float timeAccum, float physicsDt) { const float interpolationFactor = timeAccum / physicsDt; - - // account for force change of actor's position in the main thread - const auto correction = actorData.mActorRaw->getWorldPosition() - actorData.mOrigin; - if (correction.length() != 0) - { - actorData.mActorRaw->adjustPosition(correction); - actorData.mPosition = actorData.mActorRaw->getPosition(); - } - return actorData.mPosition * interpolationFactor + actorData.mActorRaw->getPreviousPosition() * (1.f - interpolationFactor); } @@ -511,9 +502,7 @@ namespace MWPhysics { if(const auto actor = actorData.mActor.lock()) { - bool positionChanged = actorData.mPosition != actorData.mActorRaw->getPosition(); - actorData.mActorRaw->setPosition(actorData.mPosition); - if (positionChanged) + if (actor->setPosition(actorData.mPosition)) { actor->updateCollisionObjectPosition(); mCollisionWorld->updateSingleAabb(actor->getCollisionObject()); diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index a908940ed..103c6629d 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -32,11 +32,7 @@ namespace MWScript std::vector actors; MWBase::Environment::get().getWorld()->getActorsStandingOn (ptr, actors); for (auto& actor : actors) - { - osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); - actorPos += diff; - MWBase::Environment::get().getWorld()->moveObject(actor, actorPos.x(), actorPos.y(), actorPos.z()); - } + MWBase::Environment::get().getWorld()->moveObjectBy(actor, diff); } template @@ -727,14 +723,12 @@ namespace MWScript return; osg::Vec3f diff = ptr.getRefData().getBaseNode()->getAttitude() * posChange; - osg::Vec3f worldPos(ptr.getRefData().getPosition().asVec3()); - worldPos += diff; // We should move actors, standing on moving object, too. // This approach can be used to create elevators. moveStandingActors(ptr, diff); dynamic_cast(runtime.getContext()).updatePtr(ptr, - MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x(), worldPos.y(), worldPos.z())); + MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff)); } }; @@ -755,15 +749,14 @@ namespace MWScript Interpreter::Type_Float movement = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); - const float *objPos = ptr.getRefData().getPosition().pos; osg::Vec3f diff; if (axis == "x") - diff.x() += movement; + diff.x() = movement; else if (axis == "y") - diff.y() += movement; + diff.y() = movement; else if (axis == "z") - diff.z() += movement; + diff.z() = movement; else return; @@ -771,7 +764,7 @@ namespace MWScript // This approach can be used to create elevators. moveStandingActors(ptr, diff); dynamic_cast(runtime.getContext()).updatePtr(ptr, - MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0]+diff.x(), objPos[1]+diff.y(), objPos[2]+diff.z())); + MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff)); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3756ea04b..3086fed83 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1251,6 +1251,18 @@ namespace MWWorld return moveObjectImp(ptr, x, y, z, true, moveToActive); } + MWWorld::Ptr World::moveObjectBy(const Ptr& ptr, osg::Vec3f vec) + { + auto* actor = mPhysics->getActor(ptr); + if (actor) + { + actor->adjustPosition(vec); + return ptr; + } + osg::Vec3f newpos = ptr.getRefData().getPosition().asVec3() + vec; + return moveObject(ptr, newpos.x(), newpos.y(), newpos.z()); + } + void World::scaleObject (const Ptr& ptr, float scale) { if (mPhysics->getActor(ptr)) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 1fc5ebc20..75717b16b 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -380,6 +380,9 @@ namespace MWWorld MWWorld::Ptr moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z, bool movePhysics=true) override; ///< @return an updated Ptr + MWWorld::Ptr moveObjectBy(const Ptr& ptr, osg::Vec3f vec) override; + ///< @return an updated Ptr + void scaleObject (const Ptr& ptr, float scale) override; /// World rotates object, uses radians