From 39ed87570bdb2f86969d4be821c94b722dc71179 Mon Sep 17 00:00:00 2001 From: Joe Ludwig Date: Wed, 26 Jun 2013 15:22:04 -0700 Subject: First version of the SOurce SDK 2013 --- mp/src/game/shared/SpriteTrail.cpp | 662 +++++++++++++++++++++++++++++++++++++ 1 file changed, 662 insertions(+) create mode 100644 mp/src/game/shared/SpriteTrail.cpp (limited to 'mp/src/game/shared/SpriteTrail.cpp') diff --git a/mp/src/game/shared/SpriteTrail.cpp b/mp/src/game/shared/SpriteTrail.cpp new file mode 100644 index 00000000..409a2770 --- /dev/null +++ b/mp/src/game/shared/SpriteTrail.cpp @@ -0,0 +1,662 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "SpriteTrail.h" + +#ifdef CLIENT_DLL + +#include "clientsideeffects.h" +#include "materialsystem/imaterialsystem.h" +#include "materialsystem/imesh.h" +#include "mathlib/vmatrix.h" +#include "view.h" +#include "beamdraw.h" +#include "enginesprite.h" +#include "tier0/vprof.h" + +extern CEngineSprite *Draw_SetSpriteTexture( const model_t *pSpriteModel, int frame, int rendermode ); + +#endif // CLIENT_DLL + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// constants +//----------------------------------------------------------------------------- +#define SCREEN_SPACE_TRAILS 0 + + +//----------------------------------------------------------------------------- +// Save/Restore +//----------------------------------------------------------------------------- +#if defined( CLIENT_DLL ) + +BEGIN_SIMPLE_DATADESC( TrailPoint_t ) +#if SCREEN_SPACE_TRAILS + DEFINE_FIELD( m_vecScreenPos, FIELD_VECTOR ), +#else + DEFINE_FIELD( m_vecScreenPos, FIELD_POSITION_VECTOR ), +#endif + + DEFINE_FIELD( m_flDieTime, FIELD_TIME ), + DEFINE_FIELD( m_flTexCoord, FIELD_FLOAT ), + DEFINE_FIELD( m_flWidthVariance,FIELD_FLOAT ), +END_DATADESC() + +#endif + +BEGIN_DATADESC( CSpriteTrail ) + + DEFINE_KEYFIELD( m_flLifeTime, FIELD_FLOAT, "lifetime" ), + DEFINE_KEYFIELD( m_flStartWidth, FIELD_FLOAT, "startwidth" ), + DEFINE_KEYFIELD( m_flEndWidth, FIELD_FLOAT, "endwidth" ), + DEFINE_KEYFIELD( m_iszSpriteName, FIELD_STRING, "spritename" ), + DEFINE_KEYFIELD( m_bAnimate, FIELD_BOOLEAN, "animate" ), + DEFINE_FIELD( m_flStartWidthVariance, FIELD_FLOAT ), + DEFINE_FIELD( m_flTextureRes, FIELD_FLOAT ), + DEFINE_FIELD( m_flMinFadeLength, FIELD_FLOAT ), + DEFINE_FIELD( m_vecSkyboxOrigin, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( m_flSkyboxScale, FIELD_FLOAT ), + + // These are client-only +#if defined( CLIENT_DLL ) + DEFINE_EMBEDDED_AUTO_ARRAY( m_vecSteps ), + DEFINE_FIELD( m_nFirstStep, FIELD_INTEGER ), + DEFINE_FIELD( m_nStepCount, FIELD_INTEGER ), + DEFINE_FIELD( m_flUpdateTime, FIELD_TIME ), + DEFINE_FIELD( m_vecPrevSkyboxOrigin, FIELD_POSITION_VECTOR ), + DEFINE_FIELD( m_flPrevSkyboxScale, FIELD_FLOAT ), + DEFINE_FIELD( m_vecRenderMins, FIELD_VECTOR ), + DEFINE_FIELD( m_vecRenderMaxs, FIELD_VECTOR ), +#endif + +END_DATADESC() + +LINK_ENTITY_TO_CLASS( env_spritetrail, CSpriteTrail ); + + +//----------------------------------------------------------------------------- +// Networking +//----------------------------------------------------------------------------- +IMPLEMENT_NETWORKCLASS_ALIASED( SpriteTrail, DT_SpriteTrail ); + +BEGIN_NETWORK_TABLE( CSpriteTrail, DT_SpriteTrail ) +#if !defined( CLIENT_DLL ) + SendPropFloat( SENDINFO(m_flLifeTime), 0, SPROP_NOSCALE ), + SendPropFloat( SENDINFO(m_flStartWidth), 0, SPROP_NOSCALE ), + SendPropFloat( SENDINFO(m_flEndWidth), 0, SPROP_NOSCALE ), + SendPropFloat( SENDINFO(m_flStartWidthVariance), 0, SPROP_NOSCALE ), + SendPropFloat( SENDINFO(m_flTextureRes), 0, SPROP_NOSCALE ), + SendPropFloat( SENDINFO(m_flMinFadeLength), 0, SPROP_NOSCALE ), + SendPropVector( SENDINFO(m_vecSkyboxOrigin),0, SPROP_NOSCALE ), + SendPropFloat( SENDINFO(m_flSkyboxScale), 0, SPROP_NOSCALE ), +#else + RecvPropFloat( RECVINFO(m_flLifeTime)), + RecvPropFloat( RECVINFO(m_flStartWidth)), + RecvPropFloat( RECVINFO(m_flEndWidth)), + RecvPropFloat( RECVINFO(m_flStartWidthVariance)), + RecvPropFloat( RECVINFO(m_flTextureRes)), + RecvPropFloat( RECVINFO(m_flMinFadeLength)), + RecvPropVector( RECVINFO(m_vecSkyboxOrigin)), + RecvPropFloat( RECVINFO(m_flSkyboxScale)), +#endif +END_NETWORK_TABLE() + +//----------------------------------------------------------------------------- +// Prediction +//----------------------------------------------------------------------------- +BEGIN_PREDICTION_DATA( CSpriteTrail ) +END_PREDICTION_DATA() + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CSpriteTrail::CSpriteTrail( void ) +{ +#ifdef CLIENT_DLL + m_nFirstStep = 0; + m_nStepCount = 0; +#endif + + m_flStartWidthVariance = 0; + m_vecSkyboxOrigin.Init( 0, 0, 0 ); + m_flSkyboxScale = 1.0f; + m_flEndWidth = -1.0f; + m_bDrawForMoveParent = true; +} + +void CSpriteTrail::Spawn( void ) +{ +#ifdef CLIENT_DLL + BaseClass::Spawn(); +#else + + if ( GetModelName() != NULL_STRING ) + { + BaseClass::Spawn(); + return; + } + + SetModelName( m_iszSpriteName ); + BaseClass::Spawn(); + + SetSolid( SOLID_NONE ); + SetMoveType( MOVETYPE_NOCLIP ); + + SetCollisionBounds( vec3_origin, vec3_origin ); + TurnOn(); + +#endif +} + +//----------------------------------------------------------------------------- +// Sets parameters of the sprite trail +//----------------------------------------------------------------------------- +void CSpriteTrail::Precache( void ) +{ + BaseClass::Precache(); + + if ( m_iszSpriteName != NULL_STRING ) + { + PrecacheModel( STRING(m_iszSpriteName) ); + } +} + +//----------------------------------------------------------------------------- +// Sets parameters of the sprite trail +//----------------------------------------------------------------------------- +void CSpriteTrail::SetLifeTime( float time ) +{ + m_flLifeTime = time; +} + +void CSpriteTrail::SetStartWidth( float flStartWidth ) +{ + m_flStartWidth = flStartWidth; + m_flStartWidth /= m_flSkyboxScale; +} + +void CSpriteTrail::SetStartWidthVariance( float flStartWidthVariance ) +{ + m_flStartWidthVariance = flStartWidthVariance; + m_flStartWidthVariance /= m_flSkyboxScale; +} + +void CSpriteTrail::SetEndWidth( float flEndWidth ) +{ + m_flEndWidth = flEndWidth; + m_flEndWidth /= m_flSkyboxScale; +} + +void CSpriteTrail::SetTextureResolution( float flTexelsPerInch ) +{ + m_flTextureRes = flTexelsPerInch; + m_flTextureRes *= m_flSkyboxScale; +} + +void CSpriteTrail::SetMinFadeLength( float flMinFadeLength ) +{ + m_flMinFadeLength = flMinFadeLength; + m_flMinFadeLength /= m_flSkyboxScale; +} + +void CSpriteTrail::SetSkybox( const Vector &vecSkyboxOrigin, float flSkyboxScale ) +{ + m_flTextureRes /= m_flSkyboxScale; + m_flMinFadeLength *= m_flSkyboxScale; + m_flStartWidth *= m_flSkyboxScale; + m_flEndWidth *= m_flSkyboxScale; + m_flStartWidthVariance *= m_flSkyboxScale; + + m_vecSkyboxOrigin = vecSkyboxOrigin; + m_flSkyboxScale = flSkyboxScale; + + m_flTextureRes *= m_flSkyboxScale; + m_flMinFadeLength /= m_flSkyboxScale; + m_flStartWidth /= m_flSkyboxScale; + m_flEndWidth /= m_flSkyboxScale; + m_flStartWidthVariance /= m_flSkyboxScale; + + if ( IsInSkybox() ) + { + AddEFlags( EFL_IN_SKYBOX ); + } + else + { + RemoveEFlags( EFL_IN_SKYBOX ); + } +} + + +//----------------------------------------------------------------------------- +// Is the trail in the skybox? +//----------------------------------------------------------------------------- +bool CSpriteTrail::IsInSkybox() const +{ + return (m_flSkyboxScale != 1.0f) || (m_vecSkyboxOrigin != vec3_origin); +} + + + +#ifdef CLIENT_DLL + + +//----------------------------------------------------------------------------- +// On data update +//----------------------------------------------------------------------------- +void CSpriteTrail::OnPreDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnPreDataChanged( updateType ); + m_vecPrevSkyboxOrigin = m_vecSkyboxOrigin; + m_flPrevSkyboxScale = m_flSkyboxScale; +} + +void CSpriteTrail::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + if ( updateType == DATA_UPDATE_CREATED ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } + else + { + if ((m_flPrevSkyboxScale != m_flSkyboxScale) || (m_vecPrevSkyboxOrigin != m_vecSkyboxOrigin)) + { + ConvertSkybox(); + } + } +} + + +//----------------------------------------------------------------------------- +// Compute position + bounding box +//----------------------------------------------------------------------------- +void CSpriteTrail::ClientThink() +{ + // Update the trail + bounding box + UpdateTrail(); + UpdateBoundingBox(); +} + + +//----------------------------------------------------------------------------- +// Render bounds +//----------------------------------------------------------------------------- +void CSpriteTrail::GetRenderBounds( Vector& mins, Vector& maxs ) +{ + mins = m_vecRenderMins; + maxs = m_vecRenderMaxs; +} + + +//----------------------------------------------------------------------------- +// Converts the trail when it changes skyboxes +//----------------------------------------------------------------------------- +void CSpriteTrail::ConvertSkybox() +{ + for ( int i = 0; i < m_nStepCount; ++i ) + { + // This makes it so that we're always drawing to the current location + TrailPoint_t *pPoint = GetTrailPoint(i); + + VectorSubtract( pPoint->m_vecScreenPos, m_vecPrevSkyboxOrigin, pPoint->m_vecScreenPos ); + pPoint->m_vecScreenPos *= m_flPrevSkyboxScale / m_flSkyboxScale; + VectorSubtract( pPoint->m_vecScreenPos, m_vecSkyboxOrigin, pPoint->m_vecScreenPos ); + pPoint->m_flWidthVariance *= m_flPrevSkyboxScale / m_flSkyboxScale; + } +} + + +//----------------------------------------------------------------------------- +// Gets at the nth item in the list +//----------------------------------------------------------------------------- +TrailPoint_t *CSpriteTrail::GetTrailPoint( int n ) +{ + Assert( n < MAX_SPRITE_TRAIL_POINTS ); + COMPILE_TIME_ASSERT( (MAX_SPRITE_TRAIL_POINTS & (MAX_SPRITE_TRAIL_POINTS-1)) == 0 ); + int nIndex = (n + m_nFirstStep) & MAX_SPRITE_TRAIL_MASK; + return &m_vecSteps[nIndex]; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CSpriteTrail::ComputeScreenPosition( Vector *pScreenPos ) +{ +#if SCREEN_SPACE_TRAILS + VMatrix viewMatrix; + materials->GetMatrix( MATERIAL_VIEW, &viewMatrix ); + *pScreenPos = viewMatrix * GetRenderOrigin(); +#else + *pScreenPos = GetRenderOrigin(); +#endif +} + + +//----------------------------------------------------------------------------- +// Compute position + bounding box +//----------------------------------------------------------------------------- +void CSpriteTrail::UpdateBoundingBox( void ) +{ + Vector vecRenderOrigin = GetRenderOrigin(); + m_vecRenderMins = vecRenderOrigin; + m_vecRenderMaxs = vecRenderOrigin; + + float flMaxWidth = m_flStartWidth; + if (( m_flEndWidth >= 0.0f ) && ( m_flEndWidth > m_flStartWidth )) + { + flMaxWidth = m_flEndWidth; + } + + Vector mins, maxs; + for ( int i = 0; i < m_nStepCount; ++i ) + { + TrailPoint_t *pPoint = GetTrailPoint(i); + + float flActualWidth = (flMaxWidth + pPoint->m_flWidthVariance) * 0.5f; + Vector size( flActualWidth, flActualWidth, flActualWidth ); + VectorSubtract( pPoint->m_vecScreenPos, size, mins ); + VectorAdd( pPoint->m_vecScreenPos, size, maxs ); + + VectorMin( m_vecRenderMins, mins, m_vecRenderMins ); + VectorMax( m_vecRenderMaxs, maxs, m_vecRenderMaxs ); + } + + m_vecRenderMins -= vecRenderOrigin; + m_vecRenderMaxs -= vecRenderOrigin; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CSpriteTrail::UpdateTrail( void ) +{ + // Can't update too quickly + if ( m_flUpdateTime > gpGlobals->curtime ) + return; + + Vector screenPos; + ComputeScreenPosition( &screenPos ); + TrailPoint_t *pLast = m_nStepCount ? GetTrailPoint( m_nStepCount-1 ) : NULL; + if ( ( pLast == NULL ) || ( pLast->m_vecScreenPos.DistToSqr( screenPos ) > 4.0f ) ) + { + // If we're over our limit, steal the last point and put it up front + if ( m_nStepCount >= MAX_SPRITE_TRAIL_POINTS ) + { + --m_nStepCount; + ++m_nFirstStep; + } + + // Save off its screen position, not its world position + TrailPoint_t *pNewPoint = GetTrailPoint( m_nStepCount ); + pNewPoint->m_vecScreenPos = screenPos; + pNewPoint->m_flDieTime = gpGlobals->curtime + m_flLifeTime; + pNewPoint->m_flWidthVariance = random->RandomFloat( -m_flStartWidthVariance, m_flStartWidthVariance ); + if (pLast) + { + pNewPoint->m_flTexCoord = pLast->m_flTexCoord + pLast->m_vecScreenPos.DistTo( screenPos ) * m_flTextureRes; + } + else + { + pNewPoint->m_flTexCoord = 0.0f; + } + + ++m_nStepCount; + } + + // Don't update again for a bit + m_flUpdateTime = gpGlobals->curtime + ( m_flLifeTime / (float) MAX_SPRITE_TRAIL_POINTS ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CSpriteTrail::DrawModel( int flags ) +{ + VPROF_BUDGET( "CSpriteTrail::DrawModel", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); + + // Must have at least one point + if ( m_nStepCount < 1 ) + return 1; + + //See if we should draw + if ( !IsVisible() || ( m_bReadyToDraw == false ) ) + return 0; + + CEngineSprite *pSprite = Draw_SetSpriteTexture( GetModel(), m_flFrame, GetRenderMode() ); + if ( pSprite == NULL ) + return 0; + + // Specify all the segments. + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + CBeamSegDraw segDraw; + segDraw.Start( pRenderContext, m_nStepCount + 1, pSprite->GetMaterial( GetRenderMode() ) ); + + // Setup the first point, always emanating from the attachment point + TrailPoint_t *pLast = GetTrailPoint( m_nStepCount-1 ); + TrailPoint_t currentPoint; + currentPoint.m_flDieTime = gpGlobals->curtime + m_flLifeTime; + ComputeScreenPosition( ¤tPoint.m_vecScreenPos ); + currentPoint.m_flTexCoord = pLast->m_flTexCoord + currentPoint.m_vecScreenPos.DistTo(pLast->m_vecScreenPos) * m_flTextureRes; + currentPoint.m_flWidthVariance = 0.0f; + +#if SCREEN_SPACE_TRAILS + VMatrix viewMatrix; + materials->GetMatrix( MATERIAL_VIEW, &viewMatrix ); + viewMatrix = viewMatrix.InverseTR(); +#endif + + TrailPoint_t *pPrevPoint = NULL; + float flTailAlphaDist = m_flMinFadeLength; + for ( int i = 0; i <= m_nStepCount; ++i ) + { + // This makes it so that we're always drawing to the current location + TrailPoint_t *pPoint = (i != m_nStepCount) ? GetTrailPoint(i) : ¤tPoint; + + float flLifePerc = (pPoint->m_flDieTime - gpGlobals->curtime) / m_flLifeTime; + flLifePerc = clamp( flLifePerc, 0.0f, 1.0f ); + + BeamSeg_t curSeg; + curSeg.m_vColor.x = (float) m_clrRender->r / 255.0f; + curSeg.m_vColor.y = (float) m_clrRender->g / 255.0f; + curSeg.m_vColor.z = (float) m_clrRender->b / 255.0f; + + float flAlphaFade = flLifePerc; + if ( flTailAlphaDist > 0.0f ) + { + if ( pPrevPoint ) + { + float flDist = pPoint->m_vecScreenPos.DistTo( pPrevPoint->m_vecScreenPos ); + flTailAlphaDist -= flDist; + } + + if ( flTailAlphaDist > 0.0f ) + { + float flTailFade = Lerp( (m_flMinFadeLength - flTailAlphaDist) / m_flMinFadeLength, 0.0f, 1.0f ); + if ( flTailFade < flAlphaFade ) + { + flAlphaFade = flTailFade; + } + } + } + curSeg.m_flAlpha = ( (float) GetRenderBrightness() / 255.0f ) * flAlphaFade; + +#if SCREEN_SPACE_TRAILS + curSeg.m_vPos = viewMatrix * pPoint->m_vecScreenPos; +#else + curSeg.m_vPos = pPoint->m_vecScreenPos; +#endif + + if ( m_flEndWidth >= 0.0f ) + { + curSeg.m_flWidth = Lerp( flLifePerc, m_flEndWidth.Get(), m_flStartWidth.Get() ); + } + else + { + curSeg.m_flWidth = m_flStartWidth.Get(); + } + curSeg.m_flWidth += pPoint->m_flWidthVariance; + if ( curSeg.m_flWidth < 0.0f ) + { + curSeg.m_flWidth = 0.0f; + } + + curSeg.m_flTexCoord = pPoint->m_flTexCoord; + + segDraw.NextSeg( &curSeg ); + + // See if we're done with this bad boy + if ( pPoint->m_flDieTime <= gpGlobals->curtime ) + { + // Push this back onto the top for use + ++m_nFirstStep; + --i; + --m_nStepCount; + } + + pPrevPoint = pPoint; + } + + segDraw.End(); + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Vector const& +//----------------------------------------------------------------------------- +const Vector &CSpriteTrail::GetRenderOrigin( void ) +{ + static Vector vOrigin; + vOrigin = GetAbsOrigin(); + + if ( m_hAttachedToEntity ) + { + C_BaseEntity *ent = m_hAttachedToEntity->GetBaseEntity(); + if ( ent ) + { + QAngle dummyAngles; + ent->GetAttachment( m_nAttachment, vOrigin, dummyAngles ); + } + } + + return vOrigin; +} + +const QAngle &CSpriteTrail::GetRenderAngles( void ) +{ + return vec3_angle; +} + +#endif //CLIENT_DLL + +#if !defined( CLIENT_DLL ) + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pSpriteName - +// &origin - +// animate - +// Output : CSpriteTrail +//----------------------------------------------------------------------------- +CSpriteTrail *CSpriteTrail::SpriteTrailCreate( const char *pSpriteName, const Vector &origin, bool animate ) +{ + CSpriteTrail *pSprite = CREATE_ENTITY( CSpriteTrail, "env_spritetrail" ); + + pSprite->SpriteInit( pSpriteName, origin ); + pSprite->SetSolid( SOLID_NONE ); + pSprite->SetMoveType( MOVETYPE_NOCLIP ); + + UTIL_SetSize( pSprite, vec3_origin, vec3_origin ); + + if ( animate ) + { + pSprite->TurnOn(); + } + + return pSprite; +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +int CSpriteTrail::ShouldTransmit( const CCheckTransmitInfo *pInfo ) +{ + CBaseEntity *pRecipientEntity = CBaseEntity::Instance( pInfo->m_pClientEnt ); + + Assert( pRecipientEntity->IsPlayer() ); + + CBasePlayer *pRecipientPlayer = static_cast( pRecipientEntity ); + + if ( !m_bDrawForMoveParent ) + { + if ( GetMoveParent() && !GetMoveParent()->IsPlayer() ) + { + if ( GetMoveParent()->GetMoveParent() == pRecipientPlayer ) + { + return FL_EDICT_DONTSEND; + } + } + else if ( GetMoveParent() == pRecipientPlayer ) + { + return FL_EDICT_DONTSEND; + } + + } + + return BaseClass::ShouldTransmit( pInfo ); +} + +#endif //CLIENT_DLL == false + +#if defined( CLIENT_DLL ) +// It's okay to draw attached entities with these sprites. +const char* g_spriteWhiteList[] = +{ + "effects/beam001_white.vmt", + "effects/beam001_red.vmt", + "effects/beam001_blu.vmt", +}; + +//----------------------------------------------------------------------------- +// Purpose: TF prevents drawing of any entity attached to players that aren't items in the inventory of the player. +// This is to prevent servers creating fake cosmetic items and attaching them to players. +//----------------------------------------------------------------------------- +bool CSpriteTrail::ValidateEntityAttachedToPlayer( bool &bShouldRetry ) +{ + bShouldRetry = false; + return true; + + /* +#if defined( TF_CLIENT_DLL ) + + const char *pszModelName = modelinfo->GetModelName( GetModel() ); + if ( pszModelName && pszModelName[0] ) + { + // We attach sprites directly to players in some cases, such as phase trails on an evading scout + for ( int i=0; i