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.
530 lines
14 KiB
C++
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();
|
|
}
|
|
}
|