@ -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 ) ,
@ -62,20 +66,19 @@ namespace MWRender
mVanityToggleQueuedValue ( false ) ,
mViewModeToggleQueued ( false ) ,
mCameraDistance ( 0.f ) ,
mThirdPersonMode ( ThirdPersonViewMode : : Standard ) ,
mOverShoulderOffset ( osg : : Vec2f ( 30.0f , - 10.0f ) ) ,
mSmoothTransitionToCombatMode ( 0.f )
mMaxNextCameraDistance ( 800.f ) ,
mFocalPointCurrentOffset ( osg : : Vec2d ( ) ) ,
mFocalPointTargetOffset ( osg : : Vec2d ( ) ) ,
mFocalPointTransitionSpeedCoef ( 1.f ) ,
mSkipFocalPointTransition ( true ) ,
mPreviousTransitionInfluence ( 0.f ) ,
mSmoothedSpeed ( 0.f ) ,
mZoomOutWhenMoveCoef ( Settings : : Manager : : getFloat ( " zoom out when move coef " , " Camera " ) ) ,
mDynamicCameraDistanceEnabled ( 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 ) ;
@ -87,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 = track Node- > getParentalNodePaths ( ) ;
osg : : NodePathList nodepaths = mTrackingNode - > getParentalNodePaths ( ) ;
if ( nodepaths . empty ( ) )
return osg : : Vec3d ( ) ;
osg : : Matrix worldMat = osg : : computeLocalToWorld ( nodepaths [ 0 ] ) ;
@ -119,15 +116,9 @@ namespace MWRender
osg : : Vec3d Camera : : getFocalPointOffset ( ) const
{
osg : : Vec3d offset ( 0 , 0 , 10.f ) ;
if ( mThirdPersonMode = = ThirdPersonViewMode : : OverShoulder & & ! mPreviewMode & & ! mVanity . enabled )
{
float horizontalOffset = mOverShoulderOffset . x ( ) * ( 1.f - mSmoothTransitionToCombatMode ) ;
float verticalOffset = mSmoothTransitionToCombatMode * 15.f + ( 1.f - mSmoothTransitionToCombatMode ) * mOverShoulderOffset . y ( ) ;
offset . x ( ) + = horizontalOffset * cos ( getYaw ( ) ) ;
offset . y ( ) + = horizontalOffset * sin ( getYaw ( ) ) ;
offset . z ( ) + = verticalOffset ;
}
offset . x ( ) + = mFocalPointCurrentOffset . x ( ) * cos ( getYaw ( ) ) ;
offset . y ( ) + = mFocalPointCurrentOffset . x ( ) * sin ( getYaw ( ) ) ;
offset . z ( ) + = mFocalPointCurrentOffset . y ( ) ;
return offset ;
}
@ -145,9 +136,6 @@ namespace MWRender
void Camera : : updateCamera ( osg : : Camera * cam )
{
if ( mTrackingPtr . isEmpty ( ) )
return ;
osg : : Vec3d focal , position ;
getPosition ( focal , position ) ;
@ -177,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 ( ) )
@ -194,7 +177,6 @@ namespace MWRender
}
if ( mViewModeToggleQueued )
{
togglePreviewMode ( false ) ;
toggleViewMode ( ) ;
mViewModeToggleQueued = false ;
@ -206,36 +188,86 @@ namespace MWRender
// only show the crosshair in game mode
MWBase : : WindowManager * wm = MWBase : : Environment : : get ( ) . getWindowManager ( ) ;
wm - > showCrosshair ( ! wm - > isGuiMode ( ) & & ! mVanity . enabled & & ! mPreviewMode
& & ( mFirstPersonView | | m ThirdPersonMode ! = ThirdPersonViewMode : : Standard ) ) ;
wm - > showCrosshair ( ! wm - > isGuiMode ( ) & & mMode ! = Mode : : Preview & & mMode ! = Mode : : Vanity
& & ( mFirstPersonView | | m ShowCrosshairInThirdPersonMode ) ) ;
if ( mVanity . enabled )
{
if ( mMode = = Mode : : Vanity )
rotateCamera ( 0.f , osg : : DegreesToRadians ( 3.f * duration ) , true ) ;
updateFocalPointOffset ( duration ) ;
float speed = mTrackingPtr . getClass ( ) . getSpeed ( mTrackingPtr ) ;
speed / = ( 1.f + speed / 500.f ) ;
float maxDelta = 300.f * duration ;
mSmoothedSpeed + = osg : : clampBetween ( speed - mSmoothedSpeed , - maxDelta , maxDelta ) ;
mMaxNextCameraDistance = mCameraDistance + duration * ( 100.f + mBaseCameraDistance ) ;
updateStandingPreviewMode ( ) ;
}
updateSmoothTransitionToCombatMode ( duration ) ;
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 : : setOverShoulderOffset ( float horizontal , float vertical )
void Camera : : set FocalPointTargetOffset( osg : : Vec2d v )
{
mOverShoulderOffset = osg : : Vec2f ( horizontal , vertical ) ;
mFocalPointTargetOffset = v ;
mPreviousTransitionSpeed = mFocalPointTransitionSpeed ;
mPreviousTransitionInfluence = 1.0f ;
}
void Camera : : updateSmoothTransitionToCombatMode ( float duration )
void Camera : : update FocalPointOffset ( float duration )
{
bool combatMode = true ;
if ( mTrackingPtr . getClass ( ) . isActor ( ) )
combatMode = mTrackingPtr . getClass ( ) . getCreatureStats ( mTrackingPtr ) . getDrawState ( ) ! = MWMechanics : : DrawState_Nothing ;
float speed = ( ( combatMode ? 1.f : 0.f ) - mSmoothTransitionToCombatMode ) * 5 ;
if ( speed ! = 0 )
speed + = speed > 0 ? 1 : - 1 ;
if ( duration < = 0 )
return ;
if ( mSkipFocalPointTransition )
{
mSkipFocalPointTransition = false ;
mPreviousExtraOffset = osg : : Vec2d ( ) ;
mPreviousTransitionInfluence = 0.f ;
mFocalPointCurrentOffset = mFocalPointTargetOffset ;
}
osg : : Vec2d oldOffset = mFocalPointCurrentOffset ;
if ( mPreviousTransitionInfluence > 0 )
{
mFocalPointCurrentOffset - = mPreviousExtraOffset ;
mPreviousExtraOffset = mPreviousExtraOffset / mPreviousTransitionInfluence + mPreviousTransitionSpeed * duration ;
mPreviousTransitionInfluence =
std : : max ( 0.f , mPreviousTransitionInfluence - duration * mFocalPointTransitionSpeedCoef ) ;
mPreviousExtraOffset * = mPreviousTransitionInfluence ;
mFocalPointCurrentOffset + = mPreviousExtraOffset ;
}
osg : : Vec2d delta = mFocalPointTargetOffset - mFocalPointCurrentOffset ;
if ( delta . length2 ( ) > 0 )
{
float coef = duration * ( 1.0 + 5.0 / delta . length ( ) ) *
mFocalPointTransitionSpeedCoef * ( 1.0f - mPreviousTransitionInfluence ) ;
mFocalPointCurrentOffset + = delta * std : : min ( coef , 1.0f ) ;
}
else
{
mPreviousExtraOffset = osg : : Vec2d ( ) ;
mPreviousTransitionInfluence = 0.f ;
}
mSmoothTransitionToCombatMode + = speed * duration ;
if ( mSmoothTransitionToCombatMode > 1 )
mSmoothTransitionToCombatMode = 1 ;
if ( mSmoothTransitionToCombatMode < 0 )
mSmoothTransitionToCombatMode = 0 ;
mFocalPointTransitionSpeed = ( mFocalPointCurrentOffset - oldOffset ) / duration ;
}
void Camera : : toggleViewMode ( bool force )
@ -254,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 )
@ -275,26 +312,18 @@ namespace MWRender
return false ;
}
if ( ! mVanity . a llowed & & enable )
if ( ! mVanityA llowed & & 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 ;
}
@ -303,22 +332,21 @@ namespace MWRender
if ( mFirstPersonView & & ! mAnimation - > upperBodyReady ( ) )
return ;
if ( mPreviewMode = = enable )
if ( ( mMode = = Mode : : Preview ) = = enable )
return ;
m Preview Mode = enable ;
processViewChange ( ) ;
float offset = mCameraDistance ;
if ( mPreviewMode ) {
mMainCam . offset = offset ;
offset = mPreviewCam . offset ;
} else {
mPreviewCam . offset = offset ;
offset = mMainCam . offset ;
m Mode = 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 )
@ -326,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 ) {
@ -340,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
@ -383,70 +380,53 @@ 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 ) ;
}
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
{
return mThirdPersonMode ! = ThirdPersonViewMode : : Standard ? std : : max ( - getPitch ( ) , 0.f ) * 50.f : 0 ;
if ( ! mDynamicCameraDistanceEnabled )
return 0 ;
float pitchCorrection = std : : max ( - getPitch ( ) , 0.f ) * 50.f ;
float smoothedSpeedSqr = mSmoothedSpeed * mSmoothedSpeed ;
float speedCorrection = smoothedSpeedSqr / ( smoothedSpeedSqr + 300.f * 300.f ) * mZoomOutWhenMoveCoef ;
return pitchCorrection + speedCorrection ;
}
void Camera : : setCameraDistance ( )
{
if ( mVanity . enabled | | mPreviewMode )
mCameraDistance = mPreviewCam . offset ;
else if ( ! mFirstPersonView )
mCameraDistance = mBaseCameraDistance + getCameraDistanceCorrection ( ) ;
mFocalPointAdjustment = osg : : Vec3d ( ) ;
if ( isFirstPerson ( ) )
return ;
mCameraDistance = mBaseCameraDistance + getCameraDistanceCorrection ( ) ;
if ( mDynamicCameraDistanceEnabled )
mCameraDistance = std : : min ( mCameraDistance , mMaxNextCameraDistance ) ;
}
void Camera : : setAnimation ( NpcAnimation * anim )
{
mAnimation = anim ;
processViewChange ( ) ;
}
@ -473,13 +453,74 @@ namespace MWRender
rotateCamera ( getPitch ( ) , getYaw ( ) , false ) ;
}
bool Camera : : isVanityOrPreviewModeEnabled ( ) const
void Camera : : applyDeferredPreviewRotationToPlayer ( float dt )
{
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 )
{
return mPreviewMode | | mVanity . enabled ;
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 ;
}
}
void Camera : : rotateCameraToTrackingPtr ( )
{
setPitch ( - mTrackingPtr . getRefData ( ) . getPosition ( ) . rot [ 0 ] - mDeferredRotation . x ( ) ) ;
setYaw ( - mTrackingPtr . getRefData ( ) . getPosition ( ) . rot [ 2 ] - mDeferredRotation . z ( ) ) ;
}
bool Camera : : isNearest ( ) const
void Camera : : instantTransition ( )
{
return mIsNearest ;
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 ;
}
}