diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 75835120f..b8421cc62 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -67,7 +67,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) mEnvironment.setFrameDuration (evt.timeSinceLastFrame); // update input - MWBase::Environment::get().getInputManager()->update(); + MWBase::Environment::get().getInputManager()->update(evt.timeSinceLastFrame); // sound if (mUseSound) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 8b809d399..c2db2acf1 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -248,6 +248,8 @@ namespace MWBase virtual bool isSwimming(const MWWorld::Ptr &object) = 0; virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) = 0; + + virtual void togglePOV() = 0; }; } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 8def5c74d..6bdd87d2a 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -62,6 +62,7 @@ namespace MWInput A_ToggleSneak, //Toggles Sneak, add Push-Sneak later A_ToggleWalk, //Toggle Walking/Running A_Crouch, + A_TogglePOV, A_QuickSave, A_QuickLoad, @@ -90,6 +91,8 @@ namespace MWInput std::map mControlSwitch; + float mPreviewPOVDelay; + /* InputImpl Methods */ public: void adjustMouseRegion(int width, int height) @@ -340,6 +343,8 @@ private: poller.bind(A_Jump, KC_E); poller.bind(A_Crouch, KC_LCONTROL); + + poller.bind(A_TogglePOV, KC_TAB); } void setDragDrop(bool dragDrop) @@ -348,7 +353,7 @@ private: } //NOTE: Used to check for movement keys - void update () + void update (float duration) { // Tell OIS to handle all input events input.capture(); @@ -400,6 +405,21 @@ private: player.setUpDown (-1); else player.setUpDown (0); + + if (poller.isDown(A_TogglePOV)) { + if (mPreviewPOVDelay <= 0.5 && + (mPreviewPOVDelay += duration) > 0.5) + { + // enable preview mode + } + } else { + if (mPreviewPOVDelay > 0.5) { + //disable preview mode + } else if (mPreviewPOVDelay > 0.f) { + togglePOV(); + } + mPreviewPOVDelay = 0.f; + } } } @@ -452,6 +472,11 @@ private: mControlSwitch[sw] = value; } + void togglePOV() + { + MWBase::Environment::get().getWorld()->togglePOV(); + } + }; /***CONSTRUCTOR***/ @@ -470,9 +495,9 @@ private: delete impl; } - void MWInputManager::update() + void MWInputManager::update(float duration) { - impl->update(); + impl->update(duration); } void MWInputManager::setDragDrop(bool dragDrop) diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 5092198da..70436e207 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -52,7 +52,7 @@ namespace MWInput OMW::Engine& engine); virtual ~MWInputManager(); - virtual void update(); + void update(float duration); virtual void changeInputMode(bool guiMode); diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 94a3f71c8..a99d69945 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" @@ -12,82 +13,119 @@ namespace MWRender { Player::Player (Ogre::Camera *camera, Ogre::SceneNode* node) - : mCamera (camera), - mNode (node), + : mCamera(camera), + mPlayerNode(node), + mCameraNode(mPlayerNode->createChildSceneNode()), mFirstPersonView(true), - mVanityModeEnabled(false) - {} - - bool Player::setRotation(const Ogre::Vector3 &rot) + mVanityMode(false), + mPreviewMode(false) { - Ogre::SceneNode *sceneNode = mNode; - Ogre::Node* yawNode = sceneNode->getChildIterator().getNext(); - Ogre::Node* pitchNode = yawNode->getChildIterator().getNext(); + Ogre::SceneNode *pitchNode = mCameraNode->createChildSceneNode(); + pitchNode->attachObject(mCamera); + } + + bool Player::rotate(const Ogre::Vector3 &rot, bool adjust) + { + bool force = !mVanityMode && !mPreviewMode; + Ogre::Vector3 newRot = rot; - // we are only interested in X and Y rotation + rotateCamera(newRot, adjust); - // Rotate around X axis - Ogre::Radian radx(rot.x); - if (radx.valueDegrees() > 89.5f) { - radx = Ogre::Degree(89.5f); - } else if (radx.valueDegrees() < -89.5f) { - radx = Ogre::Degree(-89.5f); + if (!force || !mFirstPersonView) { + moveCamera(400.f, 1600.f); } - Ogre::Quaternion xr(radx, Ogre::Vector3::UNIT_X); - - // Rotate around Y axis - Ogre::Quaternion yr(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Y); - - pitchNode->setOrientation(xr); - yawNode->setOrientation(yr); - updateListener(); - return !mVanityModeEnabled; + return force; } - std::string Player::getHandle() const - { - return mNode->getName(); - } - - void Player::attachTo(const MWWorld::Ptr &ptr) - { - ptr.getRefData().setBaseNode(mNode); - } - - bool Player::adjustRotation(const Ogre::Vector3 &rot) + void Player::rotateCamera(Ogre::Vector3 &rot, bool adjust) { Ogre::SceneNode *pitchNode = mCamera->getParentSceneNode(); Ogre::SceneNode *yawNode = pitchNode->getParentSceneNode(); - float f = controlFlip(Ogre::Radian(rot.x).valueDegrees()); - if (f != 0.0) { - pitchNode->pitch(Ogre::Degree(f)); + if (adjust) { + float f = + limitPitchAngle(89.5f, Ogre::Radian(rot.x).valueDegrees()); + + if (f != 0.0) { + pitchNode->pitch(Ogre::Degree(f)); + } + yawNode->yaw(Ogre::Radian(-rot.z)); + } else { + Ogre::Radian radx(rot.x); + if (radx.valueDegrees() > 89.5f) { + radx = Ogre::Degree(89.5f); + } else if (radx.valueDegrees() < -89.5f) { + radx = Ogre::Degree(-89.5f); + } + Ogre::Quaternion xr(radx, Ogre::Vector3::UNIT_X); + Ogre::Quaternion yr(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Y); + + pitchNode->setOrientation(xr); + yawNode->setOrientation(yr); } - yawNode->yaw(Ogre::Radian(-rot.z)); - - updateListener(); - - return !mVanityModeEnabled; } - float Player::controlFlip(float shift) + void Player::moveCamera(float rsq, float hsq) { - Ogre::SceneNode *pitchNode = mCamera->getParentSceneNode(); - Ogre::Quaternion orient = pitchNode->getOrientation(); +/* + Ogre::Quaternion orient = + mCamera->getParentSceneNode()->getOrientation(); float pitchAngle = (2 * Ogre::Degree(Ogre::Math::ASin(orient.x)).valueDegrees()); - if (pitchAngle + shift < 89.5f && pitchAngle + shift > -89.5f) { + orient = mCameraNode->getOrientation(); + float yawAngle = + (2 * Ogre::Degree(Ogre::Math::ASin(orient.y)).valueDegrees()); + + float tana = Ogre::Math::Tan(Ogre::Degree(pitchAngle)); + float tansq = tana * tana; + + float r1 = hsq * rsq / (hsq + rsq * tansq); + float zsq = r1 * tansq; + r1 = Ogre::Math::Sqrt(r1); + + Ogre::Vector3 pos; + pos.y = -Ogre::Math::Sqrt(zsq); + pos.z = r1 * Ogre::Math::Sin(Ogre::Degree(yawAngle).valueDegrees()); + pos.x = r1 * Ogre::Math::Cos(Ogre::Degree(yawAngle).valueDegrees()); +*/ + Ogre::Vector3 dir = mCamera->getRealDirection(); + dir.x = -dir.x, dir.y = -dir.y, dir.z = -dir.z; + + Ogre::Ray ray(Ogre::Vector3(0, 0, 0), dir); + + mCameraNode->setPosition(ray.getPoint(800.f)); + } + + std::string Player::getHandle() const + { + return mPlayerNode->getName(); + } + + void Player::attachTo(const MWWorld::Ptr &ptr) + { + ptr.getRefData().setBaseNode(mPlayerNode); + } + + float Player::limitPitchAngle(float limitAbs, float shift) + { + Ogre::Quaternion orient = + mCamera->getParentSceneNode()->getOrientation(); + + float pitchAngle = + (2 * Ogre::Degree(Ogre::Math::ASin(orient.x)).valueDegrees()); + + if (pitchAngle + shift < limitAbs && pitchAngle + shift > -limitAbs) { return shift; } if (pitchAngle > 0) { - float f = 89.5f - pitchAngle - shift; + float f = limitAbs - pitchAngle - shift; return (f > 0.f) ? f : 0.f; } else if (pitchAngle < 0) { - float f = -89.5 - pitchAngle - shift; + float f = -limitAbs - pitchAngle - shift; return (f < 0.f) ? f : 0.f; } return 0.f; @@ -104,4 +142,38 @@ namespace MWRender MWBase::Environment::get().getSoundManager()->setListenerPosDir(pos, dir); } + + void Player::update(float duration) + { + if (mFirstPersonView && !mVanityMode) { + return; + } + if (mVanityMode) { + /// \todo adjust rotation constantly + } else { + /// \todo move camera closer or change view mode if needed + } + } + + void Player::toggleViewMode() + { + mFirstPersonView = !mFirstPersonView; + if (mFirstPersonView) { + mCameraNode->setPosition(0.f, 0.f, 0.f); + } else { + moveCamera(400.f, 1600.f); + } + } + + void Player::toggleVanityMode() + { + /// \todo move camera + mVanityMode = !mVanityMode; + } + + void Player::togglePreviewMode() + { + /// \todo move camera + mPreviewMode = !mPreviewMode; + } } diff --git a/apps/openmw/mwrender/player.hpp b/apps/openmw/mwrender/player.hpp index 981ecfe0b..739b4cd8b 100644 --- a/apps/openmw/mwrender/player.hpp +++ b/apps/openmw/mwrender/player.hpp @@ -22,16 +22,24 @@ namespace MWRender class Player { Ogre::Camera *mCamera; - Ogre::SceneNode* mNode; + + Ogre::SceneNode *mPlayerNode; + Ogre::SceneNode *mCameraNode; bool mFirstPersonView; - bool mVanityModeEnabled; + bool mVanityMode; + bool mPreviewMode; - float controlFlip(float shift = 0.f); + float mTimeIdle; + + float limitPitchAngle(float limitAbs, float shift = 0.f); /// Updates sound manager listener data void updateListener(); + void rotateCamera(Ogre::Vector3 &rot, bool adjust); + void moveCamera(float r, float h); + public: Player (Ogre::Camera *camera, Ogre::SceneNode* mNode); @@ -39,11 +47,7 @@ namespace MWRender /// Set where the player is looking at. Uses Morrowind (euler) angles /// \param rot Rotation angles in radians /// \return true if player object needs to bo rotated physically - bool setRotation(const Ogre::Vector3 &rot); - - /// \param rot Rotation angles in radians - /// \return true if player object needs to bo rotated physically - bool adjustRotation(const Ogre::Vector3 &rot); + bool rotate(const Ogre::Vector3 &rot, bool adjust); std::string getHandle() const; @@ -52,13 +56,13 @@ namespace MWRender /// several different objects void attachTo(const MWWorld::Ptr &); - void toggleViewMode() { - mFirstPersonView = !mFirstPersonView; - } + void toggleViewMode(); - void toggleVanityMode() { - mVanityModeEnabled = !mVanityModeEnabled; - } + void toggleVanityMode(); + + void togglePreviewMode(); + + void update(float duration); }; } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index d0019c6b8..91d83caf3 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -133,11 +133,10 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mObjects.setMwRoot(mMwRoot); mActors.setMwRoot(mMwRoot); + Ogre::SceneNode *playerNode = mMwRoot->createChildSceneNode ("player"); playerNode->pitch(Degree(90)); - Ogre::SceneNode *cameraYawNode = playerNode->createChildSceneNode(); - Ogre::SceneNode *cameraPitchNode = cameraYawNode->createChildSceneNode(); - cameraPitchNode->attachObject(mRendering.getCamera()); + mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode); mShadows = new Shadows(&mRendering); @@ -147,7 +146,6 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode()); - mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode); mSun = 0; mDebugging = new Debugging(mMwRoot, engine); @@ -259,11 +257,7 @@ RenderingManager::rotateObject( bool force = true; if (isPlayer) { - if (adjust) { - force = mPlayer->adjustRotation(rot); - } else { - force = mPlayer->setRotation(rot); - } + force = mPlayer->rotate(rot, adjust); } MWWorld::Class::get(ptr).adjustRotation(ptr, rot.x, rot.y, rot.z); @@ -329,6 +323,8 @@ void RenderingManager::update (float duration){ ); mWater->update(duration); } + + mPlayer->update(duration); } void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store){ diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index ef6f18a75..f100fdd59 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -56,6 +56,10 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine); virtual ~RenderingManager(); + void togglePOV() { + mPlayer->toggleViewMode(); + } + void attachCameraTo(const MWWorld::Ptr &ptr); SkyManager* getSkyManager(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8ace54378..20706438d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1151,5 +1151,4 @@ namespace MWWorld } return pos.z < cell.water; } - } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 4031a180a..2e5f73702 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -277,6 +277,9 @@ namespace MWWorld virtual bool isSwimming(const MWWorld::Ptr &object); virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos); + virtual void togglePOV() { + mRendering->togglePOV(); + } }; }