Files
firestorm/Gameleap/code/mw4/Libraries/Adept/LightManager.cpp
T
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
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.
2026-06-24 21:28:16 -05:00

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);
}