Port spectator changes from HLSDK 2.4.

This commit is contained in:
Andrey Akhmichin 2024-02-13 03:41:13 +05:00
parent 011f1afeb6
commit 955f7ad436
11 changed files with 657 additions and 41 deletions

View File

@ -70,6 +70,7 @@ SRCS+=./in_camera.cpp
SRCS+=./input.cpp
SRCS+=./input_goldsource.cpp
SRCS+=./input_mouse.cpp
SRCS+=./interpolation.cpp
#SRCS+=./inputw32.cpp
SRCS+=./menu.cpp
SRCS+=./message.cpp

View File

@ -107,6 +107,7 @@ set (CLDLL_SOURCES
input_goldsource.cpp
input_mouse.cpp
input_xash3d.cpp
interpolation.cpp
menu.cpp
message.cpp
parsemsg.cpp

View File

@ -52,6 +52,7 @@ set SOURCES=../dlls/crossbow.cpp ^
input_goldsource.cpp ^
input_mouse.cpp ^
input_xash3d.cpp ^
interpolation.cpp ^
menu.cpp ^
message.cpp ^
parsemsg.cpp ^

View File

@ -87,6 +87,11 @@ void CHud::Think( void )
// only let players adjust up in fov, and only if they are not overriden by something else
m_iFOV = Q_max( default_fov->value, 90 );
}
if( gEngfuncs.IsSpectateOnly() )
{
m_iFOV = gHUD.m_Spectator.GetFOV(); // default_fov->value;
}
}
// Redraw

View File

