240 lines
7.0 KiB
C++
240 lines
7.0 KiB
C++
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose: Dynamic light
|
|
//
|
|
// $Workfile: $
|
|
// $Date: $
|
|
// $NoKeywords: $
|
|
//=============================================================================//
|
|
#include "cbase.h"
|
|
#include "dlight.h"
|
|
#include "iefx.h"
|
|
#include "IViewRender.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
|
|
#if HL2_EPISODIC
|
|
// In Episodic we unify the NO_WORLD_ILLUMINATION lights to use
|
|
// the more efficient elight structure instead. This should theoretically
|
|
// be extended to other projects but may have unintended consequences
|
|
// and bears more thorough testing.
|
|
//
|
|
// For an earlier iteration on this technique see changelist 214433,
|
|
// which had a specific flag for use of elights.
|
|
#define DLIGHT_NO_WORLD_USES_ELIGHT 1
|
|
#endif
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// A dynamic light, with the goofy hack needed for spotlights
|
|
//-----------------------------------------------------------------------------
|
|
class C_DynamicLight : public C_BaseEntity
|
|
{
|
|
public:
|
|
DECLARE_CLASS( C_DynamicLight, C_BaseEntity );
|
|
DECLARE_CLIENTCLASS();
|
|
|
|
C_DynamicLight();
|
|
|
|
public:
|
|
void OnDataChanged(DataUpdateType_t updateType);
|
|
bool ShouldDraw();
|
|
void ClientThink( void );
|
|
void Release( void );
|
|
|
|
unsigned char m_Flags;
|
|
unsigned char m_LightStyle;
|
|
|
|
float m_Radius;
|
|
int m_Exponent;
|
|
float m_InnerAngle;
|
|
float m_OuterAngle;
|
|
float m_SpotRadius;
|
|
|
|
private:
|
|
dlight_t* m_pDynamicLight;
|
|
dlight_t* m_pSpotlightEnd;
|
|
|
|
|
|
inline bool ShouldBeElight() { return (m_Flags & DLIGHT_NO_WORLD_ILLUMINATION); }
|
|
};
|
|
|
|
IMPLEMENT_CLIENTCLASS_DT(C_DynamicLight, DT_DynamicLight, CDynamicLight)
|
|
RecvPropInt (RECVINFO(m_Flags)),
|
|
RecvPropInt (RECVINFO(m_LightStyle)),
|
|
RecvPropFloat (RECVINFO(m_Radius)),
|
|
RecvPropInt (RECVINFO(m_Exponent)),
|
|
RecvPropFloat (RECVINFO(m_InnerAngle)),
|
|
RecvPropFloat (RECVINFO(m_OuterAngle)),
|
|
RecvPropFloat (RECVINFO(m_SpotRadius)),
|
|
END_RECV_TABLE()
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose :
|
|
//------------------------------------------------------------------------------
|
|
C_DynamicLight::C_DynamicLight(void) : m_pSpotlightEnd(0), m_pDynamicLight(0)
|
|
{
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose :
|
|
//------------------------------------------------------------------------------
|
|
void C_DynamicLight::OnDataChanged(DataUpdateType_t updateType)
|
|
{
|
|
if ( updateType == DATA_UPDATE_CREATED )
|
|
{
|
|
SetNextClientThink(gpGlobals->curtime + 0.05);
|
|
}
|
|
|
|
BaseClass::OnDataChanged( updateType );
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose :
|
|
//------------------------------------------------------------------------------
|
|
bool C_DynamicLight::ShouldDraw()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose : Disable drawing of this light when entity perishes
|
|
//------------------------------------------------------------------------------
|
|
void C_DynamicLight::Release()
|
|
{
|
|
if (m_pDynamicLight)
|
|
{
|
|
m_pDynamicLight->die = gpGlobals->curtime;
|
|
m_pDynamicLight = 0;
|
|
}
|
|
|
|
if (m_pSpotlightEnd)
|
|
{
|
|
m_pSpotlightEnd->die = gpGlobals->curtime;
|
|
m_pSpotlightEnd = 0;
|
|
}
|
|
|
|
BaseClass::Release();
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose :
|
|
//------------------------------------------------------------------------------
|
|
void C_DynamicLight::ClientThink(void)
|
|
{
|
|
Vector forward;
|
|
AngleVectors( GetAbsAngles(), &forward );
|
|
|
|
if ( (m_Flags & DLIGHT_NO_MODEL_ILLUMINATION) == 0 )
|
|
{
|
|
// Deal with the model light
|
|
if ( !m_pDynamicLight || (m_pDynamicLight->key != index) )
|
|
{
|
|
#if DLIGHT_NO_WORLD_USES_ELIGHT
|
|
m_pDynamicLight = ShouldBeElight() != 0
|
|
? effects->CL_AllocElight( index )
|
|
: effects->CL_AllocDlight( index );
|
|
#else
|
|
m_pDynamicLight = effects->CL_AllocDlight( index );
|
|
#endif
|
|
Assert (m_pDynamicLight);
|
|
m_pDynamicLight->minlight = 0;
|
|
}
|
|
|
|
m_pDynamicLight->style = m_LightStyle;
|
|
m_pDynamicLight->radius = m_Radius;
|
|
m_pDynamicLight->flags = m_Flags;
|
|
if ( m_OuterAngle > 0 )
|
|
m_pDynamicLight->flags |= DLIGHT_NO_WORLD_ILLUMINATION;
|
|
color24 c = GetRenderColor();
|
|
m_pDynamicLight->color.r = c.r;
|
|
m_pDynamicLight->color.g = c.g;
|
|
m_pDynamicLight->color.b = c.b;
|
|
m_pDynamicLight->color.exponent = m_Exponent; // this makes it match the world
|
|
m_pDynamicLight->origin = GetAbsOrigin();
|
|
m_pDynamicLight->m_InnerAngle = m_InnerAngle;
|
|
m_pDynamicLight->m_OuterAngle = m_OuterAngle;
|
|
m_pDynamicLight->die = gpGlobals->curtime + 1e6;
|
|
m_pDynamicLight->m_Direction = forward;
|
|
}
|
|
else
|
|
{
|
|
// In this case, the m_Flags could have changed; which is how we turn the light off
|
|
if (m_pDynamicLight)
|
|
{
|
|
m_pDynamicLight->die = gpGlobals->curtime;
|
|
m_pDynamicLight = 0;
|
|
}
|
|
}
|
|
|
|
#if DLIGHT_NO_WORLD_USES_ELIGHT
|
|
if (( m_OuterAngle > 0 ) && !ShouldBeElight())
|
|
#else
|
|
if (( m_OuterAngle > 0 ) && ((m_Flags & DLIGHT_NO_WORLD_ILLUMINATION) == 0))
|
|
#endif
|
|
{
|
|
// Raycast to where the endpoint goes
|
|
// Deal with the environment light
|
|
if ( !m_pSpotlightEnd || (m_pSpotlightEnd->key != -index) )
|
|
{
|
|
m_pSpotlightEnd = effects->CL_AllocDlight( -index );
|
|
Assert (m_pSpotlightEnd);
|
|
}
|
|
|
|
// Trace a line outward, don't use hitboxes (too slow)
|
|
Vector end;
|
|
VectorMA( GetAbsOrigin(), m_Radius, forward, end );
|
|
|
|
trace_t pm;
|
|
C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace
|
|
UTIL_TraceLine( GetAbsOrigin(), end, MASK_NPCWORLDSTATIC, NULL, COLLISION_GROUP_NONE, &pm );
|
|
C_BaseEntity::PopEnableAbsRecomputations();
|
|
VectorCopy( pm.endpos, m_pSpotlightEnd->origin );
|
|
|
|
if (pm.fraction == 1.0f)
|
|
{
|
|
m_pSpotlightEnd->die = gpGlobals->curtime;
|
|
m_pSpotlightEnd = 0;
|
|
}
|
|
else
|
|
{
|
|
float falloff = 1.0 - pm.fraction;
|
|
falloff *= falloff;
|
|
|
|
m_pSpotlightEnd->style = m_LightStyle;
|
|
m_pSpotlightEnd->flags = DLIGHT_NO_MODEL_ILLUMINATION | (m_Flags & DLIGHT_DISPLACEMENT_MASK);
|
|
m_pSpotlightEnd->radius = m_SpotRadius; // * falloff;
|
|
m_pSpotlightEnd->die = gpGlobals->curtime + 1e6;
|
|
color24 c = GetRenderColor();
|
|
m_pSpotlightEnd->color.r = c.r * falloff;
|
|
m_pSpotlightEnd->color.g = c.g * falloff;
|
|
m_pSpotlightEnd->color.b = c.b * falloff;
|
|
m_pSpotlightEnd->color.exponent = m_Exponent;
|
|
|
|
// For bumped lighting
|
|
m_pSpotlightEnd->m_Direction = forward;
|
|
|
|
// Update list of surfaces we influence
|
|
render->TouchLight( m_pSpotlightEnd );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// In this case, the m_Flags could have changed; which is how we turn the light off
|
|
if (m_pSpotlightEnd)
|
|
{
|
|
m_pSpotlightEnd->die = gpGlobals->curtime;
|
|
m_pSpotlightEnd = 0;
|
|
}
|
|
}
|
|
|
|
SetNextClientThink(gpGlobals->curtime + 0.001);
|
|
}
|
|
|