Files
firestorm/Gameleap/code/mw4/Libraries/elementrenderer/SwitchElement.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

1248 lines
30 KiB
C++

#include "ElementRendererHeaders.hpp"
//############################################################################
//############################ SwitchElement ################################
//############################################################################
HGOSHEAP
ElementRenderer::SwitchElement::s_Heap = NULL;
ElementRenderer::SwitchElement::ClassData*
ElementRenderer::SwitchElement::DefaultData = NULL;
ElementRenderer::Element::SyncMethod
ElementRenderer::SwitchElement::SyncMethods[SyncStateCount]=
{
//
// Root mode
//
SYNC_METHOD(SwitchElement, CleanRoot),
SYNC_METHOD(SwitchElement, DirtyRoot),
SYNC_METHOD(SwitchElement, CleanRoot),
SYNC_METHOD(SwitchElement, DirtyRoot),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
SYNC_METHOD(SwitchElement, CleanRoot),
SYNC_METHOD(SwitchElement, DirtyRoot),
SYNC_METHOD(SwitchElement, CleanRoot),
SYNC_METHOD(SwitchElement, DirtyRoot),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
//
// Sphere Cull
//
SYNC_METHOD(SwitchElement, CleanSphere),
SYNC_METHOD(SwitchElement, MatrixDirtySphere),
SYNC_METHOD(SwitchElement, BoundsWrongSphere),
SYNC_METHOD(SwitchElement, FullSphere),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
//
// OBB Cull
//
SYNC_METHOD(SwitchElement, CleanOBB),
SYNC_METHOD(SwitchElement, MatrixDirtyOBB),
SYNC_METHOD(SwitchElement, BoundsWrongOBB),
SYNC_METHOD(SwitchElement, FullOBB),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
//
// Never Cull
//
SYNC_METHOD(SwitchElement, Clean),
SYNC_METHOD(SwitchElement, Dirty),
SYNC_METHOD(SwitchElement, Clean),
SYNC_METHOD(SwitchElement, Dirty),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
SYNC_METHOD(SwitchElement, Clean),
SYNC_METHOD(SwitchElement, Dirty),
SYNC_METHOD(SwitchElement, Clean),
SYNC_METHOD(SwitchElement, Dirty),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
//
// Always Cull
//
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, None)
};
ElementRenderer::Element::DrawMethod
ElementRenderer::SwitchElement::DrawMethods[DrawStateCount]=
{
DRAW_METHOD(SwitchElement, Inherit),
DRAW_METHOD(SwitchElement, Override),
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::InitializeClass()
{
Verify(!s_Heap);
s_Heap = gos_CreateMemoryHeap("Switch", 0, g_LibraryHeap);
Check_Pointer(s_Heap);
Verify(!DefaultData);
DefaultData =
new ClassData(
SwitchElementClassID,
"ElementRenderer::SwitchElement",
BaseClass::DefaultData,
reinterpret_cast<Factory>(&Make)
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
Check_Pointer(s_Heap);
gos_DestroyMemoryHeap(s_Heap);
s_Heap = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::SwitchElement::SwitchElement(
ClassData *class_data,
Stuff::MemoryStream *stream,
int version,
ShapeHolder shapes
):
ListElement(class_data, stream, version, shapes)
{
Check_Pointer(this);
Check_Object(stream);
unsigned index = (m_state>>SyncStateBit) & SyncStateMask;
Verify(index < SyncStateCount);
m_sync = SyncMethods[index];
index = (m_state>>CullStateBit) & CullStateMask;
Verify(index < CullStateCount);
m_cameraCull = CullMethods[index].m_cameraCull;
m_rayCull = CullMethods[index].m_rayCull;
m_sphereTest = CullMethods[index].m_sphereTest;
index = (m_state>>DrawStateBit) & DrawStateMask;
Verify(index < DrawStateCount);
m_draw = DrawMethods[index];
//
//---------------------------------
// Create the shape from the stream
//---------------------------------
//
Verify(m_list.GetLength() < 65536);
*stream >> m_switch;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::SwitchElement::SwitchElement(ClassData *class_data):
ListElement(class_data)
{
Check_Pointer(this);
unsigned index = (m_state>>SyncStateBit) & SyncStateMask;
Verify(index < SyncStateCount);
m_sync = SyncMethods[index];
index = (m_state>>CullStateBit) & CullStateMask;
Verify(index < CullStateCount);
m_cameraCull = CullMethods[index].m_cameraCull;
m_rayCull = CullMethods[index].m_rayCull;
m_sphereTest = CullMethods[index].m_sphereTest;
index = (m_state>>DrawStateBit) & DrawStateMask;
Verify(index < DrawStateCount);
m_draw = DrawMethods[index];
m_switch = 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::SwitchElement::~SwitchElement()
{
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::SwitchElement*
ElementRenderer::SwitchElement::Make(
Stuff::MemoryStream *stream,
int version,
ShapeHolder shapes
)
{
Check_Object(stream);
gos_PushCurrentHeap(s_Heap);
SwitchElement *element = new SwitchElement(DefaultData, stream, version, shapes);
gos_PopCurrentHeap();
return element;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::Save(Stuff::MemoryStream *stream)
{
Check_Object(this);
Check_Object(stream);
BaseClass::Save(stream);
//
//--------------------
// Save each Switch entry
//--------------------
//
*stream << m_switch;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::TestInstance()
{
Verify(!AreBoundsLocked());
Verify(IsDerivedFrom(DefaultData));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::SetSize(WORD max_size)
{
Check_Object(this);
BaseClass::SetSize(max_size);
m_switch = max_size;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::SetSyncState()
{
Check_Object(this);
Verify(
GetCullMode() != VolumeCullMode
|| AreBoundsWrong()
|| IsSyncDeferred()
|| (
m_localOBB.sphereRadius>0.0f
&& (IsMatrixDirty() || m_worldOBB.sphereRadius>0.0f
)
)
);
Verify(
GetCullMode() == RootMode || m_parent != NULL || AreBoundsWrong()
);
unsigned index = (m_state>>SyncStateBit) & SyncStateMask;
Verify(index < SyncStateCount);
m_sync = SyncMethods[index];
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::SetDrawState()
{
Check_Object(this);
unsigned index = (m_state>>DrawStateBit) & DrawStateMask;
Verify(index < DrawStateCount);
m_draw = DrawMethods[index];
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::CleanRootSyncMethod()
{
Check_Object(this);
Verify(!IsMatrixDirty() && GetCullMode()==RootMode);
SYNC_LOGIC("Root::Clean::Switch");
//
//--------------------
// Update our children
//--------------------
//
if (m_switch < m_list.GetLength())
{
Element *element = m_list[m_switch];
if (element)
{
Check_Object(element);
element->Sync();
}
}
else if (m_switch & 0xf0) // special case
{
Element *element = GetFirstSwitchElement();
if (element)
{
Check_Object(element);
element->Sync();
}
element = GetSecondSwitchElement();
if (element)
{
Check_Object(element);
element->Sync();
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::DirtyRootSyncMethod()
{
Check_Object(this);
Verify(IsMatrixDirty() && GetCullMode()==RootMode);
SYNC_LOGIC("Root::Dirty::Switch");
//
//------------------------------------------------------
// If the local-to-parent matrix is dirty, make it clean
//------------------------------------------------------
//
m_localToWorld = m_localToParent = m_newLocalToParent;
MatrixIsClean();
CleanRootSyncMethod();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::CleanSyncMethod()
{
Check_Object(this);
Verify(!IsMatrixDirty() && GetCullMode()==NeverCullMode);
SYNC_LOGIC("Clean::Switch");
//
//-------------------------------
// Update our m_localToWorld matrix
//-------------------------------
//
Check_Object(m_parent);
if (!IsLocalToParentIdentity())
m_localToWorld.Multiply(m_localToParent, m_parent->GetLocalToWorld());
else
m_localToWorld = m_parent->GetLocalToWorld();
//
//--------------------
// Update our children
//--------------------
//
if (m_switch < m_list.GetLength())
{
Element *element = m_list[m_switch];
if (element)
{
Check_Object(element);
element->Sync();
}
}
else if (m_switch & 0xf0) // special case
{
Element *element = GetFirstSwitchElement();
if (element)
{
Check_Object(element);
element->Sync();
}
element = GetSecondSwitchElement();
if (element)
{
Check_Object(element);
element->Sync();
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::DirtySyncMethod()
{
Check_Object(this);
Verify(IsMatrixDirty() && GetCullMode()==NeverCullMode);
SYNC_LOGIC("Dirty::Switch");
//
//--------------------
// Update our matrices
//--------------------
//
m_localToParent = m_newLocalToParent;
Check_Object(m_parent);
if (!IsLocalToParentIdentity())
m_localToWorld.Multiply(m_localToParent, m_parent->GetLocalToWorld());
else
m_localToWorld = m_parent->GetLocalToWorld();
MatrixIsClean();
//
//--------------------
// Update our children
//--------------------
//
if (m_switch < m_list.GetLength())
{
Element *element = m_list[m_switch];
if (element)
{
Check_Object(element);
element->Sync();
}
}
else if (m_switch & 0xf0) // special case
{
Element *element = GetFirstSwitchElement();
if (element)
{
Check_Object(element);
element->Sync();
}
element = GetSecondSwitchElement();
if (element)
{
Check_Object(element);
element->Sync();
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::CleanSphereSyncMethod()
{
Check_Object(this);
Verify(m_localOBB.sphereRadius > 0.0f);
Verify(
!IsMatrixDirty() && GetCullMode()==VolumeCullMode && IsBoundedBySphere()
);
SYNC_LOGIC("Sphere::Clean::Switch");
//
//-------------------------------
// Update our m_localToWorld matrix
//-------------------------------
//
Check_Object(m_parent);
if (!IsLocalToParentIdentity())
m_localToWorld.Multiply(m_localToParent, m_parent->GetLocalToWorld());
else
m_localToWorld = m_parent->GetLocalToWorld();
//
//------------------------------
// Transform the bounding sphere
//------------------------------
//
m_worldOBB.MultiplySphereOnly(m_localOBB, m_localToWorld);
//
//--------------------
// Update our children
//--------------------
//
if (m_switch < m_list.GetLength())
{
Element *element = m_list[m_switch];
if (element)
{
Check_Object(element);
element->Sync();
}
}
else if (m_switch & 0xf0) // special case
{
Element *element = GetFirstSwitchElement();
if (element)
{
Check_Object(element);
element->Sync();
}
element = GetSecondSwitchElement();
if (element)
{
Check_Object(element);
element->Sync();
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::MatrixDirtySphereSyncMethod()
{
Check_Object(this);
Verify(m_localOBB.sphereRadius > 0.0f);
Verify(
IsMatrixDirty() && GetCullMode()==VolumeCullMode && IsBoundedBySphere()
);
SYNC_LOGIC("Sphere::Dirty::Switch");
//
//--------------------
// Update our matrices
//--------------------
//
m_localToParent = m_newLocalToParent;
Check_Object(m_parent);
if (!IsLocalToParentIdentity())
m_localToWorld.Multiply(m_localToParent, m_parent->GetLocalToWorld());
else
m_localToWorld = m_parent->GetLocalToWorld();
//
//------------------------------
// Transform the bounding sphere
//------------------------------
//
m_worldOBB.MultiplySphereOnly(m_localOBB, m_localToWorld);
MatrixIsClean();
//
//--------------------
// Update our children
//--------------------
//
if (m_switch < m_list.GetLength())
{
Element *element = m_list[m_switch];
if (element)
{
Check_Object(element);
element->Sync();
}
}
else if (m_switch & 0xf0) // special case
{
Element *element = GetFirstSwitchElement();
if (element)
{
Check_Object(element);
element->Sync();
}
element = GetSecondSwitchElement();
if (element)
{
Check_Object(element);
element->Sync();
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::BoundsWrongSphereSyncMethod()
{
Check_Object(this);
Verify(
!IsMatrixDirty() && AreBoundsWrong()
&& GetCullMode()==VolumeCullMode && IsBoundedBySphere()
);
SYNC_LOGIC("Sphere::Recalc::Switch");
//
//-------------------------------
// Update our m_localToWorld matrix
//-------------------------------
//
Check_Object(m_parent);
if (!IsLocalToParentIdentity())
m_localToWorld.Multiply(m_localToParent, m_parent->GetLocalToWorld());
else
m_localToWorld = m_parent->GetLocalToWorld();
//
//--------------------
// Update our children
//--------------------
//
WORD i;
Verify(m_list.GetLength() < 65536);
WORD switch_count = static_cast<WORD>(m_list.GetLength());
Stuff::Point3D centroid = Stuff::Point3D::Identity;
WORD bounded_children = 0;
for (i=0; i<switch_count; ++i)
{
Element *element = m_list[i];
if (element)
{
Check_Object(element);
element->Sync();
if (element->GetCullMode() == VolumeCullMode)
{
++bounded_children;
Stuff::LinearMatrix4D child_to_parent = element->GetLocalToParent();
Stuff::Point3D child_center(element->m_localOBB.localToParent);
Stuff::Point3D child_center_in_parent;
child_center_in_parent.Multiply(child_center, child_to_parent);
centroid += child_center_in_parent;
}
}
}
//
//---------------------------------------------------
// If we have no bounded children, we will never cull
//---------------------------------------------------
//
if (!bounded_children)
{
m_localOBB.sphereRadius = 0.0f;
SetNeverCullMode();
}
//
//-----------------------------------------------------------------
// Otherwise, find the tightest bounds from our calculated centroid
//-----------------------------------------------------------------
//
else
{
centroid /= static_cast<Stuff::Scalar>(bounded_children);
m_localOBB.localToParent.BuildTranslation(centroid);
m_localOBB.sphereRadius = -1.0f;
for (i=0; i<switch_count; ++i)
{
Element *element = m_list[i];
if (element)
{
Check_Object(element);
if (element->GetCullMode() == VolumeCullMode)
{
Stuff::LinearMatrix4D child_to_parent = element->GetLocalToParent();
Stuff::Point3D child_center(element->m_localOBB.localToParent);
Stuff::Point3D child_center_in_parent;
child_center_in_parent.Multiply(child_center, child_to_parent);
child_center_in_parent -= centroid;
Stuff::Scalar range =
child_center_in_parent.GetLength()
+ element->m_localOBB.sphereRadius;
if (range > m_localOBB.sphereRadius)
m_localOBB.sphereRadius = range;
}
}
}
Verify(m_localOBB.sphereRadius > 0.0f);
m_worldOBB.MultiplySphereOnly(m_localOBB, m_localToWorld);
}
BoundsAreRight();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::FullSphereSyncMethod()
{
Check_Object(this);
Verify(
IsMatrixDirty() && AreBoundsWrong()
&& GetCullMode()==VolumeCullMode && IsBoundedBySphere()
);
SYNC_LOGIC("Sphere::Full::Switch");
//
//--------------------
// Update our matrices
//--------------------
//
m_localToParent = m_newLocalToParent;
Check_Object(m_parent);
if (!IsLocalToParentIdentity())
m_localToWorld.Multiply(m_localToParent, m_parent->GetLocalToWorld());
else
m_localToWorld = m_parent->GetLocalToWorld();
//
//--------------------
// Update our children
//--------------------
//
WORD i;
Verify(m_list.GetLength() < 65536);
WORD switch_count = static_cast<WORD>(m_list.GetLength());
Stuff::Point3D centroid = Stuff::Point3D::Identity;
WORD bounded_children = 0;
for (i=0; i<switch_count; ++i)
{
Element *element = m_list[i];
if (element)
{
Check_Object(element);
element->Sync();
if (element->GetCullMode() == VolumeCullMode)
{
++bounded_children;
Stuff::LinearMatrix4D child_to_parent = element->GetLocalToParent();
Stuff::Point3D child_center(element->m_localOBB.localToParent);
Stuff::Point3D child_center_in_parent;
child_center_in_parent.Multiply(child_center, child_to_parent);
centroid += child_center_in_parent;
}
}
}
//
//---------------------------------------------------
// If we have no bounded children, we will never cull
//---------------------------------------------------
//
if (!bounded_children)
{
m_localOBB.sphereRadius = 0.0f;
SetNeverCullMode();
}
//
//-----------------------------------------------------------------
// Otherwise, find the tightest bounds from our calculated centroid
//-----------------------------------------------------------------
//
else
{
centroid /= static_cast<Stuff::Scalar>(bounded_children);
m_localOBB.localToParent.BuildTranslation(centroid);
m_localOBB.sphereRadius = -1.0f;
for (i=0; i<switch_count; ++i)
{
Element *element = m_list[i];
if (element)
{
Check_Object(element);
if (element->GetCullMode() == VolumeCullMode)
{
Stuff::LinearMatrix4D child_to_parent = element->GetLocalToParent();
Stuff::Point3D child_center(element->m_localOBB.localToParent);
Stuff::Point3D child_center_in_parent;
child_center_in_parent.Multiply(child_center, child_to_parent);
child_center_in_parent -= centroid;
Stuff::Scalar range =
child_center_in_parent.GetLength()
+ element->m_localOBB.sphereRadius;
if (range > m_localOBB.sphereRadius)
m_localOBB.sphereRadius = range;
}
}
}
Verify(m_localOBB.sphereRadius > 0.0f);
m_worldOBB.MultiplySphereOnly(m_localOBB, m_localToWorld);
}
m_state &= ~(MatrixDirtyFlag|BoundsWrongFlag);
SetSyncState();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::CleanOBBSyncMethod()
{
Check_Object(this);
Verify(
!IsMatrixDirty() && GetCullMode()==VolumeCullMode && IsBoundedByOBB()
);
Verify(Stuff::Close_Enough(m_localOBB.sphereRadius, m_localOBB.axisExtents.GetLength(), m_localOBB.sphereRadius*0.02f));
SYNC_LOGIC("OBB::Clean::Switch");
//
//-------------------------------
// Update our m_localToWorld matrix
//-------------------------------
//
Check_Object(m_parent);
if (!IsLocalToParentIdentity())
m_localToWorld.Multiply(m_localToParent, m_parent->GetLocalToWorld());
else
m_localToWorld = m_parent->GetLocalToWorld();
//
//------------------------------
// Transform the bounding sphere
//------------------------------
//
m_worldOBB.Multiply(m_localOBB, m_localToWorld);
//
//--------------------
// Update our children
//--------------------
//
if (m_switch < m_list.GetLength())
{
Element *element = m_list[m_switch];
if (element)
{
Check_Object(element);
element->Sync();
}
}
else if (m_switch & 0xf0) // special case
{
Element *element = GetFirstSwitchElement();
if (element)
{
Check_Object(element);
element->Sync();
}
element = GetSecondSwitchElement();
if (element)
{
Check_Object(element);
element->Sync();
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::MatrixDirtyOBBSyncMethod()
{
Check_Object(this);
Verify(
IsMatrixDirty() && GetCullMode()==VolumeCullMode && IsBoundedByOBB()
);
Verify(Stuff::Close_Enough(m_localOBB.sphereRadius, m_localOBB.axisExtents.GetLength(), m_localOBB.sphereRadius*0.02f));
SYNC_LOGIC("OBB::Dirty::Switch");
//
//--------------------
// Update our matrices
//--------------------
//
m_localToParent = m_newLocalToParent;
Check_Object(m_parent);
if (!IsLocalToParentIdentity())
m_localToWorld.Multiply(m_localToParent, m_parent->GetLocalToWorld());
else
m_localToWorld = m_parent->GetLocalToWorld();
//
//------------------------------
// Transform the bounding sphere
//------------------------------
//
m_worldOBB.Multiply(m_localOBB, m_localToWorld);
MatrixIsClean();
//
//--------------------
// Update our children
//--------------------
//
if (m_switch < m_list.GetLength())
{
Element *element = m_list[m_switch];
if (element)
{
Check_Object(element);
element->Sync();
}
}
else if (m_switch & 0xf0) // special case
{
Element *element = GetFirstSwitchElement();
if (element)
{
Check_Object(element);
element->Sync();
}
element = GetSecondSwitchElement();
if (element)
{
Check_Object(element);
element->Sync();
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::BoundsWrongOBBSyncMethod()
{
Check_Object(this);
STOP(("OBB's cannot recalculate bounds!"));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::FullOBBSyncMethod()
{
Check_Object(this);
STOP(("OBB's cannot recalculate bounds!"));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
ElementRenderer::SwitchElement::CastCulledRay(CollisionQuery *query)
{
Check_Object(this);
Check_Object(query);
Verify(!query->m_data);
//
//-----------------------------
// Test it against the MLRShape
//-----------------------------
//
if (m_switch < m_list.GetLength())
{
Element *element = m_list[m_switch];
if (element)
{
Check_Object(element);
if (element->CastRay(query))
{
if (!query->m_data)
query->m_data = m_data;
return true;
}
}
}
else if (m_switch & 0xf0) // special case
{
Element *element = GetFirstSwitchElement();
if (element)
{
Check_Object(element);
if (element->CastRay(query))
{
if (!query->m_data)
query->m_data = m_data;
return true;
}
}
element = GetSecondSwitchElement();
if (element)
{
Check_Object(element);
if (element->CastRay(query))
{
if (!query->m_data)
query->m_data = m_data;
return true;
}
}
}
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::Element*
ElementRenderer::SwitchElement::FindSmallestElementContainingCulled(SphereTest *test)
{
Check_Object(this);
Check_Object(test);
//
//------------------
// Draw our children
//------------------
//
Element *result = this;
if (m_switch < m_list.GetLength())
{
Element *element = m_list[m_switch];
if (element)
{
Check_Object(element);
Element *temp = element->FindSmallestElementContaining(test);
if (temp)
result = temp;
}
}
else if (m_switch & 0xf0) // special case
{
Element *element = GetFirstSwitchElement();
if (element)
{
Check_Object(element);
Element *temp = element->FindSmallestElementContaining(test);
if (temp)
result = temp;
}
element = GetSecondSwitchElement();
if (element)
{
Check_Object(element);
Element *temp = element->FindSmallestElementContaining(test);
if (temp)
result = temp;
}
}
return result;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::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
//
//------------------------------
// Only draw the switch selected
//------------------------------
//
if (m_switch < m_list.GetLength())
{
Element *element = m_list[m_switch];
if (element)
{
Check_Object(element);
camera->DrawElement(element, inherited_state);
}
}
else if (m_switch & 0xf0) // special case
{
Element *element = GetFirstSwitchElement();
if (element)
{
Check_Object(element);
camera->DrawElement(element, inherited_state);
}
element = GetSecondSwitchElement();
if (element)
{
Check_Object(element);
camera->DrawElement(element, inherited_state);
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::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
//
//------------------------------
// Only draw the switch selected
//------------------------------
//
if (m_switch < m_list.GetLength())
{
Element *element = m_list[m_switch];
if (element)
{
Check_Object(element);
camera->DrawElement(element, &mixed);
}
}
else if (m_switch & 0xf0) // special case
{
Element *element = GetFirstSwitchElement();
if (element)
{
Check_Object(element);
camera->DrawElement(element, &mixed);
}
element = GetSecondSwitchElement();
if (element)
{
Check_Object(element);
camera->DrawElement(element, &mixed);
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::CleanDamage()
{
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::ApplyDamage(
const Stuff::LinearMatrix4D &damage_spot,
Stuff::Scalar radius
)
{
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::ApplyDamageDecal(
const Stuff::LinearMatrix4D &damage_spot,
Stuff::Scalar radius,
MidLevelRenderer::MLRTexture *texture
)
{
Check_Object(this);
Check_Object(texture);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::CastShadow(
const Stuff::LinearMatrix4D &shadow_to_world,
const Stuff::UnitVector3D &sun_in_world,
Stuff::Scalar radius
)
{
Check_Object(this);
if (!IsShadowed())
return;
WORD current = GetSwitch();
if (current < GetActiveCount())
{
Element *element = GetIndexedElement(current);
if (element)
{
Check_Object(element);
element->CastShadow(shadow_to_world, sun_in_world, radius);
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::SwitchElement::MakeFootStep(
MidLevelRenderer::MLRShape *shape,
const Stuff::LinearMatrix4D &foot,
Stuff::Scalar radius,
MidLevelRenderer::MLRTexture *tex
)
{
Check_Object(this);
WORD current = GetSwitch();
if (current < GetActiveCount())
{
Element *element = GetIndexedElement(current);
if (element)
{
Check_Object(element);
element->MakeFootStep(shape, foot, radius, tex);
}
}
}