From 4d206d2c678a56c98ebfdd812a1216681fe3714a Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Sat, 27 Jun 2020 00:58:33 +0200 Subject: [PATCH] Improved preview mode --- apps/openmw/mwbase/world.hpp | 2 + apps/openmw/mwinput/actionmanager.cpp | 24 ++++++--- apps/openmw/mwinput/inputmanagerimp.cpp | 3 ++ apps/openmw/mwinput/mousemanager.cpp | 7 ++- apps/openmw/mwinput/sensormanager.cpp | 5 +- apps/openmw/mwrender/camera.cpp | 66 ++++++++++++----------- apps/openmw/mwrender/camera.hpp | 5 ++ apps/openmw/mwrender/renderingmanager.cpp | 55 ++++++++++++++++++- apps/openmw/mwrender/renderingmanager.hpp | 8 +++ apps/openmw/mwrender/viewovershoulder.cpp | 13 +++-- apps/openmw/mwworld/worldimp.cpp | 10 ++++ apps/openmw/mwworld/worldimp.hpp | 3 ++ files/settings-default.cfg | 4 ++ 13 files changed, 157 insertions(+), 48 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 627e2f2b7..17e233053 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -422,6 +422,8 @@ namespace MWBase virtual void changeVanityModeScale(float factor) = 0; virtual bool vanityRotateCamera(float * rot) = 0; virtual void setCameraDistance(float dist, bool adjust = false, bool override = true)=0; + virtual void applyDeferredPreviewRotationToPlayer(float dt) = 0; + virtual void disableDeferredPreviewRotation() = 0; virtual void setupPlayer() = 0; virtual void renderPlayer() = 0; diff --git a/apps/openmw/mwinput/actionmanager.cpp b/apps/openmw/mwinput/actionmanager.cpp index f2af3089d..bbfad1fdd 100644 --- a/apps/openmw/mwinput/actionmanager.cpp +++ b/apps/openmw/mwinput/actionmanager.cpp @@ -110,23 +110,31 @@ namespace MWInput if (MWBase::Environment::get().getInputManager()->getControlSwitch("playerviewswitch")) { + static const bool separatePreviewCamera = Settings::Manager::getBool("separate preview camera", "Camera"); if (mBindingsManager->actionIsActive(A_TogglePOV)) { - if (mPreviewPOVDelay <= 0.5 && - (mPreviewPOVDelay += dt) > 0.5) + if (separatePreviewCamera) { - mPreviewPOVDelay = 1.f; - MWBase::Environment::get().getWorld()->togglePreviewMode(true); + if (mPreviewPOVDelay <= 0.5 && (mPreviewPOVDelay += dt) > 0.5) + { + mPreviewPOVDelay = 1.f; + MWBase::Environment::get().getWorld()->togglePreviewMode(true); + } + } + else + { + if (mPreviewPOVDelay == 0) + MWBase::Environment::get().getWorld()->togglePreviewMode(true); + mPreviewPOVDelay += dt; } } else { //disable preview mode - MWBase::Environment::get().getWorld()->togglePreviewMode(false); - if (mPreviewPOVDelay > 0.f && mPreviewPOVDelay <= 0.5) - { + if (mPreviewPOVDelay > 0 || separatePreviewCamera) + MWBase::Environment::get().getWorld()->togglePreviewMode(false); + if (mPreviewPOVDelay > 0.f && mPreviewPOVDelay <= (separatePreviewCamera ? 0.5 : 0.25)) MWBase::Environment::get().getWorld()->togglePOV(); - } mPreviewPOVDelay = 0.f; } } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 79541fbe4..690183c57 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -9,6 +9,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/esmstore.hpp" @@ -101,6 +102,8 @@ namespace MWInput mMouseManager->update(dt); mSensorManager->update(dt); mActionManager->update(dt, controllerMove); + + MWBase::Environment::get().getWorld()->applyDeferredPreviewRotationToPlayer(dt); } void InputManager::setDragDrop(bool dragDrop) diff --git a/apps/openmw/mwinput/mousemanager.cpp b/apps/openmw/mwinput/mousemanager.cpp index 3fef62345..5a0446093 100644 --- a/apps/openmw/mwinput/mousemanager.cpp +++ b/apps/openmw/mwinput/mousemanager.cpp @@ -108,6 +108,8 @@ namespace MWInput player.yaw(x); player.pitch(y); } + else if (!input->getControlSwitch("playerlooking")) + MWBase::Environment::get().getWorld()->disableDeferredPreviewRotation(); if (arg.zrel && input->getControlSwitch("playerviewswitch") && input->getControlSwitch("playercontrols")) //Check to make sure you are allowed to zoomout and there is a change { @@ -212,12 +214,15 @@ namespace MWInput rot[2] = xAxis * dt * 1000.0f * mCameraSensitivity * (mInvertX ? -1 : 1) / 256.f; // Only actually turn player when we're not in vanity mode - if (!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols")) + bool controls = MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"); + if (!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && controls) { MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer(); player.yaw(rot[2]); player.pitch(rot[0]); } + else if (!controls) + MWBase::Environment::get().getWorld()->disableDeferredPreviewRotation(); MWBase::Environment::get().getInputManager()->resetIdleTime(); } diff --git a/apps/openmw/mwinput/sensormanager.cpp b/apps/openmw/mwinput/sensormanager.cpp index f3c2c2305..5a3d8847b 100644 --- a/apps/openmw/mwinput/sensormanager.cpp +++ b/apps/openmw/mwinput/sensormanager.cpp @@ -254,12 +254,15 @@ namespace MWInput rot[2] = mGyroXSpeed * dt * mGyroHSensitivity * 4 * (mInvertX ? -1 : 1); // Only actually turn player when we're not in vanity mode - if (!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && MWBase::Environment::get().getInputManager()->getControlSwitch("playerlooking")) + bool playerLooking = MWBase::Environment::get().getInputManager()->getControlSwitch("playerlooking"); + if (!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && playerLooking) { MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer(); player.yaw(rot[2]); player.pitch(rot[0]); } + else if (!playerLooking) + MWBase::Environment::get().getWorld()->disableDeferredPreviewRotation(); MWBase::Environment::get().getInputManager()->resetIdleTime(); } diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 7c43a522c..787e016ef 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -58,6 +58,7 @@ namespace MWRender mIsNearest(false), mHeight(124.f), mBaseCameraDistance(Settings::Manager::getFloat("third person camera distance", "Camera")), + mUseSeparatePreviewCam(Settings::Manager::getBool("separate preview camera", "Camera")), mVanityToggleQueued(false), mVanityToggleQueuedValue(false), mViewModeToggleQueued(false), @@ -126,7 +127,7 @@ namespace MWRender osg::Vec3d Camera::getFocalPointOffset() const { osg::Vec3d offset(0, 0, 10.f); - if (!mPreviewMode && !mVanity.enabled) + if (!mUseSeparatePreviewCam || (!mPreviewMode && !mVanity.enabled)) { offset.x() += mFocalPointCurrentOffset.x() * cos(getYaw()); offset.y() += mFocalPointCurrentOffset.x() * sin(getYaw()); @@ -322,17 +323,19 @@ namespace MWRender processViewChange(); - float offset = mPreviewCam.offset; - - if (mVanity.enabled) { - setPitch(osg::DegreesToRadians(-30.f)); - mMainCam.offset = mCameraDistance; - } else { - offset = mMainCam.offset; + if (mUseSeparatePreviewCam) + { + float offset = mPreviewCam.offset; + if (mVanity.enabled) + { + setPitch(osg::DegreesToRadians(-30.f)); + mMainCam.offset = mCameraDistance; + } + else + offset = mMainCam.offset; + mCameraDistance = offset; } - mCameraDistance = offset; - return true; } @@ -347,16 +350,18 @@ namespace MWRender mPreviewMode = enable; processViewChange(); - float offset = mCameraDistance; - if (mPreviewMode) { - mMainCam.offset = offset; - offset = mPreviewCam.offset; - } else { - mPreviewCam.offset = offset; - offset = mMainCam.offset; + if (mUseSeparatePreviewCam) + { + float offset = mCameraDistance; + if (mPreviewMode) { + mMainCam.offset = offset; + offset = mPreviewCam.offset; + } else { + mPreviewCam.offset = offset; + offset = mMainCam.offset; + } + mCameraDistance = offset; } - - mCameraDistance = offset; } void Camera::setSneakOffset(float offset) @@ -366,7 +371,7 @@ namespace MWRender float Camera::getYaw() const { - if(mVanity.enabled || mPreviewMode) + if (mUseSeparatePreviewCam && (mVanity.enabled || mPreviewMode)) return mPreviewCam.yaw; return mMainCam.yaw; } @@ -378,18 +383,16 @@ namespace MWRender } else if (angle < -osg::PI) { angle += osg::PI*2; } - if (mVanity.enabled || mPreviewMode) { + if (mUseSeparatePreviewCam && (mVanity.enabled || mPreviewMode)) mPreviewCam.yaw = angle; - } else { + else mMainCam.yaw = angle; - } } float Camera::getPitch() const { - if (mVanity.enabled || mPreviewMode) { + if (mUseSeparatePreviewCam && (mVanity.enabled || mPreviewMode)) return mPreviewCam.pitch; - } return mMainCam.pitch; } @@ -397,7 +400,7 @@ namespace MWRender { const float epsilon = 0.000001f; float limit = osg::PI_2 - epsilon; - if(mPreviewMode) + if(mUseSeparatePreviewCam && mPreviewMode) limit /= 2; if(angle > limit) @@ -405,11 +408,10 @@ namespace MWRender else if(angle < -limit) angle = -limit; - if (mVanity.enabled || mPreviewMode) { + if (mUseSeparatePreviewCam && (mVanity.enabled || mPreviewMode)) mPreviewCam.pitch = angle; - } else { + else mMainCam.pitch = angle; - } } float Camera::getCameraDistance() const @@ -428,7 +430,7 @@ namespace MWRender if (adjust) { - if (mVanity.enabled || mPreviewMode) + if (mUseSeparatePreviewCam && (mVanity.enabled || mPreviewMode)) dist += mCameraDistance; else dist += std::min(mCameraDistance - getCameraDistanceCorrection(), mBaseCameraDistance); @@ -443,7 +445,7 @@ namespace MWRender mIsNearest = true; } - if (mVanity.enabled || mPreviewMode) + if (mUseSeparatePreviewCam && (mVanity.enabled || mPreviewMode)) mPreviewCam.offset = dist; else if (!mFirstPersonView) { @@ -482,7 +484,7 @@ namespace MWRender void Camera::setCameraDistance() { - if (mVanity.enabled || mPreviewMode) + if (mUseSeparatePreviewCam && (mVanity.enabled || mPreviewMode)) mCameraDistance = mPreviewCam.offset; else if (!mFirstPersonView) { diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index d1acb814c..fb83cf4d3 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -48,6 +48,7 @@ namespace MWRender float mHeight, mBaseCameraDistance; CamData mMainCam, mPreviewCam; + bool mUseSeparatePreviewCam; bool mVanityToggleQueued; bool mVanityToggleQueuedValue; @@ -115,6 +116,9 @@ namespace MWRender bool toggleVanityMode(bool enable); void allowVanityMode(bool allow); + void useSeparatePreviewCamera(bool v) { mUseSeparatePreviewCam = v; } + bool isUsingSeparatePreviewCamera() const { return mUseSeparatePreviewCam; } + /// @note this may be ignored if an important animation is currently playing void togglePreviewMode(bool enable); @@ -152,6 +156,7 @@ namespace MWRender void getPosition(osg::Vec3d &focal, osg::Vec3d &camera) const; bool isVanityOrPreviewModeEnabled() const; + bool isVanityModeEnabled() const { return mVanity.enabled; } bool isNearest() const; }; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index d91da5a08..46b573b2e 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -58,6 +58,7 @@ #include "../mwgui/loadingscreen.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwmechanics/movement.hpp" #include "sky.hpp" #include "effectmanager.hpp" @@ -203,6 +204,8 @@ namespace MWRender , mNightEyeFactor(0.f) , mFieldOfViewOverridden(false) , mFieldOfViewOverride(0.f) + , mDeferredRotation(osg::Vec3f()) + , mDeferredRotationDisabled(false) { resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders"); @@ -653,7 +656,8 @@ namespace MWRender if(ptr == mCamera->getTrackingPtr() && !mCamera->isVanityOrPreviewModeEnabled()) { - mCamera->rotateCamera(-ptr.getRefData().getPosition().rot[0], -ptr.getRefData().getPosition().rot[2], false); + mCamera->rotateCamera(-ptr.getRefData().getPosition().rot[0] - mDeferredRotation.x(), + -ptr.getRefData().getPosition().rot[2] - mDeferredRotation.z(), false); } ptr.getRefData().getBaseNode()->setAttitude(rot); @@ -1324,6 +1328,50 @@ namespace MWRender return true; } + void RenderingManager::applyDeferredPreviewRotationToPlayer(float dt) + { + MWWorld::Ptr ptr = mCamera->getTrackingPtr(); + if (mCamera->isVanityOrPreviewModeEnabled() || ptr.isEmpty()) + return; + + osg::Vec3f rot = mDeferredRotation; + float delta = rot.normalize(); + delta = std::min(delta, (delta + 1.f) * 3 * dt); + rot *= delta; + mDeferredRotation -= rot; + + auto& movement = ptr.getClass().getMovementSettings(ptr); + movement.mRotation[0] += rot.x(); + movement.mRotation[1] += rot.y(); + movement.mRotation[2] += rot.z(); + } + + void RenderingManager::calculateDeferredRotation() + { + MWWorld::Ptr ptr = mCamera->getTrackingPtr(); + if (mCamera->isVanityOrPreviewModeEnabled() || mCamera->isUsingSeparatePreviewCamera() || ptr.isEmpty()) + return; + if (mCamera->isFirstPerson() || mDeferredRotationDisabled) + { + mDeferredRotationDisabled = false; + mDeferredRotation = osg::Vec3f(); + mCamera->rotateCamera(-ptr.getRefData().getPosition().rot[0], + -ptr.getRefData().getPosition().rot[2], false); + return; + } + + mDeferredRotation.x() = -ptr.getRefData().getPosition().rot[0] - mCamera->getPitch(); + mDeferredRotation.z() = -ptr.getRefData().getPosition().rot[2] - mCamera->getYaw(); + if (mDeferredRotation.x() > osg::PI) + mDeferredRotation.x() -= 2 * osg::PI; + if (mDeferredRotation.x() < -osg::PI) + mDeferredRotation.x() += 2 * osg::PI; + if (mDeferredRotation.z() > osg::PI) + mDeferredRotation.z() -= 2 * osg::PI; + if (mDeferredRotation.z() < -osg::PI) + mDeferredRotation.z() += 2 * osg::PI; + } + void RenderingManager::setCameraDistance(float dist, bool adjust, bool override) { if(!mCamera->isVanityOrPreviewModeEnabled() && !mCamera->isFirstPerson()) @@ -1373,11 +1421,14 @@ namespace MWRender void RenderingManager::togglePreviewMode(bool enable) { mCamera->togglePreviewMode(enable); + calculateDeferredRotation(); } bool RenderingManager::toggleVanityMode(bool enable) { - return mCamera->toggleVanityMode(enable); + bool res = mCamera->toggleVanityMode(enable); + calculateDeferredRotation(); + return res; } void RenderingManager::allowVanityMode(bool allow) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index d6a0f89c3..000826caa 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -221,6 +221,9 @@ namespace MWRender void allowVanityMode(bool allow); void changeVanityModeScale(float factor); + void applyDeferredPreviewRotationToPlayer(float dt); + void disableDeferredPreviewRotation() { mDeferredRotationDisabled = true; } + /// temporarily override the field of view with given value. void overrideFieldOfView(float val); /// reset a previous overrideFieldOfView() call, i.e. revert to field of view specified in the settings file. @@ -310,6 +313,11 @@ namespace MWRender float mFieldOfView; float mFirstPersonFieldOfView; + // Used to rotate player to the direction of view after exiting preview or vanity mode. + osg::Vec3f mDeferredRotation; + bool mDeferredRotationDisabled; + void calculateDeferredRotation(); + void operator = (const RenderingManager&); RenderingManager(const RenderingManager&); }; diff --git a/apps/openmw/mwrender/viewovershoulder.cpp b/apps/openmw/mwrender/viewovershoulder.cpp index 5d7ec7117..12f47b5f7 100644 --- a/apps/openmw/mwrender/viewovershoulder.cpp +++ b/apps/openmw/mwrender/viewovershoulder.cpp @@ -33,12 +33,13 @@ namespace MWRender void ViewOverShoulderController::update() { - if (mCamera->isVanityOrPreviewModeEnabled() || mCamera->isFirstPerson()) + if (mCamera->isFirstPerson()) return; Mode oldMode = mMode; auto ptr = mCamera->getTrackingPtr(); - if (ptr.getClass().isActor() && ptr.getClass().getCreatureStats(ptr).getDrawState() != MWMechanics::DrawState_Nothing) + bool combat = ptr.getClass().isActor() && ptr.getClass().getCreatureStats(ptr).getDrawState() != MWMechanics::DrawState_Nothing; + if (combat && !mCamera->isVanityOrPreviewModeEnabled()) mMode = Mode::Combat; else if (MWBase::Environment::get().getWorld()->isSwimming(ptr)) mMode = Mode::Swimming; @@ -46,9 +47,13 @@ namespace MWRender mMode = mDefaultShoulderIsRight ? Mode::RightShoulder : Mode::LeftShoulder; if (mAutoSwitchShoulder && (mMode == Mode::LeftShoulder || mMode == Mode::RightShoulder)) trySwitchShoulder(); - if (oldMode == mMode) return; - if (oldMode == Mode::Combat || mMode == Mode::Combat) + if (oldMode == mMode) + return; + + if (mCamera->isVanityOrPreviewModeEnabled()) + mCamera->setFocalPointTransitionSpeed(mCamera->isVanityModeEnabled() ? 0.2 : 1); + else if (oldMode == Mode::Combat || mMode == Mode::Combat) mCamera->setFocalPointTransitionSpeed(5.f); else mCamera->setFocalPointTransitionSpeed(1.f); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6e459d5e2..423c55732 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2405,6 +2405,16 @@ namespace MWWorld return mRendering->toggleVanityMode(enable); } + void World::disableDeferredPreviewRotation() + { + mRendering->disableDeferredPreviewRotation(); + } + + void World::applyDeferredPreviewRotationToPlayer(float dt) + { + mRendering->applyDeferredPreviewRotationToPlayer(dt); + } + void World::allowVanityMode(bool allow) { mRendering->allowVanityMode(allow); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index aeb6bbae4..c08206600 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -536,6 +536,9 @@ namespace MWWorld bool vanityRotateCamera(float * rot) override; void setCameraDistance(float dist, bool adjust = false, bool override = true) override; + void applyDeferredPreviewRotationToPlayer(float dt) override; + void disableDeferredPreviewRotation() override; + void setupPlayer() override; void renderPlayer() override; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 35be128a8..e4ef28f02 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -33,6 +33,10 @@ field of view = 60.0 # Best to leave this at the default since vanilla assets are not complete enough to adapt to high FoV's. Too low FoV would clip the hands off screen. first person field of view = 60.0 +# true - standard bahaviour of preview and vanity camera +# false - smooth preview mode +separate preview camera = true + # Distance from the camera to the character in third person mode. third person camera distance = 192