Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
937 lines
28 KiB
C++
937 lines
28 KiB
C++
#include "AdeptHeaders.hpp"
|
|
#include "LightManager.hpp"
|
|
#include "CollisionVolume.hpp"
|
|
#include <MLR\MLRAmbientLight.hpp>
|
|
#include <MLR\MLRInfiniteLight.hpp>
|
|
#include <MLR\MLRSpotLight.hpp>
|
|
#include <MLR\MLRPointLight.hpp>
|
|
#include <MLR\MLRProjectLight.hpp>
|
|
#include <MLR\MLRShadowLight.hpp>
|
|
#include <MLR\MLRCenterPointLight.hpp>
|
|
#include "CollisionGrid.hpp"
|
|
#include "Tile.hpp"
|
|
#include "Map.hpp"
|
|
#include "Zone.hpp"
|
|
#include <MLR\MLRLightMap.hpp>
|
|
#include <MLR\MLRLookUpLight.hpp>
|
|
#include <ElementRenderer\ShapeElement.hpp>
|
|
#include <ElementRenderer\CameraElement.hpp>
|
|
#include <ElementRenderer\SwitchElement.hpp>
|
|
#include <ElementRenderer\ShapeLODElement.hpp>
|
|
#include <ElementRenderer\LODElement.hpp>
|
|
#include "VideoRenderer.hpp"
|
|
#include <MLR\MLRTexturePool.hpp>
|
|
#include <MLR\MLRClipper.hpp>
|
|
#include <MLR\MLRTexture.hpp>
|
|
|
|
static DWORD Light_Count=0;
|
|
extern void _stdcall End3DScene();
|
|
DECLARE_TIMER(static, Shadow_Casting);
|
|
DECLARE_TIMER(static, Shadow_Start);
|
|
DECLARE_TIMER(static, Shadow_Traversal);
|
|
DECLARE_TIMER(static, Shadow_End);
|
|
|
|
#define HUNT_LIGHT_CRASH
|
|
|
|
#if 0
|
|
#define SHADOW_RENDER(string) RENDER("Shadow::" string)
|
|
#else
|
|
#define SHADOW_RENDER(string)
|
|
#endif
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
EnvironmentalLight::EnvironmentalLight(MidLevelRenderer::MLRLight *light):
|
|
gosFX::Light(light)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(light);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
EnvironmentalLight::~EnvironmentalLight()
|
|
{
|
|
Check_Object(this);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
AmbientLight::AmbientLight(MidLevelRenderer::MLRAmbientLight *light):
|
|
EnvironmentalLight(light)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(light);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
InfiniteLight::InfiniteLight(MidLevelRenderer::MLRInfiniteLight *light):
|
|
EnvironmentalLight(light)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(light);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
LookupLight::LookupLight(MidLevelRenderer::MLRLookUpLight *light):
|
|
InfiniteLight(light)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(light);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
FiniteLight::FiniteLight(MidLevelRenderer::MLRInfiniteLightWithFalloff *light):
|
|
gosFX::Light(light)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(light);
|
|
m_minRow = m_maxRow = m_minColumn = m_maxColumn = 255;
|
|
Set_Statistic(Light_Count, Light_Count+1);
|
|
if (light->GetLightMask()&MidLevelRenderer::MLRState::LightMapLightingMode)
|
|
light->SetDynamicLight();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
FiniteLight::~FiniteLight()
|
|
{
|
|
Check_Object(this);
|
|
|
|
Set_Statistic(Light_Count, Light_Count-1);
|
|
if (CollisionGrid::Instance && m_minRow != 255)
|
|
{
|
|
Check_Object(CollisionGrid::Instance);
|
|
for (BYTE z=m_minRow; z<=m_maxRow; ++z)
|
|
{
|
|
for (BYTE x=m_minColumn; x<=m_maxColumn; ++x)
|
|
{
|
|
Tile *tile = CollisionGrid::Instance->GetTile(z, x);
|
|
Check_Object(tile);
|
|
tile->m_lightsChanged = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void
|
|
FiniteLight::ChangeLight(gosFX::LightManager::Info *info)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(info);
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// Update the radius, then compute what the new tile limits of the lights
|
|
// are
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
// BaseClass::ChangeLight(info);
|
|
Check_Object(CollisionGrid::Instance);
|
|
Scalar row_scale = 1.0f/CollisionGrid::Instance->m_rowCellSize;
|
|
Scalar column_scale = 1.0f/CollisionGrid::Instance->m_columnCellSize;
|
|
Scalar x = info->m_origin(3,0);
|
|
Scalar z = info->m_origin(3,2);
|
|
|
|
//
|
|
//-------------------------------
|
|
// Figure out the grid boundaries
|
|
//-------------------------------
|
|
//
|
|
Scalar min_z =
|
|
(z - info->m_outer - CollisionGrid::Instance->m_rowOffset) * row_scale;
|
|
BYTE min_row =
|
|
(min_z < 0.0f) ? (BYTE)0 : Truncate_Float_To_Byte(min_z);
|
|
Scalar max_z =
|
|
(z + info->m_outer - CollisionGrid::Instance->m_rowOffset) * row_scale;
|
|
BYTE max_row = Truncate_Float_To_Byte(max_z);
|
|
if (max_row >= CollisionGrid::Instance->m_rowCellCount)
|
|
max_row =
|
|
static_cast<BYTE>(CollisionGrid::Instance->m_rowCellCount - 1);
|
|
|
|
Scalar min_x =
|
|
(x - info->m_outer - CollisionGrid::Instance->m_columnOffset) * column_scale;
|
|
BYTE min_col =
|
|
(min_x < 0.0f) ? (BYTE)0 : Truncate_Float_To_Byte(min_x);
|
|
Scalar max_x =
|
|
(x + info->m_outer - CollisionGrid::Instance->m_columnOffset) * column_scale;
|
|
BYTE max_col = Truncate_Float_To_Byte(max_x);
|
|
if (max_col >= CollisionGrid::Instance->m_columnCellCount)
|
|
max_col =
|
|
static_cast<BYTE>(CollisionGrid::Instance->m_columnCellCount - 1);
|
|
|
|
//
|
|
//------------------------------------------------
|
|
// Update the tile boundaries if they have changed
|
|
//------------------------------------------------
|
|
//
|
|
if (
|
|
min_row != m_minRow || max_row != m_maxRow
|
|
|| min_col != m_minColumn || max_col != m_maxColumn ||
|
|
(info->m_intensity<Stuff::SMALL)^(GetMLRLight()->GetIntensity()<Stuff::SMALL)
|
|
)
|
|
{
|
|
|
|
//
|
|
//------------------------------------
|
|
// Remove the light from all the zones
|
|
//------------------------------------
|
|
//
|
|
if (m_minRow < 255)
|
|
{
|
|
Verify(
|
|
m_minColumn <= m_maxColumn
|
|
&& m_maxColumn < CollisionGrid::Instance->m_columnCellCount
|
|
);
|
|
Verify(
|
|
m_minRow <= m_maxRow
|
|
&& m_maxRow < CollisionGrid::Instance->m_rowCellCount
|
|
);
|
|
for (BYTE z=m_minRow; z<=m_maxRow; ++z)
|
|
{
|
|
for (BYTE x=m_minColumn; x<=m_maxColumn; ++x)
|
|
{
|
|
Tile *tile = CollisionGrid::Instance->GetTile(z, x);
|
|
Check_Object(tile);
|
|
tile->m_lights.RemovePlug(this);
|
|
tile->m_lightsChanged = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//------------------------
|
|
// Add it to the new zones
|
|
//------------------------
|
|
//
|
|
m_minRow = min_row;
|
|
m_maxRow = max_row;
|
|
m_minColumn = min_col;
|
|
m_maxColumn = max_col;
|
|
Verify(
|
|
m_minColumn <= m_maxColumn
|
|
&& m_maxColumn < CollisionGrid::Instance->m_columnCellCount
|
|
);
|
|
Verify(
|
|
m_minRow <= m_maxRow
|
|
&& m_maxRow < CollisionGrid::Instance->m_rowCellCount
|
|
);
|
|
if(info->m_intensity > Stuff::SMALL)
|
|
{
|
|
for (BYTE z=m_minRow; z<=m_maxRow; ++z)
|
|
{
|
|
for (BYTE x=m_minColumn; x<=m_maxColumn; ++x)
|
|
{
|
|
Tile *tile = CollisionGrid::Instance->GetTile(z, x);
|
|
Check_Object(tile);
|
|
tile->m_lights.Add(this);
|
|
tile->m_lightsChanged = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BaseClass::ChangeLight(info);
|
|
|
|
|
|
MidLevelRenderer::MLRInfiniteLightWithFalloff *light = GetMLRLight();
|
|
Check_Object(light);
|
|
light->SetFalloffDistance(info->m_inner, info->m_outer);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void
|
|
FiniteLight::GetInfo(gosFX::LightManager::Info *info)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(info);
|
|
|
|
BaseClass::GetInfo(info);
|
|
MidLevelRenderer::MLRInfiniteLightWithFalloff *light = GetMLRLight();
|
|
Check_Object(light);
|
|
light->GetFalloffDistance(
|
|
info->m_inner,
|
|
info->m_outer
|
|
);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
PointLight::PointLight(MidLevelRenderer::MLRPointLight *light):
|
|
FiniteLight(light)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(light);
|
|
|
|
gosFX::LightManager::Info info;
|
|
PointLight::GetInfo(&info);
|
|
if (info.m_outer > 0.0f)
|
|
PointLight::ChangeLight(&info);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
SpotLight::SpotLight(MidLevelRenderer::MLRSpotLight *light):
|
|
FiniteLight(light)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(light);
|
|
|
|
gosFX::LightManager::Info info;
|
|
SpotLight::GetInfo(&info);
|
|
if (info.m_outer > 0.0f)
|
|
SpotLight::ChangeLight(&info);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void
|
|
SpotLight::ChangeLight(gosFX::LightManager::Info *info)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(info);
|
|
|
|
BaseClass::ChangeLight(info);
|
|
MidLevelRenderer::MLRSpotLight *light = GetMLRLight();
|
|
Check_Object(light);
|
|
light->SetSpreadAngle(info->m_spread);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void
|
|
SpotLight::GetInfo(gosFX::LightManager::Info *info)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(info);
|
|
|
|
BaseClass::GetInfo(info);
|
|
MidLevelRenderer::MLRSpotLight *light = GetMLRLight();
|
|
Check_Object(light);
|
|
light->GetSpreadAngle(&info->m_spread);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
ProjectLight::ProjectLight(MidLevelRenderer::MLRProjectLight *light):
|
|
FiniteLight(light)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(light);
|
|
|
|
gosFX::LightManager::Info info;
|
|
ProjectLight::GetInfo(&info);
|
|
if (info.m_outer > 0.0f)
|
|
ProjectLight::ChangeLight(&info);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void
|
|
ProjectLight::ChangeLight(gosFX::LightManager::Info *info)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(info);
|
|
|
|
BaseClass::ChangeLight(info);
|
|
MidLevelRenderer::MLRProjectLight *light = GetMLRLight();
|
|
Check_Object(light);
|
|
light->SetSpreadAngle(info->m_spread);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void
|
|
ProjectLight::GetInfo(gosFX::LightManager::Info *info)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(info);
|
|
|
|
BaseClass::GetInfo(info);
|
|
MidLevelRenderer::MLRProjectLight *light = GetMLRLight();
|
|
Check_Object(light);
|
|
light->GetSpreadAngle(&info->m_spread);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
ShadowLight::ShadowLight(MidLevelRenderer::MLRShadowLight *light):
|
|
FiniteLight(light)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(light);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void
|
|
ShadowLight::ChangeLight(gosFX::LightManager::Info *info)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(info);
|
|
|
|
BaseClass::ChangeLight(info);
|
|
// MidLevelRenderer::MLRShadowLight *light = GetMLRLight();
|
|
// Check_Object(light);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void
|
|
ShadowLight::GetInfo(gosFX::LightManager::Info *info)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(info);
|
|
|
|
BaseClass::GetInfo(info);
|
|
// MidLevelRenderer::MLRShadowLight *light = GetMLRLight();
|
|
// Check_Object(light);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
CenterPointLight::CenterPointLight(MidLevelRenderer::MLRCenterPointLight *light):
|
|
FiniteLight(light)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(light);
|
|
|
|
gosFX::LightManager::Info info;
|
|
CenterPointLight::GetInfo(&info);
|
|
if (info.m_outer > 0.0f)
|
|
CenterPointLight::ChangeLight(&info);
|
|
}
|
|
|
|
//############################################################################
|
|
//############################ LightManager ################################
|
|
//############################################################################
|
|
|
|
TiledLightManager*
|
|
&TiledLightManager::Instance=*Cast_Pointer(TiledLightManager**, &gosFX::LightManager::Instance);
|
|
|
|
TiledLightManager::ShadowMode
|
|
TiledLightManager::s_ShadowMode=e_ArticulatedShadows;
|
|
|
|
static bool __stdcall CheckNoShadows()
|
|
{
|
|
return TiledLightManager::s_ShadowMode==TiledLightManager::e_NoShadows;
|
|
}
|
|
|
|
static void __stdcall EnableNoShadows()
|
|
{
|
|
TiledLightManager::s_ShadowMode = TiledLightManager::e_NoShadows;
|
|
}
|
|
|
|
static bool __stdcall CheckSimpleShadows()
|
|
{
|
|
return TiledLightManager::s_ShadowMode==TiledLightManager::e_Shadows;
|
|
}
|
|
|
|
static void __stdcall EnableSimpleShadows()
|
|
{
|
|
TiledLightManager::s_ShadowMode = TiledLightManager::e_Shadows;
|
|
}
|
|
|
|
static bool __stdcall CheckArticulatedShadows()
|
|
{
|
|
return TiledLightManager::s_ShadowMode==TiledLightManager::e_ArticulatedShadows;
|
|
}
|
|
|
|
static void __stdcall EnableArticulatedShadows()
|
|
{
|
|
TiledLightManager::s_ShadowMode = TiledLightManager::e_ArticulatedShadows;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void
|
|
TiledLightManager::InitializeClass(NotationFile *startup_ini)
|
|
{
|
|
Verify(!Instance);
|
|
gos_PushCurrentHeap(VideoRenderer::s_Heap);
|
|
Instance = new TiledLightManager;
|
|
gos_PopCurrentHeap();
|
|
|
|
#if !defined(NO_STATS)
|
|
AddStatistic("Local Lights", "lights", gos_DWORD, &Light_Count, 0);
|
|
#endif
|
|
|
|
Initialize_Timer(Shadow_Casting, "Shadow Casting");
|
|
Initialize_Timer(Shadow_Start, " Shadow Texture Start");
|
|
Initialize_Timer(Shadow_Traversal, " Shadow Traversal");
|
|
Initialize_Timer(Shadow_End, " Shadow Texture End");
|
|
|
|
AddDebuggerMenuItem("Libraries\\Graphics Options\\No Shadows", CheckNoShadows, EnableNoShadows, 0 );
|
|
AddDebuggerMenuItem("Libraries\\Graphics Options\\Simple Shadows", CheckSimpleShadows, EnableSimpleShadows, 0 );
|
|
AddDebuggerMenuItem("Libraries\\Graphics Options\\Articulated Shadows", CheckArticulatedShadows, EnableArticulatedShadows, 0 );
|
|
|
|
if (startup_ini)
|
|
{
|
|
Check_Object(startup_ini);
|
|
Page *page = startup_ini->FindPage("Graphics Options");
|
|
if (page)
|
|
{
|
|
Check_Object(page);
|
|
int mode;
|
|
if (page->GetEntry("ShadowMode", &mode))
|
|
s_ShadowMode = static_cast<ShadowMode>(mode);
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void
|
|
TiledLightManager::TerminateClass(NotationFile *startup_ini)
|
|
{
|
|
|
|
// MSL 5.02 Prevent Option Overwrite
|
|
// Prevents Software from Overwriting Options.ini Settings
|
|
// if (startup_ini)
|
|
// {
|
|
// Check_Object(startup_ini);
|
|
// Page *page = startup_ini->SetPage("Graphics Options");
|
|
// Check_Object(page);
|
|
// int mode = s_ShadowMode;
|
|
// page->SetEntry("ShadowMode", mode);
|
|
// }
|
|
|
|
Check_Object(Instance);
|
|
delete Instance;
|
|
Instance = NULL;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
TiledLightManager::TiledLightManager():
|
|
m_shadows(NULL)
|
|
{
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
TiledLightManager::~TiledLightManager()
|
|
{
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
gosFX::Light*
|
|
TiledLightManager::MakeAmbientLight()
|
|
{
|
|
Check_Object(this);
|
|
|
|
gos_PushCurrentHeap(MidLevelRenderer::LightsHeap);
|
|
MidLevelRenderer::MLRAmbientLight *mlr_light = new MidLevelRenderer::MLRAmbientLight;
|
|
Check_Object(mlr_light);
|
|
gos_PopCurrentHeap();
|
|
return new AmbientLight(mlr_light);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
gosFX::Light*
|
|
TiledLightManager::MakeInfiniteLight()
|
|
{
|
|
Check_Object(this);
|
|
|
|
gos_PushCurrentHeap(MidLevelRenderer::LightsHeap);
|
|
MidLevelRenderer::MLRInfiniteLight *mlr_light = new MidLevelRenderer::MLRInfiniteLight;
|
|
Check_Object(mlr_light);
|
|
gos_PopCurrentHeap();
|
|
return new InfiniteLight(mlr_light);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
gosFX::Light*
|
|
TiledLightManager::MakeLookupLight()
|
|
{
|
|
Check_Object(this);
|
|
|
|
gos_PushCurrentHeap(MidLevelRenderer::LightsHeap);
|
|
MidLevelRenderer::MLRLookUpLight *mlr_light = new MidLevelRenderer::MLRLookUpLight;
|
|
Check_Object(mlr_light);
|
|
gos_PopCurrentHeap();
|
|
return new InfiniteLight(mlr_light);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
gosFX::Light*
|
|
TiledLightManager::MakePointLight(
|
|
const char* light_map,
|
|
bool light_vertex
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
|
|
gos_PushCurrentHeap(MidLevelRenderer::LightsHeap);
|
|
MidLevelRenderer::MLRPointLight *mlr_light = new MidLevelRenderer::MLRPointLight;
|
|
Check_Object(mlr_light);
|
|
if (light_map)
|
|
{
|
|
MString name = light_map;
|
|
Check_Object(MidLevelRenderer::MLRTexturePool::Instance);
|
|
MidLevelRenderer::MLRTexture *texture =
|
|
(*MidLevelRenderer::MLRTexturePool::Instance)(name, 0);
|
|
if (!texture)
|
|
texture = MidLevelRenderer::MLRTexturePool::Instance->Add(name, 0);
|
|
Check_Object(texture);
|
|
MidLevelRenderer::MLRLightMap *map = new MidLevelRenderer::MLRLightMap(texture);
|
|
Check_Object(map);
|
|
mlr_light->SetLightMap(map);
|
|
if (!light_vertex)
|
|
{
|
|
int mask = mlr_light->GetLightMask();
|
|
mask &= ~MidLevelRenderer::MLRState::VertexLightingMode;
|
|
mlr_light->SetLightMask(mask);
|
|
}
|
|
}
|
|
gos_PopCurrentHeap();
|
|
return new PointLight(mlr_light);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
gosFX::Light*
|
|
TiledLightManager::MakeSpotLight(
|
|
const char* light_map,
|
|
bool light_vertex
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
|
|
gos_PushCurrentHeap(MidLevelRenderer::LightsHeap);
|
|
MidLevelRenderer::MLRSpotLight *mlr_light = new MidLevelRenderer::MLRSpotLight;
|
|
Check_Object(mlr_light);
|
|
gos_PopCurrentHeap();
|
|
if (light_map)
|
|
{
|
|
MString name = light_map;
|
|
Check_Object(MidLevelRenderer::MLRTexturePool::Instance);
|
|
MidLevelRenderer::MLRTexture *texture =
|
|
(*MidLevelRenderer::MLRTexturePool::Instance)(name, 0);
|
|
if (!texture)
|
|
texture = MidLevelRenderer::MLRTexturePool::Instance->Add(name, 0);
|
|
Check_Object(texture);
|
|
MidLevelRenderer::MLRLightMap *map = new MidLevelRenderer::MLRLightMap(texture);
|
|
Check_Object(map);
|
|
mlr_light->SetLightMap(map);
|
|
if (!light_vertex)
|
|
{
|
|
int mask = mlr_light->GetLightMask();
|
|
mask &= ~MidLevelRenderer::MLRState::VertexLightingMode;
|
|
mlr_light->SetLightMask(mask);
|
|
}
|
|
}
|
|
return new SpotLight(mlr_light);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
gosFX::Light*
|
|
TiledLightManager::MakeProjectLight(
|
|
const char* light_map,
|
|
bool light_vertex
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
|
|
gos_PushCurrentHeap(MidLevelRenderer::LightsHeap);
|
|
MidLevelRenderer::MLRProjectLight *mlr_light = new MidLevelRenderer::MLRProjectLight;
|
|
Check_Object(mlr_light);
|
|
gos_PopCurrentHeap();
|
|
if (light_map)
|
|
{
|
|
MString name = light_map;
|
|
Check_Object(MidLevelRenderer::MLRTexturePool::Instance);
|
|
MidLevelRenderer::MLRTexture *texture =
|
|
(*MidLevelRenderer::MLRTexturePool::Instance)(name, 0);
|
|
if (!texture)
|
|
texture = MidLevelRenderer::MLRTexturePool::Instance->Add(name, 0);
|
|
Check_Object(texture);
|
|
MidLevelRenderer::MLRLightMap *map = new MidLevelRenderer::MLRLightMap(texture);
|
|
Check_Object(map);
|
|
mlr_light->SetLightMap(map);
|
|
if (!light_vertex)
|
|
{
|
|
int mask = mlr_light->GetLightMask();
|
|
mask &= ~MidLevelRenderer::MLRState::VertexLightingMode;
|
|
mlr_light->SetLightMask(mask);
|
|
}
|
|
}
|
|
return new ProjectLight(mlr_light);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
gosFX::Light*
|
|
TiledLightManager::MakeShadowLight(
|
|
const char* light_map,
|
|
bool light_vertex
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
|
|
gos_PushCurrentHeap(MidLevelRenderer::LightsHeap);
|
|
MidLevelRenderer::MLRShadowLight *mlr_light = new MidLevelRenderer::MLRShadowLight;
|
|
Check_Object(mlr_light);
|
|
gos_PopCurrentHeap();
|
|
if (light_map)
|
|
{
|
|
MString name = light_map;
|
|
Check_Object(MidLevelRenderer::MLRTexturePool::Instance);
|
|
MidLevelRenderer::MLRTexture *texture =
|
|
(*MidLevelRenderer::MLRTexturePool::Instance)(name, 0);
|
|
if (!texture)
|
|
texture = MidLevelRenderer::MLRTexturePool::Instance->Add(name, 0);
|
|
Check_Object(texture);
|
|
MidLevelRenderer::MLRLightMap *map = new MidLevelRenderer::MLRLightMap(texture);
|
|
Check_Object(map);
|
|
mlr_light->SetLightMap(map);
|
|
if (!light_vertex)
|
|
{
|
|
int mask = mlr_light->GetLightMask();
|
|
mask &= ~MidLevelRenderer::MLRState::VertexLightingMode;
|
|
mlr_light->SetLightMask(mask);
|
|
}
|
|
}
|
|
return new ShadowLight(mlr_light);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
gosFX::Light*
|
|
TiledLightManager::MakeLight(MidLevelRenderer::MLRLight *light)
|
|
{
|
|
Check_Object(this);
|
|
|
|
if (light->IsDerivedFrom(MidLevelRenderer::MLRAmbientLight::DefaultData))
|
|
return new AmbientLight(Cast_Object(MidLevelRenderer::MLRAmbientLight*, light));
|
|
if (light->IsDerivedFrom(MidLevelRenderer::MLRLookUpLight::DefaultData))
|
|
return new LookupLight(Cast_Object(MidLevelRenderer::MLRLookUpLight*, light));
|
|
if (light->IsDerivedFrom(MidLevelRenderer::MLRInfiniteLight::DefaultData))
|
|
return new InfiniteLight(Cast_Object(MidLevelRenderer::MLRInfiniteLight*, light));
|
|
if (light->IsDerivedFrom(MidLevelRenderer::MLRSpotLight::DefaultData))
|
|
return new SpotLight(Cast_Object(MidLevelRenderer::MLRSpotLight*, light));
|
|
if (light->IsDerivedFrom(MidLevelRenderer::MLRPointLight::DefaultData))
|
|
return new PointLight(Cast_Object(MidLevelRenderer::MLRPointLight*, light));
|
|
if (light->IsDerivedFrom(MidLevelRenderer::MLRProjectLight::DefaultData))
|
|
return new ProjectLight(Cast_Object(MidLevelRenderer::MLRProjectLight*, light));
|
|
if (light->IsDerivedFrom(MidLevelRenderer::MLRShadowLight::DefaultData))
|
|
{
|
|
ShadowLight *shadow = new ShadowLight(Cast_Object(MidLevelRenderer::MLRShadowLight*, light));
|
|
Check_Object(shadow);
|
|
m_shadows.Add(shadow);
|
|
return shadow;
|
|
}
|
|
STOP(("Non-supported light"));
|
|
return NULL;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void
|
|
TiledLightManager::CastShadows(ElementRenderer::CameraElement *camera)
|
|
{
|
|
Check_Object(this);
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// Go through the list of shadows, checking each light for its LOD setting
|
|
//------------------------------------------------------------------------
|
|
//
|
|
if (s_ShadowMode == e_NoShadows)
|
|
return;
|
|
SHADOW_RENDER("");
|
|
Start_Timer(ElementRenderer::Total_Video);
|
|
Start_Timer(Shadow_Casting);
|
|
const LinearMatrix4D &camera_to_world = camera->GetLocalToWorld();
|
|
ChainIteratorOf<ShadowLight*> shadows(&m_shadows);
|
|
ShadowLight *shadow;
|
|
while ((shadow = shadows.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(shadow);
|
|
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// Get the shadow information and set the shadow to the default mode of
|
|
// blob
|
|
//---------------------------------------------------------------------
|
|
//
|
|
MidLevelRenderer::MLRShadowLight *shadow_light = shadow->GetMLRLight();
|
|
Check_Object(shadow_light);
|
|
Info info;
|
|
shadow->GetInfo(&info);
|
|
shadow_light->SeeDetailShadow(false);
|
|
Scalar blob_distance = shadow_light->GetBlobDistance();
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// Get the light information and compute the vector between the center
|
|
// of the shadow and the eye (normalized to the x-z plane). If we are
|
|
// too far away, or if shadows are simple, don't articulate
|
|
//--------------------------------------------------------------------
|
|
//
|
|
Vector3D dist(
|
|
camera_to_world(3,0) - info.m_origin(3,0),
|
|
0.0f,
|
|
camera_to_world(3,2) - info.m_origin(3,2)
|
|
);
|
|
if (dist.GetLengthSquared() >= blob_distance*blob_distance || s_ShadowMode==e_Shadows)
|
|
continue;
|
|
|
|
//
|
|
//---------------------------------------------------------
|
|
// Make sure that the shadow is within the viewing frustrum
|
|
//---------------------------------------------------------
|
|
//
|
|
Point3D center(info.m_origin);
|
|
const Plane* plane = &camera->GetWorldCullingPlane(0);
|
|
for (int i=0; i<ElementRenderer::CameraElement::CullingPlaneCount; ++i, ++plane)
|
|
{
|
|
Scalar distance = plane->GetDistanceTo(center);
|
|
if (distance >= info.m_inner)
|
|
break;
|
|
}
|
|
if (i<ElementRenderer::CameraElement::CullingPlaneCount)
|
|
continue;
|
|
//
|
|
//-------------------------------------------------------------
|
|
// Compute the direction of the sunlight from the lights origin
|
|
//-------------------------------------------------------------
|
|
//
|
|
UnitVector3D sun_light;
|
|
info.m_origin.GetLocalForwardInWorld(&sun_light);
|
|
|
|
//
|
|
// For some reason the shadow is becoming interesting too early and the origin of the light is not
|
|
// synced. This can cause the y portion of the sun_light vector to be 0.0. So we are going to throw
|
|
// out all cases where the sunlight is horizontal or up. This was causing div by 0 below.
|
|
//
|
|
if (sun_light.y >= -SMALL)
|
|
continue;
|
|
|
|
//
|
|
//-------------------------------------------------------------------
|
|
// The shadow will be in the frustrum and close enough, so now set up
|
|
// the renderer and the rasterizer to start drawing the object
|
|
//-------------------------------------------------------------------
|
|
//
|
|
MidLevelRenderer::MLRState dState;
|
|
camera->GetClipper()->StartDraw(
|
|
Stuff::LinearMatrix4D::Identity,
|
|
Stuff::Matrix4D::Identity,
|
|
Stuff::RGBAColor::White,
|
|
&Stuff::RGBAColor::White,
|
|
dState,
|
|
NULL
|
|
);
|
|
const MidLevelRenderer::MLRTexture *shadow_texture = shadow_light->GetShadowTexture();
|
|
Check_Object(shadow_texture);
|
|
{
|
|
SHADOW_RENDER("Start Render");
|
|
Start_Timer(Shadow_Start);
|
|
gos_StartRenderToTexture( shadow_texture->GetImage()->GetHandle() );
|
|
Stop_Timer(Shadow_Start);
|
|
}
|
|
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// Compute where the sun would strike a x-z plane containing the origin
|
|
// of the vehicle if the ray runs thru the center of the vehicle's
|
|
// collision volume
|
|
//---------------------------------------------------------------------
|
|
//
|
|
SHADOW_RENDER("Traversal");
|
|
{
|
|
Start_Timer(Shadow_Traversal);
|
|
Entity *vehicle = Cast_Object(Entity*, shadow->m_shadowCaster->GetClientData());
|
|
CollisionVolume *cv = vehicle->GetSolidVolume();
|
|
|
|
#if defined(HUNT_LIGHT_CRASH) && defined(LAB_ONLY)
|
|
|
|
if (cv == NULL)
|
|
{
|
|
if (vehicle->instanceName)
|
|
{
|
|
const char *name;
|
|
name = vehicle->GetModelName ();
|
|
|
|
STOP(("VEHICLE HAS NO CV : %s : %s", (char *)vehicle->instanceName, name));
|
|
}
|
|
else
|
|
{
|
|
const char *name;
|
|
name = vehicle->GetModelName ();
|
|
|
|
STOP(("VEHICLE HAS NO CV : noname : %s", name));
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
Check_Object(cv);
|
|
LinearMatrix4D world_bounds;
|
|
world_bounds.Multiply(cv->m_localSpaceBounds.localToParent, vehicle->GetLocalToWorld());
|
|
Stuff::Point3D shadow_translation(world_bounds);
|
|
Stuff::Point3D vehicle_translation(shadow->m_shadowCaster->GetLocalToWorld());
|
|
Stuff::Scalar height = shadow_translation.y - vehicle_translation.y;
|
|
shadow_translation.AddScaled(shadow_translation, sun_light, -height/sun_light.y);
|
|
|
|
//
|
|
//-------------------------------------------------------------------
|
|
// The matrix will face the way the light did, but it will ignore any
|
|
// pitch by aligning the local Y axis to the world Y axis
|
|
//-------------------------------------------------------------------
|
|
//
|
|
Stuff::LinearMatrix4D shadow_plane_matrix(info.m_origin);
|
|
shadow_plane_matrix.BuildTranslation(shadow_translation);
|
|
shadow_plane_matrix.AlignLocalAxisToWorldVector(Stuff::Vector3D::Up, Y_Axis, X_Axis, Z_Axis);
|
|
|
|
//
|
|
//------------------------------------------------------
|
|
// Now actually traverse the targeted object and draw it
|
|
//------------------------------------------------------
|
|
//
|
|
shadow->m_shadowCaster->CastShadow(
|
|
shadow_plane_matrix,
|
|
sun_light,
|
|
info.m_outer
|
|
);
|
|
Stop_Timer(Shadow_Traversal);
|
|
}
|
|
|
|
//
|
|
//--------------
|
|
// Now rasterize
|
|
//--------------
|
|
//
|
|
{
|
|
SHADOW_RENDER("End Render");
|
|
Start_Timer(Shadow_End);
|
|
gos_EndRenderToTexture(true);
|
|
End3DScene();
|
|
Stop_Timer(Shadow_End);
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------
|
|
// Set up some parameters for the shadow - the falloff distance bit
|
|
// is flaky
|
|
//-----------------------------------------------------------------
|
|
//
|
|
shadow_light->SeeDetailShadow(true);
|
|
}
|
|
Stop_Timer(Shadow_Casting);
|
|
Stop_Timer(ElementRenderer::Total_Video);
|
|
}
|