Files
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

530 lines
14 KiB
C++

#include "ProxyHeaders.hpp"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BurnLightsProcess::BurnLightsProcess():
materialsAreWhite(true),
lightsToBurn(NULL),
matrixStack(30, 20, "Light Burning Stack")
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BurnLightsProcess::BurnLightsProcess(NotationFile *data_file):
Process(data_file),
lightsToBurn(NULL),
matrixStack(30, 20, "Light Burning Stack")
{
Check_Object(data_file);
Page *page = data_file->FindPage("BurnLights");
if (page)
page->GetEntry("MaterialsAreWhite", &materialsAreWhite);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ChildProxy::FindLights(BurnLightsProcess *process)
{
Check_Object(this);
Check_Object(process);
process->FindLightsCallback(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GroupProxy::FindLights(BurnLightsProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Call the control callback
//--------------------------
//
process->FindLightsCallback(this);
if (!process->continueProcess)
return;
//
//---------------------------------------------------
// If the proxy is a group, look in it for lights
//---------------------------------------------------
//
ChildProxy *child = UseFirstChildProxy();
while (child)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
child->FindLights(process);
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
child->DetachReference();
break;
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
LightProxy::FindLights(BurnLightsProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Call the control callback
//--------------------------
//
process->FindLightsCallback(this);
if (!process->continueProcess)
return;
//
//--------------------------------------------------
// If the proxy is a light, add it to the light list
//--------------------------------------------------
//
AttachReference();
process->lightsToBurn.Add(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SceneProxy::FindLights(BurnLightsProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Call the control callback
//--------------------------
//
process->FindLightsCallback(this);
if (!process->continueProcess)
return;
//
//-----------------------------------------------
// If the proxy is a scene, look in it for lights
//-----------------------------------------------
//
ChildProxy *child = UseFirstChildProxy();
while (child)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
child->FindLights(process);
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
child->DetachReference();
break;
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
VertexProxy::BurnLights(
BurnLightsProcess *process,
DynamicArrayOf<TransformedLight> &lights
)
{
Check_Object(this);
Check_Object(process);
Check_Object(&lights);
//
//--------------------------
// Call the control callback
//--------------------------
//
process->BurnLightsCallback(this);
if (!process->continueProcess)
return;
//
//-------------------------------------------------------------
// Make sure that this vertex can be lit (i.e. it has a normal)
//-------------------------------------------------------------
//
Normal3D normal;
if (!GetNormal(&normal))
return;
//
//--------------------------------------------------------------------
// Get the current color for its alpha, then initialize to the ambient
// color
//--------------------------------------------------------------------
//
unsigned light_count = lights.GetLength();
RGBAColor total_color;
GetColor(&total_color);
total_color.red = 0.0f;
total_color.green = 0.0f;
total_color.blue = 0.0f;
//
//-----------------------------------
// Test each light against the vertex
//-----------------------------------
//
for (unsigned i=0; i<light_count; ++i)
{
LightProxy *light = lights[i].lightProxy;
Check_Object(light);
//
//----------------------------------------------------------------
// Get the light color and if it is an ambient light, just add the
// light color
//----------------------------------------------------------------
//
RGBColor light_color;
light->GetColor(&light_color);
if (light->IsAmbient())
{
total_color.red += light_color.red;
total_color.green += light_color.green;
total_color.blue += light_color.blue;
continue;
}
//
//---------------------------------------------------------------------
// Get the falloff distances. If there are no falloff distances, it is
// an infinite light, so set the light normal directly from the matrix
//---------------------------------------------------------------------
//
Scalar n,f;
UnitVector3D light_z;
if (!light->GetFalloffDistance(&n, &f))
lights[i].lightToLocal.GetLocalForwardInWorld(&light_z);
//
//---------------------------------------------------------------
// Otherwise, it will be a point or spot light, in which case the
// translation component of the lightToLocal matrix contains the
// vertex to light vector
//---------------------------------------------------------------
//
else
{
Point3D vertex_to_light;
vertex_to_light = lights[i].lightToLocal;
Point3D position;
GetPosition(&position);
vertex_to_light -= position;
//
//--------------------------------------------------------------
// If the distance to the vertex is zero, the light will not
// contribute to the vertex coloration. Otherwise, decrease the
// light level as appropriate to the distance
//--------------------------------------------------------------
//
Scalar length = vertex_to_light.GetLength();
if (Small_Enough(length) || length>=f)
continue;
else if (length > n)
{
Verify(f - n > SMALL);
Scalar falloff = (length - n) / (f - n);
light_color.red *= falloff;
light_color.green *= falloff;
light_color.blue *= falloff;
}
//
//--------------------------------------------------------------
// If this is a point light, set the light vector to the negated
// normal of vertex to light
//--------------------------------------------------------------
//
Radian spread_angle;
if (!light->GetSpreadAngle(&spread_angle))
{
length = -1.0f / length;
light_z.Vector3D::Multiply(vertex_to_light, length);
}
//
//---------------------------------------------------------------
// Otherwise, this is a spotlight, so we need to reduce the light
// level further based upon the spread angle of the light
//---------------------------------------------------------------
//
else
{
lights[i].lightToLocal.GetLocalForwardInWorld(&light_z);
length = -1.0f / length;
vertex_to_light *= length;
Scalar spread = Cos(spread_angle);
Scalar t = vertex_to_light * light_z;
if (t <= spread)
{
continue;
}
Verify(!Close_Enough(spread, 1.0f));
spread = 1.0f - ((1.0f - t) / (1.0f - spread));
light_color.red *= spread;
light_color.green *= spread;
light_color.blue *= spread;
light_z.x = vertex_to_light.x;
light_z.y = vertex_to_light.y;
light_z.z = vertex_to_light.z;
}
}
//
//-------------------------------------------------------------------
// Now we reduce the light level falling on the vertex based upon the
// cosine of the angle between light and normal
//-------------------------------------------------------------------
//
Scalar cosine = -(light_z * normal);
if (cosine > SMALL)
{
light_color.red *= cosine;
light_color.green *= cosine;
light_color.blue *= cosine;
total_color.red += light_color.red;
total_color.green += light_color.green;
total_color.blue += light_color.blue;
}
}
//
//-----------------------------------------------------------------
// We now have the total color on the vertex established, so set it
//-----------------------------------------------------------------
//
Clamp(total_color.red, 0.0f, 1.0f);
Clamp(total_color.green, 0.0f, 1.0f);
Clamp(total_color.blue, 0.0f, 1.0f);
SetColor(total_color);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ChildProxy::BurnLights(BurnLightsProcess *process)
{
Check_Object(this);
Check_Object(process);
process->BurnLightsCallback(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonMeshProxy::BurnLights(BurnLightsProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Call the control callback
//--------------------------
//
process->BurnLightsCallback(this);
if (!process->continueProcess)
return;
//
//-----------------------------------------------------------------
// Apply the local to parent matrix to the stack, then invert it in
// preparation for the polygon meshes
//-----------------------------------------------------------------
//
LinearMatrix4D local_to_parent;
GetLocalToParent(&local_to_parent);
process->matrixStack.Concatenate(local_to_parent);
LinearMatrix4D world_to_local;
world_to_local.Invert(process->matrixStack);
//
//-----------------
// Count the lights
//-----------------
//
ChainIteratorOf<LightProxy*> light_itr(&process->lightsToBurn);
LightProxy* light;
int light_count = 0;
while ((light = light_itr.ReadAndNext()) != NULL)
{
Check_Object(light);
++light_count;
}
//
//------------------------------------------
// transform all the lights into local space
//------------------------------------------
//
DynamicArrayOf<TransformedLight> lights(light_count);
light_itr.First();
unsigned i;
for (i=0; i<light_count; ++i)
{
light = light_itr.ReadAndNext();
lights[i].lightProxy = light;
LinearMatrix4D light_to_world;
light->GetLocalToWorld(&light_to_world);
lights[i].lightToLocal.Multiply(light_to_world, world_to_local);
}
//
//------------------------------------------
// Recurse the children, and stop if told to
//------------------------------------------
//
DynamicArrayOf<VertexProxy*> vertices;
unsigned vertex_count = UseVertexArray(&vertices);
Verify(vertex_count == vertices.GetLength());
for (i=0; i<vertex_count; ++i)
{
VertexProxy *vertex = vertices[i];
Check_Object(vertex);
vertex->BurnLights(process, lights);
if (!process->continueProcess)
break;
}
DetachArrayReferences(&vertices);
process->matrixStack.Pop();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GroupProxy::BurnLights(BurnLightsProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Call the control callback
//--------------------------
//
process->BurnLightsCallback(this);
if (!process->continueProcess)
return;
//
//----------------------------------------------
// Apply the local to parent matrix to the stack
//----------------------------------------------
//
LinearMatrix4D local_to_parent;
GetLocalToParent(&local_to_parent);
process->matrixStack.Concatenate(local_to_parent);
//
//------------------------------------------
// Recurse the children, and stop if told to
//------------------------------------------
//
ChildProxy *child = UseFirstChildProxy();
while (child)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
child->BurnLights(process);
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
child->DetachReference();
break;
}
}
process->matrixStack.Pop();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SceneProxy::BurnLights(BurnLightsProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Call the control callback
//--------------------------
//
process->BurnLightsCallback(this);
if (!process->continueProcess)
return;
//
//-------------------------------------------------------------
// Get the ambient color and put a identity matrix on the stack
//-------------------------------------------------------------
//
process->matrixStack.Push(LinearMatrix4D::Identity);
//
//---------------------------------------------
// Burn the lights into each child of the scene
//---------------------------------------------
//
ChildProxy *child = UseFirstChildProxy();
while (child)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
child->BurnLights(process);
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
child->DetachReference();
break;
}
}
//
//-----------------------
// Remove the last matrix
//-----------------------
//
process->matrixStack.Pop();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
BurnLightsProcess::DiscardLights()
{
Check_Object(this);
ChainIteratorOf<LightProxy*> lights(&lightsToBurn);
LightProxy* light;
while ((light = lights.ReadAndNext()) != NULL)
{
Check_Object(light);
light->DetachReference();
}
}