@ -37,8 +37,6 @@ extern "C" float vJumpAngles[3];
extern void V_GetInEyePos( int entity, float * origin, float * angles );
extern void V_ResetChaseCam();
extern void V_GetChasePos( int target, float * cl_angles, float * origin, float * angles );
extern void VectorAngles( const float *forward, float *angles );
extern "C" void NormalizeAngles( float *angles );
extern float * GetClientColor( int clientIndex );
extern vec3_t v_origin; // last view origin
@ -46,6 +44,37 @@ extern vec3_t v_angles; // last view angle
extern vec3_t v_cl_angles; // last client/mouse angle
extern vec3_t v_sim_org; // last sim origin
#if 0
const char *GetSpectatorLabel( int iMode )
{
switch( iMode )
{
case OBS_CHASE_LOCKED:
return "#OBS_CHASE_LOCKED";
case OBS_CHASE_FREE:
return "#OBS_CHASE_FREE";
case OBS_ROAMING:
return "#OBS_ROAMING";
case OBS_IN_EYE:
return "#OBS_IN_EYE";
case OBS_MAP_FREE:
return "#OBS_MAP_FREE";
case OBS_MAP_CHASE:
return "#OBS_MAP_CHASE";
case OBS_NONE:
default:
return "#OBS_NONE";
}
}
#endif
void SpectatorMode( void )
{
if( gEngfuncs.Cmd_Argc() <= 1 )
@ -152,6 +181,7 @@ int CHudSpectator::Init()
m_flNextObserverInput = 0.0f;
m_zoomDelta = 0.0f;
m_moveDelta = 0.0f;
m_FOV = 90.0f;
m_chatEnabled = ( gHUD.m_SayText.m_HUD_saytext->value != 0 );
iJumpSpectator = 0;
@ -363,6 +393,178 @@ void CHudSpectator::SetSpectatorStartPosition()
iJumpSpectator = 1; // jump anyway
}
void CHudSpectator::SetCameraView( vec3_t pos, vec3_t angle, float fov )
{
m_FOV = fov;
VectorCopy( pos, vJumpOrigin );
VectorCopy( angle, vJumpAngles );
gEngfuncs.SetViewAngles( vJumpAngles );
iJumpSpectator = 1; // jump anyway
}
void CHudSpectator::AddWaypoint( float time, vec3_t pos, vec3_t angle, float fov, int flags )
{
if( flags == 0 && time == 0.0f )
{
// switch instantly to this camera view
SetCameraView( pos, angle, fov );
return;
}
if( m_NumWayPoints >= MAX_CAM_WAYPOINTS )
{
gEngfuncs.Con_Printf( "Too many camera waypoints!\n" );
return;
}
VectorCopy( angle, m_CamPath[m_NumWayPoints].angle );
VectorCopy( pos, m_CamPath[m_NumWayPoints].position );
m_CamPath[m_NumWayPoints].flags = flags;
m_CamPath[m_NumWayPoints].fov = fov;
m_CamPath[m_NumWayPoints].time = time;
gEngfuncs.Con_DPrintf( "Added waypoint %i\n", m_NumWayPoints );
m_NumWayPoints++;
}
void CHudSpectator::SetWayInterpolation( cameraWayPoint_t *prev, cameraWayPoint_t *start, cameraWayPoint_t *end, cameraWayPoint_t *next )
{
m_WayInterpolation.SetViewAngles( start->angle, end->angle );
m_WayInterpolation.SetFOVs( start->fov, end->fov );
m_WayInterpolation.SetSmoothing( ( start->flags & DRC_FLAG_SLOWSTART ) != 0,
( start->flags & DRC_FLAG_SLOWEND ) != 0 );
if( prev && next )
{
m_WayInterpolation.SetWaypoints( &prev->position, start->position, end->position, &next->position );
}
else if( prev )
{
m_WayInterpolation.SetWaypoints( &prev->position, start->position, end->position, NULL );
}
else if( next )
{
m_WayInterpolation.SetWaypoints( NULL, start->position, end->position, &next->position );
}
else
{
m_WayInterpolation.SetWaypoints( NULL, start->position, end->position, NULL );
}
}
bool CHudSpectator::GetDirectorCamera( vec3_t &position, vec3_t &angle )
{
float now = gHUD.m_flTime;
float fov = 90.0f;
if( m_ChaseEntity )
{
cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_ChaseEntity );
if( ent )
{
vec3_t vt = ent->curstate.origin;
if( m_ChaseEntity <= gEngfuncs.GetMaxClients())
{
if( ent->curstate.solid == SOLID_NOT )
{
vt[2]+= -8 ; // PM_DEAD_VIEWHEIGHT
}
else if( ent->curstate.usehull == 1 )
{
vt[2]+= 12; // VEC_DUCK_VIEW;
}
else
{
vt[2]+= 28; // DEFAULT_VIEWHEIGHT
}
}
vt = vt - position;
VectorAngles( vt, angle );
angle[0] = -angle[0];
return true;
}
else
{
return false;
}
}
if( !m_IsInterpolating )
return false;
if( m_WayPoint < 0 || m_WayPoint >= ( m_NumWayPoints - 1 ))
return false;
cameraWayPoint_t *wp1 = &m_CamPath[m_WayPoint];
cameraWayPoint_t *wp2 = &m_CamPath[m_WayPoint+1];
if( now < wp1->time )
return false;
while( now > wp2->time )
{
// go to next waypoint, if possible
m_WayPoint++;
if( m_WayPoint >= ( m_NumWayPoints - 1 ))
{
m_IsInterpolating = false;
return false; // there is no following waypoint
}
wp1 = wp2;
wp2 = &m_CamPath[m_WayPoint + 1];
if( m_WayPoint > 0 )
{
// we have a predecessor
if( m_WayPoint < ( m_NumWayPoints - 1 ))
{
// we have also a successor
SetWayInterpolation( &m_CamPath[m_WayPoint - 1], wp1, wp2, &m_CamPath[m_WayPoint + 2] );
}
else
{
SetWayInterpolation( &m_CamPath[m_WayPoint - 1], wp1, wp2, NULL );
}
}
else if( m_WayPoint < ( m_NumWayPoints - 1 ))
{
// we only have a successor
SetWayInterpolation( NULL, wp1, wp2, &m_CamPath[m_WayPoint + 2] );
}
else
{
// we have only two waypoints
SetWayInterpolation( NULL, wp1, wp2, NULL );
}
}
if( wp2->time <= wp1->time )
return false;
float fraction = ( now - wp1->time ) / ( wp2->time - wp1->time );
if( fraction < 0.0f )
fraction = 0.0f;
else if( fraction > 1.0f )
fraction = 1.0f;
m_WayInterpolation.Interpolate( fraction, position, angle, &fov );
// gEngfuncs.Con_Printf( "Interpolate time: %.2f, fraction %.2f, point : %.2f,%.2f,%.2f\n", now, fraction, position[0], position[1], position[2] );
SetCameraView( position, angle, fov );
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Loads new icons
//-----------------------------------------------------------------------------
@ -377,9 +579,21 @@ int CHudSpectator::VidInit()
m_hsprCamera = SPR_Load( "sprites/camera.spr" );
m_hCrosshair = SPR_Load( "sprites/crosshairs.spr" );
m_lastPrimaryObject = m_lastSecondaryObject = 0;
m_flNextObserverInput = 0.0f;
m_lastHudMessage = 0;
m_iSpectatorNumber = 0;
iJumpSpectator = 0;
g_iUser1 = g_iUser2 = 0;
return 1;
}
float CHudSpectator::GetFOV( void )
{
return m_FOV;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : flTime -
@ -427,8 +641,11 @@ int CHudSpectator::Draw( float flTime )
return 1;
// make sure we have player info
#if USE_VGUI
gViewPort->GetAllPlayersInfo();
#else
gHUD.GetAllPlayersInfo();
#endif
// loop through all the players and draw additional infos to their sprites on the map
for( int i = 0; i < MAX_PLAYERS; i++ )
{
@ -461,8 +678,10 @@ int CHudSpectator::Draw( float flTime )
void CHudSpectator::DirectorMessage( int iSize, void *pbuf )
{
float value;
float f1, f2;
char *string;
vec3_t v1, v2;
int i1, i2, i3;
BEGIN_READ( pbuf, iSize );
@ -479,7 +698,7 @@ void CHudSpectator::DirectorMessage( int iSize, void *pbuf )
gHUD.MsgFunc_InitHUD( NULL, 0, NULL );
gHUD.MsgFunc_ResetHUD( NULL, 0, NULL );
break;
case DRC_CMD_EVENT:
case DRC_CMD_EVENT: // old director style message
m_lastPrimaryObject = READ_WORD();
m_lastSecondaryObject = READ_WORD();
m_iObserverFlags = READ_LONG();
@ -502,19 +721,22 @@ void CHudSpectator::DirectorMessage( int iSize, void *pbuf )
}
break;
case DRC_CMD_CAMERA:
v1[0] = READ_COORD(); // position
v1[1] = READ_COORD();
v1[2] = READ_COORD(); // vJumpOrigin
v1[0] = READ_COORD(); // view angle
v1[1] = READ_COORD(); // vJumpAngles
v1[2] = READ_COORD();
f1 = READ_BYTE(); // fov
i1 = READ_WORD(); // target
if( m_autoDirector->value )
{
vJumpOrigin[0] = READ_COORD(); // position
vJumpOrigin[1] = READ_COORD();
vJumpOrigin[2] = READ_COORD();
vJumpAngles[0] = READ_COORD(); // view angle
vJumpAngles[1] = READ_COORD();
vJumpAngles[2] = READ_COORD();
gEngfuncs.SetViewAngles( vJumpAngles );
iJumpSpectator = 1;
SetModes( OBS_ROAMING, -1 );
SetCameraView( v1, v2, f1 );
m_ChaseEntity = i1;
}
break;
case DRC_CMD_MESSAGE:
@ -551,13 +773,13 @@ void CHudSpectator::DirectorMessage( int iSize, void *pbuf )
break;
case DRC_CMD_SOUND:
string = READ_STRING();
value = READ_FLOAT();
f1 = READ_FLOAT();
// gEngfuncs.Con_Printf("DRC_CMD_FX_SOUND: %s %.2f\n", string, value );
gEngfuncs.pEventAPI->EV_PlaySound( 0, v_origin, CHAN_BODY, string, value, ATTN_NORM, 0, PITCH_NORM );
// gEngfuncs.Con_Printf("DRC_CMD_FX_SOUND: %s %.2f\n", string, f1 );
gEngfuncs.pEventAPI->EV_PlaySound( 0, v_origin, CHAN_BODY, string, f1, ATTN_NORM, 0, PITCH_NORM );
break;
case DRC_CMD_TIMESCALE:
value = READ_FLOAT();
f1 = READ_FLOAT();
break;
case DRC_CMD_STATUS:
READ_LONG(); // total number of spectator slots
@ -574,13 +796,71 @@ void CHudSpectator::DirectorMessage( int iSize, void *pbuf )
gViewPort->UpdateSpectatorPanel();
#endif
break;
case DRC_CMD_FADE:
break;
case DRC_CMD_STUFFTEXT:
gEngfuncs.pfnFilteredClientCmd( READ_STRING() );
break;
case DRC_CMD_CAMPATH:
v1[0] = READ_COORD(); // position
v1[1] = READ_COORD();
v1[2] = READ_COORD(); // vJumpOrigin
v2[0] = READ_COORD(); // view angle
v2[1] = READ_COORD(); // vJumpAngles
v2[2] = READ_COORD();
f1 = READ_BYTE(); // FOV
i1 = READ_BYTE(); // flags
if( m_autoDirector->value )
{
SetModes( OBS_ROAMING, -1 );
SetCameraView( v1, v2, f1 );
}
break;
case DRC_CMD_WAYPOINTS:
i1 = READ_BYTE();
m_NumWayPoints = 0;
m_WayPoint = 0;
for( i2 = 0; i2 < i1; i2++ )
{
f1 = gHUD.m_flTime + (float)( READ_SHORT()) / 100.0f;
v1[0] = READ_COORD(); // position
v1[1] = READ_COORD();
v1[2] = READ_COORD(); // vJumpOrigin
v2[0] = READ_COORD(); // view angle
v2[1] = READ_COORD(); // vJumpAngles
v2[2] = READ_COORD();
f2 = READ_BYTE(); // fov
i3 = READ_BYTE(); // flags
AddWaypoint( f1, v1, v2, f2, i3 );
}
// gEngfuncs.Con_Printf( "CHudSpectator::DirectorMessage: waypoints %i.\n", m_NumWayPoints );
if( !m_autoDirector->value )
{
// ignore waypoints
m_NumWayPoints = 0;
break;
}
SetModes( OBS_ROAMING, -1 );
m_IsInterpolating = true;
if( m_NumWayPoints > 2 )
{
SetWayInterpolation( NULL, &m_CamPath[0], &m_CamPath[1], &m_CamPath[2] );
}
else
{
SetWayInterpolation( NULL, &m_CamPath[0], &m_CamPath[1], NULL );
}
break;
default:
gEngfuncs.Con_DPrintf( "CHudSpectator::DirectorMessage: unknown command %i.\n", cmd );
break;
}
}
@ -595,9 +875,10 @@ void CHudSpectator::FindNextPlayer( bool bReverse )
// if we are NOT in HLTV mode, spectator targets are set on server
if( !gEngfuncs.IsSpectateOnly() )
{
char cmdstring[32];
char cmdstring[256];
// forward command to server
sprintf( cmdstring, "follownext %i", bReverse ? 1 : 0 );
_snprintf( cmdstring, sizeof( cmdstring ) - 1,"follownext %i", bReverse ? 1 : 0 );
cmdstring[sizeof( cmdstring ) - 1] = '\0';
gEngfuncs.pfnServerCmd( cmdstring );
return;
}
@ -614,8 +895,11 @@ void CHudSpectator::FindNextPlayer( bool bReverse )
int iDir = bReverse ? -1 : 1;
// make sure we have player info
#if USE_VGUI
gViewPort->GetAllPlayersInfo();
#else
gHUD.GetAllPlayersInfo();
#endif
do
{
iCurrent += iDir;
@ -656,7 +940,7 @@ void CHudSpectator::FindNextPlayer( bool bReverse )
#endif
}
void CHudSpectator::FindPlayer(const char *name)
void CHudSpectator::FindPlayer( const char *name )
{
// MOD AUTHORS: Modify the logic of this function if you want to restrict the observer to watching
// only a subset of the players. e.g. Make it check the target's team.
@ -664,18 +948,22 @@ void CHudSpectator::FindPlayer(const char *name)
// if we are NOT in HLTV mode, spectator targets are set on server
if ( !gEngfuncs.IsSpectateOnly() )
{
char cmdstring[32];
char cmdstring[256];
// forward command to server
sprintf(cmdstring,"follow %s",name);
gEngfuncs.pfnServerCmd(cmdstring);
_snprintf( cmdstring, sizeof( cmdstring ) - 1, "follow %s", name );
cmdstring[sizeof( cmdstring ) - 1] = '\0';
gEngfuncs.pfnServerCmd( cmdstring );
return;
}
g_iUser2 = 0;
// make sure we have player info
#if USE_VGUI
gViewPort->GetAllPlayersInfo();
#else
gHUD.GetAllPlayersInfo();
#endif
cl_entity_t * pEnt = NULL;
for (int i = 1; i < MAX_PLAYERS; i++ )
@ -847,12 +1135,20 @@ void CHudSpectator::SetModes( int iNewMainMode, int iNewInsetMode )
return;
}
// main modes ettings will override inset window settings
m_IsInterpolating = false;
m_ChaseEntity = 0;
// main modes settings will override inset window settings
if( iNewMainMode != g_iUser1 )
{
// if we are NOT in HLTV mode, main spectator mode is set on server
if( !gEngfuncs.IsSpectateOnly() )
{
char cmdstring[256];
// forward command to server
_snprintf( cmdstring, sizeof( cmdstring ) - 1,"specmode %i", iNewMainMode );
cmdstring[sizeof( cmdstring ) - 1] = '\0';
gEngfuncs.pfnServerCmd( cmdstring );
return;
}
@ -1548,8 +1844,9 @@ void CHudSpectator::CheckSettings()
if( gEngfuncs.IsSpectateOnly() )
{
// tell proxy our new chat mode
char chatcmd[32];
sprintf( chatcmd, "ignoremsg %i", m_chatEnabled ? 0 : 1 );
char chatcmd[256];
_snprintf( chatcmd, sizeof( chatcmd ) - 1, "ignoremsg %i", m_chatEnabled ? 0 : 1 );
chatcmd[sizeof( chatcmd ) - 1] = '\0';
gEngfuncs.pfnServerCmd( chatcmd );
}
}
@ -1626,6 +1923,12 @@ void CHudSpectator::Reset()
memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities) );
m_FOV = 90.0f;
m_IsInterpolating = false;
m_ChaseEntity = 0;
SetSpectatorStartPosition();
}
@ -1648,7 +1951,7 @@ void CHudSpectator::InitHUDData()
Reset();
SetModes( OBS_CHASE_FREE, INSET_OFF );
SetModes( OBS_CHASE_LOCKED, INSET_OFF );
g_iUser2 = 0; // fake not target until first camera command

