From 9343b4459e42f25c9ab657153c0ee431e985c520 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Apr 2013 14:59:15 +0200 Subject: [PATCH] Opening doors --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/world.hpp | 3 ++ apps/openmw/mwclass/door.cpp | 14 +++---- apps/openmw/mwworld/actiondoor.cpp | 16 ++++++++ apps/openmw/mwworld/actiondoor.hpp | 18 +++++++++ apps/openmw/mwworld/physicssystem.cpp | 6 ++- apps/openmw/mwworld/physicssystem.hpp | 1 + apps/openmw/mwworld/worldimp.cpp | 56 ++++++++++++++++++++++++++- apps/openmw/mwworld/worldimp.hpp | 6 +++ libs/openengine/bullet/physic.cpp | 23 +++++++++++ libs/openengine/bullet/physic.hpp | 2 + 11 files changed, 137 insertions(+), 10 deletions(-) create mode 100644 apps/openmw/mwworld/actiondoor.cpp create mode 100644 apps/openmw/mwworld/actiondoor.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index f4fdcb390..08033f822 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -54,7 +54,7 @@ add_openmw_dir (mwworld containerstore actiontalk actiontake manualref player cellfunctors failedaction cells localscripts customdata weather inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat - esmstore store recordcmp fallback actionrepair actionsoulgem livecellref + esmstore store recordcmp fallback actionrepair actionsoulgem livecellref actiondoor ) add_openmw_dir (mwclass diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index a00ae9c3c..42821e361 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -326,6 +326,9 @@ namespace MWBase virtual void setupPlayer(bool newGame) = 0; virtual void renderPlayer() = 0; + virtual void activateDoor(const MWWorld::Ptr& door) = 0; + ///< activate (open or close) an non-teleport door + virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0; virtual int canRest() = 0; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 163cf0277..5b061e090 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -12,6 +12,7 @@ #include "../mwworld/nullaction.hpp" #include "../mwworld/failedaction.hpp" #include "../mwworld/actionteleport.hpp" +#include "../mwworld/actiondoor.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/inventorystore.hpp" @@ -71,7 +72,7 @@ namespace MWClass ptr.get(); const std::string &openSound = ref->mBase->mOpenSound; - //const std::string &closeSound = ref->mBase->closeSound; + const std::string &closeSound = ref->mBase->mCloseSound; const std::string lockedSound = "LockedDoor"; const std::string trapActivationSound = "Disarm Trap Fail"; @@ -139,12 +140,11 @@ namespace MWClass else { // animated door - // TODO return action for rotating the door - - // This is a little pointless, but helps with testing - boost::shared_ptr action(new MWWorld::NullAction); - - action->setSound(openSound); + boost::shared_ptr action(new MWWorld::ActionDoor(ptr)); + if (ptr.getRefData().getLocalRotation().rot[2] == 0) + action->setSound(openSound); + else + action->setSound(closeSound); return action; } diff --git a/apps/openmw/mwworld/actiondoor.cpp b/apps/openmw/mwworld/actiondoor.cpp new file mode 100644 index 000000000..6e3441e22 --- /dev/null +++ b/apps/openmw/mwworld/actiondoor.cpp @@ -0,0 +1,16 @@ +#include "actiondoor.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +namespace MWWorld +{ + ActionDoor::ActionDoor (const MWWorld::Ptr& object) : Action (false, object) + { + } + + void ActionDoor::executeImp (const MWWorld::Ptr& actor) + { + MWBase::Environment::get().getWorld()->activateDoor(getTarget()); + } +} diff --git a/apps/openmw/mwworld/actiondoor.hpp b/apps/openmw/mwworld/actiondoor.hpp new file mode 100644 index 000000000..2dc5ad8c1 --- /dev/null +++ b/apps/openmw/mwworld/actiondoor.hpp @@ -0,0 +1,18 @@ +#ifndef GAME_MWWORLD_ACTIONDOOR_H +#define GAME_MWWORLD_ACTIONDOOR_H + +#include "action.hpp" +#include "ptr.hpp" + +namespace MWWorld +{ + class ActionDoor : public Action + { + virtual void executeImp (const MWWorld::Ptr& actor); + + public: + ActionDoor (const Ptr& object); + }; +} + +#endif diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 19ee2e517..34e6036e6 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -131,7 +131,6 @@ namespace MWWorld return position; } - static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity, OEngine::Physic::PhysicEngine *engine) { @@ -390,6 +389,11 @@ namespace MWWorld } } + std::vector PhysicsSystem::getCollisions(const Ptr &ptr) + { + return mEngine->getCollisions(ptr.getRefData().getBaseNode()->getName()); + } + Ogre::Vector3 PhysicsSystem::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity) { return MovementSolver::move(ptr, movement, time, gravity, mEngine); diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 4eec9367c..48214029e 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -51,6 +51,7 @@ namespace MWWorld bool toggleCollisionMode(); Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity); + std::vector getCollisions(const MWWorld::Ptr &ptr); ///< get handles this object collides with Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr); std::pair getFacedHandle (MWWorld::World& world, float queryDistance); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7ceb3e2f7..e4f28ecc5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -978,7 +978,45 @@ namespace MWWorld !isSwimming(player->first) && !isFlying(player->first)); moveObjectImp(player->first, vec.x, vec.y, vec.z); } - // the only purpose this has currently is to update the debug drawer + + // doors + for (std::map::iterator it = mDoorStates.begin(); it != mDoorStates.end(); ++it) + { + if (!it->first.getRefData().getCount()) + mDoorStates.erase(it); + else + { + if (mPlayer->getPlayer().getCell() != it->first.getCell()) + continue; + float oldRot = Ogre::Radian(it->first.getRefData().getLocalRotation().rot[2]).valueDegrees(); + float diff = duration * 90 * (it->second ? 1 : -1); + float targetRot = std::min(std::max(0.f, oldRot + diff), 90.f); + localRotateObject(it->first, 0, 0, targetRot); + + std::vector collisions = mPhysics->getCollisions(it->first); + for (std::vector::iterator cit = collisions.begin(); cit != collisions.end(); ++cit) + { + MWWorld::Ptr ptr = getPtrViaHandle(*cit); + if (MWWorld::Class::get(ptr).isActor()) + { + // figure out which side of the door the object we collided with is + Ogre::Vector3 relativePos = it->first.getRefData().getBaseNode()-> + convertWorldToLocalPosition(ptr.getRefData().getBaseNode()->_getDerivedPosition()); + if(relativePos.y >= 0) + targetRot = std::min(std::max(0.f, oldRot + diff*0.1f), 90.f); + else + targetRot = std::min(std::max(0.f, oldRot - diff*0.1f), 90.f); + + localRotateObject(it->first, 0, 0, targetRot); + break; + } + } + + if ((targetRot == 90.f && it->second) || targetRot == 0.f) + mDoorStates.erase(it); + } + } + mPhysEngine->stepSimulation (duration); } @@ -1480,4 +1518,20 @@ namespace MWWorld { mRendering->frameStarted(dt); } + + void World::activateDoor(const MWWorld::Ptr& door) + { + if (mDoorStates.find(door) != mDoorStates.end()) + { + // if currently opening, then close, if closing, then open + mDoorStates[door] = !mDoorStates[door]; + } + else + { + if (door.getRefData().getLocalRotation().rot[2] == 0) + mDoorStates[door] = 1; // open + else + mDoorStates[door] = 0; // close + } + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index a51bdc2e6..35c53e29e 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -85,6 +85,9 @@ namespace MWWorld float mFaced2Distance; int mNumFacing; + std::map mDoorStates; + ///< only holds doors that are currently moving. 0 means closing, 1 opening + unsigned long lastTick; Ogre::Timer mTimer; @@ -368,6 +371,9 @@ namespace MWWorld virtual void setupPlayer(bool newGame); virtual void renderPlayer(); + virtual void activateDoor(const MWWorld::Ptr& door); + ///< activate (open or close) an non-teleport door + virtual void setupExternalRendering (MWRender::ExternalRendering& rendering); virtual int canRest(); diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index eaeae7dc3..d522ebaf8 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -509,6 +509,29 @@ namespace Physic } } + class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback + { + public: + std::vector mResult; + virtual btScalar addSingleResult(btManifoldPoint& cp, + const btCollisionObjectWrapper* colObj0Wrap,int partId0,int index0, + const btCollisionObjectWrapper* colObj1Wrap,int partId1,int index1) + { + const RigidBody* body = dynamic_cast(colObj0Wrap->m_collisionObject); + if (body) + mResult.push_back(body->mName); + return 0.f; + } + }; + + std::vector PhysicEngine::getCollisions(const std::string& name) + { + RigidBody* body = getRigidBody(name); + ContactTestResultCallback callback; + dynamicsWorld->contactTest(body, callback); + return callback.mResult; + } + void PhysicEngine::stepSimulation(double deltaT) { // This seems to be needed for character controller objects diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 6ce4edba3..6d88fcb55 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -298,6 +298,8 @@ namespace Physic */ std::vector< std::pair > rayTest2(btVector3& from, btVector3& to); + std::vector getCollisions(const std::string& name); + //event list of non player object std::list NPEventList;