|
|
//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//
#include <ssemath.h>
#include <lightdesc.h>
#include "mathlib.h"
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
void LightDesc_t::RecalculateOneOverThetaDotMinusPhiDot() { float flSpread = m_ThetaDot - m_PhiDot; if ( flSpread > 1.0e-10f ) { // note - this quantity is very sensitive to round off error. the sse
// reciprocal approximation won't cut it here.
m_OneOverThetaDotMinusPhiDot = 1.0f / flSpread; } else { // hard falloff instead of divide by zero
m_OneOverThetaDotMinusPhiDot = 1.0f; } }
void LightDesc_t::RecalculateDerivedValues(void) { m_Flags = LIGHTTYPE_OPTIMIZATIONFLAGS_DERIVED_VALUES_CALCED; if ( m_Attenuation0 ) { m_Flags|=LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0; } if ( m_Attenuation1 ) { m_Flags|=LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1; } if ( m_Attenuation2 ) { m_Flags|=LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2; } if ( m_Type == MATERIAL_LIGHT_SPOT ) { m_ThetaDot = cos( m_Theta ); m_PhiDot = cos( m_Phi ); RecalculateOneOverThetaDotMinusPhiDot(); } if ( m_Type == MATERIAL_LIGHT_DIRECTIONAL ) { // set position to be real far away in the right direction
m_Position = m_Direction; m_Position *= 2.0e6; } m_RangeSquared = m_Range*m_Range; }
void LightDesc_t::ComputeLightAtPointsForDirectional( const FourVectors &pos, const FourVectors &normal, FourVectors &color, bool DoHalfLambert ) const { FourVectors delta; delta.DuplicateVector(m_Direction); // delta.VectorNormalizeFast();
fltx4 strength=delta*normal; if (DoHalfLambert) { strength=AddSIMD(MulSIMD(strength,Four_PointFives),Four_PointFives); } else strength=MaxSIMD(Four_Zeros,delta*normal); color.x=AddSIMD(color.x,MulSIMD(strength,ReplicateX4(m_Color.x))); color.y=AddSIMD(color.y,MulSIMD(strength,ReplicateX4(m_Color.y))); color.z=AddSIMD(color.z,MulSIMD(strength,ReplicateX4(m_Color.z))); }
float LightDesc_t::DistanceAtWhichBrightnessIsLessThan( float flAmount ) const { float bright = m_Color.Length(); if ( bright > 0.0 ) { flAmount /= m_Color.Length(); // calculate terms for quadratic equation
float a = flAmount * m_Attenuation2; float b = flAmount * m_Attenuation1; float c = flAmount * m_Attenuation0 - 1; float r0, r1; if ( SolveQuadratic( a, b, c, r0, r1 ) ) { float rslt = MAX( 0, MAX( r0, r1 ) ); #ifdef _DEBUG
if ( rslt > 0.0 ) { float fltest = 1.0 / ( m_Attenuation0 + rslt * m_Attenuation1 + rslt * rslt * m_Attenuation2 ); Assert( fabs( fltest - flAmount ) < 0.1 ); } #endif
return rslt; } } return 0; }
void LightDesc_t::ComputeLightAtPoints( const FourVectors &pos, const FourVectors &normal, FourVectors &color, bool DoHalfLambert ) const { FourVectors delta; Assert((m_Type==MATERIAL_LIGHT_POINT) || (m_Type==MATERIAL_LIGHT_SPOT) || (m_Type==MATERIAL_LIGHT_DIRECTIONAL)); switch (m_Type) { case MATERIAL_LIGHT_POINT: case MATERIAL_LIGHT_SPOT: delta.DuplicateVector(m_Position); delta-=pos; break; case MATERIAL_LIGHT_DIRECTIONAL: ComputeLightAtPointsForDirectional( pos, normal, color, DoHalfLambert ); return; }
fltx4 dist2 = delta*delta;
dist2=MaxSIMD( Four_Ones, dist2 );
fltx4 falloff;
if( m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0 ) { falloff = ReplicateX4(m_Attenuation0); } else falloff= Four_Epsilons;
if( m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1 ) { falloff=AddSIMD(falloff,MulSIMD(ReplicateX4(m_Attenuation1),SqrtEstSIMD(dist2))); }
if( m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2 ) { falloff=AddSIMD(falloff,MulSIMD(ReplicateX4(m_Attenuation2),dist2)); }
falloff=ReciprocalEstSIMD(falloff); // 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 (m_Range != 0.f) { fltx4 RangeSquared=ReplicateX4(m_RangeSquared); // !!speed!!
falloff=AndSIMD(falloff,CmpLtSIMD(dist2,RangeSquared)); }
delta.VectorNormalizeFast(); fltx4 strength=delta*normal; if (DoHalfLambert) { strength=AddSIMD(MulSIMD(strength,Four_PointFives),Four_PointFives); } else strength=MaxSIMD(Four_Zeros,delta*normal); switch(m_Type) { case MATERIAL_LIGHT_POINT: // half-lambert
break; case MATERIAL_LIGHT_SPOT: { fltx4 dot2=SubSIMD(Four_Zeros,delta*m_Direction); // dot position with spot light dir for cone falloff
fltx4 cone_falloff_scale=MulSIMD(ReplicateX4(m_OneOverThetaDotMinusPhiDot), SubSIMD(dot2,ReplicateX4(m_PhiDot))); cone_falloff_scale=MinSIMD(cone_falloff_scale,Four_Ones); if ((m_Falloff!=0.0) && (m_Falloff!=1.0)) { // !!speed!! could compute integer exponent needed by powsimd and store in light
cone_falloff_scale=PowSIMD(cone_falloff_scale,m_Falloff); } strength=MulSIMD(cone_falloff_scale,strength);
// now, zero out lighting where dot2<phidot. This will mask out any invalid results
// from pow function, etc
bi32x4 OutsideMask=CmpGtSIMD(dot2,ReplicateX4(m_PhiDot)); // outside light cone?
strength=AndSIMD(OutsideMask,strength); } break;
} strength=MulSIMD(strength,falloff); color.x=AddSIMD(color.x,MulSIMD(strength,ReplicateX4(m_Color.x))); color.y=AddSIMD(color.y,MulSIMD(strength,ReplicateX4(m_Color.y))); color.z=AddSIMD(color.z,MulSIMD(strength,ReplicateX4(m_Color.z))); }
void LightDesc_t::ComputeNonincidenceLightAtPoints( const FourVectors &pos, FourVectors &color ) const { FourVectors delta; Assert((m_Type==MATERIAL_LIGHT_POINT) || (m_Type==MATERIAL_LIGHT_SPOT) || (m_Type==MATERIAL_LIGHT_DIRECTIONAL)); switch (m_Type) { case MATERIAL_LIGHT_POINT: case MATERIAL_LIGHT_SPOT: delta.DuplicateVector(m_Position); delta-=pos; break; case MATERIAL_LIGHT_DIRECTIONAL: return; }
fltx4 dist2 = delta*delta;
dist2=MaxSIMD( Four_Ones, dist2 );
fltx4 falloff;
if( m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0 ) { falloff = ReplicateX4(m_Attenuation0); } else falloff= Four_Epsilons;
if( m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1 ) { falloff=AddSIMD(falloff,MulSIMD(ReplicateX4(m_Attenuation1),SqrtEstSIMD(dist2))); }
if( m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2 ) { falloff=AddSIMD(falloff,MulSIMD(ReplicateX4(m_Attenuation2),dist2)); }
falloff=ReciprocalEstSIMD(falloff); // 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 (m_Range != 0.f) { fltx4 RangeSquared=ReplicateX4(m_RangeSquared); // !!speed!!
falloff=AndSIMD(falloff,CmpLtSIMD(dist2,RangeSquared)); }
delta.VectorNormalizeFast(); fltx4 strength = Four_Ones; //fltx4 strength=delta;
//fltx4 strength = MaxSIMD(Four_Zeros,delta);
switch(m_Type) { case MATERIAL_LIGHT_POINT: // half-lambert
break; case MATERIAL_LIGHT_SPOT: { fltx4 dot2=SubSIMD(Four_Zeros,delta*m_Direction); // dot position with spot light dir for cone falloff
fltx4 cone_falloff_scale=MulSIMD(ReplicateX4(m_OneOverThetaDotMinusPhiDot), SubSIMD(dot2,ReplicateX4(m_PhiDot))); cone_falloff_scale=MinSIMD(cone_falloff_scale,Four_Ones); if ((m_Falloff!=0.0) && (m_Falloff!=1.0)) { // !!speed!! could compute integer exponent needed by powsimd and store in light
cone_falloff_scale=PowSIMD(cone_falloff_scale,m_Falloff); } strength=MulSIMD(cone_falloff_scale,strength);
// now, zero out lighting where dot2<phidot. This will mask out any invalid results
// from pow function, etc
bi32x4 OutsideMask=CmpGtSIMD(dot2,ReplicateX4(m_PhiDot)); // outside light cone?
strength=AndSIMD(OutsideMask,strength); } break;
} strength=MulSIMD(strength,falloff); color.x=AddSIMD(color.x,MulSIMD(strength,ReplicateX4(m_Color.x))); color.y=AddSIMD(color.y,MulSIMD(strength,ReplicateX4(m_Color.y))); color.z=AddSIMD(color.z,MulSIMD(strength,ReplicateX4(m_Color.z))); }
void LightDesc_t::SetupOldStyleAttenuation( float fQuadraticAttn, float fLinearAttn, float fConstantAttn ) { // old-style manually typed quadrtiac coefficients
if ( fQuadraticAttn < EQUAL_EPSILON ) fQuadraticAttn = 0; if ( fLinearAttn < EQUAL_EPSILON) fLinearAttn = 0; if ( fConstantAttn < EQUAL_EPSILON) fConstantAttn = 0; if ( ( fConstantAttn < EQUAL_EPSILON ) && ( fLinearAttn < EQUAL_EPSILON ) && ( fQuadraticAttn < EQUAL_EPSILON ) ) fConstantAttn = 1;
m_Attenuation2=fQuadraticAttn; m_Attenuation1=fLinearAttn; m_Attenuation0=fConstantAttn; float fScaleFactor = fQuadraticAttn * 10000 + fLinearAttn * 100 + fConstantAttn; if ( fScaleFactor > 0 ) m_Color *= fScaleFactor; }
void LightDesc_t::SetupNewStyleAttenuation( float fFiftyPercentDistance, float fZeroPercentDistance ) { // new style storing 50% and 0% distances
float d50=fFiftyPercentDistance; float d0=fZeroPercentDistance; if (d0<d50) { // !!warning in lib code???!!!
Warning("light has _fifty_percent_distance of %f but no zero_percent_distance\n",d50); d0=2.0*d50; } float a=0,b=1,c=0; if (! SolveInverseQuadraticMonotonic(0,1.0,d50,2.0,d0,256.0,a,b,c)) { Warning("can't solve quadratic for light %f %f\n",d50,d0); } float v50=c+d50*(b+d50*a); float scale=2.0/v50; a*=scale; b*=scale; c*=scale; m_Attenuation2=a; m_Attenuation1=b; m_Attenuation0=c; }
|