427 lines
13 KiB
C++
Executable File
427 lines
13 KiB
C++
Executable File
//-----------------------------------------------------------------------------
|
|
// Torque Game Engine
|
|
// Copyright (C) GarageGames.com, Inc.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "sceneGraph/lightManager.h"
|
|
#include "dgl/dgl.h"
|
|
#include "console/console.h"
|
|
#include "console/simBase.h"
|
|
#include "sceneGraph/sceneGraph.h"
|
|
#include "console/consoleTypes.h"
|
|
|
|
namespace {
|
|
static GLfloat zeroColor[] = {0.f, 0.f, 0.f, 0.f};
|
|
static GLfloat whiteColor[] = {1.f, 1.f, 1.f, 1.f};
|
|
|
|
// global settings for the lightmanager
|
|
static ColorF gOpenGLLightingAmbientColor(0.f, 0.f, 0.f, 0.f);
|
|
static ColorF gOpenGLMaterialAmbientColor(0.f, 0.f, 0.f, 0.f);
|
|
static ColorF gOpenGLMaterialDiffuseColor(1.f, 1.f, 1.f, 1.f);
|
|
static S32 gOpenGLMaxHardwareLights = LightManager::DefaultMaxLights;
|
|
|
|
bool colorIsZero(const ColorF & col)
|
|
{
|
|
return((col.red == 0.f) && (col.green == 0.f) && (col.blue == 0.f));
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Class LightManager
|
|
//------------------------------------------------------------------------------
|
|
ConsoleFunction( resetLighting, void, 1, 1, "Resets GL lighting.")
|
|
{
|
|
if(!gClientSceneGraph)
|
|
{
|
|
Con::errorf(ConsoleLogEntry::General, "LightManager::cResetLighting: no client scenegraph!");
|
|
return;
|
|
}
|
|
LightManager * lighting = gClientSceneGraph->getLightManager();
|
|
if(!lighting)
|
|
{
|
|
Con::errorf(ConsoleLogEntry::General, "LightManager::cResetLighting: lightmanager not found!");
|
|
return;
|
|
}
|
|
lighting->resetGL();
|
|
}
|
|
|
|
LightManager::LightManager()
|
|
{
|
|
mGLInitialized = false;
|
|
mGLLightsInstalled = false;
|
|
mGLLightCount = 0;
|
|
mAmbientLightColor.set(0.f,0.f,0.f);
|
|
mVectorLightsAttenuation = 1.f;
|
|
mVectorLightsEnabled = true;
|
|
|
|
mSunLight = NULL;
|
|
|
|
#ifdef DEBUG
|
|
Con::addVariable("$pref::OpenGL::lightingAmbientColor", TypeColorF, &gOpenGLLightingAmbientColor);
|
|
Con::addVariable("$pref::OpenGL::materialAmbientColor", TypeColorF, &gOpenGLMaterialAmbientColor);
|
|
Con::addVariable("$pref::OpenGL::materialDiffuseColor", TypeColorF, &gOpenGLMaterialDiffuseColor);
|
|
#endif
|
|
Con::addVariable("$pref::OpenGL::maxHardwareLights", TypeS32, &gOpenGLMaxHardwareLights);
|
|
}
|
|
|
|
void LightManager::setMaxGLLights(U32 max)
|
|
{
|
|
// ask gl for max light value, and check if this is greater..
|
|
GLint glMaxLights = 0;
|
|
glGetIntegerv(GL_MAX_LIGHTS, &glMaxLights);
|
|
|
|
// clamp to the number gl returned
|
|
if(max > glMaxLights)
|
|
{
|
|
Con::errorf(ConsoleLogEntry::General, "LightManager::setMaxGLLights: too many lights.");
|
|
max = glMaxLights;
|
|
}
|
|
|
|
mMaxGLLights = max;
|
|
|
|
// cleanup any installed lights
|
|
if(mGLLightsInstalled)
|
|
uninstallGLLights();
|
|
}
|
|
|
|
// will crash if called prior to PlatformVideo:: initialization!
|
|
void LightManager::resetGL()
|
|
{
|
|
if(!mGLInitialized)
|
|
return;
|
|
|
|
if(mGLLightsInstalled)
|
|
uninstallGLLights();
|
|
|
|
// set ambient color
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (const F32 *)gOpenGLMaterialAmbientColor);
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (const F32 *)gOpenGLMaterialDiffuseColor);
|
|
|
|
setMaxGLLights(gOpenGLMaxHardwareLights);
|
|
}
|
|
|
|
void LightManager::registerLights(bool lightingScene)
|
|
{
|
|
if(!mGLInitialized)
|
|
{
|
|
mGLInitialized = true;
|
|
resetGL();
|
|
}
|
|
|
|
if(mGLLightsInstalled)
|
|
{
|
|
Con::warnf(ConsoleLogEntry::General, "LightManager::registerLights: lights are already installed.");
|
|
uninstallGLLights();
|
|
}
|
|
|
|
// clear out the light list
|
|
mLights.clear();
|
|
|
|
// walk the lightlist and query objects for their lights
|
|
SimSet * lightSet = Sim::getLightSet();
|
|
for(SimObject ** itr = lightSet->begin(); itr != lightSet->end(); itr++)
|
|
(*itr)->registerLights(this, lightingScene);
|
|
}
|
|
|
|
void LightManager::addLight(LightInfo * light)
|
|
{
|
|
mLights.push_back(light);
|
|
|
|
if(light->mType == LightInfo::Vector)
|
|
mSunLight = light;
|
|
}
|
|
|
|
void LightManager::removeLight(LightInfo * light)
|
|
{
|
|
for(U32 i = 0; i < mLights.size(); i++)
|
|
{
|
|
if(mLights[i] == light)
|
|
{
|
|
mLights.erase_fast(i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(mSunLight == light)
|
|
mSunLight = NULL;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
U32 LightManager::installGLLights(const SphereF & sphere)
|
|
{
|
|
// score the lights:
|
|
for(U32 i = 0; i < mLights.size(); i++)
|
|
{
|
|
if(!mVectorLightsEnabled && (mLights[i]->mType == LightInfo::Vector))
|
|
mLights[i]->mScore = 0;
|
|
else
|
|
scoreLight(mLights[i], sphere);
|
|
}
|
|
|
|
return(installGLLights());
|
|
}
|
|
|
|
U32 LightManager::installGLLights(const Box3F & box)
|
|
{
|
|
SphereF sphere;
|
|
box.getCenter(&sphere.center);
|
|
sphere.radius = Point3F(box.max - sphere.center).len();
|
|
|
|
return(installGLLights(sphere));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
U32 LightManager::installGLLights()
|
|
{
|
|
AssertFatal(!mGLLightsInstalled, "LightManager::installGLLights: lights are already installed!");
|
|
mGLLightsInstalled = true;
|
|
|
|
// sort them
|
|
dQsort(mLights.address(), mLights.size(), sizeof(LightInfo*), compareLights);
|
|
|
|
// grab the best ones...
|
|
U32 count = 0;
|
|
while(count < mLights.size())
|
|
{
|
|
if(count >= mMaxGLLights)
|
|
break;
|
|
|
|
if(!mLights[count]->mScore)
|
|
break;
|
|
|
|
installGLLight(mLights[count++]);
|
|
}
|
|
|
|
// enable ambient and lighting always:
|
|
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (const F32 *)ColorF(gOpenGLLightingAmbientColor + mAmbientLightColor));
|
|
glEnable(GL_LIGHTING);
|
|
|
|
return(count);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// - restores ambient light changes
|
|
// - restores vector light enabled flag
|
|
void LightManager::uninstallGLLights()
|
|
{
|
|
if(!mGLLightsInstalled)
|
|
{
|
|
Con::errorf(ConsoleLogEntry::General, "LightManager::uninstallGLLights: no lights installed!");
|
|
return;
|
|
}
|
|
mGLLightsInstalled = false;
|
|
|
|
// restore values:
|
|
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (const F32*)gOpenGLLightingAmbientColor);
|
|
|
|
mAmbientLightColor.set(0.f, 0.f, 0.f);
|
|
mVectorLightsAttenuation = 1.f;
|
|
mVectorLightsEnabled = true;
|
|
|
|
glDisable(GL_LIGHTING);
|
|
for(U32 i = 0; i < mGLLightCount; i++)
|
|
glDisable(GL_LIGHT0 + i);
|
|
mGLLightCount = 0;
|
|
}
|
|
|
|
void LightManager::installGLLight(LightInfo * lightInfo)
|
|
{
|
|
AssertFatal(mGLLightCount < mMaxGLLights, "LightManager::installGLLight: too many lights installed");
|
|
|
|
GLfloat lightColor[] = {lightInfo->mColor.red, lightInfo->mColor.green, lightInfo->mColor.blue, 1.f};
|
|
GLfloat ambientColor[] = {lightInfo->mAmbient.red, lightInfo->mAmbient.green, lightInfo->mAmbient.blue, 1.f};
|
|
GLfloat lightPos[] = {lightInfo->mPos.x, lightInfo->mPos.y, lightInfo->mPos.z, 1.f};
|
|
GLfloat lightDir[] = {-lightInfo->mDirection.x, -lightInfo->mDirection.y, -lightInfo->mDirection.z, 0.f};
|
|
|
|
U32 light = GL_LIGHT0 + mGLLightCount++;
|
|
|
|
glEnable(light);
|
|
|
|
switch(lightInfo->mType)
|
|
{
|
|
case LightInfo::Spot:
|
|
|
|
// set the light params
|
|
glLightfv(light, GL_POSITION, (const GLfloat*)lightPos);
|
|
glLightfv(light, GL_SPOT_DIRECTION, (const GLfloat*)lightDir);
|
|
glLightfv(light, GL_DIFFUSE, (const GLfloat*)lightColor);
|
|
glLightfv(light, GL_AMBIENT, (const GLfloat*)zeroColor);
|
|
glLightfv(light, GL_SPECULAR, (const GLfloat*)lightColor);
|
|
|
|
break;
|
|
|
|
// falls through to LightInfo::Ambient
|
|
case LightInfo::Vector:
|
|
{
|
|
F32 ambientFactor = (ambientColor[0] + ambientColor[1] + ambientColor[2]) / 3.f;
|
|
F32 factor = mClampF(mVectorLightsAttenuation - ambientFactor, 0.f, 1.f);
|
|
|
|
// attenuate (for in shadow...)
|
|
for(U32 i = 0; i < 3; i++)
|
|
lightColor[i] *= factor;
|
|
}
|
|
|
|
case LightInfo::Ambient:
|
|
|
|
// set the light params
|
|
glLightfv(light, GL_POSITION, (const GLfloat*)lightDir);
|
|
glLightfv(light, GL_DIFFUSE, (const GLfloat*)lightColor);
|
|
glLightfv(light, GL_AMBIENT, (const GLfloat*)ambientColor);
|
|
glLightfv(light, GL_SPECULAR, (const GLfloat*)lightColor);
|
|
|
|
break;
|
|
|
|
case LightInfo::Point:
|
|
|
|
// set the light params
|
|
glLightfv(light, GL_POSITION, (const GLfloat*)lightPos);
|
|
glLightfv(light, GL_DIFFUSE, (const GLfloat*)lightColor);
|
|
glLightfv(light, GL_AMBIENT, (const GLfloat*)zeroColor);
|
|
glLightfv(light, GL_SPECULAR, (const GLfloat*)lightColor);
|
|
|
|
glLightf(light, GL_SPOT_CUTOFF, 180.f);
|
|
|
|
glLightf(light, GL_CONSTANT_ATTENUATION, 0.f);
|
|
glLightf(light, GL_LINEAR_ATTENUATION, 1.0f);
|
|
glLightf(light, GL_QUADRATIC_ATTENUATION, 0.f);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void LightManager::getBestLights(const PlaneF * testPlanes, const U32 numPlanes,
|
|
const Point3F & pos, LightInfoList & lightList, const U32 max)
|
|
{
|
|
for(U32 i = 0; i < mLights.size(); i++)
|
|
scoreLight(mLights[i], testPlanes, numPlanes, pos);
|
|
|
|
fillLightList(lightList, max);
|
|
}
|
|
|
|
void LightManager::getBestLights(const SphereF & sphere, LightInfoList & lightList, const U32 max)
|
|
{
|
|
// score the lights
|
|
for(U32 i = 0; i < mLights.size(); i++)
|
|
scoreLight(mLights[i], sphere);
|
|
|
|
fillLightList(lightList, max);
|
|
}
|
|
|
|
void LightManager::getBestLights(const Box3F & box, LightInfoList & lightList, const U32 max)
|
|
{
|
|
SphereF sphere;
|
|
box.getCenter(&sphere.center);
|
|
sphere.radius = Point3F(box.max - sphere.center).len();
|
|
|
|
getBestLights(sphere, lightList, max);
|
|
}
|
|
|
|
const Point3F LightManager::getShadowLightDirection() const
|
|
{
|
|
if(mSunLight)
|
|
return mSunLight->mDirection;
|
|
else
|
|
// Do a lame default...
|
|
return Point3F(0.573, 0.573, -0.573);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void LightManager::fillLightList(LightInfoList & lightList, const U32 max)
|
|
{
|
|
dQsort(mLights.address(), mLights.size(), sizeof(LightInfo*), compareLights);
|
|
|
|
// grab the best ones...
|
|
U32 count = 0;
|
|
for(U32 i = 0; i < mLights.size(); i++)
|
|
{
|
|
if(!mLights[i]->mScore)
|
|
continue;
|
|
|
|
if(count++ >= max)
|
|
break;
|
|
|
|
lightList.push_back(mLights[i]);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 0 not lit
|
|
// 1->100 point/spot lights
|
|
// 100->200 vector/ambient lights
|
|
void LightManager::scoreLight(LightInfo * lightInfo, const SphereF & sphere) const
|
|
{
|
|
switch(lightInfo->mType)
|
|
{
|
|
case LightInfo::Ambient:
|
|
case LightInfo::Vector:
|
|
{
|
|
// 100 + (color_intensity * 100)
|
|
float intensity = (lightInfo->mColor.red + lightInfo->mAmbient.red) * 0.346f +
|
|
(lightInfo->mColor.green + lightInfo->mAmbient.green) * 0.588f +
|
|
(lightInfo->mColor.blue + lightInfo->mAmbient.blue) * 0.070f;
|
|
|
|
lightInfo->mScore = 100 + S32(100.f * mClampF(intensity, 0.f, 1.f));
|
|
break;
|
|
}
|
|
|
|
case LightInfo::Point:
|
|
{
|
|
Point3F diff = lightInfo->mPos - sphere.center;
|
|
F32 lenSq = diff.lenSquared();
|
|
F32 sumRadiusSq = (sphere.radius + lightInfo->mRadius) * (sphere.radius + lightInfo->mRadius);
|
|
|
|
if(lenSq > sumRadiusSq)
|
|
{
|
|
lightInfo->mScore = 0;
|
|
break;
|
|
}
|
|
|
|
F32 radSq = sphere.radius * sphere.radius;
|
|
lightInfo->mScore = 1 + S32(99.f * (getMin((sumRadiusSq - lenSq), radSq) / radSq));
|
|
break;
|
|
}
|
|
|
|
default:
|
|
lightInfo->mScore = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void LightManager::scoreLight(LightInfo* lightInfo,
|
|
const PlaneF* /*testPlanes*/,
|
|
const U32 /*numPlanes*/,
|
|
const Point3F& /*pos*/) const
|
|
{
|
|
switch(lightInfo->mType)
|
|
{
|
|
case LightInfo::Ambient:
|
|
case LightInfo::Vector:
|
|
{
|
|
// 100 + (color_intensity * 100)
|
|
float intensity = (lightInfo->mColor.red + lightInfo->mAmbient.red) * 0.346f +
|
|
(lightInfo->mColor.green + lightInfo->mAmbient.green) * 0.588f +
|
|
(lightInfo->mColor.blue + lightInfo->mAmbient.blue) * 0.070f;
|
|
|
|
lightInfo->mScore = 100 + S32(100.f * mClampF(intensity, 0.f, 1.f));
|
|
break;
|
|
}
|
|
|
|
case LightInfo::Point:
|
|
{
|
|
lightInfo->mScore = 1;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
lightInfo->mScore = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
S32 QSORT_CALLBACK LightManager::compareLights(const void* a, const void* b)
|
|
{
|
|
return((*(LightInfo**)b)->mScore - (*(LightInfo**)a)->mScore);
|
|
}
|