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.
2104 lines
56 KiB
C++
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));
|
|
}
|