883 lines
28 KiB
C++
Executable File
883 lines
28 KiB
C++
Executable File
//-----------------------------------------------
|
|
// Synapse Gaming - Lighting System
|
|
// Copyright © Synapse Gaming 2003
|
|
// Written by John Kabus
|
|
//-----------------------------------------------
|
|
#include "lightingSystem/sgLighting.h"
|
|
|
|
#include "lightingSystem/sgLightManager.h"
|
|
#include "lightingSystem/sgLightingModel.h"
|
|
#include "lightingSystem/sgMissionLightingFilter.h"
|
|
#include "interior/interiorInstance.h"
|
|
#include "terrain/terrData.h"
|
|
#include "game/shadow.h"
|
|
#include "lightingSystem/sgLightObject.h"
|
|
#include "sim/netConnection.h"
|
|
#include "editor/worldEditor.h"
|
|
#include "platform/profiler.h"
|
|
|
|
|
|
bool LightManager::sgLightingProperties[sgPropertyCount];
|
|
bool LightManager::sgUseSelfIlluminationColor = false;
|
|
ColorF LightManager::sgSelfIlluminationColor(0.0f, 0.0f, 0.0f);
|
|
bool LightManager::sgFilterZones = false;
|
|
S32 LightManager::sgZones[2] = {-1, -1};
|
|
bool LightManager::sgDynamicParticleSystemLighting = true;
|
|
bool LightManager::sgBlendedTerrainDynamicLighting = true;
|
|
U32 LightManager::sgLightingProfileQuality = LightManager::lpqtProduction;
|
|
bool LightManager::sgLightingProfileAllowShadows = true;
|
|
LightInfo LightManager::sgDefaultLight;
|
|
bool LightManager::sgDetailMaps = true;
|
|
S32 LightManager::sgMaxBestLights = 10;
|
|
bool LightManager::sgUseDynamicShadows = true;
|
|
|
|
U32 LightManager::sgDynamicLightingOcclusionQuality = dlqtFourSample;
|
|
U32 LightManager::sgDynamicShadowQuality = 0;
|
|
bool LightManager::sgMultipleDynamicShadows = true;
|
|
bool LightManager::sgInGUIEditor = false;
|
|
|
|
bool sgRelightFilter::sgFilterRelight = false;
|
|
bool sgRelightFilter::sgFilterRelightVisible = true;
|
|
bool sgRelightFilter::sgFilterRelightByDistance = true;
|
|
F32 sgRelightFilter::sgFilterRelightByDistanceRadius = 60;
|
|
Point3F sgRelightFilter::sgFilterRelightByDistancePosition;
|
|
|
|
U32 sgStatistics::sgInteriorLexelCount = 0;
|
|
U32 sgStatistics::sgInteriorLexelTime = 0;
|
|
U32 sgStatistics::sgInteriorLexelDiffuseCount = 0;
|
|
U32 sgStatistics::sgInteriorObjectCount = 0;
|
|
U32 sgStatistics::sgInteriorObjectIncludedCount = 0;
|
|
U32 sgStatistics::sgInteriorObjectIlluminationCount = 0;
|
|
U32 sgStatistics::sgInteriorSurfaceIncludedCount = 0;
|
|
U32 sgStatistics::sgInteriorSurfaceIlluminationCount = 0;
|
|
U32 sgStatistics::sgInteriorSurfaceIlluminatedCount = 0;
|
|
U32 sgStatistics::sgInteriorSurfaceSmoothedCount = 0;
|
|
U32 sgStatistics::sgInteriorSurfaceSmoothedLexelCount = 0;
|
|
U32 sgStatistics::sgInteriorSurfaceSetupTime = 0;
|
|
U32 sgStatistics::sgInteriorSurfaceSetupCount = 0;
|
|
U32 sgStatistics::sgInteriorSurfaceMergeTime = 0;
|
|
U32 sgStatistics::sgInteriorSurfaceMergeCount = 0;
|
|
U32 sgStatistics::sgStaticMeshSurfaceOccluderCount = 0;
|
|
U32 sgStatistics::sgTerrainLexelCount = 0;
|
|
U32 sgStatistics::sgTerrainLexelTime = 0;
|
|
|
|
sgInteriorDynamicLightingCache::sgCacheEntry sgInteriorDynamicLightingCache::sgCache;
|
|
sgDTSDynamicLightingCache::sgCacheEntry sgDTSDynamicLightingCache::sgCache;
|
|
|
|
|
|
LightInfo::LightInfo()
|
|
{
|
|
mType = Vector;
|
|
mPos = Point3F(0.0f, 0.0f, 0.0f);
|
|
mDirection = Point3F(0.0f, 0.0f, 1.0f);
|
|
mColor = ColorF(0.0f, 0.0f, 0.0f);
|
|
mAmbient = ColorF(0.0f, 0.0f, 0.0f);
|
|
mRadius = 1;
|
|
mScore = 0;
|
|
|
|
sgSpotAngle = 90.0f;
|
|
sgAssignedToTSObject = false;
|
|
sgCastsShadows = true;
|
|
sgDiffuseRestrictZone = false;
|
|
sgAmbientRestrictZone = false;
|
|
sgZone[0] = -1;
|
|
sgZone[1] = -1;
|
|
sgLocalAmbientAmount = 0.0f;
|
|
sgSmoothSpotLight = false;
|
|
sgDoubleSidedAmbient = false;
|
|
sgAssignedToParticleSystem = false;
|
|
sgLightingModelName = NULL;
|
|
sgUseNormals = true;
|
|
sgSpotPlane = PlaneF(0.0f, 0.0f, 0.0f, 0.0f);
|
|
sgDTSLightingOcclusionAdjust = 1.0f;
|
|
|
|
sgMoveSnapshotId = 0;
|
|
sgTrackMoveSnapshot = false;
|
|
|
|
sgLightingTransform.identity();
|
|
}
|
|
|
|
bool LightInfo::sgIsInZone(S32 zone)
|
|
{
|
|
if((zone == sgZone[0]) || (zone ==sgZone[1]))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool LightInfo::sgAllowDiffuseZoneLighting(S32 zone)
|
|
{
|
|
if(!sgDiffuseRestrictZone)
|
|
return true;
|
|
if(sgIsInZone(zone))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
void LightInfoList::sgRegisterLight(LightInfo *light)
|
|
{
|
|
if(!light)
|
|
return;
|
|
// just add the light, we'll try to scan for dupes later...
|
|
push_back(light);
|
|
}
|
|
|
|
void LightInfoList::sgUnregisterLight(LightInfo *light)
|
|
{
|
|
// remove all of them...
|
|
LightInfoList &list = *this;
|
|
for(U32 i=0; i<list.size(); i++)
|
|
{
|
|
if(list[i] != light)
|
|
continue;
|
|
// this moves last to i, which allows
|
|
// the search to continue forward...
|
|
list.erase_fast(i);
|
|
// want to check this location again...
|
|
i--;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------
|
|
//-----------------------------------------------
|
|
|
|
bool LightManager::sgAllowBlendedTerrainDynamicLighting()
|
|
{
|
|
if(!sgBlendedTerrainDynamicLighting)
|
|
return false;
|
|
return (dglGetMaxTextureUnits() > 2);
|
|
}
|
|
|
|
LightInfo *LightManager::sgGetSpecialLight(sgSpecialLightTypesEnum type)
|
|
{
|
|
if(sgSpecialLights[type])
|
|
return sgSpecialLights[type];
|
|
// return a default light...
|
|
return &sgDefaultLight;
|
|
}
|
|
|
|
void LightManager::sgRegisterGlobalLight(LightInfo *light)
|
|
{
|
|
sgRegisteredGlobalLights.sgRegisterLight(light);
|
|
}
|
|
|
|
void LightManager::sgRegisterGlobalLights(bool staticlighting)
|
|
{
|
|
// make sure we're clean...
|
|
sgUnregisterAllLights();
|
|
|
|
// ask all light objects to register themselves...
|
|
SimSet *lightset = Sim::getLightSet();
|
|
for(SimObject **itr=lightset->begin(); itr!=lightset->end(); itr++)
|
|
(*itr)->registerLights(this, staticlighting);
|
|
}
|
|
|
|
void LightManager::sgUnregisterAllLights()
|
|
{
|
|
sgRegisteredGlobalLights.clear();
|
|
sgRegisteredLocalLights.clear();
|
|
|
|
dMemset(&sgSpecialLights, 0, sizeof(sgSpecialLights));
|
|
}
|
|
|
|
void LightManager::sgGetAllUnsortedLights(LightInfoList &list)
|
|
{
|
|
list.clear();
|
|
list.merge(sgRegisteredGlobalLights);
|
|
list.merge(sgRegisteredLocalLights);
|
|
|
|
// find dupes...
|
|
dQsort(list.address(), list.size(), sizeof(LightInfo*), sgSortLightsByAddress);
|
|
LightInfo *last = NULL;
|
|
for(U32 i=0; i<list.size(); i++)
|
|
{
|
|
if(list[i] == last)
|
|
{
|
|
list.erase(i);
|
|
i--;
|
|
continue;
|
|
}
|
|
last = list[i];
|
|
}
|
|
}
|
|
|
|
void LightManager::sgSetupLights(SceneObject *obj)
|
|
{
|
|
PROFILE_START(LightManager_sgSetupLights);
|
|
|
|
sgResetLights();
|
|
|
|
bool outside = false;
|
|
for(U32 i=0; i<obj->getNumCurrZones(); i++)
|
|
{
|
|
if(obj->getCurrZone(i) == 0)
|
|
{
|
|
outside = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
sgSetProperty(sgReceiveSunLightProp, obj->receiveSunLight);
|
|
sgSetProperty(sgAdaptiveSelfIlluminationProp, obj->useAdaptiveSelfIllumination);
|
|
sgSetProperty(sgCustomAmbientLightingProp, obj->useCustomAmbientLighting);
|
|
sgSetProperty(sgCustomAmbientForSelfIlluminationProp, obj->customAmbientForSelfIllumination);
|
|
|
|
ColorF ambientColor;
|
|
ColorF selfillum = obj->customAmbientLighting * 0.5f;
|
|
|
|
LightInfo *sun = sgGetSpecialLight(sgSunLightType);
|
|
if(obj->getLightingAmbientColor(&ambientColor))
|
|
{
|
|
const F32 directionalFactor = 0.5f;
|
|
const F32 ambientFactor = 0.5f;
|
|
|
|
dMemset(&obj->mLightingInfo.smAmbientLight, 0, sizeof(obj->mLightingInfo.smAmbientLight));
|
|
|
|
LightInfo &light = obj->mLightingInfo.smAmbientLight;
|
|
light.mType = LightInfo::Ambient;
|
|
light.mDirection = VectorF(0.0f, 0.0f, -1.0f);
|
|
light.sgCastsShadows = sun->sgCastsShadows;
|
|
|
|
// players, vehicles, ...
|
|
if(obj->overrideOptions)
|
|
{
|
|
if(outside)
|
|
{
|
|
light.mType = LightInfo::Vector;
|
|
light.mDirection = sun->mDirection;
|
|
}
|
|
//else
|
|
//{
|
|
light.mColor = ambientColor * directionalFactor;
|
|
light.mAmbient = ambientColor * ambientFactor;
|
|
//}
|
|
}// beyond here are the static dts options...
|
|
else if(sgAllowDiffuseCustomAmbient())
|
|
{
|
|
light.mColor = obj->customAmbientLighting * 0.5f;
|
|
light.mAmbient = obj->customAmbientLighting * 0.5f;
|
|
}
|
|
else if(sgAllowReceiveSunLight() && sun)
|
|
{
|
|
light.mType = LightInfo::Vector;
|
|
if(outside)
|
|
light.mDirection = sun->mDirection;
|
|
if(obj->receiveLMLighting)
|
|
light.mColor = ambientColor * 0.8f;
|
|
else
|
|
light.mColor = sun->mColor;
|
|
light.mAmbient = sun->mAmbient;
|
|
}
|
|
else if(obj->receiveLMLighting)
|
|
{
|
|
light.mColor = ambientColor * directionalFactor;
|
|
light.mAmbient = ambientColor * ambientFactor;
|
|
}
|
|
|
|
if(sgAllowCollectSelfIlluminationColor())
|
|
{
|
|
selfillum = light.mAmbient + light.mColor;
|
|
selfillum.clamp();
|
|
}
|
|
|
|
light.mPos = light.mDirection * -10000.0f;
|
|
sgRegisterLocalLight(&obj->mLightingInfo.smAmbientLight);
|
|
}
|
|
|
|
// install assigned baked lights from simgroup...
|
|
// step one get the objects...
|
|
U32 i;
|
|
NetConnection *connection = NetConnection::getConnectionToServer();
|
|
|
|
for(i=0; i<obj->lightIds.size(); i++)
|
|
{
|
|
SimObject *sim = connection->resolveGhost(obj->lightIds[i]);
|
|
if(!sim)
|
|
continue;
|
|
|
|
sgLightObject *light = dynamic_cast<sgLightObject*>(sim);
|
|
if(!light)
|
|
continue;
|
|
|
|
sgLightObjectData *data = static_cast<sgLightObjectData *>(light->getDataBlock());
|
|
if((data) && (data->sgStatic) && (data->mLightOn) && (light->mEnable))
|
|
{
|
|
light->mLight.sgAssignedToTSObject = true;
|
|
sgRegisterLocalLight(&light->mLight);
|
|
}
|
|
}
|
|
|
|
// step three install dynamic lights...
|
|
sgUseSelfIlluminationColor = sgGetProperty(sgAdaptiveSelfIlluminationProp);
|
|
if(sgUseSelfIlluminationColor)
|
|
sgSelfIlluminationColor = selfillum;
|
|
|
|
sgSetupZoneLighting(true, obj);
|
|
|
|
sgFindBestLights(obj, obj->getRenderWorldBox(), sgMaxBestLights, Point3F(0.0f, 0.0f, 0.0f), false);
|
|
sgInstallLights();
|
|
|
|
PROFILE_END();
|
|
}
|
|
|
|
void LightManager::sgSetupLights(SceneObject *obj, const Point3F &camerapos,
|
|
const Point3F &cameradir, F32 viewdist, S32 maxlights)
|
|
{
|
|
sgResetLights();
|
|
|
|
sgSetupZoneLighting(true, obj);
|
|
|
|
Box3F box;
|
|
box.max = camerapos + Point3F(viewdist, viewdist, viewdist);
|
|
box.min = camerapos - Point3F(viewdist, viewdist, viewdist);
|
|
sgFindBestLights(obj, box, maxlights, cameradir, true);
|
|
}
|
|
|
|
void LightManager::sgSetupLights(SceneObject *obj, const Box3F &box, S32 maxlights)
|
|
{
|
|
sgResetLights();
|
|
sgSetupZoneLighting(true, obj);
|
|
sgFindBestLights(obj, box, maxlights, Point3F(0.0f, 0.0f, 0.0f), true);
|
|
}
|
|
|
|
void LightManager::sgInstallLights()
|
|
{
|
|
U32 count = getMin(U32(sgBestLights.size()), U32(8));
|
|
glEnable(GL_LIGHTING);
|
|
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (const F32 *)ColorF(0.0f, 0.0f, 0.0f, 0.0f));
|
|
|
|
for(U32 i=0; i<count; i++)
|
|
{
|
|
LightInfo *light = sgBestLights[i];
|
|
sgLightingModel &lightingmodel = sgLightingModelManager::sgGetLightingModel(
|
|
light->sgLightingModelName);
|
|
lightingmodel.sgSetState(light);
|
|
|
|
U32 gllight = GL_LIGHT0 + i;
|
|
glEnable(gllight);
|
|
|
|
lightingmodel.sgLightingGL(gllight);
|
|
lightingmodel.sgResetState();
|
|
}
|
|
}
|
|
|
|
void LightManager::sgResetLights()
|
|
{
|
|
sgSetupZoneLighting(false, NULL);
|
|
sgRegisteredLocalLights.clear();
|
|
sgBestLights.clear();
|
|
|
|
// ok these seem weird, but dts rendering changes them...
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (const F32 *)ColorF(0.0f, 0.0f, 0.0f, 0.0f));
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (const F32 *)ColorF(1.0f, 1.0f, 1.0f, 1.0f));
|
|
|
|
for(S32 i=7; i>=0; i--)
|
|
glDisable(GL_LIGHT0 + i);
|
|
glDisable(GL_LIGHTING);
|
|
}
|
|
|
|
void LightManager::sgFindBestLights(SceneObject *obj, const Box3F &box, S32 maxlights, const Point3F &viewdi, bool camerabased)
|
|
{
|
|
sgBestLights.clear();
|
|
|
|
// gets them all and removes any dupes...
|
|
sgGetAllUnsortedLights(sgBestLights);
|
|
|
|
SphereF sphere;
|
|
box.getCenter(&sphere.center);
|
|
sphere.radius = Point3F(box.max - sphere.center).len();
|
|
|
|
for(U32 i=0; i<sgBestLights.size(); i++)
|
|
sgScoreLight(sgBestLights[i], obj, box, sphere, camerabased);
|
|
|
|
dQsort(sgBestLights.address(), sgBestLights.size(), sizeof(LightInfo*), sgSortLightsByScore);
|
|
|
|
for(U32 i=0; i<sgBestLights.size(); i++)
|
|
{
|
|
if((sgBestLights[i]->mScore > 0) && (i < maxlights))
|
|
continue;
|
|
|
|
sgBestLights.setSize(i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void LightManager::sgScoreLight(LightInfo *light, SceneObject *obj, const Box3F &box, const SphereF &sphere, bool camerabased)
|
|
{
|
|
if(sgFilterZones && light->sgDiffuseRestrictZone)
|
|
{
|
|
bool allowdiffuse = false;
|
|
if(sgZones[0] > -1)
|
|
{
|
|
if(light->sgAllowDiffuseZoneLighting(sgZones[0]))
|
|
allowdiffuse = true;
|
|
else if(sgZones[1] > -1)
|
|
{
|
|
if(light->sgAllowDiffuseZoneLighting(sgZones[1]))
|
|
allowdiffuse = true;
|
|
}
|
|
}
|
|
|
|
if(!allowdiffuse)
|
|
{
|
|
light->mScore = 0;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
F32 distintensity = 1.0f;
|
|
F32 colorintensity = 1.0f;
|
|
F32 weight = SG_LIGHTMANAGER_DYNAMIC_PRIORITY;
|
|
|
|
if(camerabased)
|
|
{
|
|
sgLightingModel &model = sgLightingModelManager::sgGetLightingModel(light->sgLightingModelName);
|
|
model.sgSetState(light);
|
|
F32 maxrad = model.sgGetMaxRadius(true);
|
|
model.sgResetState();
|
|
|
|
Point3F vect = sphere.center - light->mPos;
|
|
F32 dist = vect.len();
|
|
F32 distlightview = sphere.radius + maxrad;
|
|
|
|
if(distlightview <= 0.0f)
|
|
distintensity = 0.0f;
|
|
else
|
|
{
|
|
distintensity = 1.0f - (dist / distlightview);
|
|
distintensity = mClampF(distintensity, 0.0f, 1.0f);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// side test...
|
|
if((light->mType == LightInfo::Spot) || (light->mType == LightInfo::SGStaticSpot))
|
|
{
|
|
bool anyfront = false;
|
|
F32 x, y, z;
|
|
|
|
for(U32 i=0; i<8; i++)
|
|
{
|
|
if(i & 0x1)
|
|
x = box.max.x;
|
|
else
|
|
x = box.min.x;
|
|
|
|
if(i & 0x2)
|
|
y = box.max.y;
|
|
else
|
|
y = box.min.y;
|
|
|
|
if(i & 0x4)
|
|
z = box.max.z;
|
|
else
|
|
z = box.min.z;
|
|
|
|
if(light->sgSpotPlane.whichSide(Point3F(x, y, z)) == PlaneF::Back)
|
|
continue;
|
|
|
|
anyfront = true;
|
|
break;
|
|
}
|
|
|
|
if(!anyfront)
|
|
{
|
|
light->mScore = 0;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if((light->mType == LightInfo::Vector) || (light->mType == LightInfo::Ambient))
|
|
{
|
|
colorintensity =
|
|
(light->mColor.red + light->mAmbient.red) * 0.346f +
|
|
(light->mColor.green + light->mAmbient.green) * 0.588f +
|
|
(light->mColor.blue + light->mAmbient.blue) * 0.070f;
|
|
distintensity = 1;
|
|
weight = SG_LIGHTMANAGER_SUN_PRIORITY;
|
|
}
|
|
else
|
|
{
|
|
if(light->sgAssignedToParticleSystem)
|
|
{
|
|
colorintensity = SG_PARTICLESYSTEMLIGHT_FIXED_INTENSITY;
|
|
}
|
|
else
|
|
{
|
|
colorintensity =
|
|
(light->mColor.red * 0.3333f) +
|
|
(light->mColor.green * 0.3333f) +
|
|
(light->mColor.blue * 0.3333f);
|
|
}
|
|
|
|
sgLightingModel &model = sgLightingModelManager::sgGetLightingModel(light->sgLightingModelName);
|
|
model.sgSetState(light);
|
|
distintensity = model.sgScoreLight(light, sphere);
|
|
model.sgResetState();
|
|
|
|
if(light->sgAssignedToTSObject)
|
|
weight = SG_LIGHTMANAGER_ASSIGNED_PRIORITY;
|
|
else if((light->mType == LightInfo::SGStaticPoint) || (light->mType == LightInfo::SGStaticSpot))
|
|
weight = SG_LIGHTMANAGER_STATIC_PRIORITY;
|
|
|
|
|
|
if(((light->mType == LightInfo::SGStaticPoint) || (light->mType == LightInfo::SGStaticSpot)) &&
|
|
light->sgCastsShadows && (distintensity > 0.0f) && (sgDynamicLightingOcclusionQuality < dlqtNoShadows) &&
|
|
obj->useLightingOcclusion)
|
|
{
|
|
sgDTSDynamicLightingCache::sgCacheEntry *entry = sgDTSDynamicLightingCache::sgFindCacheEntry((void *)obj, light);
|
|
if((!entry->info.sgAlreadyProcessed) ||
|
|
(entry->info.sgLastObjectMoveSnapshotId != obj->moveSnapshotId) ||
|
|
(entry->info.sgLastLightMoveSnapshotId != light->sgMoveSnapshotId))
|
|
{
|
|
entry->info.sgAlreadyProcessed = true;
|
|
entry->info.sgLastObjectMoveSnapshotId = obj->moveSnapshotId;
|
|
entry->info.sgLastLightMoveSnapshotId = light->sgMoveSnapshotId;
|
|
|
|
U32 shadowcalcs = 0;
|
|
F32 shadowamount = 0.0f;
|
|
F32 x, y, z;
|
|
RayInfo info;
|
|
|
|
obj->disableCollision();
|
|
|
|
U32 samples = (sgDynamicLightingOcclusionQuality < dlqtCenterSample) ? 7 : 1;
|
|
for(U32 a=0; a<samples; a++)
|
|
{
|
|
Point3F pos = sphere.center;
|
|
switch(a)
|
|
{
|
|
//case 0:
|
|
// pos = pos;
|
|
// break;
|
|
case 1:
|
|
pos.x = box.max.x;
|
|
break;
|
|
case 2:
|
|
pos.x = box.min.x;
|
|
break;
|
|
case 3:
|
|
pos.y = box.max.y;
|
|
break;
|
|
case 4:
|
|
pos.y = box.min.y;
|
|
break;
|
|
case 5:
|
|
pos.z = box.max.z;
|
|
break;
|
|
case 6:
|
|
pos.z = box.min.z;
|
|
break;
|
|
};
|
|
|
|
Point3F planenorm = pos - sphere.center;
|
|
Point3F lightdir = sphere.center - light->mPos;
|
|
|
|
if((sgDynamicLightingOcclusionQuality > dlqtSevenSample) && (mDot(planenorm, lightdir) > 0.0f))
|
|
continue;
|
|
|
|
shadowcalcs++;
|
|
if(gClientContainer.castRay(light->mPos, pos, ShadowCasterObjectType, &info))
|
|
shadowamount += 1.0f;
|
|
}
|
|
|
|
obj->enableCollision();
|
|
|
|
entry->info.sgCachedLightingMultiplier = 1.0f - (shadowamount / ((F32)shadowcalcs));
|
|
}
|
|
|
|
distintensity *= entry->info.sgCachedLightingMultiplier;
|
|
light->sgDTSLightingOcclusionAdjust = entry->info.sgCachedLightingMultiplier;
|
|
}
|
|
else
|
|
light->sgDTSLightingOcclusionAdjust = 1.0f;
|
|
}
|
|
}
|
|
|
|
F32 intensity = colorintensity * distintensity;
|
|
if(intensity < SG_MIN_LEXEL_INTENSITY)
|
|
intensity = 0.0f;
|
|
light->mScore = S32(intensity * weight * 1024.0f);
|
|
}
|
|
|
|
void LightManager::sgInit()
|
|
{
|
|
for(U32 i=0; i<sgPropertyCount; i++)
|
|
sgLightingProperties[i] = false;
|
|
|
|
Con::addVariable("$pref::LightManager::sgDynamicParticleSystemLighting", TypeBool, &sgDynamicParticleSystemLighting);
|
|
Con::addVariable("$pref::LightManager::sgBlendedTerrainDynamicLighting", TypeBool, &sgBlendedTerrainDynamicLighting);
|
|
Con::addVariable("$pref::LightManager::sgMaxBestLights", TypeS32, &sgMaxBestLights);
|
|
Con::addVariable("$pref::LightManager::sgLightingProfileQuality", TypeS32, &sgLightingProfileQuality);
|
|
Con::addVariable("$pref::LightManager::sgLightingProfileAllowShadows", TypeBool, &sgLightingProfileAllowShadows);
|
|
|
|
Con::addVariable("$pref::LightManager::sgUseDynamicShadows", TypeBool, &sgUseDynamicShadows);
|
|
|
|
Con::addVariable("$pref::LightManager::sgDynamicLightingOcclusionQuality", TypeS32, &sgDynamicLightingOcclusionQuality);
|
|
Con::addVariable("$pref::LightManager::sgDynamicShadowQuality", TypeS32, &sgDynamicShadowQuality);
|
|
Con::addVariable("$pref::LightManager::sgMultipleDynamicShadows", TypeBool, &sgMultipleDynamicShadows);
|
|
|
|
Con::addVariable("$LightManager::sgInGUIEditor", TypeBool, &sgInGUIEditor);
|
|
|
|
Con::addVariable("$pref::Interior::sgDetailMaps", TypeBool, &sgDetailMaps);
|
|
|
|
sgRelightFilter::sgInit();
|
|
}
|
|
|
|
bool LightManager::sgAllowDetailMaps()
|
|
{
|
|
return (sgDetailMaps && (dglGetMaxTextureUnits() >= 4));
|
|
}
|
|
|
|
void LightManager::sgGetFilteredLightColor(ColorF &color, ColorF &ambient, S32 objectzone)
|
|
{
|
|
sgMissionLightingFilter *filterbasezone = NULL;
|
|
sgMissionLightingFilter *filtercurrentzone = NULL;
|
|
SimSet *filters = Sim::getsgMissionLightingFilterSet();
|
|
|
|
for(SimObject ** itr = filters->begin(); itr != filters->end(); itr++)
|
|
{
|
|
sgMissionLightingFilter *filter = dynamic_cast<sgMissionLightingFilter*>(*itr);
|
|
if(!filter)
|
|
continue;
|
|
|
|
S32 zone = filter->getCurrZone(0);
|
|
if(zone == 0)
|
|
filterbasezone = filter;
|
|
if(zone == objectzone)
|
|
{
|
|
filtercurrentzone = filter;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(filtercurrentzone)
|
|
filterbasezone = filtercurrentzone;
|
|
|
|
if(!filterbasezone)
|
|
return;
|
|
|
|
sgMissionLightingFilterData *datablock = (sgMissionLightingFilterData *)filterbasezone->getDataBlock();
|
|
|
|
if(!datablock)
|
|
return;
|
|
|
|
ColorF composite = datablock->sgLightingFilter * datablock->sgLightingIntensity;
|
|
|
|
color *= composite;
|
|
color.clamp();
|
|
|
|
ambient *= composite;
|
|
ambient.clamp();
|
|
|
|
if(!datablock->sgCinematicFilter)
|
|
return;
|
|
|
|
// must use the lighting filter intensity
|
|
// to lock the reference value relative
|
|
// to the lighting intensity
|
|
composite = datablock->sgCinematicFilterReferenceColor *
|
|
datablock->sgCinematicFilterReferenceIntensity *
|
|
datablock->sgLightingIntensity;
|
|
|
|
F32 intensity = color.red + color.green + color.blue + ambient.red + ambient.green + ambient.blue;
|
|
F32 intensityref = composite.red + composite.green + composite.blue;
|
|
|
|
intensity -= intensityref;
|
|
|
|
// blue is too intense...
|
|
if(intensity > 0.0f)
|
|
intensity *= 0.25f;
|
|
|
|
F32 redoffset = 1.0f - ((intensity) * 0.1f * datablock->sgCinematicFilterAmount);
|
|
F32 blueoffset = 1.0f + ((intensity) * 0.1f * datablock->sgCinematicFilterAmount);
|
|
F32 greenoffset = 1.0f - ((1.0f - getMin(redoffset, blueoffset)) * 0.5f);
|
|
|
|
ColorF multiplier = ColorF(redoffset, greenoffset, blueoffset);
|
|
|
|
color *= multiplier;
|
|
color.clamp();
|
|
ambient *= multiplier;
|
|
ambient.clamp();
|
|
}
|
|
|
|
void LightManager::sgSetupZoneLighting(bool enable, SimObject *sobj)
|
|
{
|
|
sgFilterZones = false;
|
|
// these must be -2...
|
|
sgZones[0] = -2;
|
|
sgZones[1] = -2;
|
|
if(!enable)
|
|
return;
|
|
if(dynamic_cast<InteriorInstance *>(sobj))
|
|
return;
|
|
SceneObject *obj = dynamic_cast<SceneObject *>(sobj);
|
|
if(!obj)
|
|
return;
|
|
sgFilterZones = true;
|
|
U32 count = getMin(obj->getNumCurrZones(), U32(2));
|
|
for(U32 i=0; i<count; i++)
|
|
{
|
|
sgZones[i] = obj->getCurrZone(i);
|
|
}
|
|
}
|
|
|
|
void LightManager::sgSetupExposureRendering()
|
|
{
|
|
if(!dglDoesSupportARBMultitexture())
|
|
return;
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, SG_LIGHTING_OVERBRIGHT_AMOUNT);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
|
|
}
|
|
|
|
void LightManager::sgResetExposureRendering()
|
|
{
|
|
if(!dglDoesSupportARBMultitexture())
|
|
return;
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, SG_LIGHTING_NORMAL_AMOUNT);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
}
|
|
|
|
// adds proper support for self-illumination...
|
|
void LightManager::sgSetAmbientSelfIllumination(LightInfo *lightinfo, F32 *lightColor,
|
|
F32 *ambientColor)
|
|
{
|
|
//LightInfo *lightInfo = (LightInfo *)lightinfo;
|
|
if(sgAllowCollectSelfIlluminationColor())
|
|
{
|
|
if(lightinfo->mType == LightInfo::Vector)
|
|
sgSelfIlluminationColor = ColorF(lightColor[0], lightColor[1], lightColor[2]);
|
|
else
|
|
sgSelfIlluminationColor = ColorF(ambientColor[0], ambientColor[1], ambientColor[2]);
|
|
}
|
|
}
|
|
|
|
void sgStatistics::sgClear()
|
|
{
|
|
sgInteriorLexelCount = 0;
|
|
sgInteriorLexelTime = 0;
|
|
sgInteriorLexelDiffuseCount = 0;
|
|
sgInteriorObjectCount = 0;
|
|
sgInteriorObjectIncludedCount = 0;
|
|
sgInteriorObjectIlluminationCount = 0;
|
|
sgInteriorSurfaceIncludedCount = 0;
|
|
sgInteriorSurfaceIlluminationCount = 0;
|
|
sgInteriorSurfaceIlluminatedCount = 0;
|
|
sgInteriorSurfaceSmoothedCount = 0;
|
|
sgInteriorSurfaceSmoothedLexelCount = 0;
|
|
sgInteriorSurfaceSetupTime = 0;
|
|
sgInteriorSurfaceSetupCount = 0;
|
|
sgInteriorSurfaceMergeTime = 0;
|
|
sgInteriorSurfaceMergeCount = 0;
|
|
sgStaticMeshSurfaceOccluderCount = 0;
|
|
sgTerrainLexelCount = 0;
|
|
sgTerrainLexelTime = 0;
|
|
}
|
|
|
|
void sgStatistics::sgPrint()
|
|
{
|
|
Con::printf("");
|
|
Con::printf(" Lighting Pack lighting system stats:");
|
|
Con::printf(" Interior Lexel Count: %d", sgInteriorLexelCount);
|
|
Con::printf(" Interior Lexel Time (ms): %f", F32(sgInteriorLexelTime) / getMax(1.0f, F32(sgInteriorLexelCount)));
|
|
Con::printf(" Interior Lexel Time Total (ms): %d", sgInteriorLexelTime);
|
|
Con::printf(" Interior Lexel Diffuse Count: %d", sgInteriorLexelDiffuseCount);
|
|
Con::printf(" Interior Object Count: %d", sgInteriorObjectCount);
|
|
Con::printf(" Interior Object Included Count: %d", sgInteriorObjectIncludedCount);
|
|
Con::printf(" Interior Object Illumination Count: %d", sgInteriorObjectIlluminationCount);
|
|
Con::printf(" Interior Surface Included Count: %d", sgInteriorSurfaceIncludedCount);
|
|
Con::printf(" Interior Surface Illumination Count: %d", sgInteriorSurfaceIlluminationCount);
|
|
Con::printf(" Interior Surface Illuminated Count: %d", sgInteriorSurfaceIlluminatedCount);
|
|
Con::printf(" Interior Surface Smoothed Count: %d", sgInteriorSurfaceSmoothedCount);
|
|
Con::printf(" Interior Surface Smoothed Lexel Count: %d", sgInteriorSurfaceSmoothedLexelCount);
|
|
Con::printf(" Interior Surface Setup Count: %d", sgInteriorSurfaceSetupCount);
|
|
Con::printf(" Interior Surface Setup Time Total (ms): %d", sgInteriorSurfaceSetupTime);
|
|
Con::printf(" Interior Surface Merge Count: %d", sgInteriorSurfaceMergeCount);
|
|
Con::printf(" Interior Surface Merge Time Total (ms): %d", sgInteriorSurfaceMergeTime);
|
|
Con::printf(" Static Mesh Surface Occluder Count: %d", sgStaticMeshSurfaceOccluderCount);
|
|
Con::printf(" Terrain Lexel Count: %d", sgTerrainLexelCount);
|
|
Con::printf(" Terrain Lexel Time (ms): %f", F32(sgTerrainLexelTime) / getMax(1.0f, F32(sgTerrainLexelCount)));
|
|
Con::printf(" Terrain Lexel Time Total (ms): %d", sgTerrainLexelTime);
|
|
}
|
|
|
|
S32 QSORT_CALLBACK LightManager::sgSortLightsByAddress(const void* a, const void* b)
|
|
{
|
|
return ((*(LightInfo**)b) - (*(LightInfo**)a));
|
|
}
|
|
|
|
S32 QSORT_CALLBACK LightManager::sgSortLightsByScore(const void* a, const void* b)
|
|
{
|
|
return((*(LightInfo**)b)->mScore - (*(LightInfo**)a)->mScore);
|
|
}
|
|
|
|
void sgRelightFilter::sgInit()
|
|
{
|
|
Con::addVariable("SceneLighting::sgFilterRelight", TypeBool, &sgRelightFilter::sgFilterRelight);
|
|
Con::addVariable("SceneLighting::sgFilterRelightVisible", TypeBool, &sgRelightFilter::sgFilterRelightVisible);
|
|
Con::addVariable("SceneLighting::sgFilterRelightByDistance", TypeBool, &sgRelightFilter::sgFilterRelightByDistance);
|
|
Con::addVariable("SceneLighting::sgFilterRelightByDistanceRadius", TypeF32, &sgRelightFilter::sgFilterRelightByDistanceRadius);
|
|
Con::addVariable("SceneLighting::sgFilterRelightByDistancePosition", TypePoint3F, &sgRelightFilter::sgFilterRelightByDistancePosition);
|
|
}
|
|
|
|
bool sgRelightFilter::sgAllowLighting(const Box3F &box, bool forcefilter)
|
|
{
|
|
if((sgRelightFilter::sgFilterRelight && sgRelightFilter::sgFilterRelightByDistance) || forcefilter)
|
|
{
|
|
if(!sgRelightFilter::sgFilterRelightVisible)
|
|
return false;
|
|
|
|
Point3F min = EditTSCtrl::smCamPos;
|
|
min.x = min.x - sgRelightFilter::sgFilterRelightByDistanceRadius;
|
|
min.y = min.y - sgRelightFilter::sgFilterRelightByDistanceRadius;
|
|
min.z = min.z - sgRelightFilter::sgFilterRelightByDistanceRadius;
|
|
|
|
Point3F max = EditTSCtrl::smCamPos;
|
|
max.x = max.x + sgRelightFilter::sgFilterRelightByDistanceRadius;
|
|
max.y = max.y + sgRelightFilter::sgFilterRelightByDistanceRadius;
|
|
max.z = max.z + sgRelightFilter::sgFilterRelightByDistanceRadius;
|
|
|
|
Box3F lightbox(min, max);
|
|
|
|
if(!box.isOverlapped(lightbox))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void sgRelightFilter::sgRenderAllowedObjects(void *editor)
|
|
{
|
|
U32 i;
|
|
WorldEditor *worldeditor = (WorldEditor *)editor;
|
|
Vector<SceneObject *> objects;
|
|
gServerContainer.findObjects(InteriorObjectType, sgFindObjectsCallback, &objects);
|
|
|
|
const ColorI color(255, 0, 255);
|
|
|
|
for(i = 0; i < objects.size(); i++)
|
|
{
|
|
SceneObject * obj = objects[i];
|
|
if(worldeditor->objClassIgnored(obj))
|
|
continue;
|
|
|
|
if(!sgRelightFilter::sgAllowLighting(obj->getWorldBox(), true))
|
|
continue;
|
|
|
|
worldeditor->renderObjectBox(obj, color);
|
|
}
|
|
}
|
|
|