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.
787 lines
21 KiB
C++
787 lines
21 KiB
C++
#include <ElementRenderer\GroupElement.hpp>
|
|
#include <ElementRenderer\ListElement.hpp>
|
|
#include <ElementRenderer\ShapeElement.hpp>
|
|
#include <MLR\MLRShape.hpp>
|
|
#include <MLR\MLRIndexedPrimitiveBase.hpp>
|
|
#include <Adept\Tile.hpp>
|
|
|
|
//#define BSP_BUG "jmalbert"
|
|
#undef BSP_BUG
|
|
|
|
extern bool Debug_Tile;
|
|
|
|
enum {
|
|
Inside_Plane = 1,
|
|
On_Plane = 2,
|
|
Outside_Plane = 4,
|
|
Split_Plane = Inside_Plane|Outside_Plane
|
|
};
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
FindPlanes(
|
|
ElementRenderer::Element *element,
|
|
Stuff::DynamicArrayOf<Stuff::Plane> *planes,
|
|
int *planes_filled
|
|
)
|
|
{
|
|
Check_Object(element);
|
|
Check_Object(planes);
|
|
Check_Pointer(planes_filled);
|
|
|
|
//
|
|
//-----------------------
|
|
// Spin through the group
|
|
//-----------------------
|
|
//
|
|
if (element->IsDerivedFrom(ElementRenderer::GroupElement::DefaultData))
|
|
{
|
|
ElementRenderer::GroupElement *group =
|
|
Cast_Object(ElementRenderer::GroupElement *, element);
|
|
Stuff::ChainIteratorOf<ElementRenderer::Element*> *children =
|
|
group->MakeIterator();
|
|
Register_Object(children);
|
|
ElementRenderer::Element *child;
|
|
while ((child = children->ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
FindPlanes(child, planes, planes_filled);
|
|
}
|
|
Unregister_Object(children);
|
|
delete children;
|
|
}
|
|
|
|
//
|
|
//----------------------
|
|
// Spin through the list
|
|
//----------------------
|
|
//
|
|
else if (element->IsDerivedFrom(ElementRenderer::ListElement::DefaultData))
|
|
{
|
|
ElementRenderer::ListElement *list =
|
|
Cast_Object(ElementRenderer::ListElement *, element);
|
|
for (unsigned i=0; i<list->GetActiveCount(); ++i)
|
|
{
|
|
ElementRenderer::Element *child = list->GetIndexedElement(i);
|
|
Check_Object(child);
|
|
FindPlanes(child, planes, planes_filled);
|
|
}
|
|
}
|
|
|
|
//
|
|
//-----------------------
|
|
// Spin through the shape
|
|
//-----------------------
|
|
//
|
|
else if (element->IsDerivedFrom(ElementRenderer::ShapeElement::DefaultData))
|
|
{
|
|
ElementRenderer::ShapeElement *shape =
|
|
Cast_Object(ElementRenderer::ShapeElement *, element);
|
|
MidLevelRenderer::MLRShape *mlr_shape = shape->GetMLRShape();
|
|
Check_Object(mlr_shape);
|
|
for (int p=0; p<mlr_shape->GetNum(); ++p)
|
|
{
|
|
MidLevelRenderer::MLRPrimitiveBase *primitive = mlr_shape->Find(p);
|
|
Check_Object(primitive);
|
|
|
|
//
|
|
//----------------------------------------------------------------
|
|
// We have gotten the given primitive, now we need to loop through
|
|
// the faces
|
|
//----------------------------------------------------------------
|
|
//
|
|
const Stuff::Point3D *points;
|
|
int point_count;
|
|
primitive->GetCoordData(&points, &point_count);
|
|
MidLevelRenderer::MLRIndexedPrimitiveBase *indexed_primitive =
|
|
Cast_Object(
|
|
MidLevelRenderer::MLRIndexedPrimitiveBase *,
|
|
primitive
|
|
);
|
|
const unsigned short *indices;
|
|
int index_count;
|
|
indexed_primitive->GetIndexData(&indices, &index_count);
|
|
Verify(!(index_count%3));
|
|
int face_count = index_count/3;
|
|
Verify(face_count == primitive->GetNumPrimitives());
|
|
|
|
//
|
|
//----------------------------------------------------------------
|
|
// We have gotten the given primitive, now we need to loop through
|
|
// the faces and get the points of each triangle
|
|
//----------------------------------------------------------------
|
|
//
|
|
int index=0;
|
|
for (int f=0; f<face_count; ++f)
|
|
{
|
|
Verify(index < index_count);
|
|
Verify(static_cast<unsigned>(indices[index]) < point_count);
|
|
const Stuff::Point3D *point1 = &points[indices[index++]];
|
|
Verify(index < index_count);
|
|
Verify(static_cast<unsigned>(indices[index]) < point_count);
|
|
const Stuff::Point3D *point2 = &points[indices[index++]];
|
|
Verify(index < index_count);
|
|
Verify(static_cast<unsigned>(indices[index]) < point_count);
|
|
const Stuff::Point3D *point3 = &points[indices[index++]];
|
|
|
|
#if defined(BSP_BUG)
|
|
if (Debug_Tile)
|
|
{
|
|
SPEW((
|
|
BSP_BUG,
|
|
"Tri %d\tv0=<%f,%f,%f>",
|
|
f,
|
|
point1->x,
|
|
point1->y,
|
|
point1->z
|
|
));
|
|
SPEW((
|
|
BSP_BUG,
|
|
"\t v1=<%f,%f,%f>",
|
|
point2->x,
|
|
point2->y,
|
|
point2->z
|
|
));
|
|
SPEW((
|
|
BSP_BUG,
|
|
"\t v1=<%f,%f,%f>",
|
|
point3->x,
|
|
point3->y,
|
|
point3->z
|
|
));
|
|
}
|
|
#endif
|
|
|
|
//
|
|
//---------------------------------------------
|
|
// Figure out the plane equation of the polygon
|
|
//---------------------------------------------
|
|
//
|
|
WORD plane = (*planes_filled)++;
|
|
(*planes)[plane].BuildPlane(
|
|
*point1,
|
|
*point2,
|
|
*point3
|
|
);
|
|
Verify((*planes)[plane].normal.y > Stuff::SMALL);
|
|
|
|
//
|
|
//-----------------------------------------------------------
|
|
// Now figure out the plane equation of a vertical plane thru
|
|
// each edge
|
|
//-----------------------------------------------------------
|
|
//
|
|
Stuff::Point3D temp = *point1;
|
|
temp.y += 10.0f;
|
|
(*planes)[(*planes_filled)++].BuildPlane(
|
|
*point1,
|
|
*point2,
|
|
temp
|
|
);
|
|
(*planes)[(*planes_filled)++].BuildPlane(
|
|
*point1,
|
|
temp,
|
|
*point3
|
|
);
|
|
temp = *point2;
|
|
temp.y += 10.0f;
|
|
(*planes)[(*planes_filled)++].BuildPlane(
|
|
temp,
|
|
*point2,
|
|
*point3
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
else
|
|
STOP(("Didn't handle this case"));
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
TestTriangles(
|
|
ElementRenderer::Element *element,
|
|
Stuff::DynamicArrayOf<Stuff::Plane> &planes,
|
|
Stuff::DynamicArrayOf<BYTE> *scoreboard,
|
|
int *triangles_tested
|
|
)
|
|
{
|
|
Check_Object(element);
|
|
Check_Object(&planes);
|
|
Check_Object(scoreboard);
|
|
Check_Pointer(triangles_tested);
|
|
|
|
//
|
|
//-----------------------
|
|
// Spin through the group
|
|
//-----------------------
|
|
//
|
|
if (element->IsDerivedFrom(ElementRenderer::GroupElement::DefaultData))
|
|
{
|
|
ElementRenderer::GroupElement *group =
|
|
Cast_Object(ElementRenderer::GroupElement *, element);
|
|
Stuff::ChainIteratorOf<ElementRenderer::Element*> *children =
|
|
group->MakeIterator();
|
|
Register_Object(children);
|
|
ElementRenderer::Element *child;
|
|
while ((child = children->ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(child);
|
|
TestTriangles(child, planes, scoreboard, triangles_tested);
|
|
}
|
|
Unregister_Object(children);
|
|
delete children;
|
|
}
|
|
|
|
//
|
|
//----------------------
|
|
// Spin through the list
|
|
//----------------------
|
|
//
|
|
else if (element->IsDerivedFrom(ElementRenderer::ListElement::DefaultData))
|
|
{
|
|
ElementRenderer::ListElement *list =
|
|
Cast_Object(ElementRenderer::ListElement *, element);
|
|
for (unsigned i=0; i<list->GetActiveCount(); ++i)
|
|
{
|
|
ElementRenderer::Element *child = list->GetIndexedElement(i);
|
|
Check_Object(child);
|
|
TestTriangles(child, planes, scoreboard, triangles_tested);
|
|
}
|
|
}
|
|
|
|
//
|
|
//-----------------------
|
|
// Spin through the shape
|
|
//-----------------------
|
|
//
|
|
else if (element->IsDerivedFrom(ElementRenderer::ShapeElement::DefaultData))
|
|
{
|
|
ElementRenderer::ShapeElement *shape =
|
|
Cast_Object(ElementRenderer::ShapeElement *, element);
|
|
MidLevelRenderer::MLRShape *mlr_shape = shape->GetMLRShape();
|
|
Check_Object(mlr_shape);
|
|
for (int p=0; p<mlr_shape->GetNum(); ++p)
|
|
{
|
|
MidLevelRenderer::MLRPrimitiveBase *primitive = mlr_shape->Find(p);
|
|
Check_Object(primitive);
|
|
|
|
//
|
|
//----------------------------------------------------------------
|
|
// We have gotten the given primitive, now we need to loop through
|
|
// the faces
|
|
//----------------------------------------------------------------
|
|
//
|
|
const Stuff::Point3D *points;
|
|
int point_count;
|
|
primitive->GetCoordData(&points, &point_count);
|
|
MidLevelRenderer::MLRIndexedPrimitiveBase *indexed_primitive =
|
|
Cast_Object(
|
|
MidLevelRenderer::MLRIndexedPrimitiveBase *,
|
|
primitive
|
|
);
|
|
const unsigned short *indices;
|
|
int index_count;
|
|
indexed_primitive->GetIndexData(&indices, &index_count);
|
|
Verify(!(index_count%3));
|
|
int face_count = index_count/3;
|
|
Verify(face_count == primitive->GetNumPrimitives());
|
|
|
|
//
|
|
//----------------------------------------------------------------
|
|
// We have gotten the given primitive, now we need to loop through
|
|
// the faces and get the points of each triangle
|
|
//----------------------------------------------------------------
|
|
//
|
|
int index=0;
|
|
int score_index = *triangles_tested * planes.GetLength();
|
|
for (int f=0; f<face_count; ++f, ++(*triangles_tested))
|
|
{
|
|
Verify(index < index_count);
|
|
Verify(static_cast<unsigned>(indices[index]) < point_count);
|
|
const Stuff::Point3D *point1 = &points[indices[index++]];
|
|
Verify(index < index_count);
|
|
Verify(static_cast<unsigned>(indices[index]) < point_count);
|
|
const Stuff::Point3D *point2 = &points[indices[index++]];
|
|
Verify(index < index_count);
|
|
Verify(static_cast<unsigned>(indices[index]) < point_count);
|
|
const Stuff::Point3D *point3 = &points[indices[index++]];
|
|
|
|
#if defined(BSP_BUG)
|
|
if (Debug_Tile)
|
|
SPEW((BSP_BUG, "Tri %d\t+", f));
|
|
#endif
|
|
|
|
//
|
|
//-----------------------------------------------------
|
|
// Now we need to test these points against every plane
|
|
//-----------------------------------------------------
|
|
//
|
|
for (int t=0; t<planes.GetLength(); ++t, ++score_index)
|
|
{
|
|
Stuff::Scalar dist = planes[t].GetDistanceTo(*point1);
|
|
BYTE &entry = (*scoreboard)[score_index];
|
|
if (dist > 0.02)
|
|
entry = Outside_Plane;
|
|
else if (dist < -0.02)
|
|
entry = Inside_Plane;
|
|
else
|
|
entry = On_Plane;
|
|
dist = planes[t].GetDistanceTo(*point2);
|
|
if (dist > 0.02)
|
|
entry |= Outside_Plane;
|
|
else if (dist < -0.02)
|
|
entry |= Inside_Plane;
|
|
else
|
|
entry |= On_Plane;
|
|
dist = planes[t].GetDistanceTo(*point3);
|
|
if (dist > 0.02)
|
|
entry |= Outside_Plane;
|
|
else if (dist < -0.02)
|
|
entry |= Inside_Plane;
|
|
else
|
|
entry |= On_Plane;
|
|
|
|
//
|
|
//---------------------------------------------------------
|
|
// If we are on both sides of the plane, count us as on the
|
|
// plane
|
|
//---------------------------------------------------------
|
|
//
|
|
if ((entry&Split_Plane) == Split_Plane)
|
|
entry |= On_Plane;
|
|
Verify(entry != On_Plane || !(t&3));
|
|
|
|
#if defined(BSP_BUG)
|
|
if (Debug_Tile)
|
|
if ((t&3) == 3)
|
|
SPEW((BSP_BUG, "%d +", entry));
|
|
else
|
|
SPEW((BSP_BUG, "%d+", entry));
|
|
#endif
|
|
}
|
|
#if defined(BSP_BUG)
|
|
if (Debug_Tile)
|
|
SPEW((BSP_BUG, ""));
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
else
|
|
STOP(("Didn't handle this case"));
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
float
|
|
ComputeScore(
|
|
int outsides,
|
|
int insides,
|
|
int splits,
|
|
int total
|
|
)
|
|
{
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// The plane is useless if no triangles are reduced on either side of the
|
|
// plane, or if this is a real polygon plane and it splits another
|
|
// polygon
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
float score;
|
|
if (
|
|
total == outsides || total == insides
|
|
|| (splits>0 && total>outsides+insides-splits)
|
|
)
|
|
score = 3.0f * total;
|
|
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// Otherwise, base the score on the sum of the child triangle count and
|
|
// how balanced it is, giving a slight bias towards load over balance
|
|
//---------------------------------------------------------------------
|
|
//
|
|
else
|
|
{
|
|
float balance = Stuff::Fabs(static_cast<float>(outsides - insides));
|
|
score = outsides + insides + 0.9f*balance;
|
|
}
|
|
|
|
#if defined(BSP_BUG)
|
|
if (Debug_Tile)
|
|
SPEW((
|
|
BSP_BUG,
|
|
"o:%d i:%d s:%d -> %f",
|
|
outsides,
|
|
insides,
|
|
splits,
|
|
score
|
|
));
|
|
#endif
|
|
return score;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
SortTriangles(
|
|
Stuff::DynamicArrayOf<Adept::TerrainBSP> *bsp,
|
|
WORD *bsp_count,
|
|
Stuff::DynamicArrayOf<Stuff::Plane> *used_planes,
|
|
WORD *used_plane_count,
|
|
Stuff::DynamicArrayOf<BYTE> &scoreboard,
|
|
Stuff::DynamicArrayOf<Stuff::Plane> &reference_planes,
|
|
Stuff::DynamicArrayOf<int> &triangles
|
|
)
|
|
{
|
|
Check_Object(bsp);
|
|
Check_Pointer(bsp_count);
|
|
Check_Object(&scoreboard);
|
|
Check_Object(&reference_planes);
|
|
Check_Object(&triangles);
|
|
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// Our first task is to compile the statistics for each of the possible
|
|
// splitting planes
|
|
//---------------------------------------------------------------------
|
|
//
|
|
int plane_count = reference_planes.GetLength();
|
|
Stuff::DynamicArrayOf<int>
|
|
insides(plane_count),
|
|
outsides(plane_count),
|
|
splits(plane_count);
|
|
|
|
unsigned triangle_count = triangles.GetLength();
|
|
int p,t;
|
|
|
|
#if defined(BSP_BUG)
|
|
if (Debug_Tile)
|
|
{
|
|
SPEW((BSP_BUG, "BSP %d:", *bsp_count));
|
|
SPEW((BSP_BUG, "\t+"));
|
|
for (t=0; t<triangles.GetLength(); ++t)
|
|
SPEW((BSP_BUG, "%d +", triangles[t]));
|
|
SPEW((BSP_BUG, ""));
|
|
}
|
|
#endif
|
|
|
|
for (p=0; p<plane_count; ++p)
|
|
{
|
|
insides[p] = 0;
|
|
outsides[p] = 0;
|
|
splits[p] = 0;
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// Test each of the test triangles against the chosen plane and sum up
|
|
// the results
|
|
//--------------------------------------------------------------------
|
|
//
|
|
for (t=0; t<triangle_count; ++t)
|
|
{
|
|
switch (scoreboard[triangles[t]*plane_count + p])
|
|
{
|
|
case Outside_Plane:
|
|
case Outside_Plane|On_Plane:
|
|
++outsides[p];
|
|
break;
|
|
|
|
case Inside_Plane:
|
|
case Inside_Plane|On_Plane:
|
|
++insides[p];
|
|
break;
|
|
|
|
case On_Plane:
|
|
Verify(!(p&3));
|
|
break;
|
|
|
|
case Split_Plane|On_Plane:
|
|
++outsides[p];
|
|
++insides[p];
|
|
++splits[p];
|
|
break;
|
|
|
|
default:
|
|
STOP(("Shouldn't happen"));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// Now that we have our results, we need to spin through the table looking
|
|
// for the best splitting plane
|
|
//------------------------------------------------------------------------
|
|
//
|
|
int best_plane = -1;
|
|
float best_score = 3.0f*triangle_count;
|
|
int b_o, b_i, b_s;
|
|
for (p=0; p<plane_count; ++p)
|
|
{
|
|
#if defined(BSP_BUG)
|
|
if (Debug_Tile)
|
|
SPEW((BSP_BUG, "\t\t%d -> +", p));
|
|
#endif
|
|
float score =
|
|
ComputeScore(outsides[p], insides[p], splits[p], triangle_count);
|
|
if (score < best_score)
|
|
{
|
|
best_plane = p;
|
|
best_score = score;
|
|
b_o = outsides[p];
|
|
b_i = insides[p];
|
|
b_s = splits[p];
|
|
}
|
|
}
|
|
#if defined(BSP_BUG)
|
|
if (Debug_Tile)
|
|
SPEW((
|
|
BSP_BUG,
|
|
"\t%d -> O:%d I:%d S:%d = %f ====",
|
|
best_plane,
|
|
b_o,
|
|
b_i,
|
|
b_s,
|
|
best_score
|
|
));
|
|
#endif
|
|
|
|
//
|
|
//-----------------------------------------------------
|
|
// We couldn't sort the rest so best plane will be zero
|
|
//-----------------------------------------------------
|
|
//
|
|
if (best_plane < 0)
|
|
{
|
|
best_plane = 0;
|
|
WORD new_plane;
|
|
for (new_plane=0; new_plane<*used_plane_count; ++new_plane)
|
|
{
|
|
if (
|
|
!memcmp(
|
|
&(*used_planes)[new_plane],
|
|
&reference_planes[best_plane],
|
|
sizeof(Stuff::Plane)
|
|
)
|
|
)
|
|
break;
|
|
}
|
|
if (new_plane == *used_plane_count)
|
|
{
|
|
new_plane = (*used_plane_count)++;
|
|
(*used_planes)[new_plane] = reference_planes[best_plane];
|
|
}
|
|
int new_bsp = (*bsp_count)++;
|
|
(*bsp)[new_bsp].m_planeIndex = new_plane;
|
|
(*bsp)[new_bsp].m_innerIndex = 0;
|
|
(*bsp)[new_bsp].m_outerIndex = 0;
|
|
return;
|
|
}
|
|
|
|
Verify(best_plane>=0 && best_plane<plane_count);
|
|
if (best_score == 3.0f*triangle_count)
|
|
STOP(("Can't sort this tree!"));
|
|
|
|
//
|
|
//-------------------------------------------------------
|
|
// Search the used plane array to see if the plane exists
|
|
//-------------------------------------------------------
|
|
//
|
|
WORD new_plane;
|
|
for (new_plane=0; new_plane<*used_plane_count; ++new_plane)
|
|
{
|
|
if (
|
|
!memcmp(
|
|
&(*used_planes)[new_plane],
|
|
&reference_planes[best_plane],
|
|
sizeof(Stuff::Plane)
|
|
)
|
|
)
|
|
break;
|
|
}
|
|
if (new_plane == *used_plane_count)
|
|
{
|
|
new_plane = (*used_plane_count)++;
|
|
(*used_planes)[new_plane] = reference_planes[best_plane];
|
|
}
|
|
|
|
//
|
|
//-------------------------------------------
|
|
// Copy this plane into the used planes array
|
|
//-------------------------------------------
|
|
//
|
|
int new_bsp = (*bsp_count)++;
|
|
(*bsp)[new_bsp].m_planeIndex = new_plane;
|
|
(*bsp)[new_bsp].m_innerIndex = 0;
|
|
(*bsp)[new_bsp].m_outerIndex = 0;
|
|
|
|
//
|
|
//----------------------------------------------------------------
|
|
// If all of the triangles are contained in the plane, we are done
|
|
//----------------------------------------------------------------
|
|
//
|
|
if (!insides[best_plane] && !outsides[best_plane])
|
|
return;
|
|
|
|
//
|
|
//--------------------------------------
|
|
// Split up the triangles into two lists
|
|
//--------------------------------------
|
|
//
|
|
int inside_count = insides[best_plane];
|
|
Stuff::DynamicArrayOf<int> inside_triangles(inside_count);
|
|
inside_count = 0;
|
|
int outside_count = outsides[best_plane];
|
|
Stuff::DynamicArrayOf<int> outside_triangles(outside_count);
|
|
outside_count = 0;
|
|
for (t=0; t<triangles.GetLength(); ++t)
|
|
{
|
|
BYTE flag = scoreboard[triangles[t]*plane_count + best_plane];
|
|
if (flag&Outside_Plane)
|
|
outside_triangles[outside_count++] = triangles[t];
|
|
if (flag&Inside_Plane)
|
|
inside_triangles[inside_count++] = triangles[t];
|
|
}
|
|
Verify(outside_triangles.GetLength() == outside_count);
|
|
Verify(inside_triangles.GetLength() == inside_count);
|
|
|
|
//
|
|
//--------------------------
|
|
// Recurse the inside branch
|
|
//--------------------------
|
|
//
|
|
if (inside_count > 0)
|
|
{
|
|
(*bsp)[new_bsp].m_innerIndex = *bsp_count;
|
|
#if defined(BSP_BUG)
|
|
if (Debug_Tile)
|
|
SPEW((BSP_BUG, "\tBSP %d.innerIndex = %d", new_bsp, *bsp_count));
|
|
#endif
|
|
SortTriangles(
|
|
bsp,
|
|
bsp_count,
|
|
used_planes,
|
|
used_plane_count,
|
|
scoreboard,
|
|
reference_planes,
|
|
inside_triangles
|
|
);
|
|
}
|
|
else
|
|
{
|
|
Verify(outside_count < triangles.GetLength());
|
|
Verify(!(best_plane&3));
|
|
}
|
|
|
|
//
|
|
//--------------------------
|
|
// Recurse the outside branch
|
|
//--------------------------
|
|
//
|
|
if (outside_count > 0)
|
|
{
|
|
(*bsp)[new_bsp].m_outerIndex = *bsp_count;
|
|
#if defined(BSP_BUG)
|
|
if (Debug_Tile)
|
|
SPEW((BSP_BUG, "\tBSP %d.outerIndex = %d", new_bsp, *bsp_count));
|
|
#endif
|
|
SortTriangles(
|
|
bsp,
|
|
bsp_count,
|
|
used_planes,
|
|
used_plane_count,
|
|
scoreboard,
|
|
reference_planes,
|
|
outside_triangles
|
|
);
|
|
}
|
|
else
|
|
{
|
|
Verify(inside_count < triangles.GetLength());
|
|
Verify(!(best_plane&3));
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MakeBSP(
|
|
Stuff::DynamicArrayOf<Stuff::Plane> *planes,
|
|
WORD *plane_count,
|
|
ElementRenderer::GroupElement *tile,
|
|
Stuff::MemoryStream *stream
|
|
)
|
|
{
|
|
Check_Object(tile);
|
|
Check_Object(stream);
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// Count the number of triangles in the tile. We will end up computing
|
|
// four planes per triangle, one for the face, and one vertical plane thru
|
|
// each edge
|
|
//------------------------------------------------------------------------
|
|
//
|
|
int tri_count = tile->CountTriangles();
|
|
int ref_plane_count = 4*tri_count;
|
|
Stuff::DynamicArrayOf<Stuff::Plane> reference_planes(ref_plane_count);
|
|
int planes_filled = 0;
|
|
FindPlanes(tile, &reference_planes, &planes_filled);
|
|
Verify(planes_filled == ref_plane_count);
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// We now need to fill the scoreboard up with the poly to plane test data
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
int total_tests = tri_count * ref_plane_count;
|
|
Stuff::DynamicArrayOf<BYTE> scoreboard(total_tests);
|
|
int triangles_tested = 0;
|
|
TestTriangles(tile, reference_planes, &scoreboard, &triangles_tested);
|
|
Verify(triangles_tested = tri_count);
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// Now build the triangle index list in order to prime the sorting process
|
|
//------------------------------------------------------------------------
|
|
//
|
|
Stuff::DynamicArrayOf<int> triangles(tri_count);
|
|
for (int t=0; t<tri_count; ++t)
|
|
triangles[t] = t;
|
|
Stuff::DynamicArrayOf<Adept::TerrainBSP> bsp(ref_plane_count);
|
|
WORD bsp_count = 0;
|
|
|
|
//
|
|
//---------------
|
|
// Sort the puppy
|
|
//---------------
|
|
//
|
|
SortTriangles(
|
|
&bsp,
|
|
&bsp_count,
|
|
planes,
|
|
plane_count,
|
|
scoreboard,
|
|
reference_planes,
|
|
triangles
|
|
);
|
|
Verify(bsp_count < bsp.GetLength());
|
|
|
|
//
|
|
//-------------------
|
|
// Write out the data
|
|
//-------------------
|
|
//
|
|
*stream << bsp_count;
|
|
stream->WriteBytes(
|
|
bsp.GetData(),
|
|
bsp_count*sizeof(Adept::TerrainBSP)
|
|
);
|
|
}
|