diff --git a/cl_dll/Android.mk b/cl_dll/Android.mk index 9cb79970..9b4974ce 100755 --- a/cl_dll/Android.mk +++ b/cl_dll/Android.mk @@ -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 diff --git a/cl_dll/CMakeLists.txt b/cl_dll/CMakeLists.txt index 37c03d7c..f6ecbb9f 100644 --- a/cl_dll/CMakeLists.txt +++ b/cl_dll/CMakeLists.txt @@ -107,6 +107,7 @@ set (CLDLL_SOURCES input_goldsource.cpp input_mouse.cpp input_xash3d.cpp + interpolation.cpp menu.cpp message.cpp parsemsg.cpp diff --git a/cl_dll/compile.bat b/cl_dll/compile.bat index 720d1e3f..b7085545 100644 --- a/cl_dll/compile.bat +++ b/cl_dll/compile.bat @@ -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 ^ diff --git a/cl_dll/hud_redraw.cpp b/cl_dll/hud_redraw.cpp index 64e24e1c..59366208 100644 --- a/cl_dll/hud_redraw.cpp +++ b/cl_dll/hud_redraw.cpp @@ -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 diff --git a/cl_dll/hud_spectator.cpp b/cl_dll/hud_spectator.cpp index 7e115f51..8e03579b 100644 --- a/cl_dll/hud_spectator.cpp +++ b/cl_dll/hud_spectator.cpp @@ -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 diff --git a/cl_dll/hud_spectator.h b/cl_dll/hud_spectator.h index 800928e0..dc192141 100644 --- a/cl_dll/hud_spectator.h +++ b/cl_dll/hud_spectator.h @@ -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 diff --git a/cl_dll/interpolation.cpp b/cl_dll/interpolation.cpp new file mode 100644 index 00000000..a06f7e29 --- /dev/null +++ b/cl_dll/interpolation.cpp @@ -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 ); +} + diff --git a/cl_dll/interpolation.h b/cl_dll/interpolation.h new file mode 100644 index 00000000..a0a3cd1b --- /dev/null +++ b/cl_dll/interpolation.h @@ -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 diff --git a/cl_dll/view.cpp b/cl_dll/view.cpp index 4c93fb87..d9d61205 100644 --- a/cl_dll/view.cpp +++ b/cl_dll/view.cpp @@ -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 ); diff --git a/common/hltv.h b/common/hltv.h index 970c4861..63393a18 100644 --- a/common/hltv.h +++ b/common/hltv.h @@ -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 diff --git a/contrib/iZarif/premake5.lua b/contrib/iZarif/premake5.lua index d959d9ad..7ad931dd 100644 --- a/contrib/iZarif/premake5.lua +++ b/contrib/iZarif/premake5.lua @@ -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",