View File

@ -10,6 +10,7 @@
#define HUD_SPECTATOR_H
#include "cl_entity.h"
#include "interpolation.h"
#define INSET_OFF 0
#define INSET_CHASE_FREE 1
@ -22,6 +23,9 @@
#define OVERVIEW_TILE_SIZE 128 // don't change this
#define OVERVIEW_MAX_LAYERS 1
extern void VectorAngles( const float *forward, float *angles );
extern "C" void NormalizeAngles( float *angles );
//-----------------------------------------------------------------------------
// Purpose: Handles the drawing of the spectator stuff (camera & top-down map and all the things on it )
//-----------------------------------------------------------------------------
@ -49,7 +53,17 @@ typedef struct overviewEntity_s
double killTime;
} overviewEntity_t;
typedef struct cameraWayPoint_s
{
float time;
vec3_t position;
vec3_t angle;
float fov;
int flags;
} cameraWayPoint_t;
#define MAX_OVERVIEW_ENTITIES 128
#define MAX_CAM_WAYPOINTS 32
class CHudSpectator : public CHudBase
{
@ -73,7 +87,7 @@ public:
void HandleButtonsDown( int ButtonPressed );
void HandleButtonsUp( int ButtonPressed );
void FindNextPlayer( bool bReverse );
void FindPlayer(const char *name);
void FindPlayer( const char *name );
void DirectorMessage( int iSize, void *pbuf );
void SetSpectatorStartPosition();
int Init();
@ -81,6 +95,13 @@ public:
int Draw( float flTime );
void AddWaypoint( float time, vec3_t pos, vec3_t angle, float fov, int flags );
void SetCameraView( vec3_t pos, vec3_t angle, float fov );
float GetFOV();
bool GetDirectorCamera( vec3_t &position, vec3_t &angle );
void SetWayInterpolation( cameraWayPoint_t *prev, cameraWayPoint_t *start, cameraWayPoint_t *end, cameraWayPoint_t *next );
int m_iDrawCycle;
client_textmessage_t m_HUDMessages[MAX_SPEC_HUD_MESSAGES];
char m_HUDMessageText[MAX_SPEC_HUD_MESSAGES][128];
@ -100,8 +121,13 @@ public:
qboolean m_chatEnabled;
qboolean m_IsInterpolating;
int m_ChaseEntity; // if != 0, follow this entity with viewangles
int m_WayPoint; // current waypoint 1
int m_NumWayPoints; // current number of waypoints
vec3_t m_cameraOrigin; // a help camera
vec3_t m_cameraAngles; // and it's angles
CInterpolation m_WayInterpolation;
private:
vec3_t m_vPlayerPos[MAX_PLAYERS];
@ -119,9 +145,11 @@ private:
struct model_s *m_MapSprite; // each layer image is saved in one sprite, where each tile is a sprite frame
float m_flNextObserverInput;
float m_FOV;
float m_zoomDelta;
float m_moveDelta;
int m_lastPrimaryObject;
int m_lastSecondaryObject;
cameraWayPoint_t m_CamPath[MAX_CAM_WAYPOINTS];
};
#endif // SPECTATOR_H

