Files
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

2104 lines
56 KiB
C++

#include "ElementRendererHeaders.hpp"
#include <MLR\MLR_I_TMesh.hpp>
//############################################################################
//############################## Element ###################################
//############################################################################
ElementRenderer::Element::ClassData*
ElementRenderer::Element::DefaultData = NULL;
ElementRenderer::Element::SyncMethod
ElementRenderer::Element::SyncMethods[SyncStateCount]=
{
//
// Root mode
//
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, DirtyRoot),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, DirtyRoot),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, DirtyRoot),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, DirtyRoot),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
//
// Stuff::Sphere Cull
//
SYNC_METHOD(Element, CleanSphere),
SYNC_METHOD(Element, DirtySphere),
SYNC_METHOD(Element, CleanSphere),
SYNC_METHOD(Element, DirtySphere),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
//
// Stuff::OBB Cull
//
SYNC_METHOD(Element, CleanOBB),
SYNC_METHOD(Element, DirtyOBB),
SYNC_METHOD(Element, CleanOBB),
SYNC_METHOD(Element, DirtyOBB),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
//
// Never Cull
//
SYNC_METHOD(Element, Clean),
SYNC_METHOD(Element, Dirty),
SYNC_METHOD(Element, Clean),
SYNC_METHOD(Element, Dirty),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
SYNC_METHOD(Element, None),
SYNC_METHOD(Element, Defer),
SYNC_METHOD(Element, Clean),
SYNC_METHOD(Element, Dirty),
SYNC_METHOD(Element, Clean),
SYNC_METHOD(Element, 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::CullMethod
ElementRenderer::Element::CullMethods[CullStateCount]=
{
//
// No billboarding
//
CULL_METHOD(Element, Never, Never),
CULL_METHOD(Element, Never, Never),
CULL_METHOD(Element, Sphere, Sphere),
CULL_METHOD(Element, OBB, OBB),
CULL_METHOD(Element, Never, Never),
CULL_METHOD(Element, Never, Never),
CULL_METHOD(Element, Always, Always),
CULL_METHOD(Element, Always, Always),
//
// Billboarding around X
//
CULL_METHOD(Element, DeferredXNever, Never),
CULL_METHOD(Element, DeferredXNever, Never),
CULL_METHOD(Element, DeferredXSphere, Sphere),
CULL_METHOD(Element, DeferredXOBB, OBB),
CULL_METHOD(Element, DeferredXNever, Never),
CULL_METHOD(Element, DeferredXNever, Never),
CULL_METHOD(Element, DeferredXAlways, Always),
CULL_METHOD(Element, DeferredXAlways, Always),
//
// Billboarding around Y
//
CULL_METHOD(Element, DeferredYNever, Never),
CULL_METHOD(Element, DeferredYNever, Never),
CULL_METHOD(Element, DeferredYSphere, Sphere),
CULL_METHOD(Element, DeferredYOBB, OBB),
CULL_METHOD(Element, DeferredYNever, Never),
CULL_METHOD(Element, DeferredYNever, Never),
CULL_METHOD(Element, DeferredYAlways, Always),
CULL_METHOD(Element, DeferredYAlways, Always),
//
// Billboarding around X and Y
//
CULL_METHOD(Element, DeferredXYNever, Never),
CULL_METHOD(Element, DeferredXYNever, Never),
CULL_METHOD(Element, DeferredXYSphere, Sphere),
CULL_METHOD(Element, DeferredXYOBB, OBB),
CULL_METHOD(Element, DeferredXYNever, Never),
CULL_METHOD(Element, DeferredXYNever, Never),
CULL_METHOD(Element, DeferredXYAlways, Always),
CULL_METHOD(Element, DeferredXYAlways, Always)
};
Stuff::RGBAColor
ElementRenderer::Element::FadeColor;
ElementRenderer::Element::Callback*
ElementRenderer::Element::CallbackSet = NULL;
ElementRenderer::Element::Callback
ElementRenderer::Element::Callbacks[1<<ElementRenderer::Element::CallbackBits]=
{
NULL,
DrawGreenBoundsCallback,
DrawYellowBoundsCallback,
DrawRedBoundsCallback,
DrawGreenBoundsOnceCallback,
DrawYellowBoundsOnceCallback,
DrawRedBoundsOnceCallback,
NULL
};
MidLevelRenderer::MLRShape
*Sphere_Object = NULL,
*Box_Object = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::InitializeClass()
{
Verify(!DefaultData);
DefaultData =
new ClassData(
ElementClassID,
"ElementRenderer::Element",
BaseClass::DefaultData,
NULL
);
Check_Object(DefaultData);
Verify(!Sphere_Object);
Verify(!Box_Object);
MidLevelRenderer::MLRState state;
state.SetAlphaMode(MidLevelRenderer::MLRState::AlphaInvAlphaMode);
state.SetBackFaceOff();
state.SetPriority(8);
MidLevelRenderer::IcoInfo icoInfo;
icoInfo.depth = 1;
icoInfo.indexed = true;
icoInfo.radius = 1.0f;
icoInfo.all = 1.0f;
icoInfo.onOff = true;
Sphere_Object =
MidLevelRenderer::CreateIndexedTriIcosahedron_NoColor_NoLit(
icoInfo,
&state
);
gos_PushCurrentHeap(MidLevelRenderer::ShapeHeap);
Box_Object = new MidLevelRenderer::MLRShape(1);
Check_Object(Box_Object);
MidLevelRenderer::MLR_I_PMesh *cube =
MidLevelRenderer::CreateIndexedCube_NoColor_NoLit(1.0f, &state);
Check_Object(cube);
gos_PopCurrentHeap();
Box_Object->Add(cube);
cube->DetachReference();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::TerminateClass()
{
Box_Object->DetachReference();
Box_Object = NULL;
Sphere_Object->DetachReference();
Sphere_Object = NULL;
Check_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::Element::Element(ClassData *class_data):
Plug(class_data)
{
Check_Pointer(this);
Check_Object(class_data);
//
//--------------------------------
// Initialize the member variables
//--------------------------------
//
m_data = NULL;
m_parent = NULL;
m_worldOBB.localToParent = m_localOBB.localToParent = Stuff::LinearMatrix4D::Identity;
m_localOBB.axisExtents = Stuff::Vector3D::Identity;
m_localOBB.sphereRadius = 0.0f;
m_worldOBB.axisExtents = Stuff::Vector3D::Identity;
m_worldOBB.sphereRadius = -1.0f;
m_newLocalToParent = Stuff::LinearMatrix4D::Identity;
m_localToParent = Stuff::LinearMatrix4D::Identity;
m_localToWorld = Stuff::LinearMatrix4D::Identity;
m_stateChange = NULL;
//
//----------------------------
// Now set the method handlers
//----------------------------
//
m_state = RootMode | MatrixDirtyFlag | LocalToParentIsIdentityFlag;
unsigned sync_state = (m_state>>SyncStateBit)&SyncStateMask;
Verify(sync_state < SyncStateCount);
m_sync = SyncMethods[sync_state];
unsigned cull_state = (m_state>>CullStateBit)&CullStateMask;
Verify(cull_state < CullStateCount);
m_cameraCull = CullMethods[cull_state].m_cameraCull;
m_rayCull = CullMethods[cull_state].m_rayCull;
m_sphereTest = CullMethods[cull_state].m_sphereTest;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::Element::Element(
ClassData *class_data,
Element *element
):
Plug(class_data)
{
Check_Pointer(this);
Check_Object(class_data);
//
//--------------------------------
// Initialize the member variables
//--------------------------------
//
m_data = NULL;
m_parent = NULL;
m_localOBB = element->m_localOBB;
m_worldOBB.localToParent = Stuff::LinearMatrix4D::Identity;
m_worldOBB.axisExtents = Stuff::Vector3D::Identity;
m_worldOBB.sphereRadius = -1.0f;
m_newLocalToParent = element->m_newLocalToParent;
m_localToParent = element->m_localToParent;
m_localToWorld = element->m_localToWorld;
if (element->m_stateChange)
{
m_stateChange = new StateChange(*element->m_stateChange);
Check_Object(m_stateChange);
}
else
m_stateChange = NULL;
//
//----------------------------
// Now set the method handlers
//----------------------------
//
m_state = element->m_state;
m_state &= ~CullMask;
m_state |= RootMode | MatrixDirtyFlag;
unsigned sync_state = (m_state>>SyncStateBit)&SyncStateMask;
Verify(sync_state < SyncStateCount);
m_sync = SyncMethods[sync_state];
unsigned cull_state = (m_state>>CullStateBit)&CullStateMask;
Verify(cull_state < CullStateCount);
m_cameraCull = CullMethods[cull_state].m_cameraCull;
m_rayCull = CullMethods[cull_state].m_rayCull;
m_sphereTest = CullMethods[cull_state].m_sphereTest;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::Element::Element(
ClassData *class_data,
Stuff::MemoryStream *stream,
int version
):
Plug(class_data)
{
Check_Pointer(this);
Check_Object(class_data);
Check_Object(stream);
//
//--------------------------------
// Initialize the member variables
//--------------------------------
//
m_data = NULL;
m_parent = NULL;
m_localToParent = Stuff::LinearMatrix4D::Identity;
m_localToWorld = Stuff::LinearMatrix4D::Identity;
m_stateChange = NULL;
m_worldOBB.localToParent = Stuff::LinearMatrix4D::Identity;
m_worldOBB.axisExtents = Stuff::Vector3D::Identity;
m_worldOBB.sphereRadius = -1.0f;
//
//----------------------------------------------------------------------
// Read mask and element state. If we are reading something from before
// version 6, make room for the new locked flag
//----------------------------------------------------------------------
//
if (version < 7)
{
int collision_mask;
*stream >> collision_mask;
}
*stream >> m_state;
if (version < 6)
m_state = (m_state&1) | ((m_state << 1)&0xFFFFFFFC);
//
//------------------------------
// Read the StateChange and name
//------------------------------
//
if (m_state & PropertyChangeFlag)
{
m_stateChange = new StateChange(stream, version);
Check_Object(m_stateChange);
}
if (version < 12)
{
Stuff::MString name;
*stream >> name;
}
if (!IsLocalToParentIdentity())
*stream >> m_newLocalToParent;
else
m_newLocalToParent = Stuff::LinearMatrix4D::Identity;
//
//-------------------------
// Read the bounding volume
//-------------------------
//
if (IsBoundedByOBB())
{
*stream >> m_localOBB.localToParent >> m_localOBB.axisExtents
>> m_localOBB.sphereRadius;
}
else
{
Stuff::Point3D center;
*stream >> center;
m_localOBB.localToParent = Stuff::LinearMatrix4D::Identity;
m_localOBB.localToParent.BuildTranslation(center);
m_localOBB.axisExtents = Stuff::Vector3D::Identity;
*stream >> m_localOBB.sphereRadius;
}
//
//----------------------------
// Now set the method handlers
//----------------------------
//
m_state |= MatrixDirtyFlag;
unsigned sync_state = (m_state>>SyncStateBit)&SyncStateMask;
Verify(sync_state < SyncStateCount);
m_sync = SyncMethods[sync_state];
unsigned cull_state = (m_state>>CullStateBit)&CullStateMask;
Verify(cull_state < CullStateCount);
m_cameraCull = CullMethods[cull_state].m_cameraCull;
m_rayCull = CullMethods[cull_state].m_rayCull;
m_sphereTest = CullMethods[cull_state].m_sphereTest;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::Element::~Element()
{
Check_Object(this);
//
//-------------------
// Unhook from parent
//-------------------
//
if (m_parent)
{
Check_Object(m_parent);
m_parent->DetachChild(this);
}
//
//--------------------------
// Unhook the properties set
//--------------------------
//
if (m_stateChange)
{
Check_Object(m_stateChange);
delete m_stateChange;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::Element*
ElementRenderer::Element::Create(
Stuff::MemoryStream *stream,
int version,
ShapeHolder shapes
)
{
RegisteredClass::ClassID class_id;
*stream >> class_id;
ClassData* class_data = Cast_Pointer(ClassData*, FindClassData(class_id));
Check_Object(class_data);
Element *child = (*class_data->m_elementFactory)(stream, version, shapes);
Check_Object(child);
return child;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::Save(Stuff::MemoryStream *stream)
{
Check_Pointer(this);
Check_Object(stream);
//
//--------------------------
// Write stuff to the stream
//--------------------------
//
*stream << static_cast<int>(GetClassID()) << m_state;
if (m_stateChange)
{
Check_Object(m_stateChange);
Verify(m_state & PropertyChangeFlag);
m_stateChange->Save(stream);
}
if (!IsLocalToParentIdentity())
*stream << m_localToParent;
//
//--------------------------
// Write the bounding volume
//--------------------------
//
if (IsBoundedByOBB())
{
*stream << m_localOBB.localToParent << m_localOBB.axisExtents
<< m_localOBB.sphereRadius;
}
else
{
Stuff::Point3D center(m_localOBB.localToParent);
*stream << center;
*stream << m_localOBB.sphereRadius;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::TestInstance()
{
Verify(IsDerivedFrom(DefaultData));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::ReadStateFromPage(
Stuff::Page *page,
const Stuff::MString &prefix,
unsigned *state,
unsigned *delta,
Stuff::OBB *bounds
)
{
Check_Object(&prefix);
Check_Object(page);
Check_Pointer(state);
Check_Pointer(bounds);
//
//------------------------
// Is it an identity state
//------------------------
//
*delta = 0;
bool identity;
if (page->GetEntry(prefix+"LocalToParentIsIdentity", &identity))
{
if (identity)
*state |= LocalToParentIsIdentityFlag;
else
*state &= ~LocalToParentIsIdentityFlag;
}
//
//---------------------------
// Is there a bounding sphere
//---------------------------
//
const char* sphere = NULL;
if (page->GetEntry(prefix+"BoundingSphere", &sphere))
{
*state &= ~OBBFlag;
*delta |= OBBFlag;
bounds->localToParent = Stuff::LinearMatrix4D::Identity;
Check_Pointer(sphere);
#if defined(_ARMOR)
int count=
#endif
sscanf(
sphere,
"%f %f %f %f",
&bounds->localToParent(3,0),
&bounds->localToParent(3,1),
&bounds->localToParent(3,2),
&bounds->sphereRadius
);
Verify(count == 4);
bounds->axisExtents = Stuff::Vector3D::Identity;
*state |= BoundsLockedFlag;
*delta |= BoundsLockedFlag;
}
//
//------------------------
// Is there a bounding Stuff::OBB
//------------------------
//
else
{
const char* obb = NULL;
if (page->GetEntry(prefix+"Stuff::OBB", &obb))
{
*state |= OBBFlag;
*delta |= OBBFlag;
Stuff::YawPitchRoll rotation;
Check_Pointer(obb);
sscanf(
obb,
"%f %f %f %f %f %f %f %f %f",
&bounds->localToParent(3,0),
&bounds->localToParent(3,1),
&bounds->localToParent(3,2),
&rotation.yaw.angle,
&rotation.pitch.angle,
&rotation.roll.angle,
&bounds->axisExtents.x,
&bounds->axisExtents.y,
&bounds->axisExtents.z
);
rotation.yaw *= Stuff::Radians_Per_Degree;
rotation.pitch *= Stuff::Radians_Per_Degree;
rotation.roll *= Stuff::Radians_Per_Degree;
bounds->localToParent.BuildRotation(rotation);
bounds->sphereRadius = bounds->axisExtents.GetLength();
*state |= BoundsLockedFlag;
*delta |= BoundsLockedFlag;
}
//
//----------------------------------------------------------------
// Otherwise, there is no Stuff::OBB, so clear out everything and set the
// radius to -1
//----------------------------------------------------------------
//
else
{
bounds->localToParent = Stuff::LinearMatrix4D::Identity;
bounds->axisExtents = Stuff::Vector3D::Identity;
bounds->sphereRadius = -1.0f;
}
}
//
//------------------
// Get the cull mode
//------------------
//
const char* cull_mode = NULL;
if (page->GetEntry(prefix+"Cull", &cull_mode))
{
*state &= ~CullMask;
*delta |= CullMask;
Check_Pointer(cull_mode);
if (!_stricmp(cull_mode, "VolumeCull"))
*state |= VolumeCullMode;
else if (!_stricmp(cull_mode, "AlwaysCull"))
{
*state |= AlwaysCullMode|BoundsLockedFlag;
*delta |= BoundsLockedFlag;
}
else if (!_stricmp(cull_mode, "NeverCull"))
{
*state |= NeverCullMode|BoundsLockedFlag;
*delta |= BoundsLockedFlag;
}
else
Verify(!_stricmp(cull_mode, "RootCull"));
}
//
//------------------------
// Look for the align bits
//------------------------
//
bool align_x;
if (page->GetEntry(prefix+"AlignZUsingX", &align_x))
{
if (align_x)
{
*state |= AlignXFlag|SyncOnCullFlag;
*delta |= AlignXFlag|SyncOnCullFlag;
}
}
bool align_y;
if (page->GetEntry(prefix+"AlignZUsingY", &align_y))
{
if (align_y)
{
*state |= AlignYFlag|SyncOnCullFlag;
*delta |= AlignYFlag|SyncOnCullFlag;
}
}
bool shadow;
if (page->GetEntry(prefix+"DisableShadow", &shadow))
{
if (shadow)
{
*state |= NoShadowFlag;
*delta |= NoShadowFlag;
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::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 sync_state = (m_state>>SyncStateBit)&SyncStateMask;
Verify(sync_state < SyncStateCount);
m_sync = SyncMethods[sync_state];
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::NoneSyncMethod()
{
Check_Object(this);
SYNC_LOGIC("None::Element");
MatrixIsClean();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::DirtyRootSyncMethod()
{
Check_Object(this);
Verify(IsMatrixDirty() && GetCullMode() == RootMode);
SYNC_LOGIC("Root::Dirty::Element");
//
//-------------------------------------
// Copy the matrix and reset the method
//-------------------------------------
//
m_localToWorld = m_localToParent = m_newLocalToParent;
MatrixIsClean();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::DeferSyncMethod()
{
Check_Object(this);
Verify(IsMatrixDirty());
SYNC_LOGIC("Defer::Element");
//
//-------------------------------------
// Copy the matrix and reset the method
//-------------------------------------
//
m_localToParent = m_newLocalToParent;
MatrixIsClean();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::CleanSyncMethod()
{
Check_Object(this);
Verify(!IsMatrixDirty() && GetCullMode()==NeverCullMode);
SYNC_LOGIC("Clean::Element");
//
//------------------------------------------------------------------
// 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();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::DirtySyncMethod()
{
Check_Object(this);
Verify(IsMatrixDirty() && GetCullMode()==NeverCullMode);
SYNC_LOGIC("Dirty::Element");
//
//-------------------------------------
// Copy the matrix and reset the method
//-------------------------------------
//
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();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::CleanSphereSyncMethod()
{
Check_Object(this);
Verify(m_localOBB.sphereRadius > 0.0f);
Verify(
!IsMatrixDirty() && IsBoundedBySphere() && GetCullMode()==VolumeCullMode
);
SYNC_LOGIC("Sphere::Clean::Element");
//
//------------------------------------------------------------------
// 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);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::DirtySphereSyncMethod()
{
Check_Object(this);
Verify(m_localOBB.sphereRadius > 0.0f);
Verify(
IsMatrixDirty() && IsBoundedBySphere() && GetCullMode()==VolumeCullMode
);
SYNC_LOGIC("Sphere::Dirty::Element");
//
//-------------------------------------
// Copy the matrix and reset the method
//-------------------------------------
//
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();
//
//------------------------------
// Transform the bounding sphere
//------------------------------
//
m_worldOBB.MultiplySphereOnly(m_localOBB, m_localToWorld);
MatrixIsClean();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::CleanOBBSyncMethod()
{
Check_Object(this);
Verify(
!IsMatrixDirty() && IsBoundedByOBB() && GetCullMode()==VolumeCullMode
);
Verify(Stuff::Close_Enough(m_localOBB.sphereRadius, m_localOBB.axisExtents.GetLength(), m_localOBB.sphereRadius*0.02f));
SYNC_LOGIC("OBB::Clean::Element");
//
//------------------------------------------------------------------
// 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);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::DirtyOBBSyncMethod()
{
Check_Object(this);
Verify(
IsMatrixDirty() && IsBoundedByOBB() && GetCullMode()==VolumeCullMode
);
Verify(Stuff::Close_Enough(m_localOBB.sphereRadius, m_localOBB.axisExtents.GetLength(), m_localOBB.sphereRadius*0.02f));
SYNC_LOGIC("OBB::Dirty::Element");
//
//-------------------------------------
// Copy the matrix and reset the method
//-------------------------------------
//
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();
//
//------------------------------
// Transform the bounding sphere
//------------------------------
//
m_worldOBB.Multiply(m_localOBB, m_localToWorld);
MatrixIsClean();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::SetCullState()
{
Check_Object(this);
unsigned cull_state = (m_state>>CullStateBit)&CullStateMask;
Verify(cull_state < CullStateCount);
m_cameraCull = CullMethods[cull_state].m_cameraCull;
m_rayCull = CullMethods[cull_state].m_rayCull;
m_sphereTest = CullMethods[cull_state].m_sphereTest;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::Element::NeverCullMethod(CameraElement *camera)
{
Check_Object(this);
Check_Object(camera);
Verify(!IsMatrixDirty());
return 0x2f;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::Element::AlwaysCullMethod(CameraElement *camera)
{
Check_Object(this);
Check_Object(camera);
Verify(!IsMatrixDirty() && GetCullMode()==AlwaysCullMode);
return -1;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::Element::SphereCullMethod(CameraElement *camera)
{
Check_Object(this);
Check_Object(camera);
Verify(m_worldOBB.sphereRadius > 0.0f);
Verify(
!IsMatrixDirty() && IsBoundedBySphere() && GetCullMode()==VolumeCullMode
);
//
//-------------------------------
// We only use the sphere portion
//-------------------------------
//
int cull_state = 0;
Stuff::Point3D center(m_worldOBB.localToParent);
//
//-----------------------------------------------------------------------
// Run each of the camera bounding planes against the sphere. First find
// the distance from the sphere center point to the bounding plane
//-----------------------------------------------------------------------
//
const Stuff::Plane* plane = &camera->GetWorldCullingPlane(0);
for (int i=0; i<ElementRenderer::CameraElement::CullingPlaneCount; ++i, ++plane)
{
Stuff::Scalar distance = plane->GetDistanceTo(center);
//
//-------------------------------------------------------------------
// Now, if this distance is greater than the sphere radius, we have a
// trivial reject
//-------------------------------------------------------------------
//
if (distance >= m_worldOBB.sphereRadius)
return -1;
//
//----------------------------------------------------------------------
// Make room in the clip state for this plane result, then if the center
// is not more than the radius away from the plane, it will need
// culling by this plane
//----------------------------------------------------------------------
//
cull_state <<= 1;
if (distance > -m_worldOBB.sphereRadius)
cull_state |= 1;
}
if (!cull_state)
camera->m_acceptingElement = this;
return cull_state;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::Element::OBBCullMethod(CameraElement *camera)
{
Check_Object(this);
Check_Object(camera);
Verify(
!IsMatrixDirty() && IsBoundedByOBB() && GetCullMode()==VolumeCullMode
);
Verify(Stuff::Close_Enough(m_localOBB.sphereRadius, m_localOBB.axisExtents.GetLength(), m_localOBB.sphereRadius*0.02f));
//
//------------------------------------------------------------------------
// We will be testing the planes inside the matrix, so compute the inverse
//------------------------------------------------------------------------
//
Stuff::LinearMatrix4D parent_to_local;
parent_to_local.Invert(m_worldOBB.localToParent);
//
//-----------------------------------------------------------------------
// Run each of the camera bounding planes against the sphere. First find
// the distance from the sphere center point to the bounding plane
//-----------------------------------------------------------------------
//
Stuff::Point3D
inside_extents,
outside_extents;
int cull_state = 0;
const Stuff::Plane* plane = &camera->GetWorldCullingPlane(0);
for (int i=0; i<ElementRenderer::CameraElement::CullingPlaneCount; ++i, ++plane)
{
Stuff::Plane local_plane;
local_plane.Multiply(*plane, parent_to_local);
//
//---------------------------------------------------------------------
// Look at the resulting vector to find out which corners of the box we
// should be testing
//---------------------------------------------------------------------
//
if (local_plane.normal.x > 0.0f)
{
inside_extents.x = -m_worldOBB.axisExtents.x;
outside_extents.x = m_worldOBB.axisExtents.x;
}
else
{
inside_extents.x = m_worldOBB.axisExtents.x;
outside_extents.x = -m_worldOBB.axisExtents.x;
}
if (local_plane.normal.y > 0.0f)
{
inside_extents.y = -m_worldOBB.axisExtents.y;
outside_extents.y = m_worldOBB.axisExtents.y;
}
else
{
inside_extents.y = m_worldOBB.axisExtents.y;
outside_extents.y = -m_worldOBB.axisExtents.y;
}
if (local_plane.normal.z > 0.0f)
{
inside_extents.z = -m_worldOBB.axisExtents.z;
outside_extents.z = m_worldOBB.axisExtents.z;
}
else
{
inside_extents.z = m_worldOBB.axisExtents.z;
outside_extents.z = -m_worldOBB.axisExtents.z;
}
//
//-------------------------------------------------------------------
// Now, if this distance is greater than the sphere radius, we have a
// trivial reject
//-------------------------------------------------------------------
//
Stuff::Scalar distance = local_plane.GetDistanceTo(inside_extents);
if (distance > 0.0f)
return -1;
//
//----------------------------------------------------------------------
// Make room in the clip state for this plane result, then if the center
// is not more than the radius away from the plane, it will need
// culling by this plane
//----------------------------------------------------------------------
//
distance = local_plane.GetDistanceTo(outside_extents);
cull_state <<= 1;
if (distance > 0.0f)
cull_state |= 1;
}
if (!cull_state)
camera->m_acceptingElement = this;
return cull_state;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::AlignX(CameraElement *camera)
{
Check_Object(this);
Check_Object(camera);
Verify(!IsMatrixDirty());
//
//----------------------------------------------------------------------
// We have to move the camera into the same parent space as the local
// matrix will be in, then figure out the relative direction the element
// should face
//----------------------------------------------------------------------
//
Check_Object(m_parent);
Stuff::Point3D world_camera(camera->GetLocalToWorld());
Stuff::Point3D parent_camera;
parent_camera.MultiplyByInverse(
world_camera,
m_parent->GetLocalToWorld()
);
Stuff::Vector3D camera_direction;
Stuff::Point3D local_origin(m_newLocalToParent);
camera_direction.Subtract(parent_camera, local_origin);
//
//------------------------------------------------------------------------
// Now align the matrix in the direction we wish it to point, then set the
// matrix inside the element and sync
//------------------------------------------------------------------------
//
m_newLocalToParent.AlignLocalAxisToWorldVector(camera_direction, Stuff::Z_Axis, Stuff::X_Axis, -1);
//
//------------------------------------------------------------------------
// In order for the sync to work properly, we have to disable the deferred
// bit for the actual sync, then re-enable it afterwords. After the sync,
// do the standard sphere cull
//------------------------------------------------------------------------
//
m_state &= ~(SyncOnCullFlag|LocalToParentIsIdentityFlag);
m_state |= MatrixDirtyFlag;
SetSyncState();
Sync();
m_state |= SyncOnCullFlag;
SetSyncState();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::Element::DeferredXNeverCullMethod(CameraElement *camera)
{
Check_Object(this);
Check_Object(camera);
Verify(!IsMatrixDirty());
AlignX(camera);
return 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::Element::DeferredXAlwaysCullMethod(CameraElement *camera)
{
Check_Object(this);
Check_Object(camera);
Verify(!IsMatrixDirty() && GetCullMode()==AlwaysCullMode);
AlignX(camera);
return -1;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::Element::DeferredXSphereCullMethod(CameraElement *camera)
{
Check_Object(this);
Check_Object(camera);
Verify(
!IsMatrixDirty() && IsBoundedBySphere() && GetCullMode()==VolumeCullMode
);
AlignX(camera);
return SphereCullMethod(camera);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::Element::DeferredXOBBCullMethod(CameraElement *camera)
{
Check_Object(this);
Check_Object(camera);
Verify(
!IsMatrixDirty() && IsBoundedByOBB() && GetCullMode()==VolumeCullMode
);
AlignX(camera);
return OBBCullMethod(camera);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::AlignY(CameraElement *camera)
{
Check_Object(this);
Check_Object(camera);
Verify(!IsMatrixDirty());
//
//----------------------------------------------------------------------
// We have to move the camera into the same parent space as the local
// matrix will be in, then figure out the relative direction the element
// should face
//----------------------------------------------------------------------
//
Check_Object(m_parent);
Stuff::Point3D world_camera(camera->GetLocalToWorld());
Stuff::Point3D parent_camera;
parent_camera.MultiplyByInverse(
world_camera,
m_parent->GetLocalToWorld()
);
Stuff::Vector3D camera_direction;
Stuff::Point3D local_origin(m_newLocalToParent);
camera_direction.Subtract(parent_camera, local_origin);
//
//------------------------------------------------------------------------
// Now align the matrix in the direction we wish it to point, then set the
// matrix inside the element and sync
//------------------------------------------------------------------------
//
m_newLocalToParent.AlignLocalAxisToWorldVector(camera_direction, Stuff::Z_Axis, Stuff::Y_Axis, -1);
//
//------------------------------------------------------------------------
// In order for the sync to work properly, we have to disable the deferred
// bit for the actual sync, then re-enable it afterwords. After the sync,
// do the standard sphere cull
//------------------------------------------------------------------------
//
m_state &= ~(SyncOnCullFlag|LocalToParentIsIdentityFlag);
m_state |= MatrixDirtyFlag;
SetSyncState();
Sync();
m_state |= SyncOnCullFlag;
SetSyncState();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::Element::DeferredYNeverCullMethod(CameraElement *camera)
{
Check_Object(this);
Check_Object(camera);
Verify(!IsMatrixDirty());
AlignY(camera);
return 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::Element::DeferredYAlwaysCullMethod(CameraElement *camera)
{
Check_Object(this);
Check_Object(camera);
Verify(!IsMatrixDirty() && GetCullMode()==AlwaysCullMode);
AlignY(camera);
return -1;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::Element::DeferredYSphereCullMethod(CameraElement *camera)
{
Check_Object(this);
Check_Object(camera);
Verify(
!IsMatrixDirty() && IsBoundedBySphere() && GetCullMode()==VolumeCullMode
);
AlignY(camera);
return SphereCullMethod(camera);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::Element::DeferredYOBBCullMethod(CameraElement *camera)
{
Check_Object(this);
Check_Object(camera);
Verify(
!IsMatrixDirty() && IsBoundedByOBB() && GetCullMode()==VolumeCullMode
);
AlignY(camera);
return OBBCullMethod(camera);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::AlignXY(CameraElement *camera)
{
Check_Object(this);
Check_Object(camera);
Verify(!IsMatrixDirty());
//
//----------------------------------------------------------------------
// We have to move the camera into the same parent space as the local
// matrix will be in, then figure out the relative direction the element
// should face
//----------------------------------------------------------------------
//
Check_Object(m_parent);
Stuff::Point3D world_camera(camera->GetLocalToWorld());
Stuff::Point3D parent_camera;
parent_camera.MultiplyByInverse(
world_camera,
m_parent->GetLocalToWorld()
);
Stuff::Vector3D camera_direction;
Stuff::Point3D local_origin(m_newLocalToParent);
camera_direction.Subtract(parent_camera, local_origin);
//
//------------------------------------------------------------------------
// Now align the matrix in the direction we wish it to point, then set the
// matrix inside the element and sync
//------------------------------------------------------------------------
//
Stuff::LinearMatrix4D old_pos = m_newLocalToParent;
m_newLocalToParent.AlignLocalAxisToWorldVector(camera_direction, Stuff::Z_Axis, Stuff::Y_Axis, Stuff::X_Axis);
//
//------------------------------------------------------------------------
// In order for the sync to work properly, we have to disable the deferred
// bit for the actual sync, then re-enable it afterwords. After the sync,
// do the standard sphere cull
//------------------------------------------------------------------------
//
m_state &= ~(SyncOnCullFlag|LocalToParentIsIdentityFlag);
m_state |= MatrixDirtyFlag;
SetSyncState();
Sync();
m_state |= SyncOnCullFlag;
SetSyncState();
m_newLocalToParent = old_pos;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::Element::DeferredXYNeverCullMethod(CameraElement *camera)
{
Check_Object(this);
Check_Object(camera);
Verify(!IsMatrixDirty());
AlignXY(camera);
return 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::Element::DeferredXYAlwaysCullMethod(CameraElement *camera)
{
Check_Object(this);
Check_Object(camera);
Verify(!IsMatrixDirty() && GetCullMode()==AlwaysCullMode);
AlignXY(camera);
return -1;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::Element::DeferredXYSphereCullMethod(CameraElement *camera)
{
Check_Object(this);
Check_Object(camera);
Verify(
!IsMatrixDirty() && IsBoundedBySphere() && GetCullMode()==VolumeCullMode
);
AlignXY(camera);
return SphereCullMethod(camera);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::Element::DeferredXYOBBCullMethod(CameraElement *camera)
{
Check_Object(this);
Check_Object(camera);
Verify(
!IsMatrixDirty() && IsBoundedByOBB() && GetCullMode()==VolumeCullMode
);
AlignXY(camera);
return OBBCullMethod(camera);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
ElementRenderer::Element::NeverRayCullMethod(CollisionQuery *query)
{
Check_Object(this);
Check_Object(query);
Verify(GetCullMode() == NeverCullMode || GetCullMode() == RootMode);
Verify(!query->m_data);
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
ElementRenderer::Element::AlwaysRayCullMethod(CollisionQuery *query)
{
Check_Object(this);
Check_Object(query);
Verify(GetCullMode() == AlwaysCullMode);
Verify(!query->m_data);
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
ElementRenderer::Element::SphereRayCullMethod(CollisionQuery *query)
{
Check_Object(this);
Check_Object(query);
Verify(m_worldOBB.sphereRadius > 0.0f);
Verify(GetCullMode()==VolumeCullMode && IsBoundedBySphere());
Verify(!query->m_data);
//
//-------------------------------
// We only use the sphere portion
//-------------------------------
//
Stuff::Sphere sphere(m_worldOBB);
Stuff::Scalar penetration;
Check_Object(query->m_line);
return query->m_line->GetDistanceTo(sphere, &penetration) >= 0.0f;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
ElementRenderer::Element::OBBRayCullMethod(CollisionQuery *query)
{
Check_Object(this);
Check_Object(query);
Verify(GetCullMode()==VolumeCullMode && IsBoundedByOBB());
Verify(Stuff::Close_Enough(m_localOBB.sphereRadius, m_localOBB.axisExtents.GetLength(), m_localOBB.sphereRadius*0.02f));
Verify(!query->m_data);
//
//-------------------------------
// We only use the sphere portion
//-------------------------------
//
Check_Object(query->m_line);
return query->m_line->GetDistanceTo(m_worldOBB) >= 0.0f;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::Element::NeverSphereTestMethod(SphereTest *query)
{
Check_Object(this);
Check_Object(query);
Verify(GetCullMode() == NeverCullMode || GetCullMode() == RootMode);
return query->m_type;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::Element::AlwaysSphereTestMethod(SphereTest *query)
{
Check_Object(this);
Check_Object(query);
Verify(GetCullMode() == AlwaysCullMode);
return SphereTest::Disjoint;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::Element::SphereSphereTestMethod(SphereTest *query)
{
Check_Object(this);
Check_Object(query);
Verify(m_worldOBB.sphereRadius > 0.0f);
Verify(GetCullMode()==VolumeCullMode && IsBoundedBySphere());
//
//-------------------------------
// We only use the sphere portion
//-------------------------------
//
Stuff::Sphere sphere(m_worldOBB);
Stuff::Vector3D diff;
diff.Subtract(sphere.center, query->m_sphere.center);
int result = SphereTest::Disjoint;
Stuff::Scalar range = diff.GetLengthSquared();
Stuff::Scalar slop;
switch (query->m_type)
{
case SphereTest::Contains:
slop = sphere.radius - query->m_sphere.radius;
if (slop >= 0.0f)
{
if (range <= slop*slop)
result = SphereTest::Contains;
}
break;
case SphereTest::Intersects:
slop = sphere.radius + query->m_sphere.radius;
if (range <= slop*slop)
result = SphereTest::Intersects;
break;
case SphereTest::Contained:
slop = sphere.radius - query->m_sphere.radius;
if (slop <= 0.0f)
{
if (range <= slop*slop)
result = SphereTest::Contained;
}
break;
default:
slop = sphere.radius + query->m_sphere.radius;
if (range <= slop*slop)
{
result |= SphereTest::Intersects;
slop = sphere.radius - query->m_sphere.radius;
if (slop >= 0.0f)
{
if (range <= slop*slop)
result |= SphereTest::Contains;
}
if (slop <= 0.0f)
{
if (range <= slop*slop)
result |= SphereTest::Contained;
}
}
break;
}
return result;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::Element::OBBSphereTestMethod(SphereTest *query)
{
Check_Object(this);
Check_Object(query);
Verify(GetCullMode()==VolumeCullMode && IsBoundedByOBB());
Verify(Stuff::Close_Enough(m_localOBB.sphereRadius, m_localOBB.axisExtents.GetLength(), m_localOBB.sphereRadius*0.02f));
STOP(("Not implemented"));
return SphereTest::Disjoint;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::Element::MixLights(
LightList new_lights,
const LightList parent_lights,
const LightList child_lights
)
{
unsigned i;
for (i=0; i<MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive && parent_lights[i]; ++i)
new_lights[i] = parent_lights[i];
for (int j=0; i<MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive && child_lights[j]; ++i,++j)
{
Verify(j < MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive);
new_lights[i] = child_lights[j];
}
if (i < MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive)
new_lights[i] = NULL;
Verify(i <= MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive);
return i;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::CleanDamage()
{
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::ApplyDamage(
const Stuff::LinearMatrix4D &damage_spot,
Stuff::Scalar radius
)
{
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::ApplyDamageDecal(
const Stuff::LinearMatrix4D &damage_spot,
Stuff::Scalar radius,
MidLevelRenderer::MLRTexture *texture
)
{
Check_Object(this);
Check_Object(texture);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::CastShadow(
const Stuff::LinearMatrix4D &shadow_to_world,
const Stuff::UnitVector3D &sun_in_world,
Stuff::Scalar radius
)
{
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::MakeFootStep(
MidLevelRenderer::MLRShape *shape,
const Stuff::LinearMatrix4D &foot,
Stuff::Scalar radius,
MidLevelRenderer::MLRTexture *tex
)
{
Check_Object(this);
Check_Object(shape);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::DrawOBB(
const Stuff::OBB& obb,
const Stuff::RGBAColor &color,
CameraElement *camera,
const StateChange *state,
int culling_state
)
{
Check_Object(&obb);
Check_Object(&color);
Check_Object(camera);
Check_Object(state);
//
//------------------
// Set up the fields
//------------------
//
MidLevelRenderer::DrawScalableShapeInformation info;
info.clippingFlags.SetClippingState(culling_state);
info.shapeToWorld = &obb.localToParent;
info.worldToShape = NULL;
info.paintMeColor = &color;
info.state = state->GetMLRState();
info.state.SetTextureHandle(0);
info.state.SetAlphaMode(MidLevelRenderer::MLRState::AlphaInvAlphaMode);
info.state.SetZBufferWriteOff();
info.state.SetPriority(1);
info.state.SetFogMode(0);
Check_Object(Box_Object);
info.shape = Box_Object;
info.scaling = &obb.axisExtents;
//
//---------------
// Draw the shape
//---------------
//
MidLevelRenderer::MLRClipper *clipper = camera->GetClipper();
Check_Object(clipper);
clipper->DrawScalableShape(&info);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::DrawSphere(
const Stuff::OBB& obb,
const Stuff::RGBAColor &color,
CameraElement *camera,
const StateChange *state,
int culling_state
)
{
Check_Object(&obb);
Check_Object(&color);
Check_Object(camera);
Check_Object(state);
//
//------------------
// Set up the fields
//------------------
//
MidLevelRenderer::DrawScalableShapeInformation info;
info.clippingFlags.SetClippingState(culling_state);
info.shapeToWorld = &obb.localToParent;
info.worldToShape = NULL;
info.paintMeColor = &color;
info.state = state->GetMLRState();
info.state.SetTextureHandle(0);
info.state.SetAlphaMode(MidLevelRenderer::MLRState::AlphaInvAlphaMode);
info.state.SetZBufferWriteOff();
info.state.SetPriority(1);
info.state.SetFogMode(0);
Verify(Stuff::Small_Enough(obb.axisExtents.GetLengthSquared()));
Stuff::Vector3D scale;
Check_Object(Sphere_Object);
info.shape = Sphere_Object;
info.scaling = &scale;
scale.x = scale.y = scale.z = obb.sphereRadius;
//
//---------------
// Draw the shape
//---------------
//
MidLevelRenderer::MLRClipper *clipper = camera->GetClipper();
Check_Object(clipper);
clipper->DrawScalableShape(&info);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::DrawGreenBoundsCallback(
CameraElement *camera,
const StateChange *state,
int culling_state,
Element *element
)
{
Check_Object(camera);
Check_Object(state);
Check_Object(element);
//
//----------------------------------
// Only volume cull bounds are shown
//----------------------------------
//
if (element->GetCullMode() != VolumeCullMode)
return;
//
//------------------
// Draw green bounds
//------------------
//
Stuff::RGBAColor color(0.5f, 1.0f, 0.5f, 0.3f);
if (element->IsBoundedBySphere())
DrawSphere(element->m_worldOBB, color, camera, state, culling_state);
else
DrawOBB(element->m_worldOBB, color, camera, state, culling_state);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::DrawYellowBoundsCallback(
CameraElement *camera,
const StateChange *state,
int culling_state,
Element *element
)
{
Check_Object(camera);
Check_Object(state);
Check_Object(element);
//
//----------------------------------
// Only volume cull bounds are shown
//----------------------------------
//
if (element->GetCullMode() != VolumeCullMode)
return;
//
//-------------------
// Draw yellow bounds
//-------------------
//
Stuff::RGBAColor color(1.0f, 1.0f, 0.5f, 0.3f);
if (element->IsBoundedBySphere())
DrawSphere(element->m_worldOBB, color, camera, state, culling_state);
else
DrawOBB(element->m_worldOBB, color, camera, state, culling_state);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::DrawRedBoundsCallback(
CameraElement *camera,
const StateChange *state,
int culling_state,
Element *element
)
{
Check_Object(camera);
Check_Object(state);
Check_Object(element);
//
//----------------------------------
// Only volume cull bounds are shown
//----------------------------------
//
if (element->GetCullMode() != VolumeCullMode)
return;
//
//----------------
// Draw red bounds
//----------------
//
Stuff::RGBAColor color(1.0f, 0.5f, 0.5f, 0.3f);
if (element->IsBoundedBySphere())
DrawSphere(element->m_worldOBB, color, camera, state, culling_state);
else
DrawOBB(element->m_worldOBB, color, camera, state, culling_state);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::DrawGreenBoundsOnceCallback(
CameraElement *camera,
const StateChange *state,
int culling_state,
Element *element
)
{
Check_Object(camera);
Check_Object(state);
Check_Object(element);
//
//----------------------------------
// Only volume cull bounds are shown
//----------------------------------
//
if (element->GetCullMode() != VolumeCullMode)
return;
//
//------------------
// Draw green bounds
//------------------
//
Stuff::RGBAColor color(0.5f, 1.0f, 0.5f, 0.3f);
if (element->IsBoundedBySphere())
DrawSphere(element->m_worldOBB, color, camera, state, culling_state);
else
DrawOBB(element->m_worldOBB, color, camera, state, culling_state);
element->SetCallbackIndex(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::DrawYellowBoundsOnceCallback(
CameraElement *camera,
const StateChange *state,
int culling_state,
Element *element
)
{
Check_Object(camera);
Check_Object(state);
Check_Object(element);
//
//----------------------------------
// Only volume cull bounds are shown
//----------------------------------
//
if (element->GetCullMode() != VolumeCullMode)
return;
//
//-------------------
// Draw yellow bounds
//-------------------
//
Stuff::RGBAColor color(1.0f, 1.0f, 0.5f, 0.3f);
if (element->IsBoundedBySphere())
DrawSphere(element->m_worldOBB, color, camera, state, culling_state);
else
DrawOBB(element->m_worldOBB, color, camera, state, culling_state);
element->SetCallbackIndex(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::DrawRedBoundsOnceCallback(
CameraElement *camera,
const StateChange *state,
int culling_state,
Element *element
)
{
Check_Object(camera);
Check_Object(state);
Check_Object(element);
//
//----------------------------------
// Only volume cull bounds are shown
//----------------------------------
//
if (element->GetCullMode() != VolumeCullMode)
return;
//
//----------------
// Draw red bounds
//----------------
//
Stuff::RGBAColor color(1.0f, 0.5f, 0.5f, 0.3f);
if (element->IsBoundedBySphere())
DrawSphere(element->m_worldOBB, color, camera, state, culling_state);
else
DrawOBB(element->m_worldOBB, color, camera, state, culling_state);
element->SetCallbackIndex(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::AdoptStateChange(StateChange *set)
{
Check_Object(this);
Check_Object(set);
//
//--------------------------------------------
// Detach the old property set if it was there
//--------------------------------------------
//
if (m_stateChange)
{
Check_Object(m_stateChange);
delete m_stateChange;
}
//
//----------------------------
// Attach the new property set
//----------------------------
//
m_stateChange = set;
m_state |= PropertyChangeFlag;
SetDrawState();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::Element::DestroyStateChange()
{
Check_Object(this);
//
//--------------------------------------------
// Detach the old property set if it was there
//--------------------------------------------
//
if (m_stateChange)
{
Check_Object(m_stateChange);
delete m_stateChange;
m_stateChange = NULL;
m_state &= ~PropertyChangeFlag;
SetDrawState();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Returns array of vertex coordinates and number of vertices
void
ElementRenderer::Element::GetCoordData(
Stuff::DynamicArrayOf<Stuff::Point3D> *array)
{
Check_Object(this);
array->SetLength(0);
}
//#############################################################################
//########################## Element__ClassData #########################
//#############################################################################
void
ElementRenderer::Element__ClassData::TestInstance()
{
Verify(IsDerivedFrom(ElementRenderer::Element::DefaultData));
}