diff options
Diffstat (limited to 'studiorender/r_studiolight.cpp')
| -rw-r--r-- | studiorender/r_studiolight.cpp | 542 |
1 files changed, 542 insertions, 0 deletions
diff --git a/studiorender/r_studiolight.cpp b/studiorender/r_studiolight.cpp new file mode 100644 index 0000000..fefc06e --- /dev/null +++ b/studiorender/r_studiolight.cpp @@ -0,0 +1,542 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//===========================================================================// + +#include "r_studiolight.h" +#include "studiorender.h" +#include "studiorendercontext.h" +#include "studio.h" +#include "materialsystem/imaterialsystemhardwareconfig.h" +#include "mathlib/vector.h" +#include "mathlib/mathlib.h" +#include <float.h> + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +void R_WorldLightDelta( const LightDesc_t *wl, const Vector& org, Vector& delta ); + + +//----------------------------------------------------------------------------- +// Copies lighting state +//----------------------------------------------------------------------------- +int CopyLocalLightingState( int nMaxLights, LightDesc_t *pDest, int nLightCount, const LightDesc_t *pSrc ) +{ + // ensure we write within array bounds + if ( nLightCount > nMaxLights ) + { + nLightCount = nMaxLights; + } + + for( int i = 0; i < nLightCount; i++ ) + { + LightDesc_t *pLight = &pDest[i]; + memcpy( pLight, &pSrc[i], sizeof( LightDesc_t ) ); + pLight->m_Flags = 0; + if( pLight->m_Attenuation0 != 0.0f ) + { + pLight->m_Flags |= LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0; + } + if( pLight->m_Attenuation1 != 0.0f ) + { + pLight->m_Flags |= LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1; + } + if( pLight->m_Attenuation2 != 0.0f ) + { + pLight->m_Flags |= LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2; + } + } + + return nLightCount; +} + + +//----------------------------------------------------------------------------- +// Computes the ambient term +//----------------------------------------------------------------------------- +void R_LightAmbient_4D( const Vector& normal, Vector4D* pLightBoxColor, Vector &lv ) +{ + VectorScale( normal[0] > 0.f ? pLightBoxColor[0].AsVector3D() : pLightBoxColor[1].AsVector3D(), normal[0]*normal[0], lv ); + VectorMA( lv, normal[1]*normal[1], normal[1] > 0.f ? pLightBoxColor[2].AsVector3D() : pLightBoxColor[3].AsVector3D(), lv ); + VectorMA( lv, normal[2]*normal[2], normal[2] > 0.f ? pLightBoxColor[4].AsVector3D() : pLightBoxColor[5].AsVector3D(), lv ); +} + +#if defined( _WIN32 ) && !defined( _X360 ) +void R_LightAmbient_4D( const FourVectors& normal, Vector4D* pLightBoxColor, FourVectors &lv ) +{ +// VPROF( "R_LightAmbient" ); + + // !!speed!! compute ambient color cube in sse format + static fltx4 FourZeros={0.,0.,0.,.0}; + + // find the contributions from each axis + fltx4 NegMask=CmpLtSIMD(normal.x,FourZeros); + fltx4 ColorSelect0=ReplicateX4(pLightBoxColor[0].AsVector3D().x); + fltx4 ColorSelect1=ReplicateX4(pLightBoxColor[1].AsVector3D().x); + fltx4 DirectionalColor=OrSIMD(AndSIMD(ColorSelect1,NegMask),AndNotSIMD(NegMask,ColorSelect0)); + fltx4 NormCompSquared=MulSIMD(normal.x,normal.x); + lv.x=MulSIMD(DirectionalColor,NormCompSquared); + ColorSelect0=ReplicateX4(pLightBoxColor[0].AsVector3D().y); + ColorSelect1=ReplicateX4(pLightBoxColor[1].AsVector3D().y); + DirectionalColor=OrSIMD(AndSIMD(ColorSelect1,NegMask),AndNotSIMD(NegMask,ColorSelect0)); + lv.y=MulSIMD(DirectionalColor,NormCompSquared); + ColorSelect0=ReplicateX4(pLightBoxColor[0].AsVector3D().z); + ColorSelect1=ReplicateX4(pLightBoxColor[1].AsVector3D().z); + DirectionalColor=OrSIMD(AndSIMD(ColorSelect1,NegMask),AndNotSIMD(NegMask,ColorSelect0)); + lv.z=MulSIMD(DirectionalColor,NormCompSquared); + + NegMask=CmpLtSIMD(normal.y,FourZeros); + ColorSelect0=ReplicateX4(pLightBoxColor[2].AsVector3D().x); + ColorSelect1=ReplicateX4(pLightBoxColor[3].AsVector3D().x); + DirectionalColor=OrSIMD(AndSIMD(ColorSelect1,NegMask),AndNotSIMD(NegMask,ColorSelect0)); + NormCompSquared=MulSIMD(normal.y,normal.y); + lv.x=AddSIMD(lv.x,MulSIMD(DirectionalColor,NormCompSquared)); + ColorSelect0=ReplicateX4(pLightBoxColor[2].AsVector3D().y); + ColorSelect1=ReplicateX4(pLightBoxColor[3].AsVector3D().y); + DirectionalColor=OrSIMD(AndSIMD(ColorSelect1,NegMask),AndNotSIMD(NegMask,ColorSelect0)); + lv.y=AddSIMD(lv.y,MulSIMD(DirectionalColor,NormCompSquared)); + ColorSelect0=ReplicateX4(pLightBoxColor[2].AsVector3D().z); + ColorSelect1=ReplicateX4(pLightBoxColor[3].AsVector3D().z); + DirectionalColor=OrSIMD(AndSIMD(ColorSelect1,NegMask),AndNotSIMD(NegMask,ColorSelect0)); + lv.z=AddSIMD(lv.z,MulSIMD(DirectionalColor,NormCompSquared)); + + NegMask=CmpLtSIMD(normal.z,FourZeros); + ColorSelect0=ReplicateX4(pLightBoxColor[4].AsVector3D().x); + ColorSelect1=ReplicateX4(pLightBoxColor[5].AsVector3D().x); + DirectionalColor=OrSIMD(AndSIMD(ColorSelect1,NegMask),AndNotSIMD(NegMask,ColorSelect0)); + NormCompSquared=MulSIMD(normal.z,normal.z); + lv.x=AddSIMD(lv.x,MulSIMD(DirectionalColor,NormCompSquared)); + ColorSelect0=ReplicateX4(pLightBoxColor[4].AsVector3D().y); + ColorSelect1=ReplicateX4(pLightBoxColor[5].AsVector3D().y); + DirectionalColor=OrSIMD(AndSIMD(ColorSelect1,NegMask),AndNotSIMD(NegMask,ColorSelect0)); + lv.y=AddSIMD(lv.y,MulSIMD(DirectionalColor,NormCompSquared)); + ColorSelect0=ReplicateX4(pLightBoxColor[4].AsVector3D().z); + ColorSelect1=ReplicateX4(pLightBoxColor[5].AsVector3D().z); + DirectionalColor=OrSIMD(AndSIMD(ColorSelect1,NegMask),AndNotSIMD(NegMask,ColorSelect0)); + lv.z=AddSIMD(lv.z,MulSIMD(DirectionalColor,NormCompSquared)); +} +#endif + + +//----------------------------------------------------------------------------- +// Computes the ambient term, parameters are 3D Vectors for optimization +//----------------------------------------------------------------------------- +void R_LightAmbient_3D( const Vector& normal, const Vector* pLightBoxColor, Vector &lv ) +{ + VectorScale( normal[0] > 0.f ? pLightBoxColor[0] : pLightBoxColor[1], normal[0]*normal[0], lv ); + VectorMA( lv, normal[1]*normal[1], normal[1] > 0.f ? pLightBoxColor[2] : pLightBoxColor[3], lv ); + VectorMA( lv, normal[2]*normal[2], normal[2] > 0.f ? pLightBoxColor[4] : pLightBoxColor[5], lv ); +} + + +//----------------------------------------------------------------------------- +// Set up light[i].dot, light[i].falloff, and light[i].delta for all lights given +// a vertex position "vert". +//----------------------------------------------------------------------------- +void R_LightStrengthWorld( const Vector& vert, int lightcount, LightDesc_t* pDesc, lightpos_t *light ) +{ +// VPROF( "R_LightStrengthWorld" ); + + // NJS: note to self, maybe switch here based on lightcount, so multiple squareroots can be done simeltaneously? + for ( int i = 0; i < lightcount; i++) + { + R_WorldLightDelta( &pDesc[i], vert, light[i].delta ); + light[i].falloff = R_WorldLightDistanceFalloff( &pDesc[i], light[i].delta ); + + VectorNormalizeFast( light[i].delta ); + light[i].dot = DotProduct( light[i].delta, pDesc[i].m_Direction ); + } +} + + +//----------------------------------------------------------------------------- +// Calculate the delta between a light and position +//----------------------------------------------------------------------------- +void R_WorldLightDelta( const LightDesc_t *wl, const Vector& org, Vector& delta ) +{ + switch (wl->m_Type) + { + case MATERIAL_LIGHT_POINT: + case MATERIAL_LIGHT_SPOT: + VectorSubtract( wl->m_Position, org, delta ); + break; + + case MATERIAL_LIGHT_DIRECTIONAL: + VectorMultiply( wl->m_Direction, -1, delta ); + break; + + default: + // Bug: need to return an error + Assert( 0 ); + break; + } +} + + +//#define NO_AMBIENT_CUBE 1 + +// TODO: cone clipping calc's wont work for boxlight since the player asks for a single point. Not sure what the volume is. +TEMPLATE_FUNCTION_TABLE( void, R_LightEffectsWorldFunctionTable, ( const LightDesc_t* pLightDesc, const lightpos_t *light, const Vector& normal, Vector &dest ), 256 ) +{ + enum + { + LightType1 = ( nArgument & 0xC0 ) >> 6, + LightType2 = ( nArgument & 0x30 ) >> 4, + LightType3 = ( nArgument & 0x0C ) >> 2, + LightType4 = ( nArgument & 0x03 ) + }; + + // VPROF( "R_LightEffectsWorld" ); + + #ifdef NO_AMBIENT_CUBE + dest[0] = dest[1] = dest[2] = 0.0f; + #endif + + // FIXME: lighting effects for normal and position are independent! + // FIXME: these can be pre-calculated per normal + if( (LightType_t)LightType1 != MATERIAL_LIGHT_DISABLE ) + { + float ratio = light[0].falloff * CWorldLightAngleWrapper<LightType1>::WorldLightAngle( &pLightDesc[0], pLightDesc[0].m_Direction, normal, light[0].delta ); + if (ratio > 0) + { + const float* pColor = (float*)&pLightDesc[0].m_Color; + dest[0] += pColor[0] * ratio; + dest[1] += pColor[1] * ratio; + dest[2] += pColor[2] * ratio; + } + } + + if( (LightType_t)LightType2 != MATERIAL_LIGHT_DISABLE ) + { + float ratio = light[1].falloff * CWorldLightAngleWrapper<LightType2>::WorldLightAngle( &pLightDesc[1], pLightDesc[1].m_Direction, normal, light[1].delta ); + if (ratio > 0) + { + const float* pColor = (float*)&pLightDesc[1].m_Color; + dest[0] += pColor[0] * ratio; + dest[1] += pColor[1] * ratio; + dest[2] += pColor[2] * ratio; + } + } + + if( (LightType_t)LightType3 != MATERIAL_LIGHT_DISABLE ) + { + float ratio = light[2].falloff * CWorldLightAngleWrapper<LightType3>::WorldLightAngle( &pLightDesc[2], pLightDesc[2].m_Direction, normal, light[2].delta ); + if (ratio > 0) + { + const float* pColor = (float*)&pLightDesc[2].m_Color; + dest[0] += pColor[0] * ratio; + dest[1] += pColor[1] * ratio; + dest[2] += pColor[2] * ratio; + } + } + + if( (LightType_t)LightType4 != MATERIAL_LIGHT_DISABLE ) + { + float ratio = light[3].falloff * CWorldLightAngleWrapper<LightType4>::WorldLightAngle( &pLightDesc[3], pLightDesc[3].m_Direction, normal, light[3].delta ); + if (ratio > 0) + { + const float* pColor = (float*)&pLightDesc[3].m_Color; + dest[0] += pColor[0] * ratio; + dest[1] += pColor[1] * ratio; + dest[2] += pColor[2] * ratio; + } + } +} + +TEMPLATE_FUNCTION_TABLE( void, R_LightEffectsWorldFunctionTableConstDirectional, ( const LightDesc_t* pLightDesc, const lightpos_t *light, const Vector& normal, Vector &dest, float flDirectionalConstant ), 256 ) +{ + enum + { + LightType1 = ( nArgument & 0xC0 ) >> 6, + LightType2 = ( nArgument & 0x30 ) >> 4, + LightType3 = ( nArgument & 0x0C ) >> 2, + LightType4 = ( nArgument & 0x03 ) + }; + + // VPROF( "R_LightEffectsWorld" ); + +#ifdef NO_AMBIENT_CUBE + dest[0] = dest[1] = dest[2] = 0.0f; +#endif + + // FIXME: lighting effects for normal and position are independent! + // FIXME: these can be pre-calculated per normal + if( (LightType_t)LightType1 != MATERIAL_LIGHT_DISABLE ) + { + float ratio = light[0].falloff * + CWorldLightAngleWrapperConstDirectional<LightType1>::WorldLightAngle( &pLightDesc[0], + pLightDesc[0].m_Direction, normal, light[0].delta, flDirectionalConstant ); + if (ratio > 0) + { + const float* pColor = (float*)&pLightDesc[0].m_Color; + dest[0] += pColor[0] * ratio; + dest[1] += pColor[1] * ratio; + dest[2] += pColor[2] * ratio; + } + } + + if( (LightType_t)LightType2 != MATERIAL_LIGHT_DISABLE ) + { + float ratio = light[1].falloff * + CWorldLightAngleWrapperConstDirectional<LightType2>::WorldLightAngle( &pLightDesc[1], + pLightDesc[1].m_Direction, normal, light[1].delta, flDirectionalConstant ); + + if (ratio > 0) + { + const float* pColor = (float*)&pLightDesc[1].m_Color; + dest[0] += pColor[0] * ratio; + dest[1] += pColor[1] * ratio; + dest[2] += pColor[2] * ratio; + } + } + + if( (LightType_t)LightType3 != MATERIAL_LIGHT_DISABLE ) + { + float ratio = light[2].falloff * + CWorldLightAngleWrapperConstDirectional<LightType3>::WorldLightAngle( &pLightDesc[2], + pLightDesc[2].m_Direction, normal, light[2].delta, flDirectionalConstant ); + + if (ratio > 0) + { + const float* pColor = (float*)&pLightDesc[2].m_Color; + dest[0] += pColor[0] * ratio; + dest[1] += pColor[1] * ratio; + dest[2] += pColor[2] * ratio; + } + } + + if( (LightType_t)LightType4 != MATERIAL_LIGHT_DISABLE ) + { + float ratio = light[3].falloff * + CWorldLightAngleWrapperConstDirectional<LightType4>::WorldLightAngle( &pLightDesc[3], + pLightDesc[3].m_Direction, normal, light[3].delta, flDirectionalConstant ); + + if (ratio > 0) + { + const float* pColor = (float*)&pLightDesc[3].m_Color; + dest[0] += pColor[0] * ratio; + dest[1] += pColor[1] * ratio; + dest[2] += pColor[2] * ratio; + } + } +} + + +//----------------------------------------------------------------------------- +// Get the function table index +//----------------------------------------------------------------------------- +static int s_pLightMask[ 5 ] = +{ + 0, // No lights + 0xC0, // 1 light + 0xF0, // 2 lights + 0xFC, // 3 lights + 0xFF, // 4 lights +}; + +inline int R_LightEffectsWorldIndex(const LightDesc_t* pLightDesc, int nNumLights) +{ + if ( nNumLights > 4 ) + { + nNumLights = 4; + } + + int nIndex = ((pLightDesc[0].m_Type & 0x3) << 6) | ((pLightDesc[1].m_Type & 0x3) << 4) | ( (pLightDesc[2].m_Type & 0x3) << 2) | (pLightDesc[3].m_Type & 0x3); + nIndex &= s_pLightMask[ nNumLights ]; + + Assert( nIndex >= 0 && nIndex < R_LightEffectsWorldFunctionTable::count ); + return nIndex; +} + + +/* + light_direction (light_pos - vertex_pos) +*/ +// TODO: move cone calcs to position +// TODO: cone clipping calc's wont work for boxlight since the player asks for a single point. Not sure what the volume is. +TEMPLATE_FUNCTION_TABLE( float, R_WorldLightDistanceFalloffFunctionTable, ( const LightDesc_t *wl, const Vector& delta ), 8) +{ + Assert( nArgument != 0 ); + + float dist2 = DotProduct( delta, delta ); + + // Cull out light beyond this radius + if (wl->m_Range != 0.f) + { + if (dist2 > wl->m_Range * wl->m_Range) + return 0.0f; + } + + // The general purpose equation: + float fTotal = FLT_EPSILON; + + if( nArgument & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0 ) + { + fTotal = wl->m_Attenuation0; + } + + if( nArgument & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1 ) + { + fTotal += wl->m_Attenuation1 * FastSqrt( dist2 ); + } + + if( nArgument & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2 ) + { + fTotal += wl->m_Attenuation2 * dist2; + } + + return 1.0f / fTotal; +} + +//----------------------------------------------------------------------------- +// Calculate the falloff from the world lights +//----------------------------------------------------------------------------- +float FASTCALL R_WorldLightDistanceFalloff( const LightDesc_t *wl, const Vector& delta ) +{ + // Ensure no invalid flags are set + Assert( ! ( wl->m_Flags & ~(LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0|LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1|LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2|LIGHTTYPE_OPTIMIZATIONFLAGS_DERIVED_VALUES_CALCED) ) ); + + // calculate falloff + int flags = wl->m_Flags & (LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0|LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1|LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2); + return R_WorldLightDistanceFalloffFunctionTable::functions[flags](wl, delta); +} + +#if defined( _WIN32 ) && !defined( _X360 ) +fltx4 FASTCALL R_WorldLightDistanceFalloff( const LightDesc_t *wl, const FourVectors &delta ) +{ + // !!speed!!: lights could store m_Attenuation2,m_Attenuation1, and m_Range^2 copies in replicated SSE format. + + // Ensure no invalid flags are set + Assert( ! ( wl->m_Flags & ~(LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0|LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1|LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2|LIGHTTYPE_OPTIMIZATIONFLAGS_DERIVED_VALUES_CALCED) ) ); + + fltx4 dist2 = delta*delta; + + fltx4 fTotal; + + if( wl->m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0 ) + { + fTotal = ReplicateX4(wl->m_Attenuation0); + } + else + fTotal= ReplicateX4(FLT_EPSILON); // !!speed!! replicate + + if( wl->m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1 ) + { + fTotal=AddSIMD(fTotal,MulSIMD(ReplicateX4(wl->m_Attenuation1),SqrtEstSIMD(dist2))); + } + + if( wl->m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2 ) + { + fTotal=AddSIMD(fTotal,MulSIMD(ReplicateX4(wl->m_Attenuation2),dist2)); + } + + fTotal=ReciprocalEstSIMD(fTotal); + // Cull out light beyond this radius + // now, zero out elements for which dist2 was > range^2. !!speed!! lights should store dist^2 in sse format + if (wl->m_Range != 0.f) + { + fltx4 RangeSquared = ReplicateX4(wl->m_Range*wl->m_Range); // !!speed!! + fTotal=AndSIMD(fTotal,CmpLtSIMD(dist2,RangeSquared)); + } + return fTotal; +} +#endif + + +int CStudioRender::R_LightGlintPosition( int index, const Vector& org, Vector& delta, Vector& intensity ) +{ + if (index >= m_pRC->m_NumLocalLights) + return false; + + R_WorldLightDelta( &m_pRC->m_LocalLights[index], org, delta ); + float falloff = R_WorldLightDistanceFalloff( &m_pRC->m_LocalLights[index], delta ); + + VectorMultiply( m_pRC->m_LocalLights[index].m_Color, falloff, intensity ); + return true; +} + + +//----------------------------------------------------------------------------- +// Setup up the function table +//----------------------------------------------------------------------------- +void CStudioRender::R_InitLightEffectsWorld3() +{ + // set the function pointer + int index = R_LightEffectsWorldIndex( m_pRC->m_LocalLights, m_pRC->m_NumLocalLights ); + R_LightEffectsWorld3 = R_LightEffectsWorldFunctionTable::functions[index]; +} + + +//----------------------------------------------------------------------------- +// Performs lighting functions common to the ComputeLighting and ComputeLightingConstantDirectional +// returns the index of the LightEffectsWorldFunction to use +//----------------------------------------------------------------------------- +static int ComputeLightingCommon( const Vector* pAmbient, int lightCount, + LightDesc_t* pLights, const Vector& pt, const Vector& normal, lightpos_t *pLightPos, Vector& lighting ) +{ + // Set up lightpos[i].dot, lightpos[i].falloff, and lightpos[i].delta for all lights + R_LightStrengthWorld( pt, lightCount, pLights, pLightPos ); + + // calculate ambient values from the ambient cube given a normal. + R_LightAmbient_3D( normal, pAmbient, lighting ); + + return R_LightEffectsWorldIndex( pLights, lightCount ); +} + + +//----------------------------------------------------------------------------- +// Compute the lighting at a point and normal +// Final Lighting is in linear space +//----------------------------------------------------------------------------- +void CStudioRenderContext::ComputeLighting( const Vector* pAmbient, int lightCount, + LightDesc_t* pLights, const Vector& pt, const Vector& normal, Vector& lighting ) +{ + if ( m_RC.m_Config.fullbright ) + { + lighting.Init( 1.0f, 1.0f, 1.0f ); + return; + } + + if ( lightCount > ARRAYSIZE( m_pLightPos ) ) + { + AssertMsg( 0, "Light count out of range in ComputeLighting\n" ); + lightCount = ARRAYSIZE( m_pLightPos ); + } + + // Calculate color given lightpos_t lightpos, a normal, and the ambient + // color from the ambient cube calculated in ComputeLightingCommon + int index = ComputeLightingCommon( pAmbient, lightCount, pLights, pt, normal, m_pLightPos, lighting ); + R_LightEffectsWorldFunctionTable::functions[index]( pLights, m_pLightPos, normal, lighting ); +} + + +//----------------------------------------------------------------------------- +// Compute the lighting at a point and normal +// Final Lighting is in linear space +// Uses flDirectionalAmount instead of directional components of lights +//----------------------------------------------------------------------------- +void CStudioRenderContext::ComputeLightingConstDirectional( const Vector* pAmbient, int lightCount, + LightDesc_t* pLights, const Vector& pt, const Vector& normal, Vector& lighting, float flDirectionalAmount ) +{ + if ( m_RC.m_Config.fullbright ) + { + lighting.Init( 1.0f, 1.0f, 1.0f ); + return; + } + + if ( lightCount > ARRAYSIZE( m_pLightPos ) ) + { + AssertMsg( 0, "Light count out of range in ComputeLighting\n" ); + lightCount = ARRAYSIZE( m_pLightPos ); + } + + // Calculate color given lightpos_t lightpos, a normal, and the ambient + // color from the ambient cube calculated in ComputeLightingCommon + int index = ComputeLightingCommon( pAmbient, lightCount, pLights, pt, normal, m_pLightPos, lighting ); + R_LightEffectsWorldFunctionTableConstDirectional::functions[index]( pLights, m_pLightPos, normal, lighting, flDirectionalAmount ); +}
\ No newline at end of file |