Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
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.

355 lines
9.4 KiB

//===== Copyright <EFBFBD> 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;
}
}
}