|
|
//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//
#include "cbase.h"
#include "dlight.h"
#include "iefx.h"
#include "beam_shared.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CSpotlightTraceCacheEntry { public: CSpotlightTraceCacheEntry() { m_origin.Init(); m_radius = -1.0f; } bool IsValidFor( const Vector &origin ) { if ( m_radius > 0 && m_origin.DistToSqr(origin) < 1.0f ) return true; return false; } void Cache( const Vector &origin, const trace_t &tr ) { m_radius = (tr.endpos - origin).Length(); m_origin = origin; }
Vector m_origin; float m_radius; };
static const int NUM_CACHE_ENTRIES = 64;
class C_BeamSpotLight : public C_BaseEntity { public: DECLARE_CLASS( C_BeamSpotLight, C_BaseEntity ); DECLARE_CLIENTCLASS();
C_BeamSpotLight(); ~C_BeamSpotLight();
bool ShouldDraw(); void ClientThink( void ); void OnDataChanged( DataUpdateType_t updateType ); void Release( void );
private:
Vector SpotlightCurrentPos(void); void SpotlightCreate(void); void SpotlightDestroy(void);
// Computes render info for a spotlight
void ComputeRenderInfo();
private:
int m_nHaloIndex; int m_nRotationAxis; float m_flRotationSpeed;
bool m_bSpotlightOn; bool m_bHasDynamicLight;
float m_flSpotlightMaxLength; float m_flSpotlightGoalWidth; float m_flHDRColorScale;
Vector m_vSpotlightTargetPos; Vector m_vSpotlightCurrentPos; Vector m_vSpotlightDir;
CHandle<C_Beam> m_hSpotlight; float m_flSpotlightCurLength;
float m_flLightScale;
dlight_t* m_pDynamicLight;
float m_lastTime; CSpotlightTraceCacheEntry *m_pCache; };
IMPLEMENT_CLIENTCLASS_DT( C_BeamSpotLight, DT_BeamSpotlight, CBeamSpotlight ) RecvPropInt( RECVINFO(m_nHaloIndex) ), RecvPropBool( RECVINFO(m_bSpotlightOn) ), RecvPropBool( RECVINFO(m_bHasDynamicLight) ), RecvPropFloat( RECVINFO(m_flSpotlightMaxLength) ), RecvPropFloat( RECVINFO(m_flSpotlightGoalWidth) ), RecvPropFloat( RECVINFO(m_flHDRColorScale) ), RecvPropInt( RECVINFO(m_nRotationAxis) ), RecvPropFloat( RECVINFO(m_flRotationSpeed) ), END_RECV_TABLE()
LINK_ENTITY_TO_CLASS( beam_spotlight, C_BeamSpotLight );
//-----------------------------------------------------------------------------
C_BeamSpotLight::C_BeamSpotLight() : m_vSpotlightTargetPos( vec3_origin ) , m_vSpotlightCurrentPos( vec3_origin ) , m_vSpotlightDir( vec3_origin ) , m_flSpotlightCurLength( 0.0f ) , m_flLightScale( 100.0f ) , m_pDynamicLight( NULL ) , m_lastTime( 0.0f ) , m_pCache(NULL) { }
C_BeamSpotLight::~C_BeamSpotLight() { delete[] m_pCache; }
//-----------------------------------------------------------------------------
bool C_BeamSpotLight::ShouldDraw() { return false; }
//-----------------------------------------------------------------------------
void C_BeamSpotLight::ClientThink( void ) { float dt = gpGlobals->curtime - m_lastTime; if ( !m_lastTime ) { dt = 0.0f; } m_lastTime = gpGlobals->curtime;
// ---------------------------------------------------
// If I don't have a spotlight attempt to create one
// ---------------------------------------------------
if ( !m_hSpotlight ) { if ( m_bSpotlightOn ) { // Make the spotlight
SpotlightCreate(); } else { SetNextClientThink( CLIENT_THINK_NEVER ); return; } } else if ( !m_bSpotlightOn ) { SpotlightDestroy(); SetNextClientThink( CLIENT_THINK_NEVER ); return; }
// update rotation
if ( m_flRotationSpeed != 0.0f ) { QAngle angles = GetAbsAngles(); angles[m_nRotationAxis] += m_flRotationSpeed * dt; angles[m_nRotationAxis] = anglemod(angles[m_nRotationAxis]); if ( !m_pCache ) { m_pCache = new CSpotlightTraceCacheEntry[NUM_CACHE_ENTRIES]; }
SetAbsAngles( angles ); } m_vSpotlightCurrentPos = SpotlightCurrentPos();
Assert( m_hSpotlight );
m_hSpotlight->SetStartPos( GetAbsOrigin() ); m_hSpotlight->SetEndPos( m_vSpotlightCurrentPos );
// Avoid sudden change in where beam fades out when cross disconinuities
Vector dir = m_vSpotlightCurrentPos - GetAbsOrigin(); float flBeamLength = VectorNormalize( dir ); m_flSpotlightCurLength = (0.60*m_flSpotlightCurLength) + (0.4*flBeamLength);
ComputeRenderInfo();
m_hSpotlight->RelinkBeam();
//NDebugOverlay::Cross3D(GetAbsOrigin(),Vector(-5,-5,-5),Vector(5,5,5),0,255,0,true,0.1);
//NDebugOverlay::Cross3D(m_vSpotlightCurrentPos,Vector(-5,-5,-5),Vector(5,5,5),0,255,0,true,0.1);
//NDebugOverlay::Cross3D(m_vSpotlightTargetPos,Vector(-5,-5,-5),Vector(5,5,5),255,0,0,true,0.1);
// Do we need to keep updating?
if ( !GetMoveParent() && m_flRotationSpeed == 0 ) { // No reason to think again, we're not going to move unless there's a data change
SetNextClientThink( CLIENT_THINK_NEVER ); } }
//-----------------------------------------------------------------------------
void C_BeamSpotLight::OnDataChanged( DataUpdateType_t updateType ) { BaseClass::OnDataChanged( updateType ); if ( updateType == DATA_UPDATE_CREATED ) { m_flSpotlightCurLength = m_flSpotlightMaxLength; }
// On a data change always think again
SetNextClientThink( CLIENT_THINK_ALWAYS ); }
//------------------------------------------------------------------------------
void C_BeamSpotLight::Release() { SpotlightDestroy(); BaseClass::Release(); }
//------------------------------------------------------------------------------
void C_BeamSpotLight::SpotlightCreate(void) { m_vSpotlightTargetPos = SpotlightCurrentPos();
{ //C_Beam *beam = CBeam::BeamCreate( "sprites/spotlight.vmt", m_flSpotlightGoalWidth );
C_Beam *beam = C_Beam::BeamCreate( "sprites/glow_test02.vmt", m_flSpotlightGoalWidth ); // Beam only exists client side
ClientEntityList().AddNonNetworkableEntity( beam ); m_hSpotlight = beam; }
// Set the temporary spawnflag on the beam so it doesn't save (we'll recreate it on restore)
m_hSpotlight->SetHDRColorScale( m_flHDRColorScale ); const color24 c = GetRenderColor(); m_hSpotlight->SetColor( c.r, c.g, c.b ); m_hSpotlight->SetHaloTexture(m_nHaloIndex); m_hSpotlight->SetHaloScale(60); m_hSpotlight->SetEndWidth(m_flSpotlightGoalWidth); m_hSpotlight->SetBeamFlags( (FBEAM_SHADEOUT|FBEAM_NOTILE) ); m_hSpotlight->SetBrightness( 64 ); m_hSpotlight->SetNoise( 0 );
m_hSpotlight->PointsInit( GetAbsOrigin(), m_vSpotlightTargetPos ); }
//------------------------------------------------------------------------------
void C_BeamSpotLight::SpotlightDestroy(void) { if ( m_hSpotlight ) { UTIL_Remove( m_hSpotlight ); m_hSpotlight.Term(); } }
//------------------------------------------------------------------------------
Vector C_BeamSpotLight::SpotlightCurrentPos(void) { QAngle angles = GetAbsAngles(); GetVectors( &m_vSpotlightDir, NULL, NULL ); Vector position = GetAbsOrigin(); int cacheIndex = -1; if ( m_pCache ) { cacheIndex = int( angles[m_nRotationAxis] * float(NUM_CACHE_ENTRIES) * (1.0f / 360.0f)) & (NUM_CACHE_ENTRIES - 1); if ( m_pCache[cacheIndex].IsValidFor(GetAbsOrigin()) ) { return position + m_vSpotlightDir * m_pCache[cacheIndex].m_radius; } }
// Get beam end point. Only collide with solid objects, not npcs
trace_t tr; UTIL_TraceLine( position, position + (m_vSpotlightDir * 2 * m_flSpotlightMaxLength), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr ); if ( cacheIndex >= 0 ) { m_pCache[cacheIndex].Cache(position, tr); }
return tr.endpos; }
//-----------------------------------------------------------------------------
// Computes render info for a spotlight
//-----------------------------------------------------------------------------
void C_BeamSpotLight::ComputeRenderInfo() { // Fade out spotlight end if past max length.
if ( m_flSpotlightCurLength > 2*m_flSpotlightMaxLength ) { SetRenderAlpha( 0 ); m_hSpotlight->SetFadeLength( m_flSpotlightMaxLength ); } else if ( m_flSpotlightCurLength > m_flSpotlightMaxLength ) { SetRenderAlpha( (1-((m_flSpotlightCurLength-m_flSpotlightMaxLength)/m_flSpotlightMaxLength)) ); m_hSpotlight->SetFadeLength( m_flSpotlightMaxLength ); } else { SetRenderAlpha( 1.0 ); m_hSpotlight->SetFadeLength( m_flSpotlightCurLength ); }
// Adjust end width to keep beam width constant
float flNewWidth = m_flSpotlightGoalWidth * (m_flSpotlightCurLength / m_flSpotlightMaxLength); flNewWidth = clamp(flNewWidth, 0, MAX_BEAM_WIDTH ); m_hSpotlight->SetEndWidth(flNewWidth);
if ( m_bHasDynamicLight ) { // <<TODO>> - magic number 1.8 depends on sprite size
m_flLightScale = 1.8*flNewWidth;
if ( m_flLightScale > 0 ) { const color24 c = GetRenderColor(); float a = GetRenderAlpha() / 255.0f; ColorRGBExp32 color; color.r = c.r * a; color.g = c.g * a; color.b = c.b * a; color.exponent = 0; if ( color.r == 0 && color.g == 0 && color.b == 0 ) return; // Deal with the environment light
if ( !m_pDynamicLight || (m_pDynamicLight->key != index) ) { m_pDynamicLight = effects->CL_AllocDlight( index ); assert (m_pDynamicLight); } //m_pDynamicLight->flags = DLIGHT_NO_MODEL_ILLUMINATION;
m_pDynamicLight->radius = m_flLightScale*3.0f; m_pDynamicLight->origin = GetAbsOrigin() + Vector(0,0,5); m_pDynamicLight->die = gpGlobals->curtime + 0.05f; m_pDynamicLight->color = color; } } }
|