2008-12-25 22:00:00 +01:00
//=======================================================================
// Copyright XashXT Group 2008 <20>
// view.cpp - view/refresh setup functions
//=======================================================================
# include "extdll.h"
2009-01-22 22:00:00 +01:00
# include "utils.h"
2009-01-11 22:00:00 +01:00
# include "ref_params.h"
2009-01-22 22:00:00 +01:00
# include "triangle_api.h"
# include "pm_movevars.h"
2010-08-20 22:00:00 +02:00
# include "r_beams.h"
2010-07-08 22:00:00 +02:00
# include "studio.h"
2010-08-12 22:00:00 +02:00
# include "pm_defs.h"
2008-12-25 22:00:00 +01:00
# include "hud.h"
2010-08-12 22:00:00 +02:00
extern void PM_ParticleLine ( float * start , float * end , int pcolor , float life , float vert ) ;
extern int PM_GetVisEntInfo ( int ent ) ;
extern int PM_GetPhysEntInfo ( int ent ) ;
extern void InterpolateAngles ( float * start , float * end , float * output , float frac ) ;
extern void NormalizeAngles ( float * angles ) ;
extern float Distance ( const float * v1 , const float * v2 ) ;
extern float AngleBetweenVectors ( const float * v1 , const float * v2 ) ;
extern float vJumpOrigin [ 3 ] ;
extern float vJumpAngles [ 3 ] ;
2009-01-22 22:00:00 +01:00
# define ORIGIN_BACKUP 64
# define ORIGIN_MASK ( ORIGIN_BACKUP - 1 )
// global view containers
Vector v_origin , v_angles , v_cl_angles ; // base client vectors
float v_idlescale , v_lastDistance ; // misc variables
Vector ev_punchangle ; // client punchangles
2010-08-07 22:00:00 +02:00
cl_entity_t * spot ;
2009-01-22 22:00:00 +01:00
typedef struct
{
Vector Origins [ ORIGIN_BACKUP ] ;
float OriginTime [ ORIGIN_BACKUP ] ;
Vector Angles [ ORIGIN_BACKUP ] ;
float AngleTime [ ORIGIN_BACKUP ] ;
int CurrentOrigin ;
int CurrentAngle ;
} viewinterp_t ;
2009-09-13 22:00:00 +02:00
typedef struct pitchdrift_s
{
int nodrift ;
float pitchvel ;
float driftmove ;
float laststop ;
} pitchdrift_t ;
2009-01-22 22:00:00 +01:00
static viewinterp_t ViewInterp ;
2009-09-13 22:00:00 +02:00
static pitchdrift_t pd ;
2009-01-22 22:00:00 +01:00
// view CVARS
cvar_t * scr_ofsx ;
cvar_t * scr_ofsy ;
cvar_t * scr_ofsz ;
cvar_t * cl_vsmoothing ;
2009-09-22 22:00:00 +02:00
cvar_t * cl_stairsmooth ;
2010-03-20 22:00:00 +01:00
cvar_t * cl_weaponlag ;
2009-01-22 22:00:00 +01:00
cvar_t * cl_bobcycle ;
cvar_t * cl_bob ;
cvar_t * cl_bobup ;
cvar_t * cl_waterdist ;
cvar_t * cl_chasedist ;
2010-04-04 22:00:00 +02:00
cvar_t * r_studio_lerping ;
2009-01-22 22:00:00 +01:00
cvar_t * v_iyaw_cycle ;
cvar_t * v_iroll_cycle ;
cvar_t * v_ipitch_cycle ;
cvar_t * v_iyaw_level ;
cvar_t * v_iroll_level ;
cvar_t * v_ipitch_level ;
2010-03-21 22:00:00 +01:00
cvar_t * v_dark ;
2009-01-22 22:00:00 +01:00
//==============================================================================
// VIEW RENDERING
//==============================================================================
//==========================
// V_ThirdPerson
//==========================
void V_ThirdPerson ( void )
{
// no thirdperson in multiplayer
2010-08-20 22:00:00 +02:00
if ( gEngfuncs . GetMaxClients ( ) > 1 ) return ;
2010-08-15 22:00:00 +02:00
gHUD . m_iCameraMode = 1 ;
2009-01-22 22:00:00 +01:00
}
//==========================
// V_FirstPerson
//==========================
void V_FirstPerson ( void )
{
2010-08-15 22:00:00 +02:00
gHUD . m_iCameraMode = 0 ;
2009-01-22 22:00:00 +01:00
}
2010-03-07 22:00:00 +01:00
/*
= = = = = = = = = = = = =
V_PunchAxis
Client side punch effect
= = = = = = = = = = = = =
*/
void V_PunchAxis ( int axis , float punch )
{
ev_punchangle [ axis ] = punch ;
}
2009-01-22 22:00:00 +01:00
//==========================
// V_Init
//==========================
void V_Init ( void )
{
2010-08-19 22:00:00 +02:00
scr_ofsx = gEngfuncs . pfnRegisterVariable ( " scr_ofsx " , " 0 " , 0 , " screen offset by X " ) ;
scr_ofsy = gEngfuncs . pfnRegisterVariable ( " scr_ofsy " , " 0 " , 0 , " screen offset by Y " ) ;
scr_ofsz = gEngfuncs . pfnRegisterVariable ( " scr_ofsz " , " 0 " , 0 , " screen offset by Z " ) ;
r_studio_lerping = gEngfuncs . pfnRegisterVariable ( " r_studio_lerping " , " 1 " , FCVAR_ARCHIVE , " enables studio model animation lerping " ) ; // get copy of engine cvar
cl_vsmoothing = gEngfuncs . pfnRegisterVariable ( " cl_vsmoothing " , " 0.05 " , 0 , " enables lepring in multiplayer " ) ;
cl_stairsmooth = gEngfuncs . pfnRegisterVariable ( " cl_vstairsmooth " , " 100 " , FCVAR_ARCHIVE , " how fast your view moves upward/downward when running up/down stairs " ) ;
v_iyaw_cycle = gEngfuncs . pfnRegisterVariable ( " v_iyaw_cycle " , " 2 " , 0 , " viewing inverse yaw cycle " ) ;
v_iroll_cycle = gEngfuncs . pfnRegisterVariable ( " v_iroll_cycle " , " 0.5 " , 0 , " viewing inverse roll cycle " ) ;
v_ipitch_cycle = gEngfuncs . pfnRegisterVariable ( " v_ipitch_cycle " , " 1 " , 0 , " viewing inverse pitch cycle " ) ;
v_iyaw_level = gEngfuncs . pfnRegisterVariable ( " v_iyaw_level " , " 0.3 " , 0 , " viewing inverse yaw level " ) ;
v_iroll_level = gEngfuncs . pfnRegisterVariable ( " v_iroll_level " , " 0.1 " , 0 , " viewing inverse roll level " ) ;
v_ipitch_level = gEngfuncs . pfnRegisterVariable ( " v_iyaw_level " , " 0.3 " , 0 , " viewing inverse pitch level " ) ;
v_dark = gEngfuncs . pfnRegisterVariable ( " v_dark " , " 0 " , 0 , " gross hack to make first frame black. half-life legacy " ) ;
cl_weaponlag = gEngfuncs . pfnRegisterVariable ( " v_viewmodel_lag " , " 0.0 " , FCVAR_ARCHIVE , " add some lag to viewmodel like in HL2 " ) ;
cl_bobcycle = gEngfuncs . pfnRegisterVariable ( " cl_bobcycle " , " 0.8 " , 0 , " bob full cycle " ) ;
cl_bob = gEngfuncs . pfnRegisterVariable ( " cl_bob " , " 0.01 " , 0 , " bob value " ) ;
cl_bobup = gEngfuncs . pfnRegisterVariable ( " cl_bobup " , " 0.5 " , 0 , " bob upper limit " ) ;
cl_waterdist = gEngfuncs . pfnRegisterVariable ( " cl_waterdist " , " 4 " , 0 , " distance between viewofs and water plane " ) ;
cl_chasedist = gEngfuncs . pfnRegisterVariable ( " cl_chasedist " , " 112 " , 0 , " max distance to chase camera " ) ;
gEngfuncs . pfnAddCommand ( " thirdperson " , V_ThirdPerson , " change camera to thirdperson " ) ;
gEngfuncs . pfnAddCommand ( " firstperson " , V_FirstPerson , " change camera to firstperson " ) ;
2009-01-22 22:00:00 +01:00
}
2009-09-13 22:00:00 +02:00
//==========================
// V_StartPitchDrift
//==========================
void V_StartPitchDrift ( void )
{
2010-08-04 22:00:00 +02:00
if ( pd . laststop = = GetClientTime ( ) )
2009-09-13 22:00:00 +02:00
return ;
if ( pd . nodrift | | ! pd . pitchvel )
{
pd . pitchvel = v_centerspeed - > value ;
pd . nodrift = 0 ;
pd . driftmove = 0 ;
}
}
//==========================
// V_StopPitchDrift
//==========================
void V_StopPitchDrift ( void )
{
pd . laststop = GetClientTime ( ) ;
pd . nodrift = 1 ;
pd . pitchvel = 0 ;
}
//==========================
// V_DriftPitch
//==========================
void V_DriftPitch ( ref_params_t * pparams )
{
float delta , move ;
2010-08-20 22:00:00 +02:00
if ( gEngfuncs . IsNoClipping ( ) | | ! pparams - > onground | | pparams - > demoplayback )
2009-09-13 22:00:00 +02:00
{
pd . driftmove = 0 ;
pd . pitchvel = 0 ;
return ;
}
if ( pd . nodrift )
{
2009-11-15 22:00:00 +01:00
if ( fabs ( pparams - > cmd - > forwardmove ) < cl_forwardspeed - > value )
2009-09-13 22:00:00 +02:00
pd . driftmove = 0 ;
else pd . driftmove + = pparams - > frametime ;
if ( pd . driftmove > v_centermove - > value ) V_StartPitchDrift ( ) ;
return ;
}
delta = pparams - > idealpitch - pparams - > cl_viewangles [ PITCH ] ;
if ( ! delta )
{
pd . pitchvel = 0 ;
return ;
}
move = pparams - > frametime * pd . pitchvel ;
pd . pitchvel + = pparams - > frametime * v_centerspeed - > value ;
if ( delta > 0 )
{
if ( move > delta )
{
pd . pitchvel = 0 ;
move = delta ;
}
pparams - > cl_viewangles [ PITCH ] + = move ;
}
else if ( delta < 0 )
{
if ( move > - delta )
{
pd . pitchvel = 0 ;
move = - delta ;
}
pparams - > cl_viewangles [ PITCH ] - = move ;
}
}
2009-01-23 22:00:00 +01:00
//==========================
// V_CalcFov
//==========================
float V_CalcFov ( float fov_x , float width , float height )
2009-01-22 22:00:00 +01:00
{
2009-01-23 22:00:00 +01:00
// check to avoid division by zero
2010-07-08 22:00:00 +02:00
if ( fov_x < 1 | | fov_x > 179 )
{
2010-08-15 22:00:00 +02:00
Con_Printf ( " V_CalcFov: invalid fov %g! \n " , fov_x ) ;
2010-07-08 22:00:00 +02:00
fov_x = 90 ;
}
2009-01-23 22:00:00 +01:00
2010-07-08 22:00:00 +02:00
float x = width / tan ( DEG2RAD ( fov_x ) * 0.5f ) ;
float half_fov_y = atan ( height / x ) ;
return RAD2DEG ( half_fov_y ) * 2 ;
2009-01-22 22:00:00 +01:00
}
//==========================
// V_DropPunchAngle
//==========================
void V_DropPunchAngle ( float frametime , Vector & ev_punchangle )
{
float len ;
len = ev_punchangle . Length ( ) ;
2009-11-10 22:00:00 +01:00
ev_punchangle = ev_punchangle . Normalize ( ) ;
2009-01-22 22:00:00 +01:00
len - = ( 10.0 + len * 0.5 ) * frametime ;
len = max ( len , 0.0 ) ;
ev_punchangle * = len ;
}
2010-08-20 22:00:00 +02:00
void V_CalcViewModelLag ( ref_params_t * pparams , Vector & origin , Vector & angles , Vector & original_angles )
2010-03-20 22:00:00 +01:00
{
static Vector m_vecLastFacing ;
Vector vOriginalOrigin = origin ;
Vector vOriginalAngles = angles ;
// Calculate our drift
Vector forward ;
AngleVectors ( angles , forward , NULL , NULL ) ;
2010-08-20 22:00:00 +02:00
if ( pparams - > frametime ! = 0.0f )
2010-03-20 22:00:00 +01:00
{
Vector vDifference ;
vDifference = forward - m_vecLastFacing ;
float flSpeed = 5.0f ;
// If we start to lag too far behind, we'll increase the "catch up" speed.
// Solves the problem with fast cl_yawspeed, m_yaw or joysticks rotating quickly.
// The old code would slam lastfacing with origin causing the viewmodel to pop to a new position
float flDiff = vDifference . Length ( ) ;
if ( ( flDiff > cl_weaponlag - > value ) & & ( cl_weaponlag - > value > 0.0f ) )
{
float flScale = flDiff / cl_weaponlag - > value ;
flSpeed * = flScale ;
}
// FIXME: Needs to be predictable?
2010-08-20 22:00:00 +02:00
m_vecLastFacing = m_vecLastFacing + vDifference * ( flSpeed * pparams - > frametime ) ;
2010-03-20 22:00:00 +01:00
// Make sure it doesn't grow out of control!!!
m_vecLastFacing = m_vecLastFacing . Normalize ( ) ;
origin = origin + ( vDifference * - 1.0f ) * 5.0f ;
ASSERT ( m_vecLastFacing . IsValid ( ) ) ;
}
Vector right , up ;
AngleVectors ( original_angles , forward , right , up ) ;
float pitch = original_angles [ PITCH ] ;
if ( pitch > 180.0f )
{
pitch - = 360.0f ;
}
else if ( pitch < - 180.0f )
{
pitch + = 360.0f ;
}
if ( cl_weaponlag - > value < = 0.0f )
{
origin = vOriginalOrigin ;
angles = vOriginalAngles ;
}
else
{
// FIXME: These are the old settings that caused too many exposed polys on some models
origin = origin + forward * ( - pitch * 0.035f ) ;
origin = origin + right * ( - pitch * 0.03f ) ;
origin = origin + up * ( - pitch * 0.02f ) ;
}
}
2009-01-22 22:00:00 +01:00
//==========================
// V_CalcGunAngle
//==========================
void V_CalcGunAngle ( ref_params_t * pparams )
{
2009-09-18 22:00:00 +02:00
if ( pparams - > fov_x > 135 ) return ;
2009-01-22 22:00:00 +01:00
2010-08-07 22:00:00 +02:00
cl_entity_t * viewent = GetViewModel ( ) ;
2009-01-22 22:00:00 +01:00
2010-08-07 22:00:00 +02:00
if ( ! viewent - > curstate . modelindex )
return ;
2009-09-18 22:00:00 +02:00
2010-08-07 22:00:00 +02:00
viewent - > curstate . effects | = EF_MINLIGHT ;
2009-01-22 22:00:00 +01:00
2010-08-07 22:00:00 +02:00
viewent - > angles [ YAW ] = pparams - > viewangles [ YAW ] + pparams - > crosshairangle [ YAW ] ;
viewent - > angles [ PITCH ] = pparams - > viewangles [ PITCH ] - pparams - > crosshairangle [ PITCH ] * 0.25 ;
viewent - > angles [ ROLL ] = pparams - > viewangles [ ROLL ] ;
viewent - > angles [ ROLL ] - = v_idlescale * sin ( pparams - > time * v_iroll_cycle - > value ) * v_iroll_level - > value ;
2009-01-22 22:00:00 +01:00
// don't apply all of the v_ipitch to prevent normally unseen parts of viewmodel from coming into view.
2010-08-07 22:00:00 +02:00
viewent - > angles [ PITCH ] - = v_idlescale * sin ( pparams - > time * v_ipitch_cycle - > value ) * ( v_ipitch_level - > value * 0.5 ) ;
viewent - > angles [ YAW ] - = v_idlescale * sin ( pparams - > time * v_iyaw_cycle - > value ) * v_iyaw_level - > value ;
2009-01-23 22:00:00 +01:00
}
2009-01-22 22:00:00 +01:00
2009-01-23 22:00:00 +01:00
//==========================
// V_PreRender
//==========================
void V_PreRender ( ref_params_t * pparams )
{
2010-08-20 22:00:00 +02:00
// pass into beam global vars
g_pViewRenderBeams - > SetViewParams ( pparams ) ;
2009-01-23 22:00:00 +01:00
// input
pparams - > intermission = gHUD . m_iIntermission ;
2009-09-18 22:00:00 +02:00
if ( gHUD . m_iCameraMode ) pparams - > flags | = RDF_THIRDPERSON ;
else pparams - > flags & = ~ RDF_THIRDPERSON ;
2009-01-23 22:00:00 +01:00
2009-09-19 22:00:00 +02:00
pparams - > fov_x = gHUD . m_flFOV ; // this is a final fov value
2009-01-23 22:00:00 +01:00
pparams - > fov_y = V_CalcFov ( pparams - > fov_x , pparams - > viewport [ 2 ] , pparams - > viewport [ 3 ] ) ;
2010-07-08 22:00:00 +02:00
memset ( pparams - > blend , 0 , sizeof ( pparams - > blend ) ) ;
2009-01-22 22:00:00 +01:00
}
//==========================
// V_CalcGlobalFog
//==========================
void V_CalcGlobalFog ( ref_params_t * pparams )
{
2010-03-18 22:00:00 +01:00
int bOn = ( pparams - > waterlevel < 2 ) & & ( gHUD . m_flStartDist > 0 ) & & ( gHUD . m_flEndDist > 0 & & gHUD . m_flStartDist ) ;
2010-08-19 22:00:00 +02:00
gEngfuncs . pTriAPI - > Fog ( gHUD . m_vecFogColor , gHUD . m_flStartDist , gHUD . m_flEndDist , bOn ) ;
2009-01-22 22:00:00 +01:00
}
//==========================
// V_CalcBob
//==========================
float V_CalcBob ( ref_params_t * pparams )
{
static double bobtime ;
static float bob ;
static float lasttime ;
float cycle ;
Vector vel ;
if ( ! pparams - > onground | | pparams - > time = = lasttime )
return bob ;
lasttime = pparams - > time ;
bobtime + = pparams - > frametime ;
cycle = bobtime - ( int ) ( bobtime / cl_bobcycle - > value ) * cl_bobcycle - > value ;
cycle / = cl_bobcycle - > value ;
2009-01-23 22:00:00 +01:00
if ( cycle < cl_bobup - > value ) cycle = M_PI * cycle / cl_bobup - > value ;
2009-01-22 22:00:00 +01:00
else cycle = M_PI + M_PI * ( cycle - cl_bobup - > value ) / ( 1.0 - cl_bobup - > value ) ;
2009-09-18 22:00:00 +02:00
vel = pparams - > simvel ;
2009-01-22 22:00:00 +01:00
vel [ 2 ] = 0 ;
bob = sqrt ( vel [ 0 ] * vel [ 0 ] + vel [ 1 ] * vel [ 1 ] ) * cl_bob - > value ;
2009-01-23 22:00:00 +01:00
bob = bob * 0.3 + bob * 0.7 * sin ( cycle ) ;
2009-01-22 22:00:00 +01:00
bob = min ( bob , 4 ) ;
bob = max ( bob , - 7 ) ;
return bob ;
}
//==========================
// V_AddIdle
//==========================
void V_AddIdle ( ref_params_t * pparams )
{
pparams - > viewangles [ ROLL ] + = v_idlescale * sin ( pparams - > time * v_iroll_cycle - > value ) * v_iroll_level - > value ;
pparams - > viewangles [ PITCH ] + = v_idlescale * sin ( pparams - > time * v_ipitch_cycle - > value ) * v_ipitch_level - > value ;
pparams - > viewangles [ YAW ] + = v_idlescale * sin ( pparams - > time * v_iyaw_cycle - > value ) * v_iyaw_level - > value ;
}
//==========================
// V_CalcViewRoll
//==========================
void V_CalcViewRoll ( ref_params_t * pparams )
{
float sign , side , value ;
2010-08-07 22:00:00 +02:00
cl_entity_t * viewentity ;
2009-01-23 22:00:00 +01:00
Vector right ;
2009-09-18 22:00:00 +02:00
viewentity = GetEntityByIndex ( pparams - > viewentity ) ;
if ( ! viewentity ) return ;
if ( pparams - > health < = 0 & & ( pparams - > viewheight [ 2 ] ! = 0 ) )
2009-01-23 22:00:00 +01:00
{
2010-08-07 22:00:00 +02:00
GetViewModel ( ) - > curstate . modelindex = 0 ; // clear the viewmodel
pparams - > viewangles [ ROLL ] = 80 ; // dead view angle
2009-01-23 22:00:00 +01:00
return ;
}
2009-01-22 22:00:00 +01:00
2010-02-09 22:00:00 +01:00
if ( pparams - > demoplayback ) return ;
2010-08-07 22:00:00 +02:00
AngleVectors ( viewentity - > angles , NULL , right , NULL ) ;
2009-09-18 22:00:00 +02:00
side = right . Dot ( pparams - > simvel ) ;
2009-01-22 22:00:00 +01:00
sign = side < 0 ? - 1 : 1 ;
side = fabs ( side ) ;
value = pparams - > movevars - > rollangle ;
if ( side < pparams - > movevars - > rollspeed )
side = side * value / pparams - > movevars - > rollspeed ;
else side = value ;
side = side * sign ;
pparams - > viewangles [ ROLL ] + = side ;
}
//==========================
2010-07-08 22:00:00 +02:00
// V_SetViewport
2009-01-22 22:00:00 +01:00
//==========================
2010-07-08 22:00:00 +02:00
void V_SetViewport ( ref_params_t * pparams )
2009-01-22 22:00:00 +01:00
{
pparams - > viewport [ 0 ] = 0 ;
pparams - > viewport [ 1 ] = 0 ;
pparams - > viewport [ 2 ] = VIEWPORT_SIZE ;
pparams - > viewport [ 3 ] = VIEWPORT_SIZE ;
}
//==========================
// V_GetChaseOrigin
//==========================
void V_GetChaseOrigin ( Vector angles , Vector origin , float distance , Vector & result )
{
Vector vecEnd ;
Vector forward ;
Vector vecStart ;
2010-08-12 22:00:00 +02:00
pmtrace_t * trace ;
2009-01-22 22:00:00 +01:00
int maxLoops = 8 ;
2010-08-07 22:00:00 +02:00
cl_entity_t * ent = NULL ;
2010-08-12 22:00:00 +02:00
int ignoreent = - 1 ; // first, ignore no entity
2009-01-22 22:00:00 +01:00
// trace back from the target using the player's view angles
AngleVectors ( angles , forward , NULL , NULL ) ;
forward * = - 1 ;
vecStart = origin ;
vecEnd . MA ( distance , vecStart , forward ) ;
while ( maxLoops > 0 )
{
2010-08-19 22:00:00 +02:00
trace = gEngfuncs . PM_TraceLine ( vecStart , vecEnd , PM_TRACELINE_PHYSENTSONLY , 2 , ignoreent ) ;
2010-08-12 22:00:00 +02:00
if ( trace - > ent < = 0 ) break ; // we hit the world or nothing, stop trace
2009-01-22 22:00:00 +01:00
2010-08-12 22:00:00 +02:00
ent = GetEntityByIndex ( PM_GetPhysEntInfo ( trace - > ent ) ) ;
if ( ent = = NULL )
break ;
2009-01-22 22:00:00 +01:00
// hit non-player solid BSP, stop here
2010-08-12 22:00:00 +02:00
if ( ent - > curstate . solid = = SOLID_BSP & & ! ent - > player )
2009-01-23 22:00:00 +01:00
break ;
2009-01-22 22:00:00 +01:00
// if close enought to end pos, stop, otherwise continue trace
2010-08-12 22:00:00 +02:00
if ( trace - > endpos . Distance ( vecEnd ) < 1.0f )
2009-01-23 22:00:00 +01:00
break ;
2009-01-22 22:00:00 +01:00
else
{
2010-08-12 22:00:00 +02:00
ignoreent = trace - > ent ; // ignore last hit entity
vecStart = trace - > endpos ;
2009-01-22 22:00:00 +01:00
}
maxLoops - - ;
}
2010-08-12 22:00:00 +02:00
result . MA ( 4 , trace - > endpos , trace - > plane . normal ) ;
v_lastDistance = trace - > endpos . Distance ( origin ) ; // real distance without offset
2009-01-22 22:00:00 +01:00
}
//==========================
// V_GetChasePos
//==========================
2010-08-07 22:00:00 +02:00
void V_GetChasePos ( ref_params_t * pparams , cl_entity_t * ent , float * cl_angles , Vector & origin , Vector & angles )
2009-01-22 22:00:00 +01:00
{
2010-08-07 22:00:00 +02:00
if ( ! ent )
2009-01-22 22:00:00 +01:00
{
// just copy a save in-map position
angles = Vector ( 0 , 0 , 0 ) ;
origin = Vector ( 0 , 0 , 0 ) ;
return ;
}
2010-08-07 22:00:00 +02:00
if ( cl_angles = = NULL )
2009-01-22 22:00:00 +01:00
{
// no mouse angles given, use entity angles ( locked mode )
2010-08-07 22:00:00 +02:00
angles = ent - > angles ;
2009-01-22 22:00:00 +01:00
angles . x * = - 1 ;
}
2010-08-07 22:00:00 +02:00
else
{
angles = cl_angles ;
}
2009-01-22 22:00:00 +01:00
2009-01-23 22:00:00 +01:00
// refresh the position
2010-08-07 22:00:00 +02:00
origin = ent - > origin ;
2009-01-22 22:00:00 +01:00
origin [ 2 ] + = 28 ; // DEFAULT_VIEWHEIGHT - some offset
V_GetChaseOrigin ( angles , origin , cl_chasedist - > value , origin ) ;
}
//==========================
// V_CalcCameraRefdef
//==========================
void V_CalcCameraRefdef ( ref_params_t * pparams )
{
if ( pparams - > intermission ) return ; // disable in intermission mode
2010-08-15 22:00:00 +02:00
if ( GetEntityByIndex ( pparams - > viewentity ) ! = GetLocalPlayer ( ) )
2010-03-21 22:00:00 +01:00
{
2010-04-05 22:00:00 +02:00
// this is a viewentity which sets by SET_VIEW builtin
2010-08-07 22:00:00 +02:00
cl_entity_t * viewentity = GetEntityByIndex ( pparams - > viewentity ) ;
2010-03-21 22:00:00 +01:00
if ( viewentity )
{
2010-08-20 22:00:00 +02:00
studiohdr_t * viewmonster = ( studiohdr_t * ) Mod_Extradata ( viewentity - > curstate . modelindex ) ;
float m_fLerp = pparams - > lerpfrac ;
2010-03-21 22:00:00 +01:00
2010-08-07 22:00:00 +02:00
if ( viewentity - > curstate . movetype = = MOVETYPE_STEP )
v_origin = LerpPoint ( viewentity - > prevstate . origin , viewentity - > curstate . origin , m_fLerp ) ;
else v_origin = viewentity - > origin ; // already interpolated
2010-03-21 22:00:00 +01:00
2010-08-06 22:00:00 +02:00
// add view offset
if ( viewmonster ) v_origin + = viewmonster - > eyeposition ;
2010-03-21 22:00:00 +01:00
2010-08-07 22:00:00 +02:00
if ( viewentity - > curstate . movetype = = MOVETYPE_STEP )
v_angles = LerpAngle ( viewentity - > prevstate . angles , viewentity - > curstate . angles , m_fLerp ) ;
else v_angles = viewentity - > angles ; // already interpolated
2010-03-21 22:00:00 +01:00
pparams - > crosshairangle [ ROLL ] = 1 ; // crosshair is hided
// refresh position
pparams - > viewangles = v_angles ;
pparams - > vieworg = v_origin ;
}
}
2009-12-03 22:00:00 +01:00
else pparams - > crosshairangle [ ROLL ] = 0 ; // show crosshair again
2009-01-22 22:00:00 +01:00
}
2010-08-07 22:00:00 +02:00
cl_entity_t * V_FindIntermisionSpot ( ref_params_t * pparams )
2009-01-22 22:00:00 +01:00
{
2010-08-07 22:00:00 +02:00
cl_entity_t * ent ;
2009-01-22 22:00:00 +01:00
int spotindex [ 16 ] ; // max number of intermission spot
int k = 0 , j = 0 ;
2009-01-23 22:00:00 +01:00
// found intermission points
for ( int i = 0 ; i < pparams - > num_entities ; i + + )
2009-01-22 22:00:00 +01:00
{
ent = GetEntityByIndex ( i ) ;
2010-08-15 22:00:00 +02:00
if ( ent & & ! stricmp ( ent - > curstate . classname , " info_intermission " ) )
2009-01-22 22:00:00 +01:00
{
if ( j > 15 ) break ; // spotlist is full
2010-08-07 22:00:00 +02:00
spotindex [ j ] = ent - > index ; // save entindex
2009-01-22 22:00:00 +01:00
j + + ;
}
}
// ok, we have list of intermission spots
if ( j )
{
2009-12-05 22:00:00 +01:00
if ( j > 1 ) k = RANDOM_LONG ( 0 , j - 1 ) ;
2009-01-22 22:00:00 +01:00
ent = GetEntityByIndex ( spotindex [ k ] ) ;
}
else ent = GetLocalPlayer ( ) ; // just get view from player
return ent ;
}
//==========================
// V_CalcIntermisionRefdef
//==========================
void V_CalcIntermisionRefdef ( ref_params_t * pparams )
{
if ( ! pparams - > intermission ) return ;
2010-08-07 22:00:00 +02:00
cl_entity_t * view ;
2009-01-22 22:00:00 +01:00
float old ;
if ( ! spot ) spot = V_FindIntermisionSpot ( pparams ) ;
view = GetViewModel ( ) ;
2009-01-23 22:00:00 +01:00
// need to lerping position ?
2010-08-07 22:00:00 +02:00
pparams - > vieworg = spot - > origin ;
pparams - > viewangles = spot - > angles ;
view - > curstate . modelindex = 0 ;
2009-01-22 22:00:00 +01:00
// allways idle in intermission
old = v_idlescale ;
v_idlescale = 1 ;
V_AddIdle ( pparams ) ;
v_idlescale = old ;
2009-01-23 22:00:00 +01:00
v_cl_angles = pparams - > cl_viewangles ;
2009-01-22 22:00:00 +01:00
v_origin = pparams - > vieworg ;
v_angles = pparams - > viewangles ;
}
2009-01-23 22:00:00 +01:00
//==========================
// V_CalcShake
//==========================
void V_CalcShake ( void )
{
float frametime ;
int i ;
float fraction , freq ;
if ( gHUD . m_Shake . time = = 0 )
return ;
if ( ( gHUD . m_flTime > gHUD . m_Shake . time ) | | gHUD . m_Shake . duration < = 0 | | gHUD . m_Shake . amplitude < = 0 | | gHUD . m_Shake . frequency < = 0 )
{
memset ( & gHUD . m_Shake , 0 , sizeof ( gHUD . m_Shake ) ) ;
return ;
}
frametime = gHUD . m_flTimeDelta ;
if ( gHUD . m_flTime > gHUD . m_Shake . nextShake )
{
// higher frequency means we recalc the extents more often and perturb the display again
gHUD . m_Shake . nextShake = gHUD . m_flTime + ( 1.0f / gHUD . m_Shake . frequency ) ;
// Compute random shake extents (the shake will settle down from this)
for ( i = 0 ; i < 3 ; i + + )
{
gHUD . m_Shake . offset [ i ] = RANDOM_FLOAT ( - gHUD . m_Shake . amplitude , gHUD . m_Shake . amplitude ) ;
}
gHUD . m_Shake . angle = RANDOM_FLOAT ( - gHUD . m_Shake . amplitude * 0.25 , gHUD . m_Shake . amplitude * 0.25 ) ;
}
// ramp down amplitude over duration (fraction goes from 1 to 0 linearly with slope 1/duration)
fraction = ( gHUD . m_Shake . time - gHUD . m_flTime ) / gHUD . m_Shake . duration ;
// ramp up frequency over duration
if ( fraction )
{
freq = ( gHUD . m_Shake . frequency / fraction ) ;
}
else
{
freq = 0 ;
}
// square fraction to approach zero more quickly
fraction * = fraction ;
// Sine wave that slowly settles to zero
fraction = fraction * sin ( gHUD . m_flTime * freq ) ;
// add to view origin
gHUD . m_Shake . appliedOffset = gHUD . m_Shake . offset * fraction ;
// add to roll
gHUD . m_Shake . appliedAngle = gHUD . m_Shake . angle * fraction ;
// drop amplitude a bit, less for higher frequency shakes
float localAmp = gHUD . m_Shake . amplitude * ( frametime / ( gHUD . m_Shake . duration * gHUD . m_Shake . frequency ) ) ;
gHUD . m_Shake . amplitude - = localAmp ;
}
//==========================
// V_ApplyShake
//==========================
void V_ApplyShake ( Vector & origin , Vector & angles , float factor )
{
origin . MA ( factor , origin , gHUD . m_Shake . appliedOffset ) ;
angles . z + = gHUD . m_Shake . appliedAngle * factor ;
}
2009-01-22 22:00:00 +01:00
//==========================
// V_CalcThirdPersonRefdef
//==========================
2009-01-23 22:00:00 +01:00
void V_CalcThirdPersonRefdef ( ref_params_t * pparams )
2009-01-22 22:00:00 +01:00
{
// passed only in third person
2009-01-23 22:00:00 +01:00
if ( gHUD . m_iCameraMode = = 0 | | pparams - > intermission )
return ;
// clear viewmodel for thirdperson
2010-08-07 22:00:00 +02:00
cl_entity_t * viewent = GetViewModel ( ) ;
viewent - > curstate . modelindex = 0 ;
2009-01-22 22:00:00 +01:00
// get current values
2009-01-23 22:00:00 +01:00
v_cl_angles = pparams - > cl_viewangles ;
2009-01-22 22:00:00 +01:00
v_angles = pparams - > viewangles ;
v_origin = pparams - > vieworg ;
2009-01-23 22:00:00 +01:00
V_GetChasePos ( pparams , GetLocalPlayer ( ) , v_cl_angles , v_origin , v_angles ) ;
2009-01-22 22:00:00 +01:00
// write back new values
2009-01-23 22:00:00 +01:00
pparams - > cl_viewangles = v_cl_angles ;
2009-01-22 22:00:00 +01:00
pparams - > viewangles = v_angles ;
pparams - > vieworg = v_origin ;
2009-01-23 22:00:00 +01:00
// apply shake for thirdperson too
V_CalcShake ( ) ;
V_ApplyShake ( pparams - > vieworg , pparams - > viewangles , 1.0 ) ;
2009-01-22 22:00:00 +01:00
}
//==========================
// V_CalcSendOrigin
//==========================
void V_CalcSendOrigin ( ref_params_t * pparams )
{
// never let view origin sit exactly on a node line, because a water plane can
// dissapear when viewed with the eye exactly on it.
pparams - > vieworg [ 0 ] + = 1.0 / 32 ;
pparams - > vieworg [ 1 ] + = 1.0 / 32 ;
pparams - > vieworg [ 2 ] + = 1.0 / 32 ;
}
//==========================
// V_CalcWaterLevel
//==========================
float V_CalcWaterLevel ( ref_params_t * pparams )
{
float waterOffset = 0 ;
if ( pparams - > waterlevel > = 2 )
{
2009-12-05 22:00:00 +01:00
int i , contents ;
float waterDist = cl_waterdist - > value ;
Vector point ;
2009-01-22 22:00:00 +01:00
2010-08-19 22:00:00 +02:00
cl_entity_t * pwater = gEngfuncs . pfnWaterEntity ( pparams - > simorg ) ;
2010-08-07 22:00:00 +02:00
if ( pwater ) waterDist + = ( pwater - > curstate . scale * 16 ) ;
2009-01-22 22:00:00 +01:00
point = pparams - > vieworg ;
// eyes are above water, make sure we're above the waves
if ( pparams - > waterlevel = = 2 )
{
point [ 2 ] - = waterDist ;
for ( i = 0 ; i < waterDist ; i + + )
{
contents = POINT_CONTENTS ( point ) ;
if ( contents > CONTENTS_WATER ) break ;
point [ 2 ] + = 1 ;
}
waterOffset = ( point [ 2 ] + waterDist ) - pparams - > vieworg [ 2 ] ;
}
else
{
// eyes are under water. Make sure we're far enough under
point [ 2 ] + = waterDist ;
for ( i = 0 ; i < waterDist ; i + + )
{
contents = POINT_CONTENTS ( point ) ;
if ( contents < = CONTENTS_WATER ) break ;
point [ 2 ] - = 1 ;
}
waterOffset = ( point [ 2 ] - waterDist ) - pparams - > vieworg [ 2 ] ;
}
}
2009-01-23 22:00:00 +01:00
// underwater refraction
if ( pparams - > waterlevel = = 3 )
{
float f = sin ( pparams - > time * 0.4 * ( M_PI * 2.7 ) ) ;
pparams - > fov_x + = f ;
pparams - > fov_y - = f ;
}
2009-01-22 22:00:00 +01:00
pparams - > vieworg [ 2 ] + = waterOffset ;
return waterOffset ;
}
//==========================
// V_CalcScrOffset
//==========================
void V_CalcScrOffset ( ref_params_t * pparams )
{
// don't allow cheats in multiplayer
2009-09-18 22:00:00 +02:00
if ( pparams - > maxclients > 1 ) return ;
2009-01-22 22:00:00 +01:00
for ( int i = 0 ; i < 3 ; i + + )
{
pparams - > vieworg [ i ] + = scr_ofsx - > value * pparams - > forward [ i ] ;
pparams - > vieworg [ i ] + = scr_ofsy - > value * pparams - > right [ i ] ;
pparams - > vieworg [ i ] + = scr_ofsz - > value * pparams - > up [ i ] ;
}
}
//==========================
2009-09-22 22:00:00 +02:00
// V_InterpolatePos
2009-01-22 22:00:00 +01:00
//==========================
2009-09-22 22:00:00 +02:00
void V_InterpolatePos ( ref_params_t * pparams )
2008-12-25 22:00:00 +01:00
{
2010-08-07 22:00:00 +02:00
cl_entity_t * view ;
2009-01-22 22:00:00 +01:00
// view is the weapon model (only visible from inside body )
view = GetViewModel ( ) ;
2009-09-22 22:00:00 +02:00
if ( cl_vsmoothing - > value & & ( pparams - > smoothing & & ( pparams - > maxclients > 1 ) ) )
2009-01-22 22:00:00 +01:00
{
2009-09-22 22:00:00 +02:00
int i , foundidx ;
float t ;
2009-01-22 22:00:00 +01:00
if ( cl_vsmoothing - > value < 0.0 ) CVAR_SET_FLOAT ( " cl_vsmoothing " , 0 ) ;
t = pparams - > time - cl_vsmoothing - > value ;
for ( i = 1 ; i < ORIGIN_MASK ; i + + )
{
foundidx = ViewInterp . CurrentOrigin - 1 - i ;
if ( ViewInterp . OriginTime [ foundidx & ORIGIN_MASK ] < = t ) break ;
}
if ( i < ORIGIN_MASK & & ViewInterp . OriginTime [ foundidx & ORIGIN_MASK ] ! = 0.0 )
{
// interpolate
Vector delta ;
double frac ;
double dt ;
Vector neworg ;
2009-09-22 22:00:00 +02:00
dt = ViewInterp . OriginTime [ ( foundidx + 1 ) & ORIGIN_MASK ] - ViewInterp . OriginTime [ foundidx & ORIGIN_MASK ] ;
2009-01-22 22:00:00 +01:00
if ( dt > 0.0 )
{
2009-09-22 22:00:00 +02:00
frac = ( t - ViewInterp . OriginTime [ foundidx & ORIGIN_MASK ] ) / dt ;
2009-01-22 22:00:00 +01:00
frac = min ( 1.0 , frac ) ;
delta = ViewInterp . Origins [ ( foundidx + 1 ) & ORIGIN_MASK ] - ViewInterp . Origins [ foundidx & ORIGIN_MASK ] ;
neworg . MA ( frac , ViewInterp . Origins [ foundidx & ORIGIN_MASK ] , delta ) ;
// don't interpolate large changes
if ( delta . Length ( ) < 64 )
{
2009-09-18 22:00:00 +02:00
delta = neworg - pparams - > simorg ;
pparams - > simorg + = delta ;
2009-01-22 22:00:00 +01:00
pparams - > vieworg + = delta ;
2010-08-07 22:00:00 +02:00
view - > origin + = delta ;
2009-01-22 22:00:00 +01:00
}
}
}
}
}
2009-09-22 22:00:00 +02:00
float V_CalcStairSmoothValue ( float oldz , float newz , float smoothtime , float stepheight )
{
if ( oldz < newz )
return bound ( newz - stepheight , oldz + smoothtime * cl_stairsmooth - > value , newz ) ;
else if ( oldz > newz )
return bound ( newz , oldz - smoothtime * cl_stairsmooth - > value , newz + stepheight ) ;
return 0.0 ;
}
2009-01-22 22:00:00 +01:00
//==========================
// V_CalcFirstPersonRefdef
//==========================
void V_CalcFirstPersonRefdef ( ref_params_t * pparams )
{
// don't pass in thirdperson or intermission
if ( gHUD . m_iCameraMode | | pparams - > intermission )
return ;
Vector angles ;
float bob , waterOffset ;
static float lasttime ;
2010-08-07 22:00:00 +02:00
cl_entity_t * view = GetViewModel ( ) ;
2009-01-22 22:00:00 +01:00
int i ;
2010-07-08 22:00:00 +02:00
V_DriftPitch ( pparams ) ;
2009-01-22 22:00:00 +01:00
bob = V_CalcBob ( pparams ) ;
2009-01-23 22:00:00 +01:00
// refresh the position
2009-09-22 22:00:00 +02:00
pparams - > vieworg = pparams - > simorg ;
pparams - > vieworg [ 2 ] + = ( bob ) ;
pparams - > vieworg + = pparams - > viewheight ;
2009-01-22 22:00:00 +01:00
2009-09-18 22:00:00 +02:00
pparams - > viewangles = pparams - > cl_viewangles ;
2009-01-22 22:00:00 +01:00
V_CalcShake ( ) ;
V_ApplyShake ( pparams - > vieworg , pparams - > viewangles , 1.0 ) ;
V_CalcSendOrigin ( pparams ) ;
waterOffset = V_CalcWaterLevel ( pparams ) ;
V_CalcViewRoll ( pparams ) ;
V_AddIdle ( pparams ) ;
// offsets
angles = pparams - > viewangles ;
AngleVectors ( angles , pparams - > forward , pparams - > right , pparams - > up ) ;
V_CalcScrOffset ( pparams ) ;
2010-03-20 22:00:00 +01:00
Vector lastAngles ;
2010-08-07 22:00:00 +02:00
lastAngles = view - > angles = pparams - > cl_viewangles ;
2009-01-22 22:00:00 +01:00
V_CalcGunAngle ( pparams ) ;
// use predicted origin as view origin.
2010-08-07 22:00:00 +02:00
view - > origin = pparams - > simorg ;
view - > origin [ 2 ] + = ( waterOffset ) ;
view - > origin + = pparams - > viewheight ;
2009-01-22 22:00:00 +01:00
// Let the viewmodel shake at about 10% of the amplitude
2010-08-07 22:00:00 +02:00
V_ApplyShake ( view - > origin , view - > angles , 0.9 ) ;
2009-01-22 22:00:00 +01:00
2010-03-20 22:00:00 +01:00
for ( i = 0 ; i < 3 ; i + + )
2010-08-07 22:00:00 +02:00
view - > origin [ i ] + = bob * 0.4 * pparams - > forward [ i ] ;
view - > origin [ 2 ] + = bob ;
2009-01-22 22:00:00 +01:00
2010-08-07 22:00:00 +02:00
view - > angles [ YAW ] - = bob * 0.5 ;
view - > angles [ ROLL ] - = bob * 1 ;
view - > angles [ PITCH ] - = bob * 0.3 ;
view - > origin [ 2 ] - = 1 ;
2009-01-23 22:00:00 +01:00
2010-03-20 22:00:00 +01:00
// add lag
2010-08-20 22:00:00 +02:00
V_CalcViewModelLag ( pparams , view - > origin , view - > angles , lastAngles ) ;
2010-03-20 22:00:00 +01:00
2009-09-22 22:00:00 +02:00
// fudge position around to keep amount of weapon visible
// roughly equal with different FOV
2010-08-07 22:00:00 +02:00
if ( pparams - > viewsize = = 110 ) view - > origin [ 2 ] + = 1 ;
else if ( pparams - > viewsize = = 100 ) view - > origin [ 2 ] + = 2 ;
else if ( pparams - > viewsize = = 90 ) view - > origin [ 2 ] + = 1 ;
else if ( pparams - > viewsize = = 80 ) view - > origin [ 2 ] + = 0.5 ;
2009-01-22 22:00:00 +01:00
2009-09-18 22:00:00 +02:00
pparams - > viewangles + = pparams - > punchangle ;
2009-01-22 22:00:00 +01:00
pparams - > viewangles + = ev_punchangle ;
2009-09-22 22:00:00 +02:00
2009-01-22 22:00:00 +01:00
V_DropPunchAngle ( pparams - > frametime , ev_punchangle ) ;
2009-09-22 22:00:00 +02:00
static float stairoldtime = 0 ;
static float old_client_z = 0 ;
static float old_weapon_z = 0 ;
2009-09-18 22:00:00 +02:00
2009-09-22 22:00:00 +02:00
// calculate how much time has passed since the last V_CalcRefdef
float smoothtime = bound ( 0.0 , pparams - > time - stairoldtime , 0.1 ) ;
stairoldtime = pparams - > time ;
// smooth stair stepping, but only if onground and enabled
if ( ! pparams - > smoothing | | ! pparams - > onground | | cl_stairsmooth - > value < = 0 )
2009-01-22 22:00:00 +01:00
{
2009-09-22 22:00:00 +02:00
old_client_z = pparams - > vieworg [ 2 ] ;
2010-08-07 22:00:00 +02:00
old_weapon_z = view - > origin [ 2 ] ;
2009-09-22 22:00:00 +02:00
}
else
{
float result ;
2009-11-10 22:00:00 +01:00
float stepheight = pparams - > movevars - > stepsize ;
2009-09-22 22:00:00 +02:00
result = V_CalcStairSmoothValue ( old_client_z , pparams - > vieworg [ 2 ] , smoothtime , stepheight ) ;
if ( result ) pparams - > vieworg [ 2 ] = old_client_z = result ;
2010-08-07 22:00:00 +02:00
result = V_CalcStairSmoothValue ( old_weapon_z , view - > origin [ 2 ] , smoothtime , stepheight ) ;
if ( result ) view - > origin [ 2 ] = old_weapon_z = result ;
2009-01-22 22:00:00 +01:00
}
2009-09-18 22:00:00 +02:00
2009-01-22 22:00:00 +01:00
static Vector lastorg ;
Vector delta ;
2009-09-22 22:00:00 +02:00
delta = pparams - > simorg - lastorg ;
2009-01-22 22:00:00 +01:00
if ( delta . Length ( ) ! = 0.0 )
{
2009-09-18 22:00:00 +02:00
ViewInterp . Origins [ ViewInterp . CurrentOrigin & ORIGIN_MASK ] = pparams - > simorg ;
2009-01-22 22:00:00 +01:00
ViewInterp . OriginTime [ ViewInterp . CurrentOrigin & ORIGIN_MASK ] = pparams - > time ;
ViewInterp . CurrentOrigin + + ;
2009-09-22 22:00:00 +02:00
lastorg = pparams - > simorg ;
2009-01-22 22:00:00 +01:00
}
2010-02-03 22:00:00 +01:00
// probably not needs in Xash3D
// V_InterpolatePos( pparams ); // smooth predicting moving in multiplayer
2009-01-22 22:00:00 +01:00
lasttime = pparams - > time ;
v_origin = pparams - > vieworg ;
}
2010-03-21 22:00:00 +01:00
//==========================
// V_CalcScreenBlend
//==========================
void V_CalcScreenBlend ( ref_params_t * pparams )
{
2010-05-28 22:00:00 +02:00
#if 0
// FIXME: get some code from q1
2010-03-21 22:00:00 +01:00
pparams - > blend [ 0 ] = 0.0f ;
pparams - > blend [ 1 ] = 0.0f ;
pparams - > blend [ 2 ] = 0.0f ;
pparams - > blend [ 3 ] = 1.0f ;
2010-05-28 22:00:00 +02:00
# endif
2010-03-21 22:00:00 +01:00
}
2010-07-08 22:00:00 +02:00
void V_CalcRefdef ( ref_params_t * pparams )
2009-01-22 22:00:00 +01:00
{
2010-07-08 22:00:00 +02:00
V_PreRender ( pparams ) ;
V_CalcGlobalFog ( pparams ) ;
2009-01-22 22:00:00 +01:00
V_CalcFirstPersonRefdef ( pparams ) ;
V_CalcThirdPersonRefdef ( pparams ) ;
V_CalcIntermisionRefdef ( pparams ) ;
V_CalcCameraRefdef ( pparams ) ;
2010-03-21 22:00:00 +01:00
V_CalcScreenBlend ( pparams ) ;
2010-07-08 22:00:00 +02:00
2008-12-25 22:00:00 +01:00
}