217
cl_dll/interpolation.cpp Normal file
View File

@ -0,0 +1,217 @@
/************ (C) Copyright 2003 Valve, L.L.C. All rights reserved. ***********
**
** The copyright to the contents herein is the property of Valve, L.L.C.
** The contents may be used and/or copied only with the written permission of
** Valve, L.L.C., or in accordance with the terms and conditions stipulated in
** the agreement/contract under which the contents have been supplied.
**
*******************************************************************************
**
** Contents:
**
** interpolation.cpp: implementation of the interpolation class
**
******************************************************************************/
#include "hud.h"
#include "cl_util.h"
#include "interpolation.h"
// = determinant of matrix a,b,c
#define Determinant( a, b, c ) ( (a)[2] * ( (b)[0]*(c)[1] - (b)[1]*(c)[0] ) + \
(a)[1] * ( (b)[2]*(c)[0] - (b)[0]*(c)[2] ) + \
(a)[0] * ( (b)[1]*(c)[2] - (b)[2]*(c)[1] ) )
// solve 3 vector linear system of equations v0 = x*v1 + y*v2 + z*v3 (if possible)
bool SolveLSE( vec3_t v0, vec3_t v1, vec3_t v2, vec3_t v3, float * x, float * y, float * z )
{
float d = Determinant( v1, v2, v3 );
if( d == 0.0f )
return false;
if( x )
*x = Determinant( v0, v2, v3 ) / d;
if( y )
*y= Determinant( v1, v0, v3 ) / d;
if( z )
*z= Determinant( v1, v2, v0 ) / d;
return true;
}
// p = closest point between vector lines a1+x*m1 and a2+x*m2
bool GetPointBetweenLines( vec3_t &p, vec3_t a1, vec3_t m1, vec3_t a2, vec3_t m2 )
{
float x, z;
vec3_t t1 = CrossProduct( m1, m2 );
vec3_t t2 = a2 - a1;
if( !SolveLSE( t2, m1, t1, m2, &x , NULL, &z ) )
return false;
t1 = a1 + x * m1;
t2 = a2 + ( -z ) * m2;
p = ( t1 + t2 ) / 2.0f;
return true;
}
// Bernstein Poynom B(u) with n = 2, i = 0
#define BernsteinPolynom20(u) ( ( 1.0f - u ) * ( 1.0f - u ))
#define BernsteinPolynom21(u) ( 2.0f * u * ( 1.0f - u ) )
#define BernsteinPolynom22(u) ( u * u )
CInterpolation::CInterpolation()
{
}
CInterpolation::~CInterpolation()
{
m_SmoothStart = m_SmoothEnd = false;
}
void CInterpolation::SetViewAngles( vec3_t start, vec3_t end )
{
m_StartAngle = start;
m_EndAngle = end;
NormalizeAngles( m_StartAngle );
NormalizeAngles( m_EndAngle );
}
void CInterpolation::SetFOVs( float start, float end )
{
m_StartFov = start;
m_EndFov = end;
}
void CInterpolation::SetWaypoints( vec3_t *prev, vec3_t start, vec3_t end, vec3_t *next )
{
m_StartPoint = start;
m_EndPoint = end;
vec3_t a, b, c, d;
if( !prev && !next )
{
// no direction given, straight linear interpolation
m_Center = ( m_StartPoint + m_EndPoint ) / 2.0f;
}
else if( !prev )
{
a = start - end;
float dist = a.Length() / 2.0f;
a = a.Normalize();
b = *next - end;
b = b.Normalize();
c = a - b;
c = c.Normalize();
m_Center = end + c * dist;
}
else if( !next )
{
a = *prev - start;
a = a.Normalize();
b = end - start;
float dist = b.Length() / 2.0f;
b = b.Normalize();
c = b - a;
c = c.Normalize();
m_Center = start + c * dist;
}
else
{
// we have a previous and a next point, great!
a = *prev - start;
a = a.Normalize();
b = end - start;
b = b.Normalize();
c = b - a;
a = start - end;
a = a.Normalize();
b = *next - end;
b = b.Normalize();
d = a - b;
GetPointBetweenLines( m_Center, start, c, end, d );
}
}
void CInterpolation::Interpolate( float t, vec3_t &point, vec3_t &angle, float *fov )
{
if( m_SmoothStart && m_SmoothEnd )
{
t = ( 1.0f - t ) * ( t * t ) + t * ( 1.0f - ( ( t - 1.0f ) * ( t - 1.0f )));
}
else if( m_SmoothStart )
{
t = t * t;
}
else if( m_SmoothEnd )
{
t = t - 1.0f;
t = -( t * t ) + 1;
}
if( point )
{
BezierInterpolatePoint( t, point );
}
if( angle )
{
InterpolateAngle( t, angle );
}
if( fov )
{
*fov = m_StartFov + ( t * ( m_EndFov - m_StartFov ));
}
}
void CInterpolation::BezierInterpolatePoint( float t, vec3_t &point )
{
point = m_StartPoint * BernsteinPolynom20( t );
point = point + m_Center * BernsteinPolynom21( t );
point = point + m_EndPoint * BernsteinPolynom22( t );
}
void CInterpolation::SetSmoothing( bool start, bool end )
{
m_SmoothStart = start;
m_SmoothEnd = end;
}
void CInterpolation::InterpolateAngle( float t, vec3_t &angle )
{
int i;
float ang1, ang2;
float d;
for( i = 0; i < 3; i++ )
{
ang1 = m_StartAngle[i];
ang2 = m_EndAngle[i];
d = ang2 - ang1;
if ( d > 180 )
{
d -= 360;
}
else if ( d < -180 )
{
d += 360;
}
angle[i] = ang1 + d * t;
}
NormalizeAngles( angle );
}

