You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
354 lines
9.4 KiB
354 lines
9.4 KiB
//===== 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; |
|
}; |
|
|
|
LINK_ENTITY_TO_CLASS( beam_spotlight, C_BeamSpotLight ); |
|
|
|
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() |
|
|
|
//----------------------------------------------------------------------------- |
|
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; |
|
} |
|
} |
|
} |
|
|
|
|