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.
507 lines
13 KiB
C++
507 lines
13 KiB
C++
#include "ElementRendererHeaders.hpp"
|
|
|
|
//############################################################################
|
|
//############################ LODElement ################################
|
|
//############################################################################
|
|
|
|
HGOSHEAP
|
|
ElementRenderer::LODElement::s_Heap = NULL;
|
|
|
|
ElementRenderer::LODElement::ClassData*
|
|
ElementRenderer::LODElement::DefaultData = NULL;
|
|
|
|
ElementRenderer::Element::DrawMethod
|
|
ElementRenderer::LODElement::DrawMethods[DrawStateCount]=
|
|
{
|
|
DRAW_METHOD(LODElement, Inherit),
|
|
DRAW_METHOD(LODElement, Override)
|
|
};
|
|
|
|
Stuff::Scalar ElementRenderer::LODElement::s_Offset = 0.0f;
|
|
bool ElementRenderer::LODElement::s_ShadeLODs = false;
|
|
Stuff::RGBAColor ElementRenderer::LODElement::s_Shades[6]={
|
|
Stuff::RGBAColor(1.0f, 1.0f, 1.0f, 1.0),
|
|
Stuff::RGBAColor(1.0f, 0.0f, 0.0f, 1.0),
|
|
Stuff::RGBAColor(0.0f, 1.0f, 0.0f, 1.0),
|
|
Stuff::RGBAColor(0.0f, 0.0f, 1.0f, 1.0),
|
|
Stuff::RGBAColor(1.0f, 1.0f, 0.0f, 1.0),
|
|
Stuff::RGBAColor(1.0f, 0.0f, 1.0f, 1.0)
|
|
};
|
|
|
|
static bool
|
|
__stdcall Check100m()
|
|
{
|
|
return ElementRenderer::LODElement::s_Offset == 625.0f;
|
|
}
|
|
|
|
static bool
|
|
__stdcall Check250m()
|
|
{
|
|
return ElementRenderer::LODElement::s_Offset == 2500.0f;
|
|
}
|
|
|
|
static bool
|
|
__stdcall Check500m()
|
|
{
|
|
return ElementRenderer::LODElement::s_Offset == 10000.0f;
|
|
}
|
|
|
|
static void
|
|
__stdcall Enable100m()
|
|
{
|
|
ElementRenderer::LODElement::s_Offset = (ElementRenderer::LODElement::s_Offset == 625.0f) ? 0.0f : 625.0f;
|
|
}
|
|
|
|
static void
|
|
__stdcall Enable250m()
|
|
{
|
|
ElementRenderer::LODElement::s_Offset = (ElementRenderer::LODElement::s_Offset == 2500.0f) ? 0.0f : 2500.0f;
|
|
}
|
|
|
|
static void
|
|
__stdcall Enable500m()
|
|
{
|
|
ElementRenderer::LODElement::s_Offset = (ElementRenderer::LODElement::s_Offset == 10000.0f) ? 0.0f : 10000.0f;
|
|
}
|
|
|
|
extern DWORD Disable_Lights;
|
|
|
|
static bool __stdcall CheckShadeLODs() {return ElementRenderer::LODElement::s_ShadeLODs;}
|
|
static void __stdcall EnableShadeLODs()
|
|
{
|
|
ElementRenderer::LODElement::s_ShadeLODs = !ElementRenderer::LODElement::s_ShadeLODs;
|
|
if (ElementRenderer::LODElement::s_ShadeLODs)
|
|
Disable_Lights = true;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::LODElement::InitializeClass(Stuff::NotationFile *startup_ini)
|
|
{
|
|
Verify(!s_Heap);
|
|
s_Heap = gos_CreateMemoryHeap("LOD", 0, g_LibraryHeap);
|
|
Check_Pointer(s_Heap);
|
|
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
LODElementClassID,
|
|
"ElementRenderer::LODElement",
|
|
BaseClass::DefaultData,
|
|
reinterpret_cast<Factory>(&Make)
|
|
);
|
|
Register_Object(DefaultData);
|
|
|
|
AddDebuggerMenuItem("Libraries\\ElementRenderer\\Shade LODs", CheckShadeLODs, EnableShadeLODs, 0 );
|
|
AddDebuggerMenuItem("Libraries\\Graphics Options\\+25m Shape LODs", Check100m, Enable100m, 0 );
|
|
AddDebuggerMenuItem("Libraries\\Graphics Options\\+50m Shape LODs", Check250m, Enable250m, 0 );
|
|
AddDebuggerMenuItem("Libraries\\Graphics Options\\+100m Shape LODs", Check500m, Enable500m, 0 );
|
|
|
|
if (startup_ini)
|
|
{
|
|
Check_Object(startup_ini);
|
|
Stuff::Page *page = startup_ini->FindPage("Graphics Options");
|
|
if (page)
|
|
{
|
|
Check_Object(page);
|
|
page->GetEntry("LOD", &s_Offset);
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::LODElement::TerminateClass(Stuff::NotationFile *startup_ini)
|
|
{
|
|
if (startup_ini)
|
|
{
|
|
Check_Object(startup_ini);
|
|
Stuff::Page *page = startup_ini->SetPage("Graphics Options");
|
|
Check_Object(page);
|
|
page->SetEntry("LOD", s_Offset);
|
|
}
|
|
|
|
Unregister_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
|
|
Check_Pointer(s_Heap);
|
|
gos_DestroyMemoryHeap(s_Heap);
|
|
s_Heap = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
ElementRenderer::LODElement::LODElement(
|
|
Stuff::MemoryStream *stream,
|
|
int version,
|
|
ShapeHolder shapes
|
|
):
|
|
SwitchElement(DefaultData, stream, version, shapes)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(stream);
|
|
|
|
unsigned index = (m_state>>DrawStateBit) & DrawStateMask;
|
|
Verify(index < DrawStateCount);
|
|
m_draw = DrawMethods[index];
|
|
|
|
//
|
|
//---------------------------------
|
|
// Create the shape from the stream
|
|
//---------------------------------
|
|
//
|
|
Verify(m_list.GetLength() < 65536);
|
|
WORD lod_count = static_cast<WORD>(m_list.GetLength());
|
|
m_LODs.SetLength(lod_count);
|
|
for (WORD lod=0; lod<lod_count; ++lod)
|
|
*stream >> m_LODs[lod].m_nearSquared >> m_LODs[lod].m_farSquared;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
ElementRenderer::LODElement::LODElement():
|
|
SwitchElement(DefaultData)
|
|
{
|
|
Check_Pointer(this);
|
|
|
|
unsigned index = (m_state>>DrawStateBit) & DrawStateMask;
|
|
Verify(index < DrawStateCount);
|
|
m_draw = DrawMethods[index];
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
ElementRenderer::LODElement::~LODElement()
|
|
{
|
|
Check_Object(this);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
ElementRenderer::LODElement*
|
|
ElementRenderer::LODElement::Make(
|
|
Stuff::MemoryStream *stream,
|
|
int version,
|
|
ShapeHolder shapes
|
|
)
|
|
{
|
|
Check_Object(stream);
|
|
|
|
gos_PushCurrentHeap(s_Heap);
|
|
LODElement *element = new LODElement(stream, version, shapes);
|
|
gos_PopCurrentHeap();
|
|
|
|
return element;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::LODElement::Save(Stuff::MemoryStream *stream)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(stream);
|
|
BaseClass::Save(stream);
|
|
|
|
//
|
|
//--------------------
|
|
// Save each LOD entry
|
|
//--------------------
|
|
//
|
|
Verify(m_list.GetLength() < 65536);
|
|
WORD lod_count = static_cast<WORD>(m_LODs.GetLength());
|
|
for (WORD lod=0; lod<lod_count; ++lod)
|
|
*stream << m_LODs[lod].m_nearSquared << m_LODs[lod].m_farSquared;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::LODElement::TestInstance()
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::LODElement::AttachLOD(
|
|
WORD index,
|
|
Element *element,
|
|
const Entry &entry
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Verify(index < m_LODs.GetLength());
|
|
m_LODs[index] = entry;
|
|
AttachIndexedChild(index, element);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::LODElement::SetSize(WORD max_size)
|
|
{
|
|
Check_Object(this);
|
|
m_LODs.SetLength(max_size);
|
|
for (WORD i=0; i<max_size; ++i)
|
|
{
|
|
m_LODs[i].m_nearSquared = 0.0f;
|
|
m_LODs[i].m_farSquared = 0.0f;
|
|
}
|
|
BaseClass::SetSize(max_size);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::LODElement::DetachChild(Element *child)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(child);
|
|
|
|
//
|
|
//-------------------------------
|
|
// Find the element and unhook it
|
|
//-------------------------------
|
|
//
|
|
Verify(m_list.GetLength() < 65536);
|
|
WORD lod_count = static_cast<WORD>(m_LODs.GetLength());
|
|
for (WORD i=0; i<lod_count; ++i)
|
|
{
|
|
Entry *entry = &m_LODs[i];
|
|
if (m_list[i] == child)
|
|
{
|
|
entry->m_nearSquared = 0.0f;
|
|
entry->m_farSquared = 0.0f;
|
|
break;
|
|
}
|
|
}
|
|
BaseClass::DetachChild(child);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::LODElement::SetDrawState()
|
|
{
|
|
Check_Object(this);
|
|
unsigned index = (m_state>>DrawStateBit) & DrawStateMask;
|
|
Verify(index < DrawStateCount);
|
|
m_draw = DrawMethods[index];
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::LODElement::InheritDrawMethod(
|
|
CameraElement *camera,
|
|
const StateChange *inherited_state,
|
|
int culling_state
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(inherited_state);
|
|
Check_Object(camera);
|
|
Verify(culling_state != -1);
|
|
|
|
//
|
|
//--------------------------------------
|
|
// Draw our bounds if we are supposed to
|
|
//--------------------------------------
|
|
//
|
|
#if defined(LAB_ONLY)
|
|
Callback *callback = GetCallbackSet();
|
|
unsigned index = GetCallbackIndex();
|
|
if (callback && callback[index])
|
|
{
|
|
Check_Pointer(callback[index]);
|
|
(*callback[index])(camera, inherited_state, culling_state, this);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// We need to find out which lod the camera should traverse into, so
|
|
// transform the camera into LOD space and get the distance from the LOD
|
|
//----------------------------------------------------------------------
|
|
//
|
|
Stuff::Point3D camera_origin(camera->GetLocalToWorld());
|
|
Stuff::Point3D lod_origin(GetLocalToWorld());
|
|
camera_origin -= lod_origin;
|
|
Stuff::Scalar distance = camera_origin.GetLengthSquared() + s_Offset;
|
|
Min_Clamp(distance, 0.0f);
|
|
|
|
//
|
|
//---------------------------------------------------
|
|
// Search the lod entries looking for the first match
|
|
//---------------------------------------------------
|
|
//
|
|
for (WORD i=0; i<m_LODs.GetLength(); ++i)
|
|
{
|
|
Entry *entry = &m_LODs[i];
|
|
if (entry->m_nearSquared <= distance && entry->m_farSquared >= distance)
|
|
{
|
|
#if defined(LAB_ONLY)
|
|
Stuff::RGBAColor old_fade;
|
|
if (s_ShadeLODs && i<ELEMENTS(s_Shades))
|
|
{
|
|
old_fade = FadeColor;
|
|
FadeColor = s_Shades[i];
|
|
}
|
|
#endif
|
|
Element *element = m_list[i];
|
|
Check_Object(element);
|
|
SetSwitch(i);
|
|
camera->DrawElement(element, inherited_state);
|
|
#if defined(LAB_ONLY)
|
|
if (s_ShadeLODs && i<ELEMENTS(s_Shades))
|
|
FadeColor = old_fade;
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::LODElement::OverrideDrawMethod(
|
|
CameraElement *camera,
|
|
const StateChange *inherited_state,
|
|
int culling_state
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(inherited_state);
|
|
Check_Object(camera);
|
|
Verify(culling_state != -1);
|
|
|
|
//
|
|
//-------------------
|
|
// Mix the properties
|
|
//-------------------
|
|
//
|
|
Check_Object(m_stateChange);
|
|
StateChange mixed;
|
|
mixed.Mix(*inherited_state, *m_stateChange);
|
|
MixLights(
|
|
mixed.m_lights,
|
|
inherited_state->m_lights,
|
|
m_stateChange->m_lights
|
|
);
|
|
|
|
//
|
|
//--------------------------------------
|
|
// Draw our bounds if we are supposed to
|
|
//--------------------------------------
|
|
//
|
|
#if defined(LAB_ONLY)
|
|
Callback *callback = GetCallbackSet();
|
|
unsigned index = GetCallbackIndex();
|
|
if (callback && callback[index])
|
|
{
|
|
Check_Pointer(callback[index]);
|
|
(*callback[index])(camera, inherited_state, culling_state, this);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// We need to find out which lod the camera should traverse into, so
|
|
// transform the camera into LOD space and get the distance from the LOD
|
|
//----------------------------------------------------------------------
|
|
//
|
|
Stuff::Point3D camera_origin(camera->GetLocalToWorld());
|
|
Stuff::Point3D lod_origin(GetLocalToWorld());
|
|
camera_origin -= lod_origin;
|
|
Stuff::Scalar distance = camera_origin.GetLengthSquared() + s_Offset;
|
|
Min_Clamp(distance, 0.0f);
|
|
|
|
//
|
|
//---------------------------------------------------
|
|
// Search the lod entries looking for the first match
|
|
//---------------------------------------------------
|
|
//
|
|
for (WORD i=0; i<m_LODs.GetLength(); ++i)
|
|
{
|
|
Entry *entry = &m_LODs[m_switch];
|
|
if (entry->m_nearSquared <= distance && entry->m_farSquared >= distance)
|
|
{
|
|
#if defined(LAB_ONLY)
|
|
Stuff::RGBAColor old_fade;
|
|
if (s_ShadeLODs && i<ELEMENTS(s_Shades))
|
|
{
|
|
old_fade = FadeColor;
|
|
FadeColor = s_Shades[i];
|
|
}
|
|
#endif
|
|
Element *element = m_list[m_switch];
|
|
Check_Object(element);
|
|
SetSwitch(i);
|
|
camera->DrawElement(element, &mixed);
|
|
#if defined(LAB_ONLY)
|
|
if (s_ShadeLODs && i<ELEMENTS(s_Shades))
|
|
FadeColor = old_fade;
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::LODElement::CleanDamage()
|
|
{
|
|
Check_Object(this);
|
|
|
|
for(WORD i=0;i<GetActiveCount();i++)
|
|
{
|
|
Element *child = GetIndexedElement(i);
|
|
Check_Object(child);
|
|
child->CleanDamage();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::LODElement::ApplyDamage(
|
|
const Stuff::LinearMatrix4D &damage_spot,
|
|
Stuff::Scalar radius
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
|
|
for(WORD i=0;i<GetActiveCount();i++)
|
|
{
|
|
Element *child = GetIndexedElement(i);
|
|
Check_Object(child);
|
|
child->ApplyDamage(damage_spot, radius);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::LODElement::ApplyDamageDecal(
|
|
const Stuff::LinearMatrix4D &damage_spot,
|
|
Stuff::Scalar radius,
|
|
MidLevelRenderer::MLRTexture *texture
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(texture);
|
|
|
|
for(WORD i=0;i<GetActiveCount();i++)
|
|
{
|
|
Element *child = GetIndexedElement(i);
|
|
Check_Object(child);
|
|
child->ApplyDamageDecal(damage_spot, radius, texture);
|
|
}
|
|
}
|