52
cl_dll/interpolation.h Normal file
View File

@ -0,0 +1,52 @@
/************ (C) Copyright 2003 Valve, L.L.C. All rights reserved. ***********
**
** The copyright to the contents herein is the property of Valve, L.L.C.
** The contents may be used and/or copied only with the written permission of
** Valve, L.L.C., or in accordance with the terms and conditions stipulated in
** the agreement/contract under which the contents have been supplied.
**
*******************************************************************************
**
** Contents:
**
** interpolation.h: Bezier inpolation classes
**
******************************************************************************/
#pragma once
#if !defined(INTERPOLATION_H)
#define INTERPOLATION_H
// interpolation class
class CInterpolation
{
public:
CInterpolation();
virtual ~CInterpolation();
void SetWaypoints( vec3_t *prev, vec3_t start, vec3_t end, vec3_t *next );
void SetViewAngles( vec3_t start, vec3_t end );
void SetFOVs( float start, float end );
void SetSmoothing( bool start, bool end );
// get interpolated point 0 =< t =< 1, 0 = start, 1 = end
void Interpolate( float t, vec3_t &point, vec3_t &angle, float * fov );
protected:
void BezierInterpolatePoint( float t, vec3_t &point );
void InterpolateAngle( float t, vec3_t &angle );
vec3_t m_StartPoint;
vec3_t m_EndPoint;
vec3_t m_StartAngle;
vec3_t m_EndAngle;
vec3_t m_Center;
float m_StartFov;
float m_EndFov;
bool m_SmoothStart;
bool m_SmoothEnd;
};
#endif // INTERPOLATION_H

