//========= Copyright © 1996-2010, Valve Corporation, All rights reserved. ============// // // Purpose: global dynamic light with cascaded shadow mapping // // $NoKeywords: $ //=============================================================================// #include "cbase.h" #include "lights.h" #include "env_cascade_light.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" //#define CsmDbgMsg Msg #define CsmDbgMsg(x) ConVar cl_csm_auto_entity( "cl_csm_auto_entity", "1", 0, "" ); CCascadeLight *g_pCascadeLight; LINK_ENTITY_TO_CLASS(env_cascade_light, CCascadeLight); BEGIN_DATADESC( CCascadeLight ) DEFINE_KEYFIELD( m_bEnabled, FIELD_BOOLEAN, "enabled" ), DEFINE_KEYFIELD( m_bStartDisabled, FIELD_BOOLEAN, "StartDisabled" ), DEFINE_FIELD( m_LightColor, FIELD_COLOR32 ), DEFINE_FIELD( m_LightColorScale, FIELD_INTEGER ), // Inputs DEFINE_INPUTFUNC( FIELD_COLOR32, "LightColor", InputSetLightColor ), DEFINE_INPUTFUNC( FIELD_INTEGER, "LightColorScale", InputSetLightColorScale ), DEFINE_INPUTFUNC( FIELD_STRING, "SetAngles", InputSetAngles ), DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), END_DATADESC() IMPLEMENT_SERVERCLASS_ST_NOBASE(CCascadeLight, DT_CascadeLight) SendPropVector(SENDINFO(m_shadowDirection), -1, SPROP_NOSCALE ), SendPropVector(SENDINFO(m_envLightShadowDirection), -1, SPROP_NOSCALE ), SendPropBool(SENDINFO(m_bEnabled) ), SendPropBool(SENDINFO(m_bUseLightEnvAngles) ), SendPropInt(SENDINFO(m_LightColor), 32, SPROP_UNSIGNED, SendProxy_Color32ToInt32 ), SendPropInt(SENDINFO(m_LightColorScale), 32, 0, SendProxy_Int32ToInt32 ), SendPropFloat(SENDINFO(m_flMaxShadowDist), 0, SPROP_NOSCALE ), END_SEND_TABLE() float CCascadeLight::m_flEnvLightShadowPitch; QAngle CCascadeLight::m_EnvLightShadowAngles; bool CCascadeLight::m_bEnvLightShadowValid; color32 CCascadeLight::m_EnvLightColor; int CCascadeLight::m_EnvLightColorScale; CCascadeLight::CCascadeLight() : CBaseEntity() { CsmDbgMsg( "CCascadeLight::CCascadeLight\n" ); m_bEnabled = true; color32 tmp = { 255, 255, 255, 1 }; m_LightColor = tmp; m_LightColorScale = 255; QAngle angles; angles.Init( 50, 43, 0 ); Vector vForward; AngleVectors( angles, &vForward ); m_shadowDirection = vForward; //m_shadowDirection.Init( 0.0f, 0.0f, -1.0f ); m_envLightShadowDirection = m_shadowDirection; m_bUseLightEnvAngles = true; m_flMaxShadowDist = 400.0f; g_pCascadeLight = this; } CCascadeLight::~CCascadeLight() { g_pCascadeLight = NULL; CsmDbgMsg( "CCascadeLight::~CCascadeLight\n" ); } //------------------------------------------------------------------------------ // Purpose : Send even though we don't have a model //------------------------------------------------------------------------------ int CCascadeLight::UpdateTransmitState() { // ALWAYS transmit to all clients. return SetTransmitState( FL_EDICT_ALWAYS ); } bool CCascadeLight::KeyValue( const char *szKeyName, const char *szValue ) { if ( FStrEq( szKeyName, "color" ) ) { /* unused? float tmp[4]; UTIL_StringToFloatArray( tmp, 4, szValue ); m_LightColor.SetR( tmp[0] ); m_LightColor.SetG( tmp[1] ); m_LightColor.SetB( tmp[2] ); m_LightColor.SetA( tmp[3] );*/ } else if ( FStrEq( szKeyName, "angles" ) ) { QAngle angles; UTIL_StringToVector( angles.Base(), szValue ); if (angles == vec3_angle) { angles.Init( 50, 43, 0 ); } Vector vForward; AngleVectors( angles, &vForward ); m_shadowDirection = vForward; return true; } else if ( FStrEq( szKeyName, "uselightenvangles" ) ) { m_bUseLightEnvAngles = ( atoi( szValue ) != 0 ); return true; } else if ( FStrEq( szKeyName, "maxshadowdistance" ) ) { m_flMaxShadowDist = atof( szValue ); return true; } return BaseClass::KeyValue( szKeyName, szValue ); } bool CCascadeLight::GetKeyValue( const char *szKeyName, char *szValue, int iMaxLen ) { if ( FStrEq( szKeyName, "color" ) ) { // path unused? Q_snprintf( szValue, iMaxLen, "%d %d %d %d", m_LightColor.GetR(), m_LightColor.GetG(), m_LightColor.GetB(), m_LightColor.GetA() ); return true; } return BaseClass::GetKeyValue( szKeyName, szValue, iMaxLen ); } //------------------------------------------------------------------------------ // Purpose : //------------------------------------------------------------------------------ void CCascadeLight::Spawn( void ) { Precache(); SetSolid( SOLID_NONE ); if( m_bStartDisabled ) { m_bEnabled = false; } else { m_bEnabled = true; } if ( m_bEnvLightShadowValid ) { UpdateEnvLight(); } //SetClassname( "cascadelight" ); BaseClass::Spawn(); } void CCascadeLight::Release( void ) { g_pCascadeLight = NULL; } //------------------------------------------------------------------------------ // Purpose : //------------------------------------------------------------------------------ void CCascadeLight::OnActivate() { } //------------------------------------------------------------------------------ // Purpose : //------------------------------------------------------------------------------ void CCascadeLight::OnDeactivate() { } //------------------------------------------------------------------------------ // Input values //------------------------------------------------------------------------------ void CCascadeLight::InputSetAngles( inputdata_t &inputdata ) { const char *pAngles = inputdata.value.String(); QAngle angles; UTIL_StringToVector( angles.Base(), pAngles ); Vector vTemp; AngleVectors( angles, &vTemp ); m_shadowDirection = vTemp; } //------------------------------------------------------------------------------ // Purpose : Input handlers //------------------------------------------------------------------------------ void CCascadeLight::InputEnable( inputdata_t &inputdata ) { m_bEnabled = true; if ( g_pCascadeLight ) { g_pCascadeLight->UpdateEnvLight(); } } void CCascadeLight::InputDisable( inputdata_t &inputdata ) { m_bEnabled = false; if ( g_pCascadeLight ) { g_pCascadeLight->UpdateEnvLight(); } } void CCascadeLight::InputSetLightColor( inputdata_t &inputdata ) { m_LightColor = inputdata.value.Color32(); } void CCascadeLight::InputSetLightColorScale( inputdata_t &inputdata ) { m_LightColorScale = inputdata.value.Int(); if ( g_pCascadeLight ) { g_pCascadeLight->UpdateEnvLight(); } } void CCascadeLight::SetLightColor( int r, int g, int b, int a ) { m_EnvLightColor.r = r; m_EnvLightColor.g = g; m_EnvLightColor.b = b; m_EnvLightColor.a = 0; // use light scale as potentially > 255 m_EnvLightColorScale = a; if ( g_pCascadeLight ) { g_pCascadeLight->UpdateEnvLight(); } } void CCascadeLight::SetEnabled( bool bEnable ) { m_bEnabled = bEnable; } void CCascadeLight::UpdateEnvLight() { QAngle angles; angles.x = -m_flEnvLightShadowPitch; angles.y = m_EnvLightShadowAngles.y; angles.z = 0; Vector vForward; AngleVectors( angles, &vForward ); m_envLightShadowDirection = vForward; m_LightColor = m_EnvLightColor; m_LightColorScale = m_EnvLightColorScale; } void CCascadeLight::SetEnvLightShadowPitch( float flPitch ) { m_flEnvLightShadowPitch = flPitch; m_bEnvLightShadowValid = true; if ( g_pCascadeLight ) { g_pCascadeLight->UpdateEnvLight(); } } void CCascadeLight::SetEnvLightShadowAngles( const QAngle &angles ) { m_EnvLightShadowAngles = angles; m_bEnvLightShadowValid = true; if ( g_pCascadeLight ) { g_pCascadeLight->UpdateEnvLight(); } } class CCSMLightManager : public CAutoGameSystemPerFrame { public: CCSMLightManager() { } virtual ~CCSMLightManager() { } virtual void LevelInitPreEntity() { CsmDbgMsg( "**** LevelInitPreEntity\n" ); } virtual void LevelInitPostEntity() { CsmDbgMsg( "**** LevelInitPostEntity\n" ); if ( !cl_csm_auto_entity.GetBool() ) return; if ( g_pCascadeLight ) return; // Create the env_cascade_light automatically for cs:go - this is a hack that will hopefully go away as we add the entity to all of our maps. CBaseEntity *entity = dynamic_cast< CBaseEntity * >( CreateEntityByName( "env_cascade_light" ) ); if (entity) { entity->Precache(); entity->KeyValue( "targetname", "cascadelight" ); DispatchSpawn(entity); } } virtual void LevelShutdownPreEntity() { CsmDbgMsg( "**** LevelShutdownPreEntity\n" ); } virtual void LevelShutdownPostEntity() { CsmDbgMsg( "**** LevelShutdownPostEntity\n" ); } virtual void Shutdown() { CsmDbgMsg( "**** Shutdown\n" ); } }; CCSMLightManager g_CSMLightManager; void C_CSM_Server_Status( const CCommand& args ) { Msg( "Entity exists: %u\n", g_pCascadeLight != NULL ); } static ConCommand cl_csm_server_status("cl_csm_server_status", C_CSM_Server_Status, "Usage:\n cl_csm_server_status\n", 0);