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.
1382 lines
36 KiB
C++
1382 lines
36 KiB
C++
#include "ElementRendererHeaders.hpp"
|
|
#include "GroupElement.hpp"
|
|
|
|
//#define BOUNDS_BUG "jmalbert"
|
|
|
|
#if defined(BOUNDS_BUG)
|
|
int prefix_len=0;
|
|
#endif
|
|
|
|
//############################################################################
|
|
//############################ GroupElement ################################
|
|
//############################################################################
|
|
|
|
HGOSHEAP
|
|
ElementRenderer::GroupElement::s_Heap = NULL;
|
|
|
|
ElementRenderer::GroupElement::ClassData*
|
|
ElementRenderer::GroupElement::DefaultData = NULL;
|
|
|
|
ElementRenderer::Element::SyncMethod
|
|
ElementRenderer::GroupElement::SyncMethods[SyncStateCount]=
|
|
{
|
|
//
|
|
// Root mode
|
|
//
|
|
SYNC_METHOD(GroupElement, CleanRoot),
|
|
SYNC_METHOD(GroupElement, DirtyRoot),
|
|
SYNC_METHOD(GroupElement, CleanRoot),
|
|
SYNC_METHOD(GroupElement, DirtyRoot),
|
|
SYNC_METHOD(Element, None),
|
|
SYNC_METHOD(Element, Defer),
|
|
SYNC_METHOD(Element, None),
|
|
SYNC_METHOD(Element, Defer),
|
|
|
|
SYNC_METHOD(GroupElement, CleanRoot),
|
|
SYNC_METHOD(GroupElement, DirtyRoot),
|
|
SYNC_METHOD(GroupElement, CleanRoot),
|
|
SYNC_METHOD(GroupElement, DirtyRoot),
|
|
SYNC_METHOD(Element, None),
|
|
SYNC_METHOD(Element, Defer),
|
|
SYNC_METHOD(Element, None),
|
|
SYNC_METHOD(Element, Defer),
|
|
|
|
//
|
|
// Stuff::Sphere Cull
|
|
//
|
|
SYNC_METHOD(GroupElement, CleanSphere),
|
|
SYNC_METHOD(GroupElement, MatrixDirtySphere),
|
|
SYNC_METHOD(GroupElement, BoundsWrongSphere),
|
|
SYNC_METHOD(GroupElement, FullSphere),
|
|
SYNC_METHOD(Element, None),
|
|
SYNC_METHOD(Element, Defer),
|
|
SYNC_METHOD(Element, None),
|
|
SYNC_METHOD(Element, Defer),
|
|
|
|
//
|
|
// OBB Cull
|
|
//
|
|
SYNC_METHOD(GroupElement, CleanOBB),
|
|
SYNC_METHOD(GroupElement, MatrixDirtyOBB),
|
|
SYNC_METHOD(GroupElement, BoundsWrongOBB),
|
|
SYNC_METHOD(GroupElement, FullOBB),
|
|
SYNC_METHOD(Element, None),
|
|
SYNC_METHOD(Element, Defer),
|
|
SYNC_METHOD(Element, None),
|
|
SYNC_METHOD(Element, Defer),
|
|
|
|
//
|
|
// Never Cull
|
|
//
|
|
SYNC_METHOD(GroupElement, Clean),
|
|
SYNC_METHOD(GroupElement, Dirty),
|
|
SYNC_METHOD(GroupElement, Clean),
|
|
SYNC_METHOD(GroupElement, Dirty),
|
|
SYNC_METHOD(Element, None),
|
|
SYNC_METHOD(Element, Defer),
|
|
SYNC_METHOD(Element, None),
|
|
SYNC_METHOD(Element, Defer),
|
|
|
|
SYNC_METHOD(GroupElement, Clean),
|
|
SYNC_METHOD(GroupElement, Dirty),
|
|
SYNC_METHOD(GroupElement, Clean),
|
|
SYNC_METHOD(GroupElement, 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::GroupElement::DrawMethods[DrawStateCount]=
|
|
{
|
|
DRAW_METHOD(GroupElement, Inherit),
|
|
DRAW_METHOD(GroupElement, Override)
|
|
};
|
|
|
|
static DWORD
|
|
Wasted_Syncs;
|
|
|
|
#if !defined(NO_STATS)
|
|
#define WASTE_CHECK()\
|
|
if (Stuff::ArmorLevel>0 && !children.GetCurrent())\
|
|
Set_Statistic(Wasted_Syncs, Wasted_Syncs+1);
|
|
#else
|
|
#define WASTE_CHECK()
|
|
#endif
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::InitializeClass()
|
|
{
|
|
Verify(!s_Heap);
|
|
s_Heap = gos_CreateMemoryHeap("Group", 0, g_LibraryHeap);
|
|
Check_Pointer(s_Heap);
|
|
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
GroupElementClassID,
|
|
"ElementRenderer::GroupElement",
|
|
BaseClass::DefaultData,
|
|
reinterpret_cast<Factory>(&Make)
|
|
);
|
|
Register_Object(DefaultData);
|
|
|
|
Wasted_Syncs = 0;
|
|
#if !defined(NO_STATS)
|
|
AddStatistic("Wasted Group Syncs", "syncs", gos_DWORD, &Wasted_Syncs, Stat_AutoReset);
|
|
#endif
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::TerminateClass()
|
|
{
|
|
Unregister_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
|
|
Check_Pointer(s_Heap);
|
|
gos_DestroyMemoryHeap(s_Heap);
|
|
s_Heap = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
ElementRenderer::GroupElement::GroupElement(
|
|
ClassData *class_data,
|
|
Stuff::MemoryStream *stream,
|
|
int version,
|
|
ShapeHolder shapes
|
|
):
|
|
Element(class_data, stream, version),
|
|
m_group(NULL)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(stream);
|
|
Check_Object(class_data);
|
|
|
|
//
|
|
//------------------
|
|
// Update the tables
|
|
//------------------
|
|
//
|
|
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];
|
|
|
|
//
|
|
//----------------------------
|
|
// Do the child creation thing
|
|
//----------------------------
|
|
//
|
|
int count;
|
|
*stream >> count;
|
|
while (count--)
|
|
{
|
|
Element *child = Create(stream, version);
|
|
Check_Object(child);
|
|
AttachChild(child);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
ElementRenderer::GroupElement::GroupElement(ClassData *class_data):
|
|
Element(class_data),
|
|
m_group(NULL)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(class_data);
|
|
|
|
//
|
|
//------------------
|
|
// Update the tables
|
|
//------------------
|
|
//
|
|
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];
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
ElementRenderer::GroupElement::~GroupElement()
|
|
{
|
|
Check_Object(this);
|
|
|
|
//
|
|
//------------------------
|
|
// Detach all the children
|
|
//------------------------
|
|
//
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child;
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Unregister_Object(child);
|
|
delete child;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
ElementRenderer::GroupElement*
|
|
ElementRenderer::GroupElement::Make(
|
|
Stuff::MemoryStream *stream,
|
|
int version,
|
|
ShapeHolder shapes
|
|
)
|
|
{
|
|
Check_Object(stream);
|
|
|
|
gos_PushCurrentHeap(s_Heap);
|
|
GroupElement *element = new GroupElement(DefaultData, stream, version, shapes);
|
|
gos_PopCurrentHeap();
|
|
|
|
return element;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::Save(Stuff::MemoryStream *stream)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(stream);
|
|
BaseClass::Save(stream);
|
|
|
|
//
|
|
//-----------------------------------------------------------
|
|
// Write out the child count and then the children themselves
|
|
//-----------------------------------------------------------
|
|
//
|
|
Stuff::ChainIteratorOf<Element*> elements(&m_group);
|
|
Element *element;
|
|
*stream << elements.GetSize();
|
|
while ((element = elements.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(element);
|
|
element->Save(stream);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::TestInstance()
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::AttachChild(Element *child)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(child);
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// Increment the child's reference count, and add it to our child list
|
|
//--------------------------------------------------------------------
|
|
//
|
|
Verify(!child->GetParentElement());
|
|
Verify(!m_group.IsPlugMember(child));
|
|
m_group.Add(child);
|
|
SetParentElement(child, this);
|
|
if (!AreBoundsLocked())
|
|
NeedNewBounds();
|
|
if (child->GetCullMode() == RootMode)
|
|
{
|
|
if (child->m_localOBB.sphereRadius > 0.0f || child->AreBoundsWrong())
|
|
child->SetVolumeCullMode();
|
|
else
|
|
child->SetNeverCullMode();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::DetachChild(Element *child)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(child);
|
|
|
|
//
|
|
//-------------------------------------------------------------------
|
|
// Decrement the child's reference count, and remove it from our list
|
|
//-------------------------------------------------------------------
|
|
//
|
|
Verify(child->GetParentElement() == this);
|
|
m_group.RemovePlug(child);
|
|
SetParentElement(child, NULL);
|
|
child->SetRootMode();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::DetachChildren()
|
|
{
|
|
Check_Object(this);
|
|
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child;
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Verify(child->GetParentElement() == this);
|
|
m_group.RemovePlug(child);
|
|
SetParentElement(child, NULL);
|
|
child->SetRootMode();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::SetSyncState()
|
|
{
|
|
Check_Object(this);
|
|
/*
|
|
Verify(
|
|
GetCullMode() != VolumeCullMode
|
|
|| AreBoundsWrong()
|
|
|| IsSyncDeferred()
|
|
|| (
|
|
m_localOBB.sphereRadius>0.0f
|
|
&& (IsMatrixDirty() || m_worldOBB.sphereRadius>0.0f
|
|
)
|
|
)
|
|
);
|
|
*/
|
|
Verify(
|
|
GetCullMode() == RootMode
|
|
|| GetCullMode() == AlwaysCullMode
|
|
|| m_parent != NULL
|
|
|| AreBoundsWrong()
|
|
);
|
|
unsigned index = (m_state>>SyncStateBit) & SyncStateMask;
|
|
Verify(index < SyncStateCount);
|
|
m_sync = SyncMethods[index];
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::SetDrawState()
|
|
{
|
|
Check_Object(this);
|
|
unsigned index = (m_state>>DrawStateBit) & DrawStateMask;
|
|
Verify(index < DrawStateCount);
|
|
m_draw = DrawMethods[index];
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::CleanRootSyncMethod()
|
|
{
|
|
Check_Object(this);
|
|
Verify(!IsMatrixDirty() && GetCullMode() == RootMode);
|
|
SYNC_LOGIC("Root::Clean::Group");
|
|
|
|
//
|
|
//--------------------
|
|
// Update our children
|
|
//--------------------
|
|
//
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child;
|
|
WASTE_CHECK();
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
child->Sync();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::DirtyRootSyncMethod()
|
|
{
|
|
Check_Object(this);
|
|
Verify(IsMatrixDirty() && GetCullMode() == RootMode);
|
|
SYNC_LOGIC("Root::Dirty::Group");
|
|
|
|
//
|
|
//------------------------------------------------------
|
|
// If the local-to-parent matrix is dirty, make it clean
|
|
//------------------------------------------------------
|
|
//
|
|
m_localToWorld = m_localToParent = m_newLocalToParent;
|
|
MatrixIsClean();
|
|
CleanRootSyncMethod();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::CleanSyncMethod()
|
|
{
|
|
Check_Object(this);
|
|
Verify(!IsMatrixDirty() && GetCullMode() == NeverCullMode);
|
|
SYNC_LOGIC("Clean::Group");
|
|
|
|
//
|
|
//------------------------------------------------------------------
|
|
// Concatenated our m_localToWorld from m_localToParent and our parent's
|
|
// m_localToWorld
|
|
//------------------------------------------------------------------
|
|
//
|
|
Check_Object(m_parent);
|
|
if (!IsLocalToParentIdentity())
|
|
m_localToWorld.Multiply(m_localToParent, m_parent->GetLocalToWorld());
|
|
else
|
|
m_localToWorld = m_parent->GetLocalToWorld();
|
|
|
|
//
|
|
//--------------------
|
|
// Update our children
|
|
//--------------------
|
|
//
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child;
|
|
WASTE_CHECK();
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
child->Sync();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::DirtySyncMethod()
|
|
{
|
|
Check_Object(this);
|
|
Verify(IsMatrixDirty() && GetCullMode() == NeverCullMode);
|
|
SYNC_LOGIC("Dirty::Group");
|
|
|
|
//
|
|
//------------------------------------------------------
|
|
// If the local-to-parent matrix is dirty, make it clean
|
|
//------------------------------------------------------
|
|
//
|
|
m_localToParent = m_newLocalToParent;
|
|
|
|
//
|
|
//------------------------------------------------------------------
|
|
// Concatenated our m_localToWorld from m_localToParent and our parent's
|
|
// m_localToWorld
|
|
//------------------------------------------------------------------
|
|
//
|
|
Check_Object(m_parent);
|
|
if (!IsLocalToParentIdentity())
|
|
m_localToWorld.Multiply(m_localToParent, m_parent->GetLocalToWorld());
|
|
else
|
|
m_localToWorld = m_parent->GetLocalToWorld();
|
|
MatrixIsClean();
|
|
|
|
//
|
|
//--------------------
|
|
// Update our children
|
|
//--------------------
|
|
//
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child;
|
|
WASTE_CHECK();
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
child->Sync();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::CleanSphereSyncMethod()
|
|
{
|
|
Check_Object(this);
|
|
Verify(m_localOBB.sphereRadius > 0.0f);
|
|
Verify(
|
|
!IsMatrixDirty() && GetCullMode()==VolumeCullMode && IsBoundedBySphere()
|
|
);
|
|
SYNC_LOGIC("Sphere::Clean::Group");
|
|
|
|
//
|
|
//------------------------------------------------------------------
|
|
// Concatenated our m_localToWorld from m_localToParent and our parent's
|
|
// m_localToWorld
|
|
//------------------------------------------------------------------
|
|
//
|
|
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
|
|
//--------------------
|
|
//
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child;
|
|
WASTE_CHECK();
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
child->Sync();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::MatrixDirtySphereSyncMethod()
|
|
{
|
|
Check_Object(this);
|
|
Verify(m_localOBB.sphereRadius > 0.0f);
|
|
Verify(
|
|
IsMatrixDirty() && GetCullMode()==VolumeCullMode && IsBoundedBySphere()
|
|
);
|
|
SYNC_LOGIC("Sphere::Dirty::Group");
|
|
|
|
//
|
|
//--------------------
|
|
// Update the matrices
|
|
//--------------------
|
|
//
|
|
m_localToParent = m_newLocalToParent;
|
|
Check_Object(&m_localToParent);
|
|
|
|
Check_Object(m_parent);
|
|
|
|
if (!IsLocalToParentIdentity())
|
|
{
|
|
Check_Object(&m_parent->GetLocalToWorld());
|
|
m_localToWorld.Multiply(m_localToParent, m_parent->GetLocalToWorld());
|
|
Check_Object(&m_localToWorld);
|
|
}
|
|
else
|
|
{
|
|
m_localToWorld = m_parent->GetLocalToWorld();
|
|
Check_Object(&m_localToWorld);
|
|
}
|
|
//
|
|
//--------------------------------------------------------------
|
|
// Transform the bounding sphere, then mark the element as clean
|
|
//--------------------------------------------------------------
|
|
//
|
|
m_worldOBB.MultiplySphereOnly(m_localOBB, m_localToWorld);
|
|
MatrixIsClean();
|
|
|
|
//
|
|
//--------------------
|
|
// Update our children
|
|
//--------------------
|
|
//
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child;
|
|
WASTE_CHECK();
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
child->Sync();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::BoundsWrongSphereSyncMethod()
|
|
{
|
|
Check_Object(this);
|
|
Verify(
|
|
!IsMatrixDirty() && AreBoundsWrong()
|
|
&& GetCullMode()==VolumeCullMode && IsBoundedBySphere()
|
|
);
|
|
SYNC_LOGIC("Sphere::RecalcBounds::Group");
|
|
|
|
//
|
|
//------------------------------------------------------------------
|
|
// Concatenated our m_localToWorld from m_localToParent and our parent's
|
|
// m_localToWorld
|
|
//------------------------------------------------------------------
|
|
//
|
|
Check_Object(m_parent);
|
|
if (!IsLocalToParentIdentity())
|
|
m_localToWorld.Multiply(m_localToParent, m_parent->GetLocalToWorld());
|
|
else
|
|
m_localToWorld = m_parent->GetLocalToWorld();
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// If our bounds are locked, just run the children and transform our local
|
|
// bounds
|
|
//------------------------------------------------------------------------
|
|
//
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child;
|
|
WASTE_CHECK();
|
|
if (AreBoundsLocked())
|
|
{
|
|
Verify(m_localOBB.sphereRadius > 0.0f);
|
|
m_worldOBB.MultiplySphereOnly(m_localOBB, m_localToWorld);
|
|
BoundsAreRight();
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
child->Sync();
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------
|
|
// Update our children, then get their bounding spheres
|
|
//-----------------------------------------------------
|
|
//
|
|
#if defined(BOUNDS_BUG)
|
|
for (int i=0; i<prefix_len; ++i)
|
|
SPEW((BOUNDS_BUG, " +"));
|
|
++prefix_len;
|
|
SPEW((BOUNDS_BUG, "%s = %x", GetClassData()->GetClassName(), this));
|
|
#endif
|
|
Stuff::Sphere bounds(Stuff::Point3D::Identity, 0.0f);
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
child->Sync();
|
|
if (child->GetCullMode() == VolumeCullMode)
|
|
{
|
|
Stuff::LinearMatrix4D child_to_parent = child->GetLocalToParent();
|
|
Stuff::Point3D child_center(child->m_localOBB.localToParent);
|
|
|
|
//
|
|
//--------------------------------------------------------------
|
|
// If we are derived from a group, we can dynamically move so we
|
|
// need to expand the bounding volume
|
|
//--------------------------------------------------------------
|
|
//
|
|
#if defined(BOUNDS_BUG)
|
|
for (int i=0; i<prefix_len; ++i)
|
|
SPEW((BOUNDS_BUG, " +"));
|
|
#endif
|
|
Stuff::Sphere child_sphere;
|
|
if (child->IsDerivedFrom(ElementRenderer::GroupElement::DefaultData))
|
|
{
|
|
child_sphere.center = child_to_parent;
|
|
child_sphere.radius =
|
|
child_center.GetLength() + child->m_localOBB.sphereRadius;
|
|
#if defined(BOUNDS_BUG)
|
|
SPEW((BOUNDS_BUG, "%s %x = +", child->GetClassData()->GetClassName(), child));
|
|
Spew(BOUNDS_BUG, child_sphere.center);
|
|
SPEW((
|
|
BOUNDS_BUG,
|
|
", %f(%f+%f)",
|
|
child_sphere.radius,
|
|
child_center.GetLength(),
|
|
child->m_localOBB.sphereRadius
|
|
));
|
|
#endif
|
|
}
|
|
|
|
//
|
|
//-------------------------------------------------------------
|
|
// If not, the object is static, so just deal with the centroid
|
|
//-------------------------------------------------------------
|
|
//
|
|
else
|
|
{
|
|
child_sphere.center.Multiply(child_center, child_to_parent);
|
|
child_sphere.radius = child->m_localOBB.sphereRadius;
|
|
#if defined(BOUNDS_BUG)
|
|
SPEW((BOUNDS_BUG, "%s %x = +", child->GetClassData()->GetClassName(), child));
|
|
Spew(BOUNDS_BUG, child_sphere.center);
|
|
SPEW((BOUNDS_BUG, ",%f", child_sphere.radius));
|
|
#endif
|
|
}
|
|
|
|
//
|
|
//---------------------
|
|
// Build the new sphere
|
|
//---------------------
|
|
//
|
|
if (bounds.radius == 0.0f)
|
|
bounds = child_sphere;
|
|
else
|
|
bounds.Union(bounds, child_sphere);
|
|
}
|
|
}
|
|
#if defined(BOUNDS_BUG)
|
|
--prefix_len;
|
|
for (i=0; i<prefix_len; ++i)
|
|
SPEW((BOUNDS_BUG, " +"));
|
|
SPEW((BOUNDS_BUG, "Bounds = +"));
|
|
Spew(BOUNDS_BUG, bounds.center);
|
|
SPEW((BOUNDS_BUG, ",%f", bounds.radius));
|
|
#endif
|
|
m_localOBB.BuildSphere(bounds);
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// If we have no bounded children, we will never cull, otherwise take the
|
|
// local bounds into world space
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
if (m_localOBB.sphereRadius == 0.0f)
|
|
SetNeverCullMode();
|
|
else
|
|
m_worldOBB.MultiplySphereOnly(m_localOBB, m_localToWorld);
|
|
BoundsAreRight();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::FullSphereSyncMethod()
|
|
{
|
|
Check_Object(this);
|
|
Verify(
|
|
IsMatrixDirty() && AreBoundsWrong()
|
|
&& GetCullMode()==VolumeCullMode && IsBoundedBySphere()
|
|
);
|
|
SYNC_LOGIC("Sphere::Full::Group");
|
|
|
|
//
|
|
//--------------------
|
|
// Update the 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();
|
|
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// If our bounds are locked, just run the children and transform our local
|
|
// bounds
|
|
//------------------------------------------------------------------------
|
|
//
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child;
|
|
WASTE_CHECK();
|
|
if (AreBoundsLocked())
|
|
{
|
|
Verify(m_localOBB.sphereRadius > 0.0f);
|
|
m_worldOBB.MultiplySphereOnly(m_localOBB, m_localToWorld);
|
|
m_state &= ~(MatrixDirtyFlag|BoundsWrongFlag);
|
|
SetSyncState();
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
child->Sync();
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------
|
|
// Update our children, then get their bounding spheres
|
|
//-----------------------------------------------------
|
|
//
|
|
#if defined(BOUNDS_BUG)
|
|
if (!prefix_len)
|
|
SPEW((BOUNDS_BUG, "%s = %x", GetClassData()->GetClassName(), this));
|
|
++prefix_len;
|
|
#endif
|
|
Stuff::Sphere bounds(Stuff::Point3D::Identity, 0.0f);
|
|
#if defined(BOUNDS_BUG)
|
|
int child_count = 0;
|
|
#endif
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
#if defined(BOUNDS_BUG)
|
|
for (int i=0; i<prefix_len; ++i)
|
|
SPEW((BOUNDS_BUG, " +"));
|
|
SPEW((BOUNDS_BUG, "%d: syncing %s(%x)", child_count, child->GetClassData()->GetClassName(), child));
|
|
#endif
|
|
child->Sync();
|
|
#if defined(BOUNDS_BUG)
|
|
for (i=0; i<=prefix_len; ++i)
|
|
SPEW((BOUNDS_BUG, " +"));
|
|
#endif
|
|
if (child->GetCullMode() == VolumeCullMode)
|
|
{
|
|
Stuff::LinearMatrix4D child_to_parent = child->GetLocalToParent();
|
|
Stuff::Point3D child_center(child->m_localOBB.localToParent);
|
|
|
|
//
|
|
//--------------------------------------------------------------
|
|
// If we are derived from a group, we can dynamically move so we
|
|
// need to expand the bounding volume
|
|
//--------------------------------------------------------------
|
|
//
|
|
Stuff::Sphere child_sphere;
|
|
if (child->IsDerivedFrom(ElementRenderer::GroupElement::DefaultData))
|
|
{
|
|
child_sphere.center = child_to_parent;
|
|
child_sphere.radius =
|
|
child_center.GetLength() + child->m_localOBB.sphereRadius;
|
|
#if defined(BOUNDS_BUG)
|
|
Spew(BOUNDS_BUG, child_sphere.center);
|
|
SPEW((
|
|
BOUNDS_BUG, ", %f(%f+%f)",
|
|
child_sphere.radius,
|
|
child_center.GetLength(),
|
|
child->m_localOBB.sphereRadius
|
|
));
|
|
#endif
|
|
}
|
|
|
|
//
|
|
//-------------------------------------------------------------
|
|
// If not, the object is static, so just deal with the centroid
|
|
//-------------------------------------------------------------
|
|
//
|
|
else
|
|
{
|
|
child_sphere.center.Multiply(child_center, child_to_parent);
|
|
child_sphere.radius = child->m_localOBB.sphereRadius;
|
|
#if defined(BOUNDS_BUG)
|
|
Spew(BOUNDS_BUG, child_sphere.center);
|
|
SPEW((BOUNDS_BUG, ", %f", child_sphere.radius));
|
|
#endif
|
|
}
|
|
|
|
//
|
|
//---------------------
|
|
// Build the new sphere
|
|
//---------------------
|
|
//
|
|
if (bounds.radius == 0.0f)
|
|
bounds = child_sphere;
|
|
else
|
|
bounds.Union(bounds, child_sphere);
|
|
}
|
|
#if defined(BOUNDS_BUG)
|
|
else
|
|
SPEW((BOUNDS_BUG, " isn't volume culled"));
|
|
++child_count;
|
|
#endif
|
|
}
|
|
#if defined(BOUNDS_BUG)
|
|
--prefix_len;
|
|
for (int i=0; i<prefix_len; ++i)
|
|
SPEW((BOUNDS_BUG, " +"));
|
|
SPEW((BOUNDS_BUG, "%d children, Bounds = +", child_count));
|
|
Spew(BOUNDS_BUG, bounds.center);
|
|
SPEW((BOUNDS_BUG, ",%f", bounds.radius));
|
|
#endif
|
|
m_localOBB.BuildSphere(bounds);
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// If we have no bounded children, we will never cull, otherwise take the
|
|
// local bounds into world space
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
if (m_localOBB.sphereRadius == 0.0f)
|
|
SetNeverCullMode();
|
|
else
|
|
m_worldOBB.MultiplySphereOnly(m_localOBB, m_localToWorld);
|
|
m_state &= ~(MatrixDirtyFlag|BoundsWrongFlag);
|
|
SetSyncState();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::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::Group");
|
|
|
|
//
|
|
//------------------------------------------------------------------
|
|
// Concatenated our m_localToWorld from m_localToParent and our parent's
|
|
// m_localToWorld
|
|
//------------------------------------------------------------------
|
|
//
|
|
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
|
|
//--------------------
|
|
//
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child;
|
|
WASTE_CHECK();
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
child->Sync();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::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::Group");
|
|
|
|
//
|
|
//--------------------
|
|
// Update the matrices
|
|
//--------------------
|
|
//
|
|
m_localToParent = m_newLocalToParent;
|
|
Check_Object(&m_localToParent);
|
|
|
|
Check_Object(m_parent);
|
|
|
|
if (!IsLocalToParentIdentity())
|
|
{
|
|
Check_Object(&m_parent->GetLocalToWorld());
|
|
m_localToWorld.Multiply(m_localToParent, m_parent->GetLocalToWorld());
|
|
Check_Object(&m_localToWorld);
|
|
}
|
|
else
|
|
{
|
|
m_localToWorld = m_parent->GetLocalToWorld();
|
|
Check_Object(&m_localToWorld);
|
|
}
|
|
//
|
|
//--------------------------------------------------------------
|
|
// Transform the bounding sphere, then mark the element as clean
|
|
//--------------------------------------------------------------
|
|
//
|
|
m_worldOBB.Multiply(m_localOBB, m_localToWorld);
|
|
MatrixIsClean();
|
|
|
|
//
|
|
//--------------------
|
|
// Update our children
|
|
//--------------------
|
|
//
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child;
|
|
WASTE_CHECK();
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
child->Sync();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::BoundsWrongOBBSyncMethod()
|
|
{
|
|
Check_Object(this);
|
|
STOP(("OBB's cannot recalculate bounds!"));
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::FullOBBSyncMethod()
|
|
{
|
|
Check_Object(this);
|
|
STOP(("OBB's cannot recalculate bounds!"));
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
ElementRenderer::GroupElement::CastCulledRay(CollisionQuery *query)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(query);
|
|
Verify(!query->m_data);
|
|
|
|
//
|
|
//------------------
|
|
// Test our children
|
|
//------------------
|
|
//
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child;
|
|
bool result = false;
|
|
void *client_data = m_data;
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
if (child->CastRay(query))
|
|
{
|
|
result = true;
|
|
if (query->m_data)
|
|
{
|
|
client_data = query->m_data;
|
|
query->m_data = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// If we hit something, set the client data if it hasn't already been set
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
if (result)
|
|
query->m_data = client_data;
|
|
else
|
|
Verify(!query->m_data);
|
|
return result;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
ElementRenderer::Element*
|
|
ElementRenderer::GroupElement::FindSmallestElementContainingCulled(SphereTest *test)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(test);
|
|
|
|
//
|
|
//------------------
|
|
// Draw our children
|
|
//------------------
|
|
//
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child;
|
|
Element *result = this;
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
Element *temp = child->FindSmallestElementContaining(test);
|
|
if (temp)
|
|
result = temp;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::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
|
|
|
|
//
|
|
//------------------
|
|
// Draw our children
|
|
//------------------
|
|
//
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child;
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
camera->DrawElement(child, inherited_state);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::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
|
|
|
|
//
|
|
//------------------
|
|
// Draw our children
|
|
//------------------
|
|
//
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child;
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
camera->DrawElement(child, &mixed);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::CleanDamage()
|
|
{
|
|
Check_Object(this);
|
|
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child = NULL;
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
child->CleanDamage();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::ApplyDamage(
|
|
const Stuff::LinearMatrix4D &damage_spot,
|
|
Stuff::Scalar radius
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child = NULL;
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
child->ApplyDamage(damage_spot, radius);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::ApplyDamageDecal(
|
|
const Stuff::LinearMatrix4D &damage_spot,
|
|
Stuff::Scalar radius,
|
|
MidLevelRenderer::MLRTexture *texture
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(texture);
|
|
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child = NULL;
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
child->ApplyDamageDecal(damage_spot, radius, texture);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::CastShadow(
|
|
const Stuff::LinearMatrix4D &shadow_to_world,
|
|
const Stuff::UnitVector3D &sun_in_world,
|
|
Stuff::Scalar radius
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
|
|
if (!IsShadowed())
|
|
return;
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child = NULL;
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
child->CastShadow(shadow_to_world, sun_in_world, radius);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ElementRenderer::GroupElement::MakeFootStep(
|
|
MidLevelRenderer::MLRShape *shape,
|
|
const Stuff::LinearMatrix4D &foot,
|
|
Stuff::Scalar radius,
|
|
MidLevelRenderer::MLRTexture *tex
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child = NULL;
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
child->MakeFootStep(shape, foot, radius, tex);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
ElementRenderer::GroupElement::CountTriangles()
|
|
{
|
|
Check_Object(this);
|
|
|
|
//
|
|
//------------------
|
|
// Draw our children
|
|
//------------------
|
|
//
|
|
int result = 0;
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child;
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
result += child->CountTriangles();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Returns array of vertex coordinates and number of vertices
|
|
void
|
|
ElementRenderer::GroupElement::GetCoordData(
|
|
Stuff::DynamicArrayOf<Stuff::Point3D> *array)
|
|
{
|
|
Check_Object(this);
|
|
|
|
Stuff::ChainIteratorOf<Element*> children(&m_group);
|
|
Element *child;
|
|
while ((child = children.ReadAndNext()) != NULL)
|
|
{
|
|
Stuff::DynamicArrayOf<Stuff::Point3D> child_array;
|
|
child->GetCoordData(&child_array);
|
|
|
|
int point_count = array->GetLength();
|
|
array->SetLength(point_count+child_array.GetLength());
|
|
|
|
for (int v=0; v<child_array.GetLength(); ++v)
|
|
{
|
|
(*array)[point_count+v]=child_array[v];
|
|
}
|
|
}
|
|
|
|
} |