View File

@ -1462,6 +1462,8 @@ void V_CalcSpectatorRefdef( struct ref_params_s * pparams )
case OBS_ROAMING:
VectorCopy( v_cl_angles, v_angles );
VectorCopy( v_sim_org, v_origin );
// override values if director is active
gHUD.m_Spectator.GetDirectorCamera(v_origin, v_angles);
break;
case OBS_IN_EYE:
V_CalcNormalRefdef( pparams );

View File

@ -37,11 +37,14 @@
#define DRC_CMD_SOUND 7 // plays a particular sound
#define DRC_CMD_STATUS 8 // status info about broadcast
#define DRC_CMD_BANNER 9 // banner file name for HLTV gui
#define DRC_CMD_FADE 10 // send screen fade command
#define DRC_CMD_SHAKE 11 // send screen shake command
#define DRC_CMD_STUFFTEXT 12 // like the normal svc_stufftext but as director command
#define DRC_CMD_STUFFTEXT 10 // like the normal svc_stufftext but as director command
#define DRC_CMD_CHASE 11 // chase a certain player
#define DRC_CMD_INEYE 12 // view player through own eyes
#define DRC_CMD_MAP 13 // show overview map
#define DRC_CMD_CAMPATH 14 // define camera waypoint
#define DRC_CMD_WAYPOINTS 15 // start moving camera, inetranl message
#define DRC_CMD_LAST 12
#define DRC_CMD_LAST 15
// HLTV_EVENT event flags
#define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important)
@ -53,7 +56,9 @@
#define DRC_FLAG_FINAL (1<<9) // is a final scene
#define DRC_FLAG_NO_RANDOM (1<<10) // don't randomize event data
#define MAX_DIRECTOR_CMD_PARAMETERS 4
#define MAX_DIRECTOR_CMD_STRING 128
// DRC_CMD_WAYPOINT flags
#define DRC_FLAG_STARTPATH 1 // end with speed 0.0
#define DRC_FLAG_SLOWSTART 2 // start with speed 0.0
#define DRC_FLAG_SLOWEND 4 // end with speed 0.0
#endif//HLTV_H

View File

@ -270,6 +270,7 @@ files{"cl_dll/hl/hl_baseentity.cpp",
"cl_dll/input_goldsource.cpp",
"cl_dll/input_mouse.cpp",
"cl_dll/input_xash3d.cpp",
"cl_dll/interpolation.cpp",
"cl_dll/menu.cpp",
"cl_dll/message.cpp",
"cl_dll/overview.cpp",