Skip to content

Instantly share code, notes, and snippets.

@Kolesias123
Created January 16, 2015 23:16
Show Gist options
  • Save Kolesias123/a2c6f8b8afef08b952d6 to your computer and use it in GitHub Desktop.
Save Kolesias123/a2c6f8b8afef08b952d6 to your computer and use it in GitHub Desktop.
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Sunlight shadow control entity.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "c_baseplayer.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern ConVar r_flashlightdepthres;
extern ConVar r_flashlightdepthreshigh;
//====================================================================
// Comandos
//====================================================================
ConVar cl_globallight_freeze( "cl_globallight_freeze", "0" );
ConVar cl_globallight_xoffset( "cl_globallight_xoffset", "0" );
ConVar cl_globallight_yoffset( "cl_globallight_yoffset", "0" );
ConVar cl_globallight_off("cl_globallight_off", "0");
ConVar mat_shadow_level( "mat_shadow_level", "3", FCVAR_ARCHIVE );
//====================================================================
// Purpose : Sunlights shadow control entity
//====================================================================
class C_GlobalLight : public C_BaseEntity
{
public:
DECLARE_CLASS( C_GlobalLight, C_BaseEntity );
DECLARE_CLIENTCLASS();
C_GlobalLight();
~C_GlobalLight();
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual void Spawn();
virtual bool ShouldDraw();
virtual void ClientThink();
virtual FlashlightState_t PrepareLight();
private:
int m_iLightID;
Vector m_shadowDirection;
bool m_bEnabled;
char m_TextureName[ MAX_PATH ];
CTextureReference m_SpotlightTexture;
color32 m_LightColor;
Vector m_CurrentLinearFloatLightColor;
float m_flCurrentLinearFloatLightAlpha;
float m_flColorTransitionTime;
float m_flSunDistance;
float m_flFOV;
float m_flNearZ;
float m_flNorthOffset;
bool m_bEnableShadows;
bool m_bOldEnableShadows;
ClientShadowHandle_t m_nLightHandle;
};
//====================================================================
// Información y Red
//====================================================================
IMPLEMENT_CLIENTCLASS_DT( C_GlobalLight, DT_GlobalLight, CGlobalLight )
RecvPropInt( RECVINFO(m_iLightID) ),
RecvPropVector(RECVINFO(m_shadowDirection)),
RecvPropBool(RECVINFO(m_bEnabled)),
RecvPropString(RECVINFO(m_TextureName)),
RecvPropInt(RECVINFO(m_LightColor), 0, RecvProxy_Int32ToColor32),
RecvPropFloat(RECVINFO(m_flColorTransitionTime)),
RecvPropFloat(RECVINFO(m_flSunDistance)),
RecvPropFloat(RECVINFO(m_flFOV)),
RecvPropFloat(RECVINFO(m_flNearZ)),
RecvPropFloat(RECVINFO(m_flNorthOffset)),
RecvPropBool(RECVINFO(m_bEnableShadows)),
END_RECV_TABLE()
//====================================================================
// Constructor
//====================================================================
C_GlobalLight::C_GlobalLight()
{
m_nLightHandle = CLIENTSHADOW_INVALID_HANDLE;
}
//====================================================================
// Destructor
//====================================================================
C_GlobalLight::~C_GlobalLight()
{
// Debemos apagar y destruir la luz
if ( m_nLightHandle != CLIENTSHADOW_INVALID_HANDLE )
{
g_pClientShadowMgr->DestroyFlashlight( m_nLightHandle );
m_nLightHandle = CLIENTSHADOW_INVALID_HANDLE;
}
}
//====================================================================
//====================================================================
void C_GlobalLight::OnDataChanged( DataUpdateType_t updateType )
{
// Iniciamos la textura a proyectar
if ( updateType == DATA_UPDATE_CREATED )
m_SpotlightTexture.Init( m_TextureName, TEXTURE_GROUP_OTHER, true );
BaseClass::OnDataChanged( updateType );
}
//====================================================================
// Creación
//====================================================================
void C_GlobalLight::Spawn()
{
BaseClass::Spawn();
m_bOldEnableShadows = m_bEnableShadows;
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
//====================================================================
// We don't draw...
//====================================================================
bool C_GlobalLight::ShouldDraw()
{
return false;
}
//====================================================================
//====================================================================
void C_GlobalLight::ClientThink()
{
VPROF("C_GlobalLight::ClientThink");
// ¿Debemos quitar las sombras estaticas?
bool bSupressShadows = false;
// Congelado
// TODO: ¿Quitar esta opción en el cliente?
if ( cl_globallight_freeze.GetBool() )
return;
// Queremos desactivar todas las luces dinamicas
if ( mat_shadow_level.GetInt() <= 0 || (m_iLightID >= mat_shadow_level.GetInt() && cl_globallight_off.GetBool()) )
{
if ( m_nLightHandle != CLIENTSHADOW_INVALID_HANDLE )
{
g_pClientShadowMgr->DestroyFlashlight( m_nLightHandle );
m_nLightHandle = CLIENTSHADOW_INVALID_HANDLE;
}
g_pClientShadowMgr->SetShadowsDisabled( bSupressShadows );
g_pClientShadowMgr->SetShadowFromWorldLightsEnabled( true );
return;
}
if ( m_bEnabled )
{
Vector vLinearFloatLightColor( m_LightColor.r, m_LightColor.g, m_LightColor.b );
float flLinearFloatLightAlpha = m_LightColor.a;
if ( m_CurrentLinearFloatLightColor != vLinearFloatLightColor || m_flCurrentLinearFloatLightAlpha != flLinearFloatLightAlpha )
{
float flColorTransitionSpeed = gpGlobals->frametime * m_flColorTransitionTime * 255.0f;
m_CurrentLinearFloatLightColor.x = Approach( vLinearFloatLightColor.x, m_CurrentLinearFloatLightColor.x, flColorTransitionSpeed );
m_CurrentLinearFloatLightColor.y = Approach( vLinearFloatLightColor.y, m_CurrentLinearFloatLightColor.y, flColorTransitionSpeed );
m_CurrentLinearFloatLightColor.z = Approach( vLinearFloatLightColor.z, m_CurrentLinearFloatLightColor.z, flColorTransitionSpeed );
m_flCurrentLinearFloatLightAlpha = Approach( flLinearFloatLightAlpha, m_flCurrentLinearFloatLightAlpha, flColorTransitionSpeed );
}
// Calculamos la dirección de las sombras y la ubicación de la luz
Vector vDirection = m_shadowDirection;
VectorNormalize( vDirection );
Vector vSunDirection2D = vDirection;
vSunDirection2D.z = 0.0f;
HACK_GETLOCALPLAYER_GUARD( "C_GlobalLight::ClientThink" );
if ( !C_BasePlayer::GetLocalPlayer() )
return;
Vector vPos;
QAngle EyeAngles;
float flZNear, flZFar, flFov;
C_BasePlayer::GetLocalPlayer()->CalcView( vPos, EyeAngles, flZNear, flZFar, flFov );
vPos = ( vPos + vSunDirection2D * m_flNorthOffset ) - vDirection * m_flSunDistance;
vPos += Vector( cl_globallight_xoffset.GetFloat(), cl_globallight_yoffset.GetFloat(), 0.0f );
QAngle angAngles;
VectorAngles( vDirection, angAngles );
Vector vForward, vRight, vUp;
AngleVectors( angAngles, &vForward, &vRight, &vUp );
// Configuramos la luz
FlashlightState_t state = PrepareLight();
state.m_vecLightOrigin = vPos;
//
BasisToQuaternion( vForward, vRight, vUp, state.m_quatOrientation );
// Se ha desactivado o activado las sombras
if ( m_bOldEnableShadows != m_bEnableShadows )
{
// Debemos recrear la luz actual
if ( m_nLightHandle != CLIENTSHADOW_INVALID_HANDLE )
{
g_pClientShadowMgr->DestroyFlashlight( m_nLightHandle );
m_nLightHandle = CLIENTSHADOW_INVALID_HANDLE;
}
m_bOldEnableShadows = m_bEnableShadows;
}
// Debemos crear la luz
if ( m_nLightHandle == CLIENTSHADOW_INVALID_HANDLE )
{
m_nLightHandle = g_pClientShadowMgr->CreateFlashlight( state );
}
else
{
// Ya esta creada, la actualizamos
g_pClientShadowMgr->UpdateFlashlightState( m_nLightHandle, state );
g_pClientShadowMgr->UpdateProjectedTexture( m_nLightHandle, true );
}
bSupressShadows = m_bEnableShadows;
}
else if ( m_nLightHandle != CLIENTSHADOW_INVALID_HANDLE )
{
g_pClientShadowMgr->DestroyFlashlight( m_nLightHandle );
m_nLightHandle = CLIENTSHADOW_INVALID_HANDLE;
}
// Si hay una luz global con sombras en tiempo real, entonces será mejor desactivar las sombras estaticas
g_pClientShadowMgr->SetShadowsDisabled( bSupressShadows );
//
BaseClass::ClientThink();
}
//====================================================================
// Devuelve la configuración para la luz
//====================================================================
FlashlightState_t C_GlobalLight::PrepareLight()
{
ConVarRef r_flashlightshadowatten("r_flashlightshadowatten");
ConVarRef r_projectedtexture_filter("r_projectedtexture_filter");
ConVarRef r_flashlightdrawfrustum("r_flashlightdrawfrustum");
FlashlightState_t state;
state.m_bDrawShadowFrustum = r_flashlightdrawfrustum.GetBool();
state.m_fQuadraticAtten = 0.0f;
state.m_fConstantAtten = 0.0f;
state.m_fLinearAtten = m_flSunDistance * 2.0f;//m_LightColor.a;
state.m_FarZAtten = m_flSunDistance * 2.0f;
state.m_fHorizontalFOVDegrees = 5.0f;
state.m_fVerticalFOVDegrees = 5.0f;
// Color de la luz
state.m_Color[0] = m_CurrentLinearFloatLightColor.x * ( 1.0f / 255.0f ) * m_flCurrentLinearFloatLightAlpha;
state.m_Color[1] = m_CurrentLinearFloatLightColor.y * ( 1.0f / 255.0f ) * m_flCurrentLinearFloatLightAlpha;
state.m_Color[2] = m_CurrentLinearFloatLightColor.z * ( 1.0f / 255.0f ) * m_flCurrentLinearFloatLightAlpha;
state.m_Color[3] = 0.0f;
// Distancia y brillo
state.m_NearZ = 4.0f;
state.m_FarZ = m_flSunDistance * 2.0f;
state.m_fBrightnessScale = 1.0f;
state.m_bGlobalLight = true;
// Ortho Light
state.m_bOrtho = true;
state.m_fOrthoLeft = -m_flFOV;
state.m_fOrthoTop = -m_flFOV;
state.m_fOrthoRight = m_flFOV;
state.m_fOrthoBottom = m_flFOV;
//
state.m_pSpotlightTexture = m_SpotlightTexture;
state.m_pProjectedMaterial = NULL;
state.m_nSpotlightTextureFrame = 0;
// Propiedades de las sombras generadas
state.m_bEnableShadows = m_bEnableShadows;
state.m_flShadowAtten = r_flashlightshadowatten.GetFloat();
state.m_flShadowSlopeScaleDepthBias = g_pMaterialSystemHardwareConfig->GetShadowSlopeScaleDepthBias();
state.m_flShadowDepthBias = g_pMaterialSystemHardwareConfig->GetShadowDepthBias();
state.m_bShadowHighRes = true;
state.m_nShadowQuality = 1;
{
// Es la primera luz, debe tener mayor calidad en las sombras
if ( m_iLightID == 1 )
{
state.m_flShadowFilterSize = r_projectedtexture_filter.GetFloat();
}
else
{
state.m_flShadowFilterSize = ( r_projectedtexture_filter.GetFloat() + (0.1f*m_iLightID) );
}
// mat_shadow_level 1 = 2+ luz en 1K
// mat_shadow_level 0 = Todas en 1K
// 3+ = 1K
if ( m_iLightID >= mat_shadow_level.GetInt() )
{
state.m_bShadowHighRes = false;
state.m_nShadowQuality = 0;
}
// Iván: Por ahora queremos Juegos de gama baja
if ( m_iLightID > (mat_shadow_level.GetInt()+1) )
{
state.m_bEnableShadows = false;
}
}
return state;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment