274 lines
7.5 KiB
C++
274 lines
7.5 KiB
C++
#include "CLight.h"
|
|
#include <cmath>
|
|
#include <float.h>
|
|
#include <Core/CGraphics.h>
|
|
|
|
#define CLIGHT_NO_RADIUS 0x40
|
|
#define CLIGHT_NO_INTENSITY 0x80
|
|
|
|
CLight::CLight()
|
|
{
|
|
mPosition = skDefaultLightPos;
|
|
mDirection = skDefaultLightDir;
|
|
mDistAttenCoefficients = CVector3f(0.f, 1.f, 0.f);
|
|
mAngleAttenCoefficients = CVector3f(0.f, 1.f, 0.f);
|
|
mRadius = 0.f;
|
|
mIntensity = 0.f;
|
|
mFlags = CLIGHT_NO_RADIUS | CLIGHT_NO_INTENSITY;
|
|
}
|
|
|
|
// ************ DATA MANIPULATION ************
|
|
|
|
// This function is reverse engineered from the kiosk demo's code
|
|
float CLight::CalculateRadius()
|
|
{
|
|
if ((mDistAttenCoefficients.y >= FLT_EPSILON) ||
|
|
(mDistAttenCoefficients.z >= FLT_EPSILON))
|
|
{
|
|
float Intensity = GetIntensity();
|
|
|
|
if (mDistAttenCoefficients.z > FLT_EPSILON)
|
|
{
|
|
if (Intensity <= FLT_EPSILON)
|
|
return 0.f;
|
|
|
|
float IntensityMod = (Intensity * 5.f / 255.f * mDistAttenCoefficients.z);
|
|
return sqrt(Intensity / IntensityMod);
|
|
}
|
|
|
|
else
|
|
{
|
|
if (mDistAttenCoefficients.y <= FLT_EPSILON)
|
|
return 0.f;
|
|
|
|
float IntensityMod = (Intensity * 5.f) / 255.f;
|
|
if (IntensityMod < 0.2f)
|
|
IntensityMod = 0.2f;
|
|
|
|
return Intensity / (IntensityMod * mDistAttenCoefficients.y);
|
|
}
|
|
}
|
|
|
|
else return 3000000000000000000000000000000000000.f;
|
|
}
|
|
|
|
// This function is also reverse engineered from the kiosk demo's code
|
|
float CLight::CalculateIntensity()
|
|
{
|
|
float Multiplier = (mType == eCustom) ? mAngleAttenCoefficients.x : 1.0f;
|
|
float ColorR = float(mColor.r) / 255.f;
|
|
float ColorG = float(mColor.g) / 255.f;
|
|
float ColorB = float(mColor.b) / 255.f;
|
|
|
|
// Get the color component with the greatest numeric value
|
|
float Greatest = (ColorG >= ColorB) ? ColorG : ColorB;
|
|
Greatest = (ColorR >= Greatest) ? ColorR : Greatest;
|
|
|
|
return Greatest * Multiplier;
|
|
}
|
|
|
|
// As is this one... partly
|
|
CVector3f CLight::CalculateSpotAngleAtten()
|
|
{
|
|
if (mType != eSpot) return CVector3f(1.f, 0.f, 0.f);
|
|
|
|
if ((mSpotCutoff < 0.f) || (mSpotCutoff > 90.f))
|
|
return CVector3f(1.f, 0.f, 0.f);
|
|
|
|
float RadianCutoff = (mSpotCutoff * 3.1415927f) / 180.f;
|
|
float RadianCosine = cosf(RadianCutoff);
|
|
float InvCosine = 1.f - RadianCosine;
|
|
|
|
return CVector3f(0.f, -RadianCosine / InvCosine, 1.f / InvCosine);
|
|
}
|
|
|
|
// ************ GETTERS ************
|
|
ELightType CLight::GetType() const
|
|
{
|
|
return mType;
|
|
}
|
|
|
|
CVector3f CLight::GetPosition() const
|
|
{
|
|
return mPosition;
|
|
}
|
|
|
|
CVector3f CLight::GetDirection() const
|
|
{
|
|
return mDirection;
|
|
}
|
|
|
|
CColor CLight::GetColor() const
|
|
{
|
|
return mColor;
|
|
}
|
|
|
|
CVector3f CLight::GetDistAttenuation() const
|
|
{
|
|
return mDistAttenCoefficients;
|
|
}
|
|
|
|
CVector3f CLight::GetAngleAttenuation() const
|
|
{
|
|
return mAngleAttenCoefficients;
|
|
}
|
|
|
|
float CLight::GetRadius()
|
|
{
|
|
if (mFlags & CLIGHT_NO_RADIUS)
|
|
{
|
|
mRadius = CalculateRadius();
|
|
mFlags &= ~CLIGHT_NO_RADIUS;
|
|
}
|
|
|
|
return mRadius * 2;
|
|
}
|
|
|
|
float CLight::GetIntensity()
|
|
{
|
|
if (mFlags & CLIGHT_NO_INTENSITY)
|
|
{
|
|
mIntensity = CalculateIntensity();
|
|
mFlags &= ~CLIGHT_NO_INTENSITY;
|
|
}
|
|
|
|
return mIntensity;
|
|
}
|
|
|
|
// ************ SETTERS ************
|
|
void CLight::SetPosition(const CVector3f& Position)
|
|
{
|
|
mPosition = Position;
|
|
}
|
|
|
|
void CLight::SetDirection(const CVector3f& Direction)
|
|
{
|
|
mDirection = Direction;
|
|
}
|
|
|
|
void CLight::SetColor(const CColor& Color)
|
|
{
|
|
mColor = Color;
|
|
mFlags = CLIGHT_NO_RADIUS | CLIGHT_NO_INTENSITY;
|
|
}
|
|
|
|
void CLight::SetSpotCutoff(float Cutoff)
|
|
{
|
|
mSpotCutoff = Cutoff * 0.5f;
|
|
CalculateSpotAngleAtten();
|
|
}
|
|
|
|
void CLight::SetDistAtten(float DistCoefA, float DistCoefB, float DistCoefC)
|
|
{
|
|
mDistAttenCoefficients.x = DistCoefA;
|
|
mDistAttenCoefficients.y = DistCoefB;
|
|
mDistAttenCoefficients.z = DistCoefC;
|
|
}
|
|
|
|
void CLight::SetAngleAtten(float AngleCoefA, float AngleCoefB, float AngleCoefC)
|
|
{
|
|
mAngleAttenCoefficients.x = AngleCoefA;
|
|
mAngleAttenCoefficients.y = AngleCoefB;
|
|
mAngleAttenCoefficients.z = AngleCoefC;
|
|
}
|
|
|
|
// ************ OTHER ************
|
|
void CLight::Load() const
|
|
{
|
|
u8 Index = (u8) CGraphics::sNumLights;
|
|
if (Index >= 8) return;
|
|
|
|
CGraphics::SLightBlock::SGXLight *Light = &CGraphics::sLightBlock.Lights[Index];
|
|
CVector3f PosView = CGraphics::sMVPBlock.ViewMatrix * mPosition;
|
|
CVector3f DirView = CGraphics::sMVPBlock.ViewMatrix * mDirection;
|
|
|
|
switch (mType)
|
|
{
|
|
case eLocalAmbient:
|
|
// LocalAmbient is already accounted for in CGraphics::sAreaAmbientColor
|
|
return;
|
|
case eDirectional:
|
|
Light->Position = CVector4f(-mDirection * 1048576.f, 1.f);
|
|
Light->Direction = CVector4f(mDirection, 0.f);
|
|
Light->Color = mColor.ToVector4f() * CGraphics::sWorldLightMultiplier;
|
|
Light->DistAtten = CVector4f(1.f, 0.f, 0.f, 0.f);
|
|
Light->AngleAtten = CVector4f(1.f, 0.f, 0.f, 0.f);
|
|
break;
|
|
case eSpot:
|
|
Light->Position = CVector4f(mPosition, 1.f);
|
|
Light->Direction = CVector4f(mDirection, 0.f);
|
|
Light->Color = mColor.ToVector4f() * CGraphics::sWorldLightMultiplier;
|
|
Light->DistAtten = mDistAttenCoefficients;
|
|
Light->AngleAtten = mAngleAttenCoefficients;
|
|
break;
|
|
case eCustom:
|
|
Light->Position = CVector4f(mPosition, 1.f);
|
|
Light->Direction = CVector4f(mDirection, 0.f);
|
|
Light->Color = mColor.ToVector4f() * CGraphics::sWorldLightMultiplier;
|
|
Light->DistAtten = mDistAttenCoefficients;
|
|
Light->AngleAtten = mAngleAttenCoefficients;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
CGraphics::sNumLights++;
|
|
}
|
|
|
|
// ************ STATIC ************
|
|
CLight* CLight::BuildLocalAmbient(const CVector3f& Position, const CColor& Color)
|
|
{
|
|
CLight *Light = new CLight;
|
|
Light->mType = eLocalAmbient;
|
|
Light->mPosition = Position;
|
|
Light->mDirection = skDefaultLightDir;
|
|
Light->mColor = Color;
|
|
Light->mSpotCutoff = 0.f;
|
|
return Light;
|
|
}
|
|
|
|
CLight* CLight::BuildDirectional(const CVector3f& Position, const CVector3f& Direction, const CColor& Color)
|
|
{
|
|
CLight *Light = new CLight;
|
|
Light->mType = eDirectional;
|
|
Light->mPosition = Position;
|
|
Light->mDirection = Direction;
|
|
Light->mColor = Color;
|
|
Light->mSpotCutoff = 0.f;
|
|
return Light;
|
|
}
|
|
|
|
CLight* CLight::BuildSpot(const CVector3f& Position, const CVector3f& Direction, const CColor& Color, float Cutoff)
|
|
{
|
|
CLight *Light = new CLight;
|
|
Light->mType = eSpot;
|
|
Light->mPosition = Position;
|
|
Light->mDirection = -Direction.Normalized();
|
|
Light->mColor = Color;
|
|
Light->mSpotCutoff = Cutoff * 0.5f;
|
|
Light->mAngleAttenCoefficients = Light->CalculateSpotAngleAtten();
|
|
return Light;
|
|
}
|
|
|
|
CLight* CLight::BuildCustom(const CVector3f& Position, const CVector3f& Direction, const CColor& Color,
|
|
float DistAttenA, float DistAttenB, float DistAttenC,
|
|
float AngleAttenA, float AngleAttenB, float AngleAttenC)
|
|
{
|
|
CLight *Light = new CLight;
|
|
Light->mType = eCustom;
|
|
Light->mPosition = Position;
|
|
Light->mDirection = Direction;
|
|
Light->mColor = Color;
|
|
Light->mSpotCutoff = 0.f;
|
|
Light->mDistAttenCoefficients.x = DistAttenA;
|
|
Light->mDistAttenCoefficients.y = DistAttenB;
|
|
Light->mDistAttenCoefficients.z = DistAttenC;
|
|
Light->mAngleAttenCoefficients.x = AngleAttenA;
|
|
Light->mAngleAttenCoefficients.y = AngleAttenB;
|
|
Light->mAngleAttenCoefficients.z = AngleAttenC * AngleAttenC;
|
|
return Light;
|
|
}
|
|
|
|
// ************ CONSTANTS ************
|
|
const CVector3f CLight::skDefaultLightPos(0.f, 0.f, 0.f);
|
|
const CVector3f CLight::skDefaultLightDir(0.f,-1.f, 0.f);
|