//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Implements visual effects entities: sprites, beams, bubbles, etc. // // $NoKeywords: $ //=============================================================================// #include "cbase.h" #include "Sprite.h" #include "model_types.h" #include "engine/ivmodelinfo.h" #include "tier0/vprof.h" #include "engine/ivdebugoverlay.h" #if defined( CLIENT_DLL ) #include "enginesprite.h" #include "iclientmode.h" #include "c_baseviewmodel.h" # ifdef PORTAL #include "c_prop_portal.h" # endif //ifdef PORTAL #else #include "baseviewmodel.h" #endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" const float MAX_SPRITE_SCALE = 64.0f; const float MAX_GLOW_PROXY_SIZE = 64.0f; LINK_ENTITY_TO_CLASS( env_sprite, CSprite ); LINK_ENTITY_TO_CLASS( env_sprite_oriented, CSpriteOriented ); #if !defined( CLIENT_DLL ) LINK_ENTITY_TO_CLASS( env_glow, CSprite ); // For backwards compatibility, remove when no longer needed. #endif #if !defined( CLIENT_DLL ) BEGIN_DATADESC( CSprite ) DEFINE_FIELD( m_flLastTime, FIELD_TIME ), DEFINE_FIELD( m_flMaxFrame, FIELD_FLOAT ), DEFINE_FIELD( m_hAttachedToEntity, FIELD_EHANDLE ), DEFINE_FIELD( m_nAttachment, FIELD_INTEGER ), DEFINE_FIELD( m_flDieTime, FIELD_TIME ), DEFINE_FIELD( m_nBrightness, FIELD_INTEGER ), DEFINE_FIELD( m_flBrightnessTime, FIELD_FLOAT ), DEFINE_KEYFIELD( m_flSpriteScale, FIELD_FLOAT, "scale" ), DEFINE_KEYFIELD( m_flSpriteFramerate, FIELD_FLOAT, "framerate" ), DEFINE_KEYFIELD( m_flFrame, FIELD_FLOAT, "frame" ), #ifdef PORTAL DEFINE_FIELD( m_bDrawInMainRender, FIELD_BOOLEAN ), DEFINE_FIELD( m_bDrawInPortalRender, FIELD_BOOLEAN ), #endif DEFINE_KEYFIELD( m_flHDRColorScale, FIELD_FLOAT, "HDRColorScale" ), DEFINE_KEYFIELD( m_flGlowProxySize, FIELD_FLOAT, "GlowProxySize" ), DEFINE_FIELD( m_flScaleTime, FIELD_FLOAT ), DEFINE_FIELD( m_flStartScale, FIELD_FLOAT ), DEFINE_FIELD( m_flDestScale, FIELD_FLOAT ), DEFINE_FIELD( m_flScaleTimeStart, FIELD_TIME ), DEFINE_FIELD( m_nStartBrightness, FIELD_INTEGER ), DEFINE_FIELD( m_nDestBrightness, FIELD_INTEGER ), DEFINE_FIELD( m_flBrightnessTimeStart, FIELD_TIME ), DEFINE_FIELD( m_bWorldSpaceScale, FIELD_BOOLEAN ), // Function Pointers DEFINE_FUNCTION( AnimateThink ), DEFINE_FUNCTION( ExpandThink ), DEFINE_FUNCTION( AnimateUntilDead ), DEFINE_FUNCTION( BeginFadeOutThink ), // Inputs DEFINE_INPUT( m_flSpriteScale, FIELD_FLOAT, "SetScale" ), DEFINE_INPUTFUNC( FIELD_VOID, "HideSprite", InputHideSprite ), DEFINE_INPUTFUNC( FIELD_VOID, "ShowSprite", InputShowSprite ), DEFINE_INPUTFUNC( FIELD_VOID, "ToggleSprite", InputToggleSprite ), DEFINE_INPUTFUNC( FIELD_FLOAT, "ColorRedValue", InputColorRedValue ), DEFINE_INPUTFUNC( FIELD_FLOAT, "ColorGreenValue", InputColorGreenValue ), DEFINE_INPUTFUNC( FIELD_FLOAT, "ColorBlueValue", InputColorBlueValue ), END_DATADESC() #else BEGIN_PREDICTION_DATA( CSprite ) // Networked DEFINE_PRED_FIELD( m_hAttachedToEntity, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_nAttachment, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_flScaleTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_flSpriteScale, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_flSpriteFramerate, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_flFrame, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), #ifdef PORTAL DEFINE_PRED_FIELD( m_bDrawInMainRender, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_bDrawInPortalRender, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), #endif DEFINE_PRED_FIELD( m_flBrightnessTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_nBrightness, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), DEFINE_FIELD( m_flLastTime, FIELD_FLOAT ), DEFINE_FIELD( m_flMaxFrame, FIELD_FLOAT ), DEFINE_FIELD( m_flDieTime, FIELD_FLOAT ), // DEFINE_FIELD( m_flHDRColorScale, FIELD_FLOAT ), // DEFINE_FIELD( m_flStartScale, FIELD_FLOAT ), //Starting scale // DEFINE_FIELD( m_flDestScale, FIELD_FLOAT ), //Destination scale // DEFINE_FIELD( m_flScaleTimeStart, FIELD_FLOAT ), //Real time for start of scale // DEFINE_FIELD( m_nStartBrightness, FIELD_INTEGER ), //Starting brightness // DEFINE_FIELD( m_nDestBrightness, FIELD_INTEGER ), //Destination brightness // DEFINE_FIELD( m_flBrightnessTimeStart, FIELD_FLOAT ), //Real time for brightness END_PREDICTION_DATA() #endif IMPLEMENT_NETWORKCLASS_ALIASED( Sprite, DT_Sprite ); #if defined( CLIENT_DLL ) static void RecvProxy_SpriteScale( const CRecvProxyData *pData, void *pStruct, void *pOut ) { ((CSprite*)pStruct)->SetSpriteScale( pData->m_Value.m_Float ); } #endif BEGIN_NETWORK_TABLE( CSprite, DT_Sprite ) #if !defined( CLIENT_DLL ) SendPropEHandle( SENDINFO(m_hAttachedToEntity )), SendPropInt( SENDINFO(m_nAttachment ), 8 ), SendPropFloat( SENDINFO(m_flScaleTime ), 0, SPROP_NOSCALE ), #ifdef HL2_DLL SendPropFloat( SENDINFO(m_flSpriteScale ), 0, SPROP_NOSCALE), #else SendPropFloat( SENDINFO(m_flSpriteScale ), 8, SPROP_ROUNDUP, 0.0f, MAX_SPRITE_SCALE), #endif SendPropFloat( SENDINFO(m_flGlowProxySize ), 6, SPROP_ROUNDUP, 0.0f, MAX_GLOW_PROXY_SIZE), SendPropFloat( SENDINFO(m_flHDRColorScale ), 0, SPROP_NOSCALE, 0.0f, 100.0f), SendPropFloat( SENDINFO(m_flSpriteFramerate ), 8, SPROP_ROUNDUP, 0, 60.0f), SendPropFloat( SENDINFO(m_flFrame), 20, SPROP_ROUNDDOWN, 0.0f, 256.0f), #ifdef PORTAL SendPropBool( SENDINFO(m_bDrawInMainRender) ), SendPropBool( SENDINFO(m_bDrawInPortalRender) ), #endif //#ifdef PORTAL SendPropFloat( SENDINFO(m_flBrightnessTime ), 0, SPROP_NOSCALE ), SendPropInt( SENDINFO(m_nBrightness), 8, SPROP_UNSIGNED ), SendPropBool( SENDINFO(m_bWorldSpaceScale) ), #else RecvPropEHandle(RECVINFO(m_hAttachedToEntity)), RecvPropInt(RECVINFO(m_nAttachment)), RecvPropFloat(RECVINFO(m_flScaleTime)), RecvPropFloat(RECVINFO(m_flSpriteScale), 0, RecvProxy_SpriteScale), RecvPropFloat(RECVINFO(m_flSpriteFramerate)), RecvPropFloat(RECVINFO(m_flGlowProxySize)), RecvPropFloat( RECVINFO(m_flHDRColorScale )), RecvPropFloat(RECVINFO(m_flFrame)), #ifdef PORTAL RecvPropBool( RECVINFO(m_bDrawInMainRender) ), RecvPropBool( RECVINFO(m_bDrawInPortalRender) ), #endif //#ifdef PORTAL RecvPropFloat(RECVINFO(m_flBrightnessTime)), RecvPropInt(RECVINFO(m_nBrightness)), RecvPropBool( RECVINFO(m_bWorldSpaceScale) ), #endif END_NETWORK_TABLE() CSprite::CSprite() { m_flGlowProxySize = 2.0f; m_flHDRColorScale = 1.0f; #ifdef PORTAL m_bDrawInMainRender = true; m_bDrawInPortalRender = true; #endif } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CSprite::Spawn( void ) { SetSolid( SOLID_NONE ); SetMoveType( MOVETYPE_NONE ); m_flFrame = 0; Precache(); SetModel( STRING( GetModelName() ) ); CollisionProp()->SetSurroundingBoundsType( USE_GAME_CODE ); m_flMaxFrame = (float)modelinfo->GetModelFrameCount( GetModel() ) - 1; AddEffects( EF_NOSHADOW | EF_NORECEIVESHADOW ); #if defined( CLIENT_DLL ) SetNextClientThink( CLIENT_THINK_ALWAYS ); #endif #if !defined( CLIENT_DLL ) if ( GetEntityName() != NULL_STRING && !(m_spawnflags & SF_SPRITE_STARTON) ) { TurnOff(); } else #endif { TurnOn(); } // Worldcraft only sets y rotation, copy to Z if ( GetLocalAngles().y != 0 && GetLocalAngles().z == 0 ) { QAngle angles = GetLocalAngles(); angles.z = angles.y; angles.y = 0; SetLocalAngles( angles ); } // Clamp our scale if necessary float scale = m_flSpriteScale; if ( scale < 0 || scale > MAX_SPRITE_SCALE ) { #if !defined( CLIENT_DLL ) DevMsg( "LEVEL DESIGN ERROR: Sprite %s with bad scale %f [0..%f]\n", GetDebugName(), m_flSpriteScale.Get(), MAX_SPRITE_SCALE ); #endif scale = clamp( (float) m_flSpriteScale, 0.f, MAX_SPRITE_SCALE ); } //Set our state SetBrightness( m_clrRender->a ); SetScale( scale ); #if defined( CLIENT_DLL ) m_flStartScale = m_flDestScale = m_flSpriteScale; m_nStartBrightness = m_nDestBrightness = m_nBrightness; #endif } //----------------------------------------------------------------------------- // Purpose: Initialize absmin & absmax to the appropriate box //----------------------------------------------------------------------------- void CSprite::EnableWorldSpaceScale( bool bEnable ) { m_bWorldSpaceScale = bEnable; } //----------------------------------------------------------------------------- // Purpose: Initialize absmin & absmax to the appropriate box //----------------------------------------------------------------------------- void CSprite::ComputeWorldSpaceSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ) { float flScale = m_flSpriteScale * 0.5f; if ( m_bWorldSpaceScale == false ) { // Find the height and width of the source of the sprite float width = modelinfo->GetModelSpriteWidth( GetModel() ); float height = modelinfo->GetModelSpriteHeight( GetModel() ); flScale *= MAX( width, height ); } pVecWorldMins->Init( -flScale, -flScale, -flScale ); pVecWorldMaxs->Init( flScale, flScale, flScale ); *pVecWorldMins += GetAbsOrigin(); *pVecWorldMaxs += GetAbsOrigin(); } //----------------------------------------------------------------------------- // Purpose: // Input : *szModelName - //----------------------------------------------------------------------------- void CSprite::SetModel( const char *szModelName ) { int index_ = modelinfo->GetModelIndex( szModelName ); const model_t *pModel = modelinfo->GetModel( index_ ); if ( pModel && modelinfo->GetModelType( pModel ) != mod_sprite ) { Msg( "Setting CSprite to non-sprite model %s\n", szModelName?szModelName:"NULL" ); } #if !defined( CLIENT_DLL ) UTIL_SetModel( this, szModelName ); #else BaseClass::SetModel( szModelName ); #endif } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CSprite::Precache( void ) { if ( GetModelName() != NULL_STRING ) { PrecacheModel( STRING( GetModelName() ) ); } } //----------------------------------------------------------------------------- // Purpose: // Input : *pSpriteName - // &origin - //----------------------------------------------------------------------------- void CSprite::SpriteInit( const char *pSpriteName, const Vector &origin ) { SetModelName( MAKE_STRING(pSpriteName) ); SetLocalOrigin( origin ); Spawn(); } #if !defined( CLIENT_DLL ) int CSprite::UpdateTransmitState( void ) { if ( GetMoveParent() ) { // we must call ShouldTransmit() if we have a move parent return SetTransmitState( FL_EDICT_FULLCHECK ); } else { return SetTransmitState( FL_EDICT_ALWAYS ); } } int CSprite::ShouldTransmit( const CCheckTransmitInfo *pInfo ) { // Certain entities like sprites and ropes are strewn throughout the level and they rarely change. // For these entities, it's more efficient to transmit them once and then always leave them on // the client. Otherwise, the server will have to send big bursts of data with the entity states // as they come in and out of the PVS. if ( GetMoveParent() ) { CBaseViewModel *pViewModel = dynamic_cast( GetMoveParent() ); if ( pViewModel ) { return pViewModel->ShouldTransmit( pInfo ); } } return FL_EDICT_ALWAYS; } //----------------------------------------------------------------------------- // Purpose: Fixup parent after restore //----------------------------------------------------------------------------- void CSprite::OnRestore() { BaseClass::OnRestore(); // Reset attachment after save/restore if ( GetFollowedEntity() ) { SetAttachment( GetFollowedEntity(), m_nAttachment ); } else { // Clear attachment m_hAttachedToEntity = NULL; m_nAttachment = 0; } } //----------------------------------------------------------------------------- // Purpose: // Input : *pSpriteName - // &origin - // animate - // Output : CSprite //----------------------------------------------------------------------------- CSprite *CSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, bool animate ) { CSprite *pSprite = CREATE_ENTITY( CSprite, "env_sprite" ); pSprite->SpriteInit( pSpriteName, origin ); pSprite->SetSolid( SOLID_NONE ); UTIL_SetSize( pSprite, vec3_origin, vec3_origin ); pSprite->SetMoveType( MOVETYPE_NONE ); if ( animate ) pSprite->TurnOn(); return pSprite; } #endif //----------------------------------------------------------------------------- // Purpose: // Input : *pSpriteName - // &origin - // animate - // Output : CSprite //----------------------------------------------------------------------------- CSprite *CSprite::SpriteCreatePredictable( const char *module, int line, const char *pSpriteName, const Vector &origin, bool animate ) { CSprite *pSprite = ( CSprite * )CBaseEntity::CreatePredictedEntityByName( "env_sprite", module, line ); if ( pSprite ) { pSprite->SpriteInit( pSpriteName, origin ); pSprite->SetSolid( SOLID_NONE ); pSprite->SetSize( vec3_origin, vec3_origin ); pSprite->SetMoveType( MOVETYPE_NONE ); if ( animate ) pSprite->TurnOn(); } return pSprite; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CSprite::AnimateThink( void ) { Animate( m_flSpriteFramerate * (gpGlobals->curtime - m_flLastTime) ); SetNextThink( gpGlobals->curtime ); m_flLastTime = gpGlobals->curtime; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CSprite::AnimateUntilDead( void ) { if ( gpGlobals->curtime > m_flDieTime ) { Remove( ); } else { AnimateThink(); SetNextThink( gpGlobals->curtime ); } } //----------------------------------------------------------------------------- // Purpose: // Input : scaleSpeed - // fadeSpeed - //----------------------------------------------------------------------------- void CSprite::Expand( float scaleSpeed, float fadeSpeed ) { m_flSpeed = scaleSpeed; m_iHealth = fadeSpeed; SetThink( &CSprite::ExpandThink ); SetNextThink( gpGlobals->curtime ); m_flLastTime = gpGlobals->curtime; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CSprite::ExpandThink( void ) { float frametime = gpGlobals->curtime - m_flLastTime; SetSpriteScale( m_flSpriteScale + m_flSpeed * frametime ); int sub = (int)(m_iHealth * frametime); if ( sub > m_clrRender->a ) { SetRenderColorA( 0 ); Remove( ); } else { SetRenderColorA( m_clrRender->a - sub ); SetNextThink( gpGlobals->curtime ); m_flLastTime = gpGlobals->curtime; } } //----------------------------------------------------------------------------- // Purpose: // Input : frames - //----------------------------------------------------------------------------- void CSprite::Animate( float frames ) { m_flFrame += frames; if ( m_flFrame > m_flMaxFrame ) { #if !defined( CLIENT_DLL ) if ( m_spawnflags & SF_SPRITE_ONCE ) { TurnOff(); } else #endif { if ( m_flMaxFrame > 0 ) m_flFrame = fmod( m_flFrame, m_flMaxFrame ); } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CSprite::SetBrightness( int brightness, float time ) { m_nBrightness = brightness; //Take our current position as our starting position m_flBrightnessTime = time; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CSprite::SetSpriteScale( float scale ) { if ( scale != m_flSpriteScale ) { m_flSpriteScale = scale; //Take our current position as our new starting position // The surrounding box is based on sprite scale... it changes, box is dirty CollisionProp()->MarkSurroundingBoundsDirty(); } } void CSprite::SetScale( float scale, float time ) { m_flScaleTime = time; SetSpriteScale( scale ); // The surrounding box is based on sprite scale... it changes, box is dirty } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CSprite::TurnOff( void ) { AddEffects( EF_NODRAW ); SetNextThink( TICK_NEVER_THINK ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CSprite::TurnOn( void ) { RemoveEffects( EF_NODRAW ); if ( (m_flSpriteFramerate && m_flMaxFrame > 1.0) #if !defined( CLIENT_DLL ) || (m_spawnflags & SF_SPRITE_ONCE) #endif ) { SetThink( &CSprite::AnimateThink ); SetNextThink( gpGlobals->curtime ); m_flLastTime = gpGlobals->curtime; } m_flFrame = 0; } #if !defined( CLIENT_DLL ) // DVS TODO: Obsolete Use handler void CSprite::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { int on = !IsEffectActive( EF_NODRAW ); if ( ShouldToggle( useType, on ) ) { if ( on ) { TurnOff(); } else { TurnOn(); } } } //----------------------------------------------------------------------------- // Purpose: Input handler that hides the sprite. //----------------------------------------------------------------------------- void CSprite::InputHideSprite( inputdata_t &inputdata ) { TurnOff(); } //----------------------------------------------------------------------------- // Purpose: Input handler that hides the sprite. //----------------------------------------------------------------------------- void CSprite::InputShowSprite( inputdata_t &inputdata ) { TurnOn(); } void CSprite::InputColorRedValue( inputdata_t &inputdata ) { int nNewColor = clamp( FastFloatToSmallInt( inputdata.value.Float() ), 0, 255 ); SetColor( nNewColor, m_clrRender->g, m_clrRender->b ); } void CSprite::InputColorGreenValue( inputdata_t &inputdata ) { int nNewColor = clamp( FastFloatToSmallInt( inputdata.value.Float() ), 0, 255 ); SetColor( m_clrRender->r, nNewColor, m_clrRender->b ); } void CSprite::InputColorBlueValue( inputdata_t &inputdata ) { int nNewColor = clamp( FastFloatToSmallInt( inputdata.value.Float() ), 0, 255 ); SetColor( m_clrRender->r, m_clrRender->g, nNewColor ); } //----------------------------------------------------------------------------- // Purpose: Input handler that toggles the sprite between hidden and shown. //----------------------------------------------------------------------------- void CSprite::InputToggleSprite( inputdata_t &inputdata ) { if ( !IsEffectActive( EF_NODRAW ) ) { TurnOff(); } else { TurnOn(); } } #endif #if defined( CLIENT_DLL ) //----------------------------------------------------------------------------- // Purpose: // Output : float //----------------------------------------------------------------------------- float CSprite::GetRenderScale( void ) { //See if we're done scaling if ( ( m_flScaleTime == 0 ) || ( (m_flScaleTimeStart+m_flScaleTime) < gpGlobals->curtime ) ) return m_flSpriteScale; //Get our percentage float timeDelta = ( gpGlobals->curtime - m_flScaleTimeStart ) / m_flScaleTime; //Return the result return ( m_flStartScale + ( ( m_flDestScale - m_flStartScale ) * timeDelta ) ); } //----------------------------------------------------------------------------- // Purpose: Get the rendered extents of the sprite //----------------------------------------------------------------------------- void CSprite::GetRenderBounds( Vector &vecMins, Vector &vecMaxs ) { float flScale = GetRenderScale() * 0.5f; // If our scale is normalized we need to convert that to actual world units if ( m_bWorldSpaceScale == false ) { CEngineSprite *psprite = (CEngineSprite *) modelinfo->GetModelExtraData( GetModel() ); if ( psprite ) { float flSize = MAX( psprite->GetWidth(), psprite->GetHeight() ); flScale *= flSize; } } vecMins.Init( -flScale, -flScale, -flScale ); vecMaxs.Init( flScale, flScale, flScale ); #if 0 // Visualize the bounds if ( debugoverlay ) { debugoverlay->AddBoxOverlay( GetRenderOrigin(), vecMins, vecMaxs, GetRenderAngles(), 255, 255, 255, 0, 0.01f ); } #endif } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int CSprite::GetRenderBrightness( void ) { //See if we're done scaling if ( ( m_flBrightnessTime == 0 ) || ( (m_flBrightnessTimeStart+m_flBrightnessTime) < gpGlobals->curtime ) ) { return m_nBrightness; } //Get our percentage float timeDelta = ( gpGlobals->curtime - m_flBrightnessTimeStart ) / m_flBrightnessTime; float brightness = ( (float) m_nStartBrightness + ( (float) ( m_nDestBrightness - m_nStartBrightness ) * timeDelta ) ); //Return the result return (int) brightness; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CSprite::OnDataChanged( DataUpdateType_t updateType ) { BaseClass::OnDataChanged( updateType ); // Only think when sapping SetNextClientThink( CLIENT_THINK_ALWAYS ); if ( updateType == DATA_UPDATE_CREATED ) { m_flStartScale = m_flDestScale = m_flSpriteScale; m_nStartBrightness = m_nDestBrightness = m_nBrightness; } UpdateVisibility(); } void CSprite::ClientThink( void ) { BaseClass::ClientThink(); // Module render colors over time if ( m_flSpriteScale != m_flDestScale ) { m_flStartScale = m_flDestScale; m_flDestScale = m_flSpriteScale; m_flScaleTimeStart = gpGlobals->curtime; } if ( m_nBrightness != m_nDestBrightness ) { m_nStartBrightness = m_nDestBrightness; m_nDestBrightness = m_nBrightness; m_flBrightnessTimeStart = gpGlobals->curtime; } } extern bool g_bRenderingScreenshot; extern ConVar r_drawviewmodel; //----------------------------------------------------------------------------- // Purpose: // Input : flags - // Output : int //----------------------------------------------------------------------------- int CSprite::DrawModel( int flags ) { VPROF_BUDGET( "CSprite::DrawModel", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); //See if we should draw if ( !IsVisible() || ( m_bReadyToDraw == false ) ) return 0; #ifdef PORTAL if ( ( !g_pPortalRender->IsRenderingPortal() && !m_bDrawInMainRender ) || ( g_pPortalRender->IsRenderingPortal() && !m_bDrawInPortalRender ) ) { return 0; } #endif //#ifdef PORTAL // Tracker 16432: If rendering a savegame screenshot then don't draw sprites // who have viewmodels as their moveparent if ( g_bRenderingScreenshot || !r_drawviewmodel.GetBool() ) { C_BaseViewModel *vm = dynamic_cast< C_BaseViewModel * >( GetMoveParent() ); if ( vm ) { return 0; } } //Must be a sprite if ( modelinfo->GetModelType( GetModel() ) != mod_sprite ) { Assert( 0 ); return 0; } float renderscale = GetRenderScale(); if ( m_bWorldSpaceScale ) { CEngineSprite *psprite = ( CEngineSprite * )modelinfo->GetModelExtraData( GetModel() ); float flMinSize = MIN( psprite->GetWidth(), psprite->GetHeight() ); renderscale /= flMinSize; } //Draw it int drawn = DrawSprite( this, GetModel(), GetAbsOrigin(), GetAbsAngles(), m_flFrame, // sprite frame to render m_hAttachedToEntity, // attach to m_nAttachment, // attachment point GetRenderMode(), // rendermode m_nRenderFX, GetRenderBrightness(), // alpha m_clrRender->r, m_clrRender->g, m_clrRender->b, renderscale, // sprite scale GetHDRColorScale() // HDR Color Scale ); return drawn; } const Vector& CSprite::GetRenderOrigin() { 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; } #endif //----------------------------------------------------------------------------- // Purpose: oriented sprites // CSprites swap the roll and yaw angle inputs, and rotate the yaw 180 degrees //----------------------------------------------------------------------------- #if !defined( CLIENT_DLL ) IMPLEMENT_SERVERCLASS_ST( CSpriteOriented, DT_SpriteOriented ) END_SEND_TABLE() #else #undef CSpriteOriented IMPLEMENT_CLIENTCLASS_DT(C_SpriteOriented, DT_SpriteOriented, CSpriteOriented) #define CSpriteOriented C_SpriteOriented END_RECV_TABLE() #endif #if !defined( CLIENT_DLL ) void CSpriteOriented::Spawn( void ) { // save a copy of the angles, CSprite swaps the yaw and roll QAngle angles = GetAbsAngles(); BaseClass::Spawn(); // ORIENTED sprites "forward" vector points in the players "view" direction, not the direction "out" from the sprite (gah) angles.y = anglemod( angles.y + 180 ); SetAbsAngles( angles ); } #else bool CSpriteOriented::IsTransparent( void ) { return true; } #endif