From f56bb35301836e56582a575a75864392a0177875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20P=2E=20Tjern=C3=B8?= Date: Mon, 2 Dec 2013 19:31:46 -0800 Subject: Fix line endings. WHAMMY. --- mp/src/game/client/view_effects.cpp | 1590 +++++++++++++++++------------------ 1 file changed, 795 insertions(+), 795 deletions(-) (limited to 'mp/src/game/client/view_effects.cpp') diff --git a/mp/src/game/client/view_effects.cpp b/mp/src/game/client/view_effects.cpp index 44a4dffd..41cf27d4 100644 --- a/mp/src/game/client/view_effects.cpp +++ b/mp/src/game/client/view_effects.cpp @@ -1,795 +1,795 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// -#include "cbase.h" -#include "ivieweffects.h" -#include "shake.h" -#include "hud_macros.h" -#include "isaverestore.h" -#include "view_shared.h" -#include "iviewrender.h" -#include "viewrender.h" -#include "con_nprint.h" -#include "saverestoretypes.h" -#include "c_rumble.h" -// NVNT haptics interface system -#include "haptics/ihaptics.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -extern IntroData_t *g_pIntroData; - - -// Arbitrary limit so that bad entity logic on the server can't consume tons of memory on the client. -#define MAX_SHAKES 32 - - -//----------------------------------------------------------------------------- -// Purpose: Screen fade variables -//----------------------------------------------------------------------------- -struct screenfade_t -{ - float Speed; // How fast to fade (tics / second) (+ fade in, - fade out) - float End; // When the fading hits maximum - float Reset; // When to reset to not fading (for fadeout and hold) - byte r, g, b, alpha; // Fade color - int Flags; // Fading flags - - DECLARE_SIMPLE_DATADESC(); -}; - -BEGIN_SIMPLE_DATADESC( screenfade_t ) - DEFINE_FIELD( Speed, FIELD_FLOAT ), - DEFINE_FIELD( End, FIELD_TIME ), - DEFINE_FIELD( Reset, FIELD_TIME ), - DEFINE_FIELD( r, FIELD_CHARACTER ), - DEFINE_FIELD( g, FIELD_CHARACTER ), - DEFINE_FIELD( b, FIELD_CHARACTER ), - DEFINE_FIELD( alpha, FIELD_CHARACTER ), - DEFINE_FIELD( Flags, FIELD_INTEGER ), -END_DATADESC() - - -//----------------------------------------------------------------------------- -// Purpose: Screen shake variables -//----------------------------------------------------------------------------- -struct screenshake_t -{ - float endtime; - float duration; - float amplitude; - float frequency; - float nextShake; - Vector offset; - float angle; - int command; - - DECLARE_SIMPLE_DATADESC(); -}; - -BEGIN_SIMPLE_DATADESC( screenshake_t ) - DEFINE_FIELD( endtime, FIELD_TIME ), - DEFINE_FIELD( duration, FIELD_FLOAT ), - DEFINE_FIELD( amplitude, FIELD_FLOAT ), - DEFINE_FIELD( frequency, FIELD_FLOAT ), - DEFINE_FIELD( nextShake, FIELD_TIME ), - DEFINE_FIELD( offset, FIELD_VECTOR ), - DEFINE_FIELD( angle, FIELD_FLOAT ), -END_DATADESC() - - -void CC_Shake_Stop(); -//----------------------------------------------------------------------------- -// Purpose: Implements the view effects interface for the client .dll -//----------------------------------------------------------------------------- -class CViewEffects : public IViewEffects -{ -public: - - ~CViewEffects() - { - ClearAllFades(); - } - - virtual void Init( void ); - virtual void LevelInit( void ); - virtual void GetFadeParams( byte *r, byte *g, byte *b, byte *a, bool *blend ); - virtual void CalcShake( void ); - virtual void ApplyShake( Vector& origin, QAngle& angles, float factor ); - - virtual void Shake( ScreenShake_t &data ); - virtual void Fade( ScreenFade_t &data ); - virtual void ClearPermanentFades( void ); - virtual void FadeCalculate( void ); - virtual void ClearAllFades( void ); - - // Save / Restore - virtual void Save( ISave *pSave ); - virtual void Restore( IRestore *pRestore, bool fCreatePlayers ); - -private: - - void ClearAllShakes(); - screenshake_t *FindLongestShake(); - - CUtlVector m_FadeList; - - CUtlVector m_ShakeList; - Vector m_vecShakeAppliedOffset; - float m_flShakeAppliedAngle; - - int m_FadeColorRGBA[4]; - bool m_bModulate; - - friend void CC_Shake_Stop(); -}; - -static CViewEffects g_ViewEffects; -IViewEffects *vieweffects = ( IViewEffects * )&g_ViewEffects; - -// Callback function to call at end of screen m_Fade. -static int s_nCallbackParameter; -static void ( *s_pfnFadeDoneCallback )( int parm1 ); - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pszName - -// iSize - -// *pbuf - -// Output : static int -//----------------------------------------------------------------------------- -void __MsgFunc_Shake( bf_read &msg ) -{ - ScreenShake_t shake; - - shake.command = msg.ReadByte(); - shake.amplitude = msg.ReadFloat(); - shake.frequency = msg.ReadFloat(); - shake.duration = msg.ReadFloat(); - - g_ViewEffects.Shake( shake ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pszName - -// iSize - -// *pbuf - -// Output : static int -//----------------------------------------------------------------------------- -void __MsgFunc_Fade( bf_read &msg ) -{ - ScreenFade_t fade; - - fade.duration = msg.ReadShort(); // fade lasts this long - fade.holdTime = msg.ReadShort(); // fade lasts this long - fade.fadeFlags = msg.ReadShort(); // fade type (in / out) - fade.r = msg.ReadByte(); // fade red - fade.g = msg.ReadByte(); // fade green - fade.b = msg.ReadByte(); // fade blue - fade.a = msg.ReadByte(); // fade blue - - g_ViewEffects.Fade( fade ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CViewEffects::Init( void ) -{ - HOOK_MESSAGE( Shake ); - HOOK_MESSAGE( Fade ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CViewEffects::LevelInit( void ) -{ - ClearAllShakes(); - ClearAllFades(); -} - - -static ConVar shake_show( "shake_show", "0", 0, "Displays a list of the active screen shakes." ); -static ConCommand shake_stop("shake_stop", CC_Shake_Stop, "Stops all active screen shakes.\n", FCVAR_CHEAT ); - -//----------------------------------------------------------------------------- -// Purpose: Stops all active screen shakes. -//----------------------------------------------------------------------------- -void CC_Shake_Stop() -{ - g_ViewEffects.ClearAllShakes(); -} - - -//----------------------------------------------------------------------------- -// Purpose: Apply noise to the eye position. -// UNDONE: Feedback a bit of this into the view model position. It shakes too much -//----------------------------------------------------------------------------- -void CViewEffects::CalcShake( void ) -{ - float fraction, freq; - - // We'll accumulate the aggregate shake for this frame into these data members. - m_vecShakeAppliedOffset.Init(0, 0, 0); - m_flShakeAppliedAngle = 0; - float flRumbleAngle = 0; - - // NVNT - haptic shake effect amplitude - float hapticShakeAmp = 0; - - bool bShow = shake_show.GetBool(); - - int nShakeCount = m_ShakeList.Count(); - - for ( int nShake = nShakeCount - 1; nShake >= 0; nShake-- ) - { - screenshake_t *pShake = m_ShakeList.Element( nShake ); - - if ( pShake->endtime == 0 ) - { - // Shouldn't be any such shakes in the list. - Assert( false ); - continue; - } - - if ( ( gpGlobals->curtime > pShake->endtime ) || - pShake->duration <= 0 || - pShake->amplitude <= 0 || - pShake->frequency <= 0 ) - { - // Retire this shake. - delete m_ShakeList.Element( nShake ); - m_ShakeList.FastRemove( nShake ); - continue; - } - - if ( bShow ) - { - con_nprint_t np; - np.time_to_live = 2.0f; - np.fixed_width_font = true; - np.color[0] = 1.0; - np.color[1] = 0.8; - np.color[2] = 0.1; - np.index = nShake + 2; - - engine->Con_NXPrintf( &np, "%02d: dur(%8.2f) amp(%8.2f) freq(%8.2f)", nShake + 1, (double)pShake->duration, (double)pShake->amplitude, (double)pShake->frequency ); - } - - if ( gpGlobals->curtime > pShake->nextShake ) - { - // Higher frequency means we recalc the extents more often and perturb the display again - pShake->nextShake = gpGlobals->curtime + (1.0f / pShake->frequency); - - // Compute random shake extents (the shake will settle down from this) - for (int i = 0; i < 3; i++ ) - { - pShake->offset[i] = random->RandomFloat( -pShake->amplitude, pShake->amplitude ); - } - - pShake->angle = random->RandomFloat( -pShake->amplitude*0.25, pShake->amplitude*0.25 ); - } - - // Ramp down amplitude over duration (fraction goes from 1 to 0 linearly with slope 1/duration) - fraction = ( pShake->endtime - gpGlobals->curtime ) / pShake->duration; - - // Ramp up frequency over duration - if ( fraction ) - { - freq = (pShake->frequency / fraction); - } - else - { - freq = 0; - } - - // square fraction to approach zero more quickly - fraction *= fraction; - - // Sine wave that slowly settles to zero - float angle = gpGlobals->curtime * freq; - if ( angle > 1e8 ) - { - angle = 1e8; - } - fraction = fraction * sin( angle ); - - if( pShake->command != SHAKE_START_NORUMBLE ) - { - // As long as this isn't a NO RUMBLE effect, then accumulate rumble - flRumbleAngle += pShake->angle * fraction; - } - - if( pShake->command != SHAKE_START_RUMBLEONLY ) - { - // As long as this isn't a RUMBLE ONLY effect, then accumulate screen shake - - // Add to view origin - m_vecShakeAppliedOffset += pShake->offset * fraction; - - // Add to roll - m_flShakeAppliedAngle += pShake->angle * fraction; - } - - // Drop amplitude a bit, less for higher frequency shakes - pShake->amplitude -= pShake->amplitude * ( gpGlobals->frametime / (pShake->duration * pShake->frequency) ); - // NVNT - update our amplitude. - hapticShakeAmp += pShake->amplitude*fraction; - } - // NVNT - apply our screen shake update - if ( haptics ) - haptics->SetShake(hapticShakeAmp,1); - - // Feed this to the rumble system! - UpdateScreenShakeRumble( flRumbleAngle ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Apply the current screen shake to this origin/angles. Factor is the amount to apply -// This is so you can blend in part of the shake -// Input : origin - -// angles - -// factor - -//----------------------------------------------------------------------------- -void CViewEffects::ApplyShake( Vector& origin, QAngle& angles, float factor ) -{ - VectorMA( origin, factor, m_vecShakeAppliedOffset, origin ); - angles.z += m_flShakeAppliedAngle * factor; -} - - -//----------------------------------------------------------------------------- -// Purpose: Zeros out all active screen shakes. -//----------------------------------------------------------------------------- -void CViewEffects::ClearAllShakes() -{ - int nShakeCount = m_ShakeList.Count(); - for ( int i = 0; i < nShakeCount; i++ ) - { - delete m_ShakeList.Element( i ); - } - - m_ShakeList.Purge(); -} - - -//----------------------------------------------------------------------------- -// Purpose: Returns the shake with the longest duration. This is the shake we -// use anytime we get an amplitude or frequency command, because the -// most likely case is that we're modifying a shake with a long -// duration rather than a brief shake caused by an explosion, etc. -//----------------------------------------------------------------------------- -screenshake_t *CViewEffects::FindLongestShake() -{ - screenshake_t *pLongestShake = NULL; - - int nShakeCount = m_ShakeList.Count(); - for ( int i = 0; i < nShakeCount; i++ ) - { - screenshake_t *pShake = m_ShakeList.Element( i ); - if ( pShake && ( !pLongestShake || ( pShake->duration > pLongestShake->duration ) ) ) - { - pLongestShake = pShake; - } - } - - return pLongestShake; -} - - -//----------------------------------------------------------------------------- -// Purpose: Message hook to parse ScreenShake messages -// Input : pszName - -// iSize - -// pbuf - -// Output : -//----------------------------------------------------------------------------- -void CViewEffects::Shake( ScreenShake_t &data ) -{ - if ( ( data.command == SHAKE_START || data.command == SHAKE_START_RUMBLEONLY ) && ( m_ShakeList.Count() < MAX_SHAKES ) ) - { - screenshake_t *pNewShake = new screenshake_t; - - pNewShake->amplitude = data.amplitude; - pNewShake->frequency = data.frequency; - pNewShake->duration = data.duration; - pNewShake->nextShake = 0; - pNewShake->endtime = gpGlobals->curtime + data.duration; - pNewShake->command = data.command; - - m_ShakeList.AddToTail( pNewShake ); - } - else if ( data.command == SHAKE_STOP) - { - ClearAllShakes(); - } - else if ( data.command == SHAKE_AMPLITUDE ) - { - // Look for the most likely shake to modify. - screenshake_t *pShake = FindLongestShake(); - if ( pShake ) - { - pShake->amplitude = data.amplitude; - } - } - else if ( data.command == SHAKE_FREQUENCY ) - { - // Look for the most likely shake to modify. - screenshake_t *pShake = FindLongestShake(); - if ( pShake ) - { - pShake->frequency = data.frequency; - } - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Message hook to parse ScreenFade messages -// Input : *pszName - -// iSize - -// *pbuf - -// Output : int -//----------------------------------------------------------------------------- -void CViewEffects::Fade( ScreenFade_t &data ) -{ - // Create a new fade and append it to the list - screenfade_t *pNewFade = new screenfade_t; - pNewFade->End = data.duration * (1.0f/(float)(1<Reset = data.holdTime * (1.0f/(float)(1<r = data.r; - pNewFade->g = data.g; - pNewFade->b = data.b; - pNewFade->alpha = data.a; - pNewFade->Flags = data.fadeFlags; - pNewFade->Speed = 0; - - // Calc fade speed - if ( data.duration > 0 ) - { - if ( data.fadeFlags & FFADE_OUT ) - { - if ( pNewFade->End ) - { - pNewFade->Speed = -(float)pNewFade->alpha / pNewFade->End; - } - - pNewFade->End += gpGlobals->curtime; - pNewFade->Reset += pNewFade->End; - } - else - { - if ( pNewFade->End ) - { - pNewFade->Speed = (float)pNewFade->alpha / pNewFade->End; - } - - pNewFade->Reset += gpGlobals->curtime; - pNewFade->End += pNewFade->Reset; - } - } - - if ( data.fadeFlags & FFADE_PURGE ) - { - ClearAllFades(); - } - - m_FadeList.AddToTail( pNewFade ); -} - -//----------------------------------------------------------------------------- -// Purpose: Compute the overall color & alpha of the fades -//----------------------------------------------------------------------------- -void CViewEffects::FadeCalculate( void ) -{ - // Cycle through all fades and remove any that have finished (work backwards) - int i; - int iSize = m_FadeList.Size(); - for (i = iSize-1; i >= 0; i-- ) - { - screenfade_t *pFade = m_FadeList[i]; - - // Keep pushing reset time out indefinitely - if ( pFade->Flags & FFADE_STAYOUT ) - { - pFade->Reset = gpGlobals->curtime + 0.1; - } - - // All done? - if ( ( gpGlobals->curtime > pFade->Reset ) && ( gpGlobals->curtime > pFade->End ) ) - { - // User passed in a callback function, call it now - if ( s_pfnFadeDoneCallback ) - { - s_pfnFadeDoneCallback( s_nCallbackParameter ); - s_pfnFadeDoneCallback = NULL; - s_nCallbackParameter = 0; - } - - // Remove this Fade from the list - m_FadeList.FindAndRemove( pFade ); - delete pFade; - } - } - - m_bModulate = false; - m_FadeColorRGBA[0] = m_FadeColorRGBA[1] = m_FadeColorRGBA[2] = m_FadeColorRGBA[3] = 0; - - // Cycle through all fades in the list and calculate the overall color/alpha - for ( i = 0; i < m_FadeList.Size(); i++ ) - { - screenfade_t *pFade = m_FadeList[i]; - - // Color - m_FadeColorRGBA[0] += pFade->r; - m_FadeColorRGBA[1] += pFade->g; - m_FadeColorRGBA[2] += pFade->b; - - // Fading... - int iFadeAlpha; - if ( pFade->Flags & (FFADE_OUT|FFADE_IN) ) - { - iFadeAlpha = pFade->Speed * ( pFade->End - gpGlobals->curtime ); - if ( pFade->Flags & FFADE_OUT ) - { - iFadeAlpha += pFade->alpha; - } - iFadeAlpha = MIN( iFadeAlpha, pFade->alpha ); - iFadeAlpha = MAX( 0, iFadeAlpha ); - } - else - { - iFadeAlpha = pFade->alpha; - } - - // Use highest alpha - if ( iFadeAlpha > m_FadeColorRGBA[3] ) - { - m_FadeColorRGBA[3] = iFadeAlpha; - } - - // Modulate? - if ( pFade->Flags & FFADE_MODULATE ) - { - m_bModulate = true; - } - } - - // Divide colors - if ( m_FadeList.Size() ) - { - m_FadeColorRGBA[0] /= m_FadeList.Size(); - m_FadeColorRGBA[1] /= m_FadeList.Size(); - m_FadeColorRGBA[2] /= m_FadeList.Size(); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Clear only the permanent fades in our fade list -//----------------------------------------------------------------------------- -void CViewEffects::ClearPermanentFades( void ) -{ - int iSize = m_FadeList.Size(); - for (int i = iSize-1; i >= 0; i-- ) - { - screenfade_t *pFade = m_FadeList[i]; - - if ( pFade->Flags & FFADE_STAYOUT ) - { - // Destroy this fade - m_FadeList.FindAndRemove( pFade ); - delete pFade; - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Purge & delete all fades in the queue -//----------------------------------------------------------------------------- -void CViewEffects::ClearAllFades( void ) -{ - int iSize = m_FadeList.Size(); - for (int i = iSize-1; i >= 0; i-- ) - { - delete m_FadeList[i]; - } - m_FadeList.Purge(); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : context - Which call to Render is this ( CViewSetup::context ) -// *r - -// *g - -// *b - -// *a - -// *blend - -//----------------------------------------------------------------------------- -void CViewEffects::GetFadeParams( byte *r, byte *g, byte *b, byte *a, bool *blend ) -{ - // If the intro is overriding our fade, use that instead - if ( g_pIntroData && g_pIntroData->m_flCurrentFadeColor[3] ) - { - *r = g_pIntroData->m_flCurrentFadeColor[0]; - *g = g_pIntroData->m_flCurrentFadeColor[1]; - *b = g_pIntroData->m_flCurrentFadeColor[2]; - *a = g_pIntroData->m_flCurrentFadeColor[3]; - *blend = false; - return; - } - - FadeCalculate(); - - *r = m_FadeColorRGBA[0]; - *g = m_FadeColorRGBA[1]; - *b = m_FadeColorRGBA[2]; - *a = m_FadeColorRGBA[3]; - *blend = m_bModulate; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pSave - -//----------------------------------------------------------------------------- -void CViewEffects::Save( ISave *pSave ) -{ - // Save the view fades - int iCount = m_FadeList.Count(); - pSave->WriteInt( &iCount ); - for ( int i = 0; i < iCount; i++ ) - { - pSave->StartBlock(); - pSave->WriteAll( m_FadeList[i] ); - pSave->EndBlock(); - } - - // Save the view shakes - iCount = m_ShakeList.Count(); - pSave->WriteInt( &iCount ); - for ( int i = 0; i < iCount; i++ ) - { - pSave->StartBlock(); - pSave->WriteAll( m_ShakeList[i] ); - pSave->EndBlock(); - } -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pRestore - -// fCreatePlayers - -//----------------------------------------------------------------------------- -void CViewEffects::Restore( IRestore *pRestore, bool fCreatePlayers ) -{ - CGameSaveRestoreInfo *pSaveData = pRestore->GetGameSaveRestoreInfo(); - - // View effects is a singleton so we only need to restore it once, - // from the level that we are going into. - if( !pSaveData->levelInfo.fUseLandmark ) - { - ClearAllFades(); - ClearAllShakes(); - - // Read in the view fades - int iCount = pRestore->ReadInt(); - for ( int i = 0; i < iCount; i++ ) - { - screenfade_t *pNewFade = new screenfade_t; - - pRestore->StartBlock(); - pRestore->ReadAll( pNewFade ); - pRestore->EndBlock(); - - m_FadeList.AddToTail( pNewFade ); - } - - // Read in the view shakes - iCount = pRestore->ReadInt(); - for ( int i = 0; i < iCount; i++ ) - { - screenshake_t *pNewShake = new screenshake_t; - - pRestore->StartBlock(); - pRestore->ReadAll( pNewShake ); - pRestore->EndBlock(); - - m_ShakeList.AddToTail( pNewShake ); - } - } -} - -//==================================================================================================== -// CLIENTSIDE VIEW EFFECTS SAVE/RESTORE -//==================================================================================================== -static short VIEWEFFECTS_SAVE_RESTORE_VERSION = 2; - -class CViewEffectsSaveRestoreBlockHandler : public CDefSaveRestoreBlockHandler -{ - struct QueuedItem_t; -public: - CViewEffectsSaveRestoreBlockHandler() - { - } - - const char *GetBlockName() - { - return "ViewEffects"; - } - - //--------------------------------- - - virtual void PreSave( CSaveRestoreData * ) - { - } - - //--------------------------------- - - virtual void Save( ISave *pSave ) - { - vieweffects->Save( pSave ); - } - - //--------------------------------- - - virtual void WriteSaveHeaders( ISave *pSave ) - { - pSave->WriteShort( &VIEWEFFECTS_SAVE_RESTORE_VERSION ); - } - - //--------------------------------- - - virtual void PostSave() - { - } - - //--------------------------------- - - virtual void PreRestore() - { - } - - //--------------------------------- - - virtual void ReadRestoreHeaders( IRestore *pRestore ) - { - // No reason why any future version shouldn't try to retain backward compatability. The default here is to not do so. - short version = pRestore->ReadShort(); - m_bDoLoad = ( version == VIEWEFFECTS_SAVE_RESTORE_VERSION ); - } - - //--------------------------------- - - virtual void Restore( IRestore *pRestore, bool fCreatePlayers ) - { - if ( m_bDoLoad ) - { - vieweffects->Restore( pRestore, fCreatePlayers ); - } - } - - //--------------------------------- - - virtual void PostRestore() - { - } - -private: - bool m_bDoLoad; -}; - -//----------------------------------------------------------------------------- - -CViewEffectsSaveRestoreBlockHandler g_ViewEffectsSaveRestoreBlockHandler; - -ISaveRestoreBlockHandler *GetViewEffectsRestoreBlockHandler() -{ - return &g_ViewEffectsSaveRestoreBlockHandler; -} +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "ivieweffects.h" +#include "shake.h" +#include "hud_macros.h" +#include "isaverestore.h" +#include "view_shared.h" +#include "iviewrender.h" +#include "viewrender.h" +#include "con_nprint.h" +#include "saverestoretypes.h" +#include "c_rumble.h" +// NVNT haptics interface system +#include "haptics/ihaptics.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +extern IntroData_t *g_pIntroData; + + +// Arbitrary limit so that bad entity logic on the server can't consume tons of memory on the client. +#define MAX_SHAKES 32 + + +//----------------------------------------------------------------------------- +// Purpose: Screen fade variables +//----------------------------------------------------------------------------- +struct screenfade_t +{ + float Speed; // How fast to fade (tics / second) (+ fade in, - fade out) + float End; // When the fading hits maximum + float Reset; // When to reset to not fading (for fadeout and hold) + byte r, g, b, alpha; // Fade color + int Flags; // Fading flags + + DECLARE_SIMPLE_DATADESC(); +}; + +BEGIN_SIMPLE_DATADESC( screenfade_t ) + DEFINE_FIELD( Speed, FIELD_FLOAT ), + DEFINE_FIELD( End, FIELD_TIME ), + DEFINE_FIELD( Reset, FIELD_TIME ), + DEFINE_FIELD( r, FIELD_CHARACTER ), + DEFINE_FIELD( g, FIELD_CHARACTER ), + DEFINE_FIELD( b, FIELD_CHARACTER ), + DEFINE_FIELD( alpha, FIELD_CHARACTER ), + DEFINE_FIELD( Flags, FIELD_INTEGER ), +END_DATADESC() + + +//----------------------------------------------------------------------------- +// Purpose: Screen shake variables +//----------------------------------------------------------------------------- +struct screenshake_t +{ + float endtime; + float duration; + float amplitude; + float frequency; + float nextShake; + Vector offset; + float angle; + int command; + + DECLARE_SIMPLE_DATADESC(); +}; + +BEGIN_SIMPLE_DATADESC( screenshake_t ) + DEFINE_FIELD( endtime, FIELD_TIME ), + DEFINE_FIELD( duration, FIELD_FLOAT ), + DEFINE_FIELD( amplitude, FIELD_FLOAT ), + DEFINE_FIELD( frequency, FIELD_FLOAT ), + DEFINE_FIELD( nextShake, FIELD_TIME ), + DEFINE_FIELD( offset, FIELD_VECTOR ), + DEFINE_FIELD( angle, FIELD_FLOAT ), +END_DATADESC() + + +void CC_Shake_Stop(); +//----------------------------------------------------------------------------- +// Purpose: Implements the view effects interface for the client .dll +//----------------------------------------------------------------------------- +class CViewEffects : public IViewEffects +{ +public: + + ~CViewEffects() + { + ClearAllFades(); + } + + virtual void Init( void ); + virtual void LevelInit( void ); + virtual void GetFadeParams( byte *r, byte *g, byte *b, byte *a, bool *blend ); + virtual void CalcShake( void ); + virtual void ApplyShake( Vector& origin, QAngle& angles, float factor ); + + virtual void Shake( ScreenShake_t &data ); + virtual void Fade( ScreenFade_t &data ); + virtual void ClearPermanentFades( void ); + virtual void FadeCalculate( void ); + virtual void ClearAllFades( void ); + + // Save / Restore + virtual void Save( ISave *pSave ); + virtual void Restore( IRestore *pRestore, bool fCreatePlayers ); + +private: + + void ClearAllShakes(); + screenshake_t *FindLongestShake(); + + CUtlVector m_FadeList; + + CUtlVector m_ShakeList; + Vector m_vecShakeAppliedOffset; + float m_flShakeAppliedAngle; + + int m_FadeColorRGBA[4]; + bool m_bModulate; + + friend void CC_Shake_Stop(); +}; + +static CViewEffects g_ViewEffects; +IViewEffects *vieweffects = ( IViewEffects * )&g_ViewEffects; + +// Callback function to call at end of screen m_Fade. +static int s_nCallbackParameter; +static void ( *s_pfnFadeDoneCallback )( int parm1 ); + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pszName - +// iSize - +// *pbuf - +// Output : static int +//----------------------------------------------------------------------------- +void __MsgFunc_Shake( bf_read &msg ) +{ + ScreenShake_t shake; + + shake.command = msg.ReadByte(); + shake.amplitude = msg.ReadFloat(); + shake.frequency = msg.ReadFloat(); + shake.duration = msg.ReadFloat(); + + g_ViewEffects.Shake( shake ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pszName - +// iSize - +// *pbuf - +// Output : static int +//----------------------------------------------------------------------------- +void __MsgFunc_Fade( bf_read &msg ) +{ + ScreenFade_t fade; + + fade.duration = msg.ReadShort(); // fade lasts this long + fade.holdTime = msg.ReadShort(); // fade lasts this long + fade.fadeFlags = msg.ReadShort(); // fade type (in / out) + fade.r = msg.ReadByte(); // fade red + fade.g = msg.ReadByte(); // fade green + fade.b = msg.ReadByte(); // fade blue + fade.a = msg.ReadByte(); // fade blue + + g_ViewEffects.Fade( fade ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CViewEffects::Init( void ) +{ + HOOK_MESSAGE( Shake ); + HOOK_MESSAGE( Fade ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CViewEffects::LevelInit( void ) +{ + ClearAllShakes(); + ClearAllFades(); +} + + +static ConVar shake_show( "shake_show", "0", 0, "Displays a list of the active screen shakes." ); +static ConCommand shake_stop("shake_stop", CC_Shake_Stop, "Stops all active screen shakes.\n", FCVAR_CHEAT ); + +//----------------------------------------------------------------------------- +// Purpose: Stops all active screen shakes. +//----------------------------------------------------------------------------- +void CC_Shake_Stop() +{ + g_ViewEffects.ClearAllShakes(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Apply noise to the eye position. +// UNDONE: Feedback a bit of this into the view model position. It shakes too much +//----------------------------------------------------------------------------- +void CViewEffects::CalcShake( void ) +{ + float fraction, freq; + + // We'll accumulate the aggregate shake for this frame into these data members. + m_vecShakeAppliedOffset.Init(0, 0, 0); + m_flShakeAppliedAngle = 0; + float flRumbleAngle = 0; + + // NVNT - haptic shake effect amplitude + float hapticShakeAmp = 0; + + bool bShow = shake_show.GetBool(); + + int nShakeCount = m_ShakeList.Count(); + + for ( int nShake = nShakeCount - 1; nShake >= 0; nShake-- ) + { + screenshake_t *pShake = m_ShakeList.Element( nShake ); + + if ( pShake->endtime == 0 ) + { + // Shouldn't be any such shakes in the list. + Assert( false ); + continue; + } + + if ( ( gpGlobals->curtime > pShake->endtime ) || + pShake->duration <= 0 || + pShake->amplitude <= 0 || + pShake->frequency <= 0 ) + { + // Retire this shake. + delete m_ShakeList.Element( nShake ); + m_ShakeList.FastRemove( nShake ); + continue; + } + + if ( bShow ) + { + con_nprint_t np; + np.time_to_live = 2.0f; + np.fixed_width_font = true; + np.color[0] = 1.0; + np.color[1] = 0.8; + np.color[2] = 0.1; + np.index = nShake + 2; + + engine->Con_NXPrintf( &np, "%02d: dur(%8.2f) amp(%8.2f) freq(%8.2f)", nShake + 1, (double)pShake->duration, (double)pShake->amplitude, (double)pShake->frequency ); + } + + if ( gpGlobals->curtime > pShake->nextShake ) + { + // Higher frequency means we recalc the extents more often and perturb the display again + pShake->nextShake = gpGlobals->curtime + (1.0f / pShake->frequency); + + // Compute random shake extents (the shake will settle down from this) + for (int i = 0; i < 3; i++ ) + { + pShake->offset[i] = random->RandomFloat( -pShake->amplitude, pShake->amplitude ); + } + + pShake->angle = random->RandomFloat( -pShake->amplitude*0.25, pShake->amplitude*0.25 ); + } + + // Ramp down amplitude over duration (fraction goes from 1 to 0 linearly with slope 1/duration) + fraction = ( pShake->endtime - gpGlobals->curtime ) / pShake->duration; + + // Ramp up frequency over duration + if ( fraction ) + { + freq = (pShake->frequency / fraction); + } + else + { + freq = 0; + } + + // square fraction to approach zero more quickly + fraction *= fraction; + + // Sine wave that slowly settles to zero + float angle = gpGlobals->curtime * freq; + if ( angle > 1e8 ) + { + angle = 1e8; + } + fraction = fraction * sin( angle ); + + if( pShake->command != SHAKE_START_NORUMBLE ) + { + // As long as this isn't a NO RUMBLE effect, then accumulate rumble + flRumbleAngle += pShake->angle * fraction; + } + + if( pShake->command != SHAKE_START_RUMBLEONLY ) + { + // As long as this isn't a RUMBLE ONLY effect, then accumulate screen shake + + // Add to view origin + m_vecShakeAppliedOffset += pShake->offset * fraction; + + // Add to roll + m_flShakeAppliedAngle += pShake->angle * fraction; + } + + // Drop amplitude a bit, less for higher frequency shakes + pShake->amplitude -= pShake->amplitude * ( gpGlobals->frametime / (pShake->duration * pShake->frequency) ); + // NVNT - update our amplitude. + hapticShakeAmp += pShake->amplitude*fraction; + } + // NVNT - apply our screen shake update + if ( haptics ) + haptics->SetShake(hapticShakeAmp,1); + + // Feed this to the rumble system! + UpdateScreenShakeRumble( flRumbleAngle ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Apply the current screen shake to this origin/angles. Factor is the amount to apply +// This is so you can blend in part of the shake +// Input : origin - +// angles - +// factor - +//----------------------------------------------------------------------------- +void CViewEffects::ApplyShake( Vector& origin, QAngle& angles, float factor ) +{ + VectorMA( origin, factor, m_vecShakeAppliedOffset, origin ); + angles.z += m_flShakeAppliedAngle * factor; +} + + +//----------------------------------------------------------------------------- +// Purpose: Zeros out all active screen shakes. +//----------------------------------------------------------------------------- +void CViewEffects::ClearAllShakes() +{ + int nShakeCount = m_ShakeList.Count(); + for ( int i = 0; i < nShakeCount; i++ ) + { + delete m_ShakeList.Element( i ); + } + + m_ShakeList.Purge(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the shake with the longest duration. This is the shake we +// use anytime we get an amplitude or frequency command, because the +// most likely case is that we're modifying a shake with a long +// duration rather than a brief shake caused by an explosion, etc. +//----------------------------------------------------------------------------- +screenshake_t *CViewEffects::FindLongestShake() +{ + screenshake_t *pLongestShake = NULL; + + int nShakeCount = m_ShakeList.Count(); + for ( int i = 0; i < nShakeCount; i++ ) + { + screenshake_t *pShake = m_ShakeList.Element( i ); + if ( pShake && ( !pLongestShake || ( pShake->duration > pLongestShake->duration ) ) ) + { + pLongestShake = pShake; + } + } + + return pLongestShake; +} + + +//----------------------------------------------------------------------------- +// Purpose: Message hook to parse ScreenShake messages +// Input : pszName - +// iSize - +// pbuf - +// Output : +//----------------------------------------------------------------------------- +void CViewEffects::Shake( ScreenShake_t &data ) +{ + if ( ( data.command == SHAKE_START || data.command == SHAKE_START_RUMBLEONLY ) && ( m_ShakeList.Count() < MAX_SHAKES ) ) + { + screenshake_t *pNewShake = new screenshake_t; + + pNewShake->amplitude = data.amplitude; + pNewShake->frequency = data.frequency; + pNewShake->duration = data.duration; + pNewShake->nextShake = 0; + pNewShake->endtime = gpGlobals->curtime + data.duration; + pNewShake->command = data.command; + + m_ShakeList.AddToTail( pNewShake ); + } + else if ( data.command == SHAKE_STOP) + { + ClearAllShakes(); + } + else if ( data.command == SHAKE_AMPLITUDE ) + { + // Look for the most likely shake to modify. + screenshake_t *pShake = FindLongestShake(); + if ( pShake ) + { + pShake->amplitude = data.amplitude; + } + } + else if ( data.command == SHAKE_FREQUENCY ) + { + // Look for the most likely shake to modify. + screenshake_t *pShake = FindLongestShake(); + if ( pShake ) + { + pShake->frequency = data.frequency; + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Message hook to parse ScreenFade messages +// Input : *pszName - +// iSize - +// *pbuf - +// Output : int +//----------------------------------------------------------------------------- +void CViewEffects::Fade( ScreenFade_t &data ) +{ + // Create a new fade and append it to the list + screenfade_t *pNewFade = new screenfade_t; + pNewFade->End = data.duration * (1.0f/(float)(1<Reset = data.holdTime * (1.0f/(float)(1<r = data.r; + pNewFade->g = data.g; + pNewFade->b = data.b; + pNewFade->alpha = data.a; + pNewFade->Flags = data.fadeFlags; + pNewFade->Speed = 0; + + // Calc fade speed + if ( data.duration > 0 ) + { + if ( data.fadeFlags & FFADE_OUT ) + { + if ( pNewFade->End ) + { + pNewFade->Speed = -(float)pNewFade->alpha / pNewFade->End; + } + + pNewFade->End += gpGlobals->curtime; + pNewFade->Reset += pNewFade->End; + } + else + { + if ( pNewFade->End ) + { + pNewFade->Speed = (float)pNewFade->alpha / pNewFade->End; + } + + pNewFade->Reset += gpGlobals->curtime; + pNewFade->End += pNewFade->Reset; + } + } + + if ( data.fadeFlags & FFADE_PURGE ) + { + ClearAllFades(); + } + + m_FadeList.AddToTail( pNewFade ); +} + +//----------------------------------------------------------------------------- +// Purpose: Compute the overall color & alpha of the fades +//----------------------------------------------------------------------------- +void CViewEffects::FadeCalculate( void ) +{ + // Cycle through all fades and remove any that have finished (work backwards) + int i; + int iSize = m_FadeList.Size(); + for (i = iSize-1; i >= 0; i-- ) + { + screenfade_t *pFade = m_FadeList[i]; + + // Keep pushing reset time out indefinitely + if ( pFade->Flags & FFADE_STAYOUT ) + { + pFade->Reset = gpGlobals->curtime + 0.1; + } + + // All done? + if ( ( gpGlobals->curtime > pFade->Reset ) && ( gpGlobals->curtime > pFade->End ) ) + { + // User passed in a callback function, call it now + if ( s_pfnFadeDoneCallback ) + { + s_pfnFadeDoneCallback( s_nCallbackParameter ); + s_pfnFadeDoneCallback = NULL; + s_nCallbackParameter = 0; + } + + // Remove this Fade from the list + m_FadeList.FindAndRemove( pFade ); + delete pFade; + } + } + + m_bModulate = false; + m_FadeColorRGBA[0] = m_FadeColorRGBA[1] = m_FadeColorRGBA[2] = m_FadeColorRGBA[3] = 0; + + // Cycle through all fades in the list and calculate the overall color/alpha + for ( i = 0; i < m_FadeList.Size(); i++ ) + { + screenfade_t *pFade = m_FadeList[i]; + + // Color + m_FadeColorRGBA[0] += pFade->r; + m_FadeColorRGBA[1] += pFade->g; + m_FadeColorRGBA[2] += pFade->b; + + // Fading... + int iFadeAlpha; + if ( pFade->Flags & (FFADE_OUT|FFADE_IN) ) + { + iFadeAlpha = pFade->Speed * ( pFade->End - gpGlobals->curtime ); + if ( pFade->Flags & FFADE_OUT ) + { + iFadeAlpha += pFade->alpha; + } + iFadeAlpha = MIN( iFadeAlpha, pFade->alpha ); + iFadeAlpha = MAX( 0, iFadeAlpha ); + } + else + { + iFadeAlpha = pFade->alpha; + } + + // Use highest alpha + if ( iFadeAlpha > m_FadeColorRGBA[3] ) + { + m_FadeColorRGBA[3] = iFadeAlpha; + } + + // Modulate? + if ( pFade->Flags & FFADE_MODULATE ) + { + m_bModulate = true; + } + } + + // Divide colors + if ( m_FadeList.Size() ) + { + m_FadeColorRGBA[0] /= m_FadeList.Size(); + m_FadeColorRGBA[1] /= m_FadeList.Size(); + m_FadeColorRGBA[2] /= m_FadeList.Size(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Clear only the permanent fades in our fade list +//----------------------------------------------------------------------------- +void CViewEffects::ClearPermanentFades( void ) +{ + int iSize = m_FadeList.Size(); + for (int i = iSize-1; i >= 0; i-- ) + { + screenfade_t *pFade = m_FadeList[i]; + + if ( pFade->Flags & FFADE_STAYOUT ) + { + // Destroy this fade + m_FadeList.FindAndRemove( pFade ); + delete pFade; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Purge & delete all fades in the queue +//----------------------------------------------------------------------------- +void CViewEffects::ClearAllFades( void ) +{ + int iSize = m_FadeList.Size(); + for (int i = iSize-1; i >= 0; i-- ) + { + delete m_FadeList[i]; + } + m_FadeList.Purge(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : context - Which call to Render is this ( CViewSetup::context ) +// *r - +// *g - +// *b - +// *a - +// *blend - +//----------------------------------------------------------------------------- +void CViewEffects::GetFadeParams( byte *r, byte *g, byte *b, byte *a, bool *blend ) +{ + // If the intro is overriding our fade, use that instead + if ( g_pIntroData && g_pIntroData->m_flCurrentFadeColor[3] ) + { + *r = g_pIntroData->m_flCurrentFadeColor[0]; + *g = g_pIntroData->m_flCurrentFadeColor[1]; + *b = g_pIntroData->m_flCurrentFadeColor[2]; + *a = g_pIntroData->m_flCurrentFadeColor[3]; + *blend = false; + return; + } + + FadeCalculate(); + + *r = m_FadeColorRGBA[0]; + *g = m_FadeColorRGBA[1]; + *b = m_FadeColorRGBA[2]; + *a = m_FadeColorRGBA[3]; + *blend = m_bModulate; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pSave - +//----------------------------------------------------------------------------- +void CViewEffects::Save( ISave *pSave ) +{ + // Save the view fades + int iCount = m_FadeList.Count(); + pSave->WriteInt( &iCount ); + for ( int i = 0; i < iCount; i++ ) + { + pSave->StartBlock(); + pSave->WriteAll( m_FadeList[i] ); + pSave->EndBlock(); + } + + // Save the view shakes + iCount = m_ShakeList.Count(); + pSave->WriteInt( &iCount ); + for ( int i = 0; i < iCount; i++ ) + { + pSave->StartBlock(); + pSave->WriteAll( m_ShakeList[i] ); + pSave->EndBlock(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pRestore - +// fCreatePlayers - +//----------------------------------------------------------------------------- +void CViewEffects::Restore( IRestore *pRestore, bool fCreatePlayers ) +{ + CGameSaveRestoreInfo *pSaveData = pRestore->GetGameSaveRestoreInfo(); + + // View effects is a singleton so we only need to restore it once, + // from the level that we are going into. + if( !pSaveData->levelInfo.fUseLandmark ) + { + ClearAllFades(); + ClearAllShakes(); + + // Read in the view fades + int iCount = pRestore->ReadInt(); + for ( int i = 0; i < iCount; i++ ) + { + screenfade_t *pNewFade = new screenfade_t; + + pRestore->StartBlock(); + pRestore->ReadAll( pNewFade ); + pRestore->EndBlock(); + + m_FadeList.AddToTail( pNewFade ); + } + + // Read in the view shakes + iCount = pRestore->ReadInt(); + for ( int i = 0; i < iCount; i++ ) + { + screenshake_t *pNewShake = new screenshake_t; + + pRestore->StartBlock(); + pRestore->ReadAll( pNewShake ); + pRestore->EndBlock(); + + m_ShakeList.AddToTail( pNewShake ); + } + } +} + +//==================================================================================================== +// CLIENTSIDE VIEW EFFECTS SAVE/RESTORE +//==================================================================================================== +static short VIEWEFFECTS_SAVE_RESTORE_VERSION = 2; + +class CViewEffectsSaveRestoreBlockHandler : public CDefSaveRestoreBlockHandler +{ + struct QueuedItem_t; +public: + CViewEffectsSaveRestoreBlockHandler() + { + } + + const char *GetBlockName() + { + return "ViewEffects"; + } + + //--------------------------------- + + virtual void PreSave( CSaveRestoreData * ) + { + } + + //--------------------------------- + + virtual void Save( ISave *pSave ) + { + vieweffects->Save( pSave ); + } + + //--------------------------------- + + virtual void WriteSaveHeaders( ISave *pSave ) + { + pSave->WriteShort( &VIEWEFFECTS_SAVE_RESTORE_VERSION ); + } + + //--------------------------------- + + virtual void PostSave() + { + } + + //--------------------------------- + + virtual void PreRestore() + { + } + + //--------------------------------- + + virtual void ReadRestoreHeaders( IRestore *pRestore ) + { + // No reason why any future version shouldn't try to retain backward compatability. The default here is to not do so. + short version = pRestore->ReadShort(); + m_bDoLoad = ( version == VIEWEFFECTS_SAVE_RESTORE_VERSION ); + } + + //--------------------------------- + + virtual void Restore( IRestore *pRestore, bool fCreatePlayers ) + { + if ( m_bDoLoad ) + { + vieweffects->Restore( pRestore, fCreatePlayers ); + } + } + + //--------------------------------- + + virtual void PostRestore() + { + } + +private: + bool m_bDoLoad; +}; + +//----------------------------------------------------------------------------- + +CViewEffectsSaveRestoreBlockHandler g_ViewEffectsSaveRestoreBlockHandler; + +ISaveRestoreBlockHandler *GetViewEffectsRestoreBlockHandler() +{ + return &g_ViewEffectsSaveRestoreBlockHandler; +} -- cgit v1.2.3