mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-04 03:40:14 +00:00
Merge branch 'preview_mode2' into 'master'
Improved preview and vanity mode See merge request OpenMW/openmw!261
This commit is contained in:
commit
49b78ef463
@ -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;
|
||||
|
@ -110,23 +110,21 @@ namespace MWInput
|
||||
|
||||
if (MWBase::Environment::get().getInputManager()->getControlSwitch("playerviewswitch"))
|
||||
{
|
||||
const float switchLimit = 0.25;
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
if (mBindingsManager->actionIsActive(A_TogglePOV))
|
||||
{
|
||||
if (mPreviewPOVDelay <= 0.5 &&
|
||||
(mPreviewPOVDelay += dt) > 0.5)
|
||||
{
|
||||
mPreviewPOVDelay = 1.f;
|
||||
MWBase::Environment::get().getWorld()->togglePreviewMode(true);
|
||||
}
|
||||
if (world->isFirstPerson() ? mPreviewPOVDelay > switchLimit : mPreviewPOVDelay == 0)
|
||||
world->togglePreviewMode(true);
|
||||
mPreviewPOVDelay += dt;
|
||||
}
|
||||
else
|
||||
{
|
||||
//disable preview mode
|
||||
MWBase::Environment::get().getWorld()->togglePreviewMode(false);
|
||||
if (mPreviewPOVDelay > 0.f && mPreviewPOVDelay <= 0.5)
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->togglePOV();
|
||||
}
|
||||
if (mPreviewPOVDelay > 0)
|
||||
world->togglePreviewMode(false);
|
||||
if (mPreviewPOVDelay > 0.f && mPreviewPOVDelay <= switchLimit)
|
||||
world->togglePOV();
|
||||
mPreviewPOVDelay = 0.f;
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
{
|
||||
@ -207,17 +209,20 @@ namespace MWInput
|
||||
return;
|
||||
|
||||
float rot[3];
|
||||
rot[0] = yAxis * dt * 1000.0f * mCameraSensitivity * (mInvertY ? -1 : 1) * mCameraYMultiplier / 256.f;
|
||||
rot[0] = -yAxis * dt * 1000.0f * mCameraSensitivity * (mInvertY ? -1 : 1) * mCameraYMultiplier / 256.f;
|
||||
rot[1] = 0.0f;
|
||||
rot[2] = xAxis * dt * 1000.0f * mCameraSensitivity * (mInvertX ? -1 : 1) / 256.f;
|
||||
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]);
|
||||
player.yaw(-rot[2]);
|
||||
player.pitch(-rot[0]);
|
||||
}
|
||||
else if (!controls)
|
||||
MWBase::Environment::get().getWorld()->disableDeferredPreviewRotation();
|
||||
|
||||
MWBase::Environment::get().getInputManager()->resetIdleTime();
|
||||
}
|
||||
|
@ -249,17 +249,20 @@ namespace MWInput
|
||||
if (!mGuiCursorEnabled)
|
||||
{
|
||||
float rot[3];
|
||||
rot[0] = mGyroYSpeed * dt * mGyroVSensitivity * 4 * (mInvertY ? -1 : 1);
|
||||
rot[0] = -mGyroYSpeed * dt * mGyroVSensitivity * 4 * (mInvertY ? -1 : 1);
|
||||
rot[1] = 0.0f;
|
||||
rot[2] = mGyroXSpeed * dt * mGyroHSensitivity * 4 * (mInvertX ? -1 : 1);
|
||||
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]);
|
||||
player.yaw(-rot[2]);
|
||||
player.pitch(-rot[0]);
|
||||
}
|
||||
else if (!playerLooking)
|
||||
MWBase::Environment::get().getWorld()->disableDeferredPreviewRotation();
|
||||
|
||||
MWBase::Environment::get().getInputManager()->resetIdleTime();
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "../mwworld/refdata.hpp"
|
||||
|
||||
#include "../mwmechanics/drawstate.hpp"
|
||||
#include "../mwmechanics/movement.hpp"
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
|
||||
#include "npcanimation.hpp"
|
||||
@ -52,7 +53,10 @@ namespace MWRender
|
||||
mCamera(camera),
|
||||
mAnimation(nullptr),
|
||||
mFirstPersonView(true),
|
||||
mPreviewMode(false),
|
||||
mMode(Mode::Normal),
|
||||
mVanityAllowed(true),
|
||||
mStandingPreviewAllowed(Settings::Manager::getBool("preview if stand still", "Camera")),
|
||||
mDeferredRotationAllowed(Settings::Manager::getBool("deferred preview rotation", "Camera")),
|
||||
mNearest(30.f),
|
||||
mFurthest(800.f),
|
||||
mIsNearest(false),
|
||||
@ -71,18 +75,10 @@ namespace MWRender
|
||||
mSmoothedSpeed(0.f),
|
||||
mZoomOutWhenMoveCoef(Settings::Manager::getFloat("zoom out when move coef", "Camera")),
|
||||
mDynamicCameraDistanceEnabled(false),
|
||||
mShowCrosshairInThirdPersonMode(false)
|
||||
mShowCrosshairInThirdPersonMode(false),
|
||||
mDeferredRotation(osg::Vec3f()),
|
||||
mDeferredRotationDisabled(false)
|
||||
{
|
||||
mVanity.enabled = false;
|
||||
mVanity.allowed = true;
|
||||
|
||||
mPreviewCam.pitch = 0.f;
|
||||
mPreviewCam.yaw = 0.f;
|
||||
mPreviewCam.offset = 400.f;
|
||||
mMainCam.pitch = 0.f;
|
||||
mMainCam.yaw = 0.f;
|
||||
mMainCam.offset = 400.f;
|
||||
|
||||
mCameraDistance = mBaseCameraDistance;
|
||||
|
||||
mUpdateCallback = new UpdateRenderCameraCallback(this);
|
||||
@ -94,17 +90,11 @@ namespace MWRender
|
||||
mCamera->removeUpdateCallback(mUpdateCallback);
|
||||
}
|
||||
|
||||
MWWorld::Ptr Camera::getTrackingPtr() const
|
||||
{
|
||||
return mTrackingPtr;
|
||||
}
|
||||
|
||||
osg::Vec3d Camera::getFocalPoint() const
|
||||
{
|
||||
const osg::Node* trackNode = mTrackingNode;
|
||||
if (!trackNode)
|
||||
if (!mTrackingNode)
|
||||
return osg::Vec3d();
|
||||
osg::NodePathList nodepaths = trackNode->getParentalNodePaths();
|
||||
osg::NodePathList nodepaths = mTrackingNode->getParentalNodePaths();
|
||||
if (nodepaths.empty())
|
||||
return osg::Vec3d();
|
||||
osg::Matrix worldMat = osg::computeLocalToWorld(nodepaths[0]);
|
||||
@ -126,12 +116,9 @@ namespace MWRender
|
||||
osg::Vec3d Camera::getFocalPointOffset() const
|
||||
{
|
||||
osg::Vec3d offset(0, 0, 10.f);
|
||||
if (!mPreviewMode && !mVanity.enabled)
|
||||
{
|
||||
offset.x() += mFocalPointCurrentOffset.x() * cos(getYaw());
|
||||
offset.y() += mFocalPointCurrentOffset.x() * sin(getYaw());
|
||||
offset.z() += mFocalPointCurrentOffset.y();
|
||||
}
|
||||
offset.x() += mFocalPointCurrentOffset.x() * cos(getYaw());
|
||||
offset.y() += mFocalPointCurrentOffset.x() * sin(getYaw());
|
||||
offset.z() += mFocalPointCurrentOffset.y();
|
||||
return offset;
|
||||
}
|
||||
|
||||
@ -149,9 +136,6 @@ namespace MWRender
|
||||
|
||||
void Camera::updateCamera(osg::Camera *cam)
|
||||
{
|
||||
if (mTrackingPtr.isEmpty())
|
||||
return;
|
||||
|
||||
osg::Vec3d focal, position;
|
||||
getPosition(focal, position);
|
||||
|
||||
@ -181,11 +165,6 @@ namespace MWRender
|
||||
setPitch(pitch);
|
||||
}
|
||||
|
||||
void Camera::attachTo(const MWWorld::Ptr &ptr)
|
||||
{
|
||||
mTrackingPtr = ptr;
|
||||
}
|
||||
|
||||
void Camera::update(float duration, bool paused)
|
||||
{
|
||||
if (mAnimation->upperBodyReady())
|
||||
@ -198,7 +177,6 @@ namespace MWRender
|
||||
}
|
||||
if (mViewModeToggleQueued)
|
||||
{
|
||||
|
||||
togglePreviewMode(false);
|
||||
toggleViewMode();
|
||||
mViewModeToggleQueued = false;
|
||||
@ -210,13 +188,11 @@ namespace MWRender
|
||||
|
||||
// only show the crosshair in game mode
|
||||
MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager();
|
||||
wm->showCrosshair(!wm->isGuiMode() && !mVanity.enabled && !mPreviewMode
|
||||
wm->showCrosshair(!wm->isGuiMode() && mMode != Mode::Preview && mMode != Mode::Vanity
|
||||
&& (mFirstPersonView || mShowCrosshairInThirdPersonMode));
|
||||
|
||||
if(mVanity.enabled)
|
||||
{
|
||||
if(mMode == Mode::Vanity)
|
||||
rotateCamera(0.f, osg::DegreesToRadians(3.f * duration), true);
|
||||
}
|
||||
|
||||
updateFocalPointOffset(duration);
|
||||
|
||||
@ -226,6 +202,24 @@ namespace MWRender
|
||||
mSmoothedSpeed += osg::clampBetween(speed - mSmoothedSpeed, -maxDelta, maxDelta);
|
||||
|
||||
mMaxNextCameraDistance = mCameraDistance + duration * (100.f + mBaseCameraDistance);
|
||||
updateStandingPreviewMode();
|
||||
}
|
||||
|
||||
void Camera::updateStandingPreviewMode()
|
||||
{
|
||||
if (!mStandingPreviewAllowed)
|
||||
return;
|
||||
float speed = mTrackingPtr.getClass().getSpeed(mTrackingPtr);
|
||||
bool combat = mTrackingPtr.getClass().isActor() &&
|
||||
mTrackingPtr.getClass().getCreatureStats(mTrackingPtr).getDrawState() != MWMechanics::DrawState_Nothing;
|
||||
bool standingStill = speed == 0 && !combat && !mFirstPersonView;
|
||||
if (!standingStill && mMode == Mode::StandingPreview)
|
||||
{
|
||||
mMode = Mode::Normal;
|
||||
calculateDeferredRotation();
|
||||
}
|
||||
else if (standingStill && mMode == Mode::Normal)
|
||||
mMode = Mode::StandingPreview;
|
||||
}
|
||||
|
||||
void Camera::setFocalPointTargetOffset(osg::Vec2d v)
|
||||
@ -292,14 +286,19 @@ namespace MWRender
|
||||
mTrackingPtr.getClass().getCreatureStats(mTrackingPtr).setSideMovementAngle(0);
|
||||
|
||||
mFirstPersonView = !mFirstPersonView;
|
||||
updateStandingPreviewMode();
|
||||
instantTransition();
|
||||
processViewChange();
|
||||
}
|
||||
|
||||
void Camera::allowVanityMode(bool allow)
|
||||
{
|
||||
if (!allow && mVanity.enabled)
|
||||
if (!allow && mMode == Mode::Vanity)
|
||||
{
|
||||
disableDeferredPreviewRotation();
|
||||
toggleVanityMode(false);
|
||||
mVanity.allowed = allow;
|
||||
}
|
||||
mVanityAllowed = allow;
|
||||
}
|
||||
|
||||
bool Camera::toggleVanityMode(bool enable)
|
||||
@ -313,26 +312,18 @@ namespace MWRender
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!mVanity.allowed && enable)
|
||||
if (!mVanityAllowed && enable)
|
||||
return false;
|
||||
|
||||
if(mVanity.enabled == enable)
|
||||
if ((mMode == Mode::Vanity) == enable)
|
||||
return true;
|
||||
mVanity.enabled = enable;
|
||||
mMode = enable ? Mode::Vanity : Mode::Normal;
|
||||
if (!mDeferredRotationAllowed)
|
||||
disableDeferredPreviewRotation();
|
||||
if (!enable)
|
||||
calculateDeferredRotation();
|
||||
|
||||
processViewChange();
|
||||
|
||||
float offset = mPreviewCam.offset;
|
||||
|
||||
if (mVanity.enabled) {
|
||||
setPitch(osg::DegreesToRadians(-30.f));
|
||||
mMainCam.offset = mCameraDistance;
|
||||
} else {
|
||||
offset = mMainCam.offset;
|
||||
}
|
||||
|
||||
mCameraDistance = offset;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -341,22 +332,21 @@ namespace MWRender
|
||||
if (mFirstPersonView && !mAnimation->upperBodyReady())
|
||||
return;
|
||||
|
||||
if(mPreviewMode == enable)
|
||||
if((mMode == Mode::Preview) == enable)
|
||||
return;
|
||||
|
||||
mPreviewMode = enable;
|
||||
processViewChange();
|
||||
|
||||
float offset = mCameraDistance;
|
||||
if (mPreviewMode) {
|
||||
mMainCam.offset = offset;
|
||||
offset = mPreviewCam.offset;
|
||||
} else {
|
||||
mPreviewCam.offset = offset;
|
||||
offset = mMainCam.offset;
|
||||
mMode = enable ? Mode::Preview : Mode::Normal;
|
||||
if (mMode == Mode::Normal)
|
||||
updateStandingPreviewMode();
|
||||
else if (mFirstPersonView)
|
||||
instantTransition();
|
||||
if (mMode == Mode::Normal)
|
||||
{
|
||||
if (!mDeferredRotationAllowed)
|
||||
disableDeferredPreviewRotation();
|
||||
calculateDeferredRotation();
|
||||
}
|
||||
|
||||
mCameraDistance = offset;
|
||||
processViewChange();
|
||||
}
|
||||
|
||||
void Camera::setSneakOffset(float offset)
|
||||
@ -364,13 +354,6 @@ namespace MWRender
|
||||
mAnimation->setFirstPersonOffset(osg::Vec3f(0,0,-offset));
|
||||
}
|
||||
|
||||
float Camera::getYaw() const
|
||||
{
|
||||
if(mVanity.enabled || mPreviewMode)
|
||||
return mPreviewCam.yaw;
|
||||
return mMainCam.yaw;
|
||||
}
|
||||
|
||||
void Camera::setYaw(float angle)
|
||||
{
|
||||
if (angle > osg::PI) {
|
||||
@ -378,38 +361,14 @@ namespace MWRender
|
||||
} else if (angle < -osg::PI) {
|
||||
angle += osg::PI*2;
|
||||
}
|
||||
if (mVanity.enabled || mPreviewMode) {
|
||||
mPreviewCam.yaw = angle;
|
||||
} else {
|
||||
mMainCam.yaw = angle;
|
||||
}
|
||||
}
|
||||
|
||||
float Camera::getPitch() const
|
||||
{
|
||||
if (mVanity.enabled || mPreviewMode) {
|
||||
return mPreviewCam.pitch;
|
||||
}
|
||||
return mMainCam.pitch;
|
||||
mYaw = angle;
|
||||
}
|
||||
|
||||
void Camera::setPitch(float angle)
|
||||
{
|
||||
const float epsilon = 0.000001f;
|
||||
float limit = osg::PI_2 - epsilon;
|
||||
if(mPreviewMode)
|
||||
limit /= 2;
|
||||
|
||||
if(angle > limit)
|
||||
angle = limit;
|
||||
else if(angle < -limit)
|
||||
angle = -limit;
|
||||
|
||||
if (mVanity.enabled || mPreviewMode) {
|
||||
mPreviewCam.pitch = angle;
|
||||
} else {
|
||||
mMainCam.pitch = angle;
|
||||
}
|
||||
mPitch = osg::clampBetween(angle, -limit, limit);
|
||||
}
|
||||
|
||||
float Camera::getCameraDistance() const
|
||||
@ -421,50 +380,25 @@ namespace MWRender
|
||||
|
||||
void Camera::updateBaseCameraDistance(float dist, bool adjust)
|
||||
{
|
||||
if(mFirstPersonView && !mPreviewMode && !mVanity.enabled)
|
||||
if (isFirstPerson())
|
||||
return;
|
||||
|
||||
mIsNearest = false;
|
||||
|
||||
if (adjust)
|
||||
{
|
||||
if (mVanity.enabled || mPreviewMode)
|
||||
dist += mCameraDistance;
|
||||
else
|
||||
dist += std::min(mCameraDistance - getCameraDistanceCorrection(), mBaseCameraDistance);
|
||||
}
|
||||
dist += std::min(mCameraDistance - getCameraDistanceCorrection(), mBaseCameraDistance);
|
||||
|
||||
|
||||
if (dist >= mFurthest)
|
||||
dist = mFurthest;
|
||||
else if (dist <= mNearest)
|
||||
{
|
||||
dist = mNearest;
|
||||
mIsNearest = true;
|
||||
}
|
||||
|
||||
if (mVanity.enabled || mPreviewMode)
|
||||
mPreviewCam.offset = dist;
|
||||
else if (!mFirstPersonView)
|
||||
{
|
||||
mBaseCameraDistance = dist;
|
||||
Settings::Manager::setFloat("third person camera distance", "Camera", dist);
|
||||
}
|
||||
mIsNearest = dist <= mNearest;
|
||||
mBaseCameraDistance = osg::clampBetween(dist, mNearest, mFurthest);
|
||||
Settings::Manager::setFloat("third person camera distance", "Camera", mBaseCameraDistance);
|
||||
setCameraDistance();
|
||||
}
|
||||
|
||||
void Camera::setCameraDistance(float dist, bool adjust)
|
||||
{
|
||||
if(mFirstPersonView && !mPreviewMode && !mVanity.enabled)
|
||||
if (isFirstPerson())
|
||||
return;
|
||||
|
||||
if (adjust) dist += mCameraDistance;
|
||||
|
||||
if (dist >= mFurthest)
|
||||
dist = mFurthest;
|
||||
else if (dist < 10.f)
|
||||
dist = 10.f;
|
||||
mCameraDistance = dist;
|
||||
if (adjust)
|
||||
dist += mCameraDistance;
|
||||
mCameraDistance = osg::clampBetween(dist, 10.f, mFurthest);
|
||||
}
|
||||
|
||||
float Camera::getCameraDistanceCorrection() const
|
||||
@ -482,21 +416,17 @@ namespace MWRender
|
||||
|
||||
void Camera::setCameraDistance()
|
||||
{
|
||||
if (mVanity.enabled || mPreviewMode)
|
||||
mCameraDistance = mPreviewCam.offset;
|
||||
else if (!mFirstPersonView)
|
||||
{
|
||||
mCameraDistance = mBaseCameraDistance + getCameraDistanceCorrection();
|
||||
if (mDynamicCameraDistanceEnabled)
|
||||
mCameraDistance = std::min(mCameraDistance, mMaxNextCameraDistance);
|
||||
}
|
||||
mFocalPointAdjustment = osg::Vec3d();
|
||||
if (isFirstPerson())
|
||||
return;
|
||||
mCameraDistance = mBaseCameraDistance + getCameraDistanceCorrection();
|
||||
if (mDynamicCameraDistanceEnabled)
|
||||
mCameraDistance = std::min(mCameraDistance, mMaxNextCameraDistance);
|
||||
}
|
||||
|
||||
void Camera::setAnimation(NpcAnimation *anim)
|
||||
{
|
||||
mAnimation = anim;
|
||||
|
||||
processViewChange();
|
||||
}
|
||||
|
||||
@ -523,13 +453,74 @@ namespace MWRender
|
||||
rotateCamera(getPitch(), getYaw(), false);
|
||||
}
|
||||
|
||||
bool Camera::isVanityOrPreviewModeEnabled() const
|
||||
void Camera::applyDeferredPreviewRotationToPlayer(float dt)
|
||||
{
|
||||
return mPreviewMode || mVanity.enabled;
|
||||
if (isVanityOrPreviewModeEnabled() || mTrackingPtr.isEmpty())
|
||||
return;
|
||||
|
||||
osg::Vec3f rot = mDeferredRotation;
|
||||
float delta = rot.normalize();
|
||||
delta = std::min(delta, (delta + 1.f) * 3 * dt);
|
||||
rot *= delta;
|
||||
mDeferredRotation -= rot;
|
||||
|
||||
if (mDeferredRotationDisabled)
|
||||
{
|
||||
mDeferredRotationDisabled = delta > 0.0001;
|
||||
rotateCameraToTrackingPtr();
|
||||
return;
|
||||
}
|
||||
|
||||
auto& movement = mTrackingPtr.getClass().getMovementSettings(mTrackingPtr);
|
||||
movement.mRotation[0] += rot.x();
|
||||
movement.mRotation[1] += rot.y();
|
||||
movement.mRotation[2] += rot.z();
|
||||
if (std::abs(mDeferredRotation.z()) > 0.0001)
|
||||
{
|
||||
float s = std::sin(mDeferredRotation.z());
|
||||
float c = std::cos(mDeferredRotation.z());
|
||||
float x = movement.mPosition[0];
|
||||
float y = movement.mPosition[1];
|
||||
movement.mPosition[0] = x * c + y * s;
|
||||
movement.mPosition[1] = x * -s + y * c;
|
||||
}
|
||||
}
|
||||
|
||||
bool Camera::isNearest() const
|
||||
void Camera::rotateCameraToTrackingPtr()
|
||||
{
|
||||
return mIsNearest;
|
||||
setPitch(-mTrackingPtr.getRefData().getPosition().rot[0] - mDeferredRotation.x());
|
||||
setYaw(-mTrackingPtr.getRefData().getPosition().rot[2] - mDeferredRotation.z());
|
||||
}
|
||||
|
||||
void Camera::instantTransition()
|
||||
{
|
||||
mSkipFocalPointTransition = true;
|
||||
mDeferredRotationDisabled = false;
|
||||
mDeferredRotation = osg::Vec3f();
|
||||
rotateCameraToTrackingPtr();
|
||||
}
|
||||
|
||||
void Camera::calculateDeferredRotation()
|
||||
{
|
||||
MWWorld::Ptr ptr = mTrackingPtr;
|
||||
if (isVanityOrPreviewModeEnabled() || ptr.isEmpty())
|
||||
return;
|
||||
if (mFirstPersonView)
|
||||
{
|
||||
instantTransition();
|
||||
return;
|
||||
}
|
||||
|
||||
mDeferredRotation.x() = -ptr.getRefData().getPosition().rot[0] - mPitch;
|
||||
mDeferredRotation.z() = -ptr.getRefData().getPosition().rot[2] - mYaw;
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,11 +23,10 @@ namespace MWRender
|
||||
/// \brief Camera control
|
||||
class Camera
|
||||
{
|
||||
private:
|
||||
struct CamData {
|
||||
float pitch, yaw, offset;
|
||||
};
|
||||
public:
|
||||
enum class Mode { Normal, Vanity, Preview, StandingPreview };
|
||||
|
||||
private:
|
||||
MWWorld::Ptr mTrackingPtr;
|
||||
osg::ref_ptr<const osg::Node> mTrackingNode;
|
||||
float mHeightScale;
|
||||
@ -37,17 +36,17 @@ namespace MWRender
|
||||
NpcAnimation *mAnimation;
|
||||
|
||||
bool mFirstPersonView;
|
||||
bool mPreviewMode;
|
||||
Mode mMode;
|
||||
bool mVanityAllowed;
|
||||
bool mStandingPreviewAllowed;
|
||||
bool mDeferredRotationAllowed;
|
||||
|
||||
float mNearest;
|
||||
float mFurthest;
|
||||
bool mIsNearest;
|
||||
|
||||
struct {
|
||||
bool enabled, allowed;
|
||||
} mVanity;
|
||||
|
||||
float mHeight, mBaseCameraDistance;
|
||||
CamData mMainCam, mPreviewCam;
|
||||
float mPitch, mYaw;
|
||||
|
||||
bool mVanityToggleQueued;
|
||||
bool mVanityToggleQueuedValue;
|
||||
@ -78,15 +77,23 @@ namespace MWRender
|
||||
|
||||
osg::ref_ptr<osg::NodeCallback> mUpdateCallback;
|
||||
|
||||
// Used to rotate player to the direction of view after exiting preview or vanity mode.
|
||||
osg::Vec3f mDeferredRotation;
|
||||
bool mDeferredRotationDisabled;
|
||||
void calculateDeferredRotation();
|
||||
void updateStandingPreviewMode();
|
||||
|
||||
public:
|
||||
Camera(osg::Camera* camera);
|
||||
~Camera();
|
||||
|
||||
MWWorld::Ptr getTrackingPtr() const;
|
||||
/// Attach camera to object
|
||||
void attachTo(const MWWorld::Ptr &ptr) { mTrackingPtr = ptr; }
|
||||
MWWorld::Ptr getTrackingPtr() const { return mTrackingPtr; }
|
||||
|
||||
void setFocalPointTransitionSpeed(float v) { mFocalPointTransitionSpeedCoef = v; }
|
||||
void setFocalPointTargetOffset(osg::Vec2d v);
|
||||
void skipFocalPointTransition() { mSkipFocalPointTransition = true; }
|
||||
void instantTransition();
|
||||
void enableDynamicCameraDistance(bool v) { mDynamicCameraDistanceEnabled = v; }
|
||||
void enableCrosshairInThirdPersonMode(bool v) { mShowCrosshairInThirdPersonMode = v; }
|
||||
|
||||
@ -99,16 +106,14 @@ namespace MWRender
|
||||
/// Set where the camera is looking at. Uses Morrowind (euler) angles
|
||||
/// \param rot Rotation angles in radians
|
||||
void rotateCamera(float pitch, float yaw, bool adjust);
|
||||
void rotateCameraToTrackingPtr();
|
||||
|
||||
float getYaw() const;
|
||||
float getYaw() const { return mYaw; }
|
||||
void setYaw(float angle);
|
||||
|
||||
float getPitch() const;
|
||||
float getPitch() const { return mPitch; }
|
||||
void setPitch(float angle);
|
||||
|
||||
/// Attach camera to object
|
||||
void attachTo(const MWWorld::Ptr &);
|
||||
|
||||
/// @param Force view mode switch, even if currently not allowed by the animation.
|
||||
void toggleViewMode(bool force=false);
|
||||
|
||||
@ -118,11 +123,13 @@ namespace MWRender
|
||||
/// @note this may be ignored if an important animation is currently playing
|
||||
void togglePreviewMode(bool enable);
|
||||
|
||||
void applyDeferredPreviewRotationToPlayer(float dt);
|
||||
void disableDeferredPreviewRotation() { mDeferredRotationDisabled = true; }
|
||||
|
||||
/// \brief Lowers the camera for sneak.
|
||||
void setSneakOffset(float offset);
|
||||
|
||||
bool isFirstPerson() const
|
||||
{ return !(mVanity.enabled || mPreviewMode || !mFirstPersonView); }
|
||||
bool isFirstPerson() const { return mFirstPersonView && mMode == Mode::Normal; }
|
||||
|
||||
void processViewChange();
|
||||
|
||||
@ -151,9 +158,10 @@ namespace MWRender
|
||||
/// Stores focal and camera world positions in passed arguments
|
||||
void getPosition(osg::Vec3d &focal, osg::Vec3d &camera) const;
|
||||
|
||||
bool isVanityOrPreviewModeEnabled() const;
|
||||
bool isVanityOrPreviewModeEnabled() const { return mMode != Mode::Normal; }
|
||||
Mode getMode() const { return mMode; }
|
||||
|
||||
bool isNearest() const;
|
||||
bool isNearest() const { return mIsNearest; }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -653,7 +653,7 @@ namespace MWRender
|
||||
if(ptr == mCamera->getTrackingPtr() &&
|
||||
!mCamera->isVanityOrPreviewModeEnabled())
|
||||
{
|
||||
mCamera->rotateCamera(-ptr.getRefData().getPosition().rot[0], -ptr.getRefData().getPosition().rot[2], false);
|
||||
mCamera->rotateCameraToTrackingPtr();
|
||||
}
|
||||
|
||||
ptr.getRefData().getBaseNode()->setAttitude(rot);
|
||||
|
@ -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,12 +47,18 @@ 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->getMode() == Camera::Mode::Vanity)
|
||||
// Player doesn't touch controls for a long time. Transition should be very slow.
|
||||
mCamera->setFocalPointTransitionSpeed(0.2f);
|
||||
else if ((oldMode == Mode::Combat || mMode == Mode::Combat) && mCamera->getMode() == Camera::Mode::Normal)
|
||||
// Transition to/from combat mode and we are not it preview mode. Should be fast.
|
||||
mCamera->setFocalPointTransitionSpeed(5.f);
|
||||
else
|
||||
mCamera->setFocalPointTransitionSpeed(1.f);
|
||||
mCamera->setFocalPointTransitionSpeed(1.f); // Default transition speed.
|
||||
|
||||
switch (mMode)
|
||||
{
|
||||
@ -70,6 +77,9 @@ namespace MWRender
|
||||
|
||||
void ViewOverShoulderController::trySwitchShoulder()
|
||||
{
|
||||
if (mCamera->getMode() != Camera::Mode::Normal)
|
||||
return;
|
||||
|
||||
const float limitToSwitch = 120; // switch to other shoulder if wall is closer than this limit
|
||||
const float limitToSwitchBack = 300; // switch back to default shoulder if there is no walls at this distance
|
||||
|
||||
|
@ -945,7 +945,7 @@ namespace MWWorld
|
||||
removeContainerScripts(getPlayerPtr());
|
||||
mWorldScene->changeToInteriorCell(cellName, position, adjustPlayerPos, changeEvent);
|
||||
addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell());
|
||||
mRendering->getCamera()->skipFocalPointTransition();
|
||||
mRendering->getCamera()->instantTransition();
|
||||
}
|
||||
|
||||
void World::changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos, bool changeEvent)
|
||||
@ -961,7 +961,7 @@ namespace MWWorld
|
||||
removeContainerScripts(getPlayerPtr());
|
||||
mWorldScene->changeToExteriorCell(position, adjustPlayerPos, changeEvent);
|
||||
addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell());
|
||||
mRendering->getCamera()->skipFocalPointTransition();
|
||||
mRendering->getCamera()->instantTransition();
|
||||
}
|
||||
|
||||
void World::changeToCell (const ESM::CellId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent)
|
||||
@ -2405,6 +2405,16 @@ namespace MWWorld
|
||||
return mRendering->toggleVanityMode(enable);
|
||||
}
|
||||
|
||||
void World::disableDeferredPreviewRotation()
|
||||
{
|
||||
mRendering->getCamera()->disableDeferredPreviewRotation();
|
||||
}
|
||||
|
||||
void World::applyDeferredPreviewRotationToPlayer(float dt)
|
||||
{
|
||||
mRendering->getCamera()->applyDeferredPreviewRotationToPlayer(dt);
|
||||
}
|
||||
|
||||
void World::allowVanityMode(bool allow)
|
||||
{
|
||||
mRendering->allowVanityMode(allow);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -174,3 +174,27 @@ Slightly pulls camera away (or closer in case of negative value) when the charac
|
||||
|
||||
This setting can only be configured by editing the settings configuration file.
|
||||
|
||||
preview if stand still
|
||||
----------------------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: False
|
||||
|
||||
If enabled then the character rotation is not synchonized with the camera rotation while the character doesn't move and not in combat mode.
|
||||
|
||||
This setting can only be configured by editing the settings configuration file.
|
||||
|
||||
deferred preview rotation
|
||||
-------------------------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: True
|
||||
|
||||
Makes difference only in third person mode.
|
||||
If enabled then the character smoothly rotates to the view direction after exiting preview or vanity mode.
|
||||
If disabled then the camera rotates rather than the character.
|
||||
|
||||
This setting can only be configured by editing the settings configuration file.
|
||||
|
||||
|
@ -48,6 +48,12 @@ auto switch shoulder = true
|
||||
# Slightly pulls camera away when the character moves. Works only in 'view over shoulder' mode. Set to 0 to disable.
|
||||
zoom out when move coef = 20
|
||||
|
||||
# Automatically enable preview mode when player doesn't move.
|
||||
preview if stand still = false
|
||||
|
||||
# Rotate the character to the view direction after exiting preview mode.
|
||||
deferred preview rotation = true
|
||||
|
||||
[Cells]
|
||||
|
||||
# Preload cells in a background thread. All settings starting with 'preload' have no effect unless this is enabled.
|
||||
|
Loading…
x
Reference in New Issue
Block a user