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

1400 lines
31 KiB
C++

#include "ElementRendererHeaders.hpp"
#include "GridElement.hpp"
//#define SPEW_CULL_INFO "your_name_here"
//############################################################################
//############################ GridElement ################################
//############################################################################
HGOSHEAP
ElementRenderer::GridElement::s_Heap = NULL;
ElementRenderer::GridElement::ClassData*
ElementRenderer::GridElement::DefaultData = NULL;
ElementRenderer::Element::SyncMethod
ElementRenderer::GridElement::SyncMethods[4]=
{
SYNC_METHOD(ListElement, CleanRoot),
SYNC_METHOD(ListElement, Clean),
SYNC_METHOD(ListElement, DirtyRoot),
SYNC_METHOD(ListElement, Dirty)
};
ElementRenderer::Element::CullMethod
ElementRenderer::GridElement::CullMethods=
CULL_METHOD(GridElement, Grid, Grid);
ElementRenderer::Element::DrawMethod
ElementRenderer::GridElement::DrawMethods[DrawStateCount]=
{
DRAW_METHOD(GridElement, Inherit),
DRAW_METHOD(GridElement, Override)
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::GridElement::InitializeClass()
{
Verify(!DefaultData);
Verify(!s_Heap);
s_Heap = gos_CreateMemoryHeap("Grid", 0, g_LibraryHeap);
Check_Pointer(s_Heap);
DefaultData =
new ClassData(
GridElementClassID,
"ElementRenderer::GridElement",
BaseClass::DefaultData,
reinterpret_cast<Factory>(&Make)
);
Check_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::GridElement::TerminateClass()
{
Check_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
Check_Pointer(s_Heap);
gos_DestroyMemoryHeap(s_Heap);
s_Heap = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::GridElement::GridElement(
ClassData *class_data,
Stuff::MemoryStream *stream,
int version,
ShapeHolder shapes
):
ListElement(class_data, stream, version, shapes)
{
Check_Pointer(this);
Check_Object(stream);
if (version>=11)
*stream >> m_rowCellCount >> m_columnCellCount;
else
{
int row, col;
*stream >> row >> col;
Verify(static_cast<unsigned>(row) <= 255);
Verify(static_cast<unsigned>(col) <= 255);
m_rowCellCount = static_cast<BYTE>(row);
m_columnCellCount = static_cast<BYTE>(col);
}
*stream >> m_rowCellSize >> m_columnCellSize >> m_rowOffset >> m_columnOffset;
unsigned index = (GetCullMode() == NeverCullMode);
index |= IsMatrixDirty() ? 2 : 0;
Verify(index < 4);
m_sync = SyncMethods[index];
m_cameraCull = CullMethods.m_cameraCull;
m_rayCull = CullMethods.m_rayCull;
m_sphereTest = CullMethods.m_sphereTest;
index = (m_state>>DrawStateBit) & DrawStateMask;
Verify(index < DrawStateCount);
m_draw = DrawMethods[index];
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::GridElement::GridElement(
BYTE rowSize,
BYTE columnSize,
Stuff::Scalar row_offset,
Stuff::Scalar column_offset,
Stuff::Scalar total_row_size,
Stuff::Scalar total_column_size,
ClassData *class_data
):
ListElement(class_data)
{
Check_Pointer(this);
m_rowCellCount = rowSize;
m_columnCellCount = columnSize;
m_rowOffset = row_offset;
m_columnOffset = column_offset;
m_rowCellSize = total_row_size/m_rowCellCount;
m_columnCellSize = total_column_size/m_columnCellCount;
Verify(rowSize*columnSize < 65536);
m_activeChildren = static_cast<WORD>(rowSize*columnSize);
SetSize(m_activeChildren);
unsigned index = (GetCullMode() == NeverCullMode);
index |= IsMatrixDirty() ? 2 : 0;
Verify(index < 4);
m_sync = SyncMethods[index];
m_cameraCull = CullMethods.m_cameraCull;
m_rayCull = CullMethods.m_rayCull;
m_sphereTest = CullMethods.m_sphereTest;
index = (m_state>>DrawStateBit) & DrawStateMask;
Verify(index < DrawStateCount);
m_draw = DrawMethods[index];
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::GridElement::~GridElement()
{
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::GridElement*
ElementRenderer::GridElement::Make(
Stuff::MemoryStream *stream,
int version,
ShapeHolder shapes
)
{
Check_Object(stream);
gos_PushCurrentHeap(s_Heap);
GridElement *element = new GridElement(DefaultData, stream, version, shapes);
gos_PopCurrentHeap();
return element;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::GridElement::Save(Stuff::MemoryStream *stream)
{
Check_Object(this);
Check_Object(stream);
BaseClass::Save(stream);
*stream << m_rowCellCount << m_columnCellCount
<< m_rowCellSize << m_columnCellSize
<< m_rowOffset << m_columnOffset;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::GridElement::TestInstance()
{
Verify(IsDerivedFrom(DefaultData));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::GridElement::AttachIndexedChild(
BYTE row,
BYTE column,
Element *element
)
{
Check_Object(this);
Verify(row*m_columnCellCount+column < m_list.GetLength());
m_list[row*m_columnCellCount+column] = element;
SetParentElement(element, this);
if (element->GetCullMode() != AlwaysCullMode)
{
if (element->m_localOBB.sphereRadius > 0.0f || element->AreBoundsWrong())
element->SetVolumeCullMode();
else
element->SetNeverCullMode();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
WORD
ElementRenderer::GridElement::FindElementIndex(
Stuff::Scalar row,
Stuff::Scalar column
)
{
Check_Object(this);
column -= m_columnOffset;
row -= m_rowOffset;
column /= m_columnCellSize;
row /= m_rowCellSize;
if (column>=0.0f && column<m_columnCellCount && row>=0.0f && row<m_rowCellCount)
{
WORD index =
static_cast<WORD>(
Stuff::Truncate_Float_To_Byte(row)*m_columnCellCount + Stuff::Truncate_Float_To_Byte(column)
);
Verify(index < m_list.GetLength());
return index;
}
return static_cast<WORD>(m_list.GetLength());
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::GridElement::SetSize(WORD max_size)
{
Check_Object(this);
m_list.SetLength(max_size);
m_activeChildren = max_size;
for (WORD i=0; i<max_size; ++i)
m_list[i] = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::GridElement::SetSize(BYTE rowSize, BYTE columnSize)
{
Check_Object(this);
if(rowSize != m_rowCellCount || columnSize!= m_columnCellCount)
{
m_rowCellCount = rowSize;
m_columnCellCount = columnSize;
SetSize(static_cast<WORD>(m_rowCellCount*m_columnCellCount));
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::GridElement::GetDimensions(
Stuff::Scalar *row_offset,
Stuff::Scalar *column_offset,
Stuff::Scalar *row_cell_size,
Stuff::Scalar *column_cell_size
)
{
Check_Object(this);
Check_Pointer(row_offset);
Check_Pointer(column_offset);
Check_Pointer(row_cell_size);
Check_Pointer(column_cell_size);
*row_offset = m_rowOffset;
*column_offset = m_columnOffset;
*row_cell_size = m_rowCellSize;
*column_cell_size = m_columnCellSize;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::GridElement::SetSyncState()
{
Check_Object(this);
Verify( GetCullMode() == RootMode || GetCullMode() == NeverCullMode );
Verify(!IsSyncDeferred() && !AreBoundsWrong());
unsigned index = (GetCullMode() == NeverCullMode);
index |= IsMatrixDirty() ? 2 : 0;
Verify(index < 4);
m_sync = SyncMethods[index];
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::GridElement::SetCullState()
{
Check_Object(this);
m_cameraCull = CullMethods.m_cameraCull;
m_rayCull = CullMethods.m_rayCull;
m_sphereTest = CullMethods.m_sphereTest;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::GridElement::SetDrawState()
{
Check_Object(this);
unsigned index = (m_state>>DrawStateBit) & DrawStateMask;
Verify(index < DrawStateCount);
m_draw = DrawMethods[index];
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
ElementRenderer::GridElement::CastCulledRay(CollisionQuery *query)
{
Check_Object(this);
Check_Object(query);
Verify(!query->m_data);
//
//----------------------
// Test all the children
//----------------------
//
if (IterateLine(query, TestCell))
{
if (!query->m_data)
query->m_data = m_data;
return true;
}
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::Element*
ElementRenderer::GridElement::FindSmallestElementContainingCulled(SphereTest *test)
{
Check_Object(this);
Check_Object(test);
//
//------------------
// Draw our children
//------------------
//
Element *result = this;
for (int i=0; i<m_activeChildren; ++i)
{
Element *element = m_list[i];
Check_Object(element);
Element *temp = element->FindSmallestElementContaining(test);
if (temp)
result = temp;
}
return result;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void*
ElementRenderer::GridElement::TestCell(
GridElement *grid,
WORD cell,
CollisionQuery *query,
Stuff::Scalar enter,
Stuff::Scalar leave
)
{
Check_Object(grid);
Check_Object(query);
Verify(cell < grid->m_activeChildren);
Element *element = grid->m_list[cell];
Check_Object(element);
return reinterpret_cast<void*>(element->CastRay(query));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
inline static bool
Trim(
Stuff::Scalar dot,
Stuff::Scalar separation,
Stuff::Scalar *enter,
Stuff::Scalar *leave
)
{
Check_Pointer(enter);
Check_Pointer(leave);
Verify(Stuff::Small_Enough(dot, 1.0f));
if (dot > Stuff::SMALL)
{
Stuff::Scalar distance = -separation / dot - Stuff::SMALL;
if (distance < *leave)
*leave = distance;
return *enter <= *leave;
}
else if (dot < -Stuff::SMALL)
{
Stuff::Scalar distance = -separation / dot + Stuff::SMALL;
if (distance > *enter)
*enter = distance;
return *enter <= *leave;
}
else
return separation <= Stuff::SMALL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
inline static bool
Leave_Trim(
Stuff::Scalar dot,
Stuff::Scalar separation,
Stuff::Scalar *leave
)
{
Check_Pointer(leave);
Verify(Stuff::Small_Enough(dot, 1.0f));
if (dot > Stuff::SMALL)
{
Stuff::Scalar distance = -separation / dot;
if (distance < *leave)
{
*leave = distance;
return true;
}
}
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void*
ElementRenderer::GridElement::IterateLine(
CollisionQuery *query,
CellTest call_back
)
{
Check_Object(this);
Check_Object(query);
Check_Pointer(call_back);
Verify(query->m_line->m_length >= 0.0f);
#if defined(SPEW_CULL_INFO)
int tested=0;
#endif
//
//-------------------------------------------------------------------
// Find the cell coordinates of the the beginning and end of the m_line
//-------------------------------------------------------------------
//
Stuff::Scalar x_scale = 1.0f / m_columnCellSize;
Stuff::Scalar z_scale = 1.0f / m_rowCellSize;
Verify(Stuff::Close_Enough(x_scale, z_scale));
Check_Object(query->m_line);
Stuff::Line3D *line = query->m_line;
Stuff::Scalar x_origin = (line->m_origin.x - m_columnOffset) * x_scale;
Stuff::Scalar z_origin = (line->m_origin.z - m_rowOffset) * z_scale;
Stuff::Point3D end;
line->FindEnd(&end);
Stuff::Scalar x_end = (end.x - m_columnOffset) * x_scale;
Stuff::Scalar z_end = (end.z - m_rowOffset) * z_scale;
//
//-----------------------------------------------------------------------------
// If the m_line is within a single cell, just test that one. If the cell is
// outside the grid boundaries, return no hit. We don't use our Truncate
// functions here because we do not know the extents of the line we are testing
//-----------------------------------------------------------------------------
//
BYTE x = static_cast<BYTE>(x_origin);
BYTE z = static_cast<BYTE>(z_origin);
if (x == static_cast<BYTE>(x_end) && z == static_cast<BYTE>(z_end))
{
#if defined(SPEW_CULL_INFO)
SPEW((SPEW_CULL_INFO, "single cell test"));
#endif
if (x < m_columnCellCount && z < m_rowCellCount)
return
(*call_back)(
this,
static_cast<WORD>(z*m_columnCellCount + x),
query,
0,
line->m_length
);
return NULL;
}
//
//----------------------------------------------------------------------
// The m_line crosses cells, so we first have to clip it to the grid
// boundaries. We will treat the box boundaries as four plane equations
//----------------------------------------------------------------------
//
Stuff::Scalar enter = 0.0f;
Stuff::Scalar leave = line->m_length;
if (
!Trim(
-line->m_direction.x,
m_columnOffset - line->m_origin.x,
&enter,
&leave
)
)
{
#if defined(SPEW_CULL_INFO)
SPEW((SPEW_CULL_INFO, "Line doesn't hit grid"));
#endif
return NULL;
}
if (
!Trim(
line->m_direction.x,
line->m_origin.x - (m_columnOffset + m_columnCellCount*m_columnCellSize),
&enter,
&leave
)
)
{
#if defined(SPEW_CULL_INFO)
SPEW((SPEW_CULL_INFO, "Line doesn't hit grid"));
#endif
return NULL;
}
if (
!Trim(
-line->m_direction.z,
m_rowOffset - line->m_origin.z,
&enter,
&leave
)
)
{
#if defined(SPEW_CULL_INFO)
SPEW((SPEW_CULL_INFO, "Line doesn't hit grid"));
#endif
return NULL;
}
if (
!Trim(
line->m_direction.z,
line->m_origin.z - (m_rowOffset + m_rowCellCount*m_rowCellSize),
&enter,
&leave
)
)
{
#if defined(SPEW_CULL_INFO)
SPEW((SPEW_CULL_INFO, "Line doesn't hit grid"));
#endif
return NULL;
}
//
//---------------------------------------------------------------------------
// Now project the origin and end of the m_line in cell space and cast those
// into the integer indices we need. The clamps are there to deal with error
// not caught by trim
//---------------------------------------------------------------------------
//
line->Project(enter, &end);
x_origin = (end.x - m_columnOffset) * x_scale;
z_origin = (end.z - m_rowOffset) * z_scale;
if (x_origin <= 0.0f)
x = 0;
else if (x_origin >= m_columnCellCount)
x = static_cast<BYTE>(m_columnCellCount-1);
else
x = Stuff::Truncate_Float_To_Byte(x_origin);
if (z_origin <= 0.0f)
z = 0;
else if (z_origin >= m_rowCellCount)
z = static_cast<BYTE>(m_rowCellCount-1);
else
z = Stuff::Truncate_Float_To_Byte(z_origin);
Verify(x < m_columnCellCount && z < m_rowCellCount);
line->Project(leave, &end);
x_end = (end.x - m_columnOffset) * x_scale;
z_end = (end.z - m_rowOffset) * z_scale;
BYTE last_x, last_z;
if (x_end <= 0.0f)
last_x = 0;
else if (x_end >= m_columnCellCount)
last_x = static_cast<BYTE>(m_columnCellCount-1);
else
last_x = Stuff::Truncate_Float_To_Byte(x_end);
if (z_end <= 0.0f)
last_z = 0;
else if (z_end >= m_rowCellCount)
last_z = static_cast<BYTE>(m_rowCellCount-1);
else
last_z = Stuff::Truncate_Float_To_Byte(z_end);
Verify(last_x < m_columnCellCount && last_z < m_rowCellCount);
//
//--------------------------------
// Crawl over the cells one by one
//--------------------------------
//
Stuff::Scalar cell_leave = enter;
while (true)
{
#if defined(SPEW_CULL_INFO)
++tested;
#endif
Verify(x < m_columnCellCount && z < m_rowCellCount);
//
//-------------------------------------------------------------------
// Clip the m_line to the x boundaries of the current cell and remember
// way to leave
//-------------------------------------------------------------------
//
enter = cell_leave;
Stuff::Scalar x_leave = leave;
int dx=0;
if (
Leave_Trim(
-line->m_direction.x,
m_columnOffset + x*m_columnCellSize - line->m_origin.x,
&x_leave
)
)
dx = -1;
if (
Leave_Trim(
line->m_direction.x,
line->m_origin.x - (m_columnOffset + (x+1)*m_columnCellSize),
&x_leave
)
)
dx = 1;
//
//-------------------------------------------------------------------
// Clip the m_line to the z boundaries of the current cell and remember
// way to leave
//-------------------------------------------------------------------
//
int dz=0;
Stuff::Scalar z_leave = leave;
if (
Leave_Trim(
-line->m_direction.z,
m_rowOffset + z*m_rowCellSize - line->m_origin.z,
&z_leave
)
)
dz = -1;
if (
Leave_Trim(
line->m_direction.z,
line->m_origin.z - (m_rowOffset + (z+1)*m_rowCellSize),
&z_leave
)
)
dz = 1;
//
//----------------------------------------------------------------
// Pick which axis we leave on first. Make sure we handle corners
// appropriately
//----------------------------------------------------------------
//
if (x_leave < z_leave-Stuff::SMALL)
{
dz = 0;
cell_leave = x_leave;
}
if (z_leave < x_leave-Stuff::SMALL)
{
dx = 0;
cell_leave = z_leave;
}
else
cell_leave = x_leave;
//
//--------------------------------------------------------
// See if there is anything to hit, and if so, we are done
//--------------------------------------------------------
//
Stuff::Scalar old_length = query->m_line->m_length;
void *result =
(*call_back)(
this,
static_cast<WORD>(z*m_columnCellCount + x),
query,
enter,
cell_leave
);
if (result != NULL)
{
#if defined(SPEW_CULL_INFO)
SPEW((SPEW_CULL_INFO, "Hit! %d of %d cells tested", tested, m_columnCellCount*m_rowCellCount));
#endif
if (query->m_line->m_length <= cell_leave)
return result;
else
query->m_line->m_length = old_length;
}
//
//--------------------------------------------------------------------
// If we have reached the end, we are done, otherwise move to the next
// cell
//--------------------------------------------------------------------
//
if (x == last_x && z == last_z || !dx && !dz)
break;
x = static_cast<BYTE>(x + dx);
z = static_cast<BYTE>(z + dz);
}
//
//-------------------------
// We couldn't hit anything
//-------------------------
//
#if defined(SPEW_CULL_INFO)
SPEW((SPEW_CULL_INFO, "Missed: %d of %d cells tested", tested, m_columnCellCount*m_rowCellCount));
#endif
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::GridElement::GridCullMethod(CameraElement *camera)
{
Check_Object(this);
Check_Object(camera);
return BaseClass::NeverCullMethod(camera);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ElementRenderer::GridElement::GridSphereTestMethod(SphereTest *query)
{
Check_Object(this);
Check_Object(query);
return BaseClass::NeverSphereTestMethod(query);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
ElementRenderer::GridElement::GridRayCullMethod(CollisionQuery *query)
{
Check_Object(this);
Check_Object(query);
Verify(!query->m_data);
return BaseClass::NeverRayCullMethod(query);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::GridElement::InheritDrawMethod(
CameraElement *camera,
const StateChange *inherited_state,
int culling_state
)
{
Check_Object(this);
Check_Object(inherited_state);
Check_Object(camera);
Verify(culling_state != -1);
//
//----------------------
// Draw all the children
//----------------------
//
Stuff::Point3D theCorners[4];
theCorners[0].y = 0.0f;
theCorners[1].y = 0.0f;
theCorners[2].y = 0.0f;
theCorners[3].y = 0.0f;
const Stuff::Point3D *cullPoints = camera->GetCullPoints();
int pxmin, pxmax, pzmin, pzmax, in[5], out[4];
int i, j, k;
pxmin = pxmax = pzmin = pzmax = 0;
for(i=1;i<5;i++)
{
if(cullPoints[i].x < cullPoints[pxmin].x)
{
pxmin = i;
}
if(cullPoints[i].x > cullPoints[pxmax].x)
{
pxmax = i;
}
if(cullPoints[i].z < cullPoints[pzmin].z)
{
pzmin = i;
}
if(cullPoints[i].z > cullPoints[pzmax].z)
{
pzmax = i;
}
}
int inCount=0, outCount=0;
in[inCount++] = pzmin;
if(pzmin!=pxmin)
{
in[inCount++] = pxmin;
if(pxmin!=pzmax)
{
in[inCount++] = pzmax;
if(pzmax!=pxmax && pxmax!=pzmin)
{
in[inCount++] = pxmax;
}
}
else
{
in[inCount++] = pxmax;
}
}
else
{
in[inCount++] = pzmax;
Verify(pzmax!=pxmax && pxmax!=pzmin);
in[inCount++] = pxmax;
}
Verify(inCount<5);
for(i=0;i<5;i++)
{
for(j=0;j<inCount;j++)
{
if(i==in[j])
{
break;
}
}
if(j==inCount)
{
out[outCount++] = i;
}
}
Verify(outCount<3);
for(i=0;i<outCount;i++)
{
for(j=0;j<inCount;j++)
{
if(Stuff::Close_Enough(cullPoints[out[i]], cullPoints[in[j]]))
{
break;
}
}
if(j<inCount)
{
continue;
}
for(j=0;j<inCount;j++)
{
int end = j+1;
if(end==inCount)
{
end = 0;
}
Stuff::Vector3D vc;
vc.Cross(cullPoints[out[i]], cullPoints[in[j]], cullPoints[in[end]]);
if(vc.y > 0.0f)
{
break;
}
}
if(j<inCount)
{
for(k=inCount;k>j+1;k--)
{
in[k] = in[k-1];
}
in[j+1] = out[i];
inCount++;
}
}
#ifdef _ARMOR
//
// Checking for a convex hull
//
for(i=0;i<inCount;i++)
{
int next = (i+1)%inCount;
int nextAfter = (i+2)%inCount;
Stuff::Vector3D vc;
vc.Cross(cullPoints[in[next]], cullPoints[in[i]], cullPoints[in[nextAfter]]);
Verify(vc.y >= 0.0f);
}
#endif
#ifdef SPEW_CULL_INFO
int d = 0;
#endif
const Stuff::Scalar theCageCorrector = 4.5f;
int minZ, maxZ, minX, maxX;
minZ = (int)floor((cullPoints[pzmin].z-m_rowOffset-theCageCorrector)/m_rowCellSize);
if(minZ<0)
{
minZ = 0;
}
maxZ = (int)ceil((cullPoints[pzmax].z-m_rowOffset+theCageCorrector)/m_rowCellSize);
if(maxZ > m_rowCellCount)
{
maxZ = m_rowCellCount;
}
theCorners[0].z = m_rowOffset + minZ*m_rowCellSize;
theCorners[1].z = theCorners[0].z;
theCorners[2].z = theCorners[0].z + m_rowCellSize;
theCorners[3].z = theCorners[2].z;
minX = (int)floor((cullPoints[pxmin].x-m_columnOffset-theCageCorrector)/m_columnCellSize);
if(minX<0)
{
minX = 0;
}
maxX = (int)ceil((cullPoints[pxmax].x-m_columnOffset+theCageCorrector)/m_columnCellSize);
if(maxX > m_columnCellCount)
{
maxX = m_columnCellCount;
}
for (j=minZ; j<maxZ; ++j)
{
theCorners[0].x = m_columnOffset + minX*m_columnCellSize;
theCorners[1].x = theCorners[0].x + m_columnCellSize;
theCorners[2].x = theCorners[1].x;
theCorners[3].x = theCorners[0].x;
// bool inOrOut = false;
for (i=minX; i<maxX; ++i)
{
/*
if(inOrOut==false)
{
//
// Check the x-max side
//
int end, k, p1 = -1, p2 = -1;
for(k=0;k<inCount;++k)
{
end = k+1;
if(end>=inCount)
{
end = 0;
}
if(cullPoints[in[end]].z > cullPoints[in[k]].z)
{
if(p1 < 0 && theCorners[1].z > cullPoints[in[k]].z && theCorners[1].z < cullPoints[in[end]].z)
{
p1 = k;
}
if(p2 < 0 && theCorners[2].z > cullPoints[in[k]].z && theCorners[2].z < cullPoints[in[end]].z)
{
p2 = k;
}
}
}
if(p1<0 && p2<0)
{
if(theCorners[1].x > cullPoints[pxmin].x)
{
inOrOut = true;
}
}
else
{
Stuff::Vector3D vc;
if(p1==p2)
{
end = p1+1;
if(end>=inCount)
{
end = 0;
}
vc.Cross(theCorners[1], cullPoints[in[p1]], cullPoints[in[end]]);
if(vc.y < 0.0f)
{
inOrOut = true;
}
else
{
end = p2+1;
if(end>=inCount)
{
end = 0;
}
vc.Cross(theCorners[2], cullPoints[in[p2]], cullPoints[in[end]]);
if(vc.y < 0.0f)
{
inOrOut = true;
}
}
}
else
{
if(p2<0)
{
end = p1+1;
if(end>=inCount)
{
end = 0;
}
vc.Cross(theCorners[1], cullPoints[in[p1]], cullPoints[in[end]]);
if(vc.y < 0.0f)
{
inOrOut = true;
}
}
if(p1<0)
{
end = p2+1;
if(end>=inCount)
{
end = 0;
}
vc.Cross(theCorners[2], cullPoints[in[p2]], cullPoints[in[end]]);
if(vc.y < 0.0f)
{
inOrOut = true;
}
}
if(p1>=0 && p2>=0)
{
Verify(p2>p1);
for(k=p1+1;k<p2+1;k++)
{
if(theCorners[1].x > cullPoints[in[k]].x)
{
inOrOut = true;
break;
}
}
}
}
}
}
else
{
//
// Check the x-max side
//
}
if(inOrOut==true)
*/
{
Element *element = m_list[j*m_columnCellCount+i];
Check_Object(element);
#ifdef _ARMOR
if(element->GetCullMode() == VolumeCullMode)
{
Verify(element->GetWorldOBB().localToParent.entries[3] >= theCorners[0].x);
Verify(element->GetWorldOBB().localToParent.entries[3] <= theCorners[1].x);
Verify(element->GetWorldOBB().localToParent.entries[11] >= theCorners[0].z);
Verify(element->GetWorldOBB().localToParent.entries[11] <= theCorners[3].z);
}
#endif
camera->DrawElement(element, inherited_state);
#ifdef SPEW_CULL_INFO
d++;
#endif
}
theCorners[0].x += m_columnCellSize;
theCorners[1].x += m_columnCellSize;
theCorners[2].x += m_columnCellSize;
theCorners[3].x += m_columnCellSize;
}
theCorners[0].z += m_rowCellSize;
theCorners[1].z += m_rowCellSize;
theCorners[2].z += m_rowCellSize;
theCorners[3].z += m_rowCellSize;
}
#ifdef SPEW_CULL_INFO
SPEW((SPEW_CULL_INFO, "Drawn: %d Culled: %d", d, (m_rowCellCount*m_columnCellCount)-d));
#endif
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ElementRenderer::GridElement::OverrideDrawMethod(
CameraElement *camera,
const StateChange *inherited_state,
int culling_state
)
{
Check_Object(this);
Check_Object(inherited_state);
Check_Object(camera);
Verify(culling_state != -1);
//
//-------------------
// Mix the properties
//-------------------
//
Check_Object(m_stateChange);
StateChange mixed;
mixed.Mix(*inherited_state, *m_stateChange);
MixLights(
mixed.m_lights,
inherited_state->m_lights,
m_stateChange->m_lights
);
//
//----------------------
// Draw all the children
//----------------------
//
Stuff::Point3D theCorners[4];
theCorners[0].y = 0.0f;
theCorners[1].y = 0.0f;
theCorners[2].y = 0.0f;
theCorners[3].y = 0.0f;
const Stuff::Point3D *cullPoints = camera->GetCullPoints();
int pxmin, pxmax, pzmin, pzmax, in[5], out[4];
int i, j, k;
pxmin = pxmax = pzmin = pzmax = 0;
for(i=1;i<5;i++)
{
if(cullPoints[i].x < cullPoints[pxmin].x)
{
pxmin = i;
}
if(cullPoints[i].x > cullPoints[pxmax].x)
{
pxmax = i;
}
if(cullPoints[i].z < cullPoints[pzmin].z)
{
pzmin = i;
}
if(cullPoints[i].z > cullPoints[pzmax].z)
{
pzmax = i;
}
}
int inCount=0, outCount=0;
in[inCount++] = pzmin;
if(pzmin!=pxmin)
{
in[inCount++] = pxmin;
if(pxmin!=pzmax)
{
in[inCount++] = pzmax;
if(pzmax!=pxmax && pxmax!=pzmin)
{
in[inCount++] = pxmax;
}
}
else
{
in[inCount++] = pxmax;
}
}
else
{
in[inCount++] = pzmax;
Verify(pzmax!=pxmax && pxmax!=pzmin);
in[inCount++] = pxmax;
}
Verify(inCount<5);
for(i=0;i<5;i++)
{
for(j=0;j<inCount;j++)
{
if(i==in[j])
{
break;
}
}
if(j==inCount)
{
out[outCount++] = i;
}
}
Verify(outCount<3);
for(i=0;i<outCount;i++)
{
for(j=0;j<inCount;j++)
{
if(Stuff::Close_Enough(cullPoints[out[i]], cullPoints[in[j]]))
{
break;
}
}
if(j<inCount)
{
continue;
}
for(j=0;j<inCount;j++)
{
int end = j+1;
if(end==inCount)
{
end = 0;
}
Stuff::Vector3D vc;
vc.Cross(cullPoints[out[i]], cullPoints[in[j]], cullPoints[in[end]]);
if(vc.y > 0.0f)
{
break;
}
}
if(j<inCount)
{
for(k=inCount;k>j+1;k--)
{
in[k] = in[k-1];
}
in[j+1] = out[i];
inCount++;
}
}
#ifdef SPEW_CULL_INFO
int d = 0;
#endif
int minZ, maxZ, minX, maxX;
minZ = (int)floor((cullPoints[pzmin].z-m_rowOffset)/m_rowCellSize);
if(minZ<0)
{
minZ = 0;
}
maxZ = (int)ceil((cullPoints[pzmax].z-m_rowOffset)/m_rowCellSize);
if(maxZ > m_rowCellCount)
{
maxZ = m_rowCellCount;
}
theCorners[0].z = m_rowOffset + minZ*m_rowCellSize;
theCorners[1].z = theCorners[0].z;
theCorners[2].z = theCorners[0].z + m_rowCellSize;
theCorners[3].z = theCorners[2].z;
minX = (int)floor((cullPoints[pxmin].x-m_columnOffset)/m_columnCellSize);
if(minX<0)
{
minX = 0;
}
maxX = (int)ceil((cullPoints[pxmax].x-m_columnOffset)/m_columnCellSize);
if(maxX > m_columnCellCount)
{
maxX = m_columnCellCount;
}
for (j=minZ; j<maxZ; ++j)
{
theCorners[0].x = m_columnOffset + minX*m_columnCellSize;
theCorners[1].x = theCorners[0].x + m_columnCellSize;
theCorners[2].x = theCorners[1].x;
theCorners[3].x = theCorners[0].x;
for (i=minX; i<maxX; ++i)
{
if(1)
{
Element *element = m_list[j*m_columnCellCount+i];
Check_Object(element);
camera->DrawElement(element, inherited_state);
#ifdef SPEW_CULL_INFO
d++;
}
else
{
nd++;
#endif
}
theCorners[0].x += m_rowCellSize;
theCorners[1].x += m_rowCellSize;
theCorners[2].x += m_rowCellSize;
theCorners[3].x += m_rowCellSize;
}
theCorners[0].z += m_columnCellSize;
theCorners[1].z += m_columnCellSize;
theCorners[2].z += m_columnCellSize;
theCorners[3].z += m_columnCellSize;
}
#ifdef SPEW_CULL_INFO
SPEW((SPEW_CULL_INFO, "Drawn: %d Culled: %d", d, nd));
#endif
}