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.
446 lines
11 KiB
C++
446 lines
11 KiB
C++
#include "ProxyHeaders.hpp"
|
|
|
|
//
|
|
//############################################################################
|
|
//############################ GroupProxy ##############################
|
|
//############################################################################
|
|
//
|
|
|
|
GroupProxy::ClassData*
|
|
GroupProxy::DefaultData = NULL;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
GroupProxy::InitializeClass()
|
|
{
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
GroupProxyClassID,
|
|
"GroupProxy",
|
|
ChildProxy::DefaultData
|
|
);
|
|
Register_Object(DefaultData);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
GroupProxy::TerminateClass()
|
|
{
|
|
Unregister_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
GroupProxy::GroupProxy(
|
|
ClassData *class_data,
|
|
SceneProxy *scene,
|
|
GroupProxy *parent
|
|
):
|
|
ChildProxy(class_data, scene, parent),
|
|
activeChildProxies(NULL)
|
|
{
|
|
Check_Object(this);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
GroupProxy::~GroupProxy()
|
|
{
|
|
Check_Object(this);
|
|
Verify(activeChildProxies.IsEmpty());
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
GroupProxy::TestInstance() const
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
GroupProxy::GetCentroid(Point3D *centroid)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(centroid);
|
|
|
|
//
|
|
//-----------------------------------------------
|
|
// If we have no children, just return our origin
|
|
//-----------------------------------------------
|
|
//
|
|
unsigned child_count = GetChildCount();
|
|
*centroid = Point3D::Identity;
|
|
if (!child_count)
|
|
return;
|
|
|
|
//
|
|
//--------------------------------------------
|
|
// Otherwise, just average our child centroids
|
|
//--------------------------------------------
|
|
//
|
|
ChildProxy *child = UseFirstChildProxy();
|
|
while (child)
|
|
{
|
|
Check_Object(child);
|
|
ChildProxy *next = child->UseNextSiblingProxy();
|
|
Point3D local_centroid;
|
|
child->GetCentroid(&local_centroid);
|
|
LinearMatrix4D m;
|
|
child->GetLocalToParent(&m);
|
|
Point3D world_centroid;
|
|
world_centroid.Multiply(local_centroid, m);
|
|
*centroid += world_centroid;
|
|
child->DetachReference();
|
|
child = next;
|
|
}
|
|
Verify(!child);
|
|
*centroid /= static_cast<Scalar>(child_count);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
GroupProxy::Recenter()
|
|
{
|
|
Check_Object(this);
|
|
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
// Now, get our centroid in our mesh space, and recenter the mesh around it
|
|
// in model space
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
Point3D centroid;
|
|
GetCentroid(¢roid);
|
|
if (centroid != Point3D::Identity)
|
|
{
|
|
LinearMatrix4D matrix;
|
|
GetLocalToParent(&matrix);
|
|
matrix(3,0) += centroid.x;
|
|
matrix(3,1) += centroid.y;
|
|
matrix(3,2) += centroid.z;
|
|
SetLocalToParent(matrix);
|
|
|
|
//
|
|
//----------------------------------------------------------
|
|
// First, allow each child hierarchy to remove redundancies
|
|
//----------------------------------------------------------
|
|
//
|
|
matrix = LinearMatrix4D::Identity;
|
|
centroid.Negate(centroid);
|
|
matrix.BuildTranslation(centroid);
|
|
unsigned child_count = GetChildCount();
|
|
ChildProxy *child = UseFirstChildProxy();
|
|
for (unsigned i=0; i<child_count; ++i)
|
|
{
|
|
Check_Object(child);
|
|
ChildProxy *next = child->UseNextSiblingProxy();
|
|
child->TransformLocalToParent(matrix);
|
|
child->DetachReference();
|
|
child = next;
|
|
}
|
|
if (child)
|
|
child->DetachReference();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
GroupProxy::SortAndAddPolygons(
|
|
BinSortProcess *process,
|
|
Stuff::DynamicArrayOf<PolygonProxy*> &polygons
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(process);
|
|
Check_Object(&polygons);
|
|
Verify(process->binSize > 0);
|
|
|
|
//
|
|
//---------------------------------------------------------------
|
|
// See if we can just directly add these polygons into a new mesh
|
|
//---------------------------------------------------------------
|
|
//
|
|
unsigned polygon_count = polygons.GetLength();
|
|
if (polygon_count <= process->binSize)
|
|
{
|
|
Copy_Mesh:
|
|
PolygonMeshProxy *mesh = AppendNewPolygonMeshProxy();
|
|
Check_Object(mesh);
|
|
mesh->AddPolygons(process, polygons);
|
|
mesh->DetachReference();
|
|
return;
|
|
}
|
|
|
|
//
|
|
//---------------------------------
|
|
// Make a list of all the centroids
|
|
//---------------------------------
|
|
//
|
|
DynamicArrayOf<Point3D> centroids(polygon_count);
|
|
unsigned i;
|
|
PolygonProxy *polygon;
|
|
for (i=0; i<polygon_count; ++i)
|
|
{
|
|
polygon = polygons[i];
|
|
Check_Object(polygon);
|
|
Scalar area = polygon->GetSurfaceAreaAndCentroid(¢roids[i]);
|
|
if (area > SMALL)
|
|
centroids[i] /= area;
|
|
}
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// Calculate the dividing plane, and if none can be found, don't do nothin
|
|
//------------------------------------------------------------------------
|
|
//
|
|
Plane plane;
|
|
if (!plane.ComputeBestDividingPlane(centroids))
|
|
goto Copy_Mesh;
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// Create two new meshes under the group for the mesh to be split up into
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
DynamicArrayOf<PolygonProxy*>
|
|
group_a(polygon_count),
|
|
group_b(polygon_count);
|
|
unsigned
|
|
count_a = 0,
|
|
count_b = 0;
|
|
|
|
//
|
|
//------------------------------------------------------------------
|
|
// Sort each of the centroids against the plane into one of two bins
|
|
//------------------------------------------------------------------
|
|
//
|
|
for (i=0; i<polygon_count; ++i)
|
|
{
|
|
polygon = polygons[i];
|
|
Check_Object(polygon);
|
|
if (plane.GetDistanceTo(centroids[i]) < 0.0f)
|
|
group_b[count_b++] = polygon;
|
|
else
|
|
group_a[count_a++] = polygon;
|
|
}
|
|
group_a.SetLength(count_a);
|
|
group_b.SetLength(count_b);
|
|
|
|
//
|
|
//------------------
|
|
// Now sort each bin
|
|
//------------------
|
|
//
|
|
SortAndAddPolygons(process, group_a);
|
|
SortAndAddPolygons(process, group_b);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
GroupProxy::GetBoundingSphere(Sphere *sphere)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(sphere);
|
|
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// Put the center of the sphere at the centroid, then set the radius to
|
|
// just contain the mesh
|
|
//---------------------------------------------------------------------
|
|
//
|
|
GetCentroid(&sphere->center);
|
|
sphere->radius = -1.0f;
|
|
ChildProxy *child = UseFirstChildProxy();
|
|
while (child)
|
|
{
|
|
Check_Object(child);
|
|
ChildProxy *next = child->UseNextSiblingProxy();
|
|
|
|
//
|
|
//----------------------------------------------------------
|
|
// Transform's the child's bounding sphere into parent space
|
|
//----------------------------------------------------------
|
|
//
|
|
LinearMatrix4D child_to_parent;
|
|
child->GetLocalToParent(&child_to_parent);
|
|
Sphere child_sphere;
|
|
child->GetBoundingSphere(&child_sphere);
|
|
Point3D position;
|
|
position.Multiply(child_sphere.center, child_to_parent);
|
|
|
|
//
|
|
//-----------------------------------------------------------------
|
|
// Now stretch the radius of the bounding sphere so that it totally
|
|
// includes the child sphere
|
|
//-----------------------------------------------------------------
|
|
//
|
|
position -= sphere->center;
|
|
Scalar range = position.GetLength() + child_sphere.radius;
|
|
if (range > sphere->radius)
|
|
{
|
|
sphere->radius = range;
|
|
}
|
|
child->DetachReference();
|
|
child = next;
|
|
}
|
|
|
|
//
|
|
//-------------------------------------
|
|
// Make sure the radius is properly set
|
|
//-------------------------------------
|
|
//
|
|
if (sphere->radius == -1.0f)
|
|
{
|
|
sphere->radius = 0.0f;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
ChildProxy*
|
|
GroupProxy::AppendMatchingChildProxy(
|
|
CopyProcess *process,
|
|
ChildProxy *child
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(process);
|
|
Check_Object(child);
|
|
|
|
if (child->IsDerivedFrom(PolygonMeshProxy::DefaultData))
|
|
{
|
|
PolygonMeshProxy *proxy = AppendNewPolygonMeshProxy();
|
|
Check_Object(proxy);
|
|
proxy->Copy(process, Cast_Object(PolygonMeshProxy*, child));
|
|
return proxy;
|
|
}
|
|
else if (child->IsDerivedFrom(GroupProxy::DefaultData))
|
|
{
|
|
GroupProxy *proxy = AppendNewGroupProxy();
|
|
Check_Object(proxy);
|
|
proxy->Copy(process, Cast_Object(GroupProxy*, child));
|
|
return proxy;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
ChildProxy*
|
|
GroupProxy::InsertMatchingChildProxy(
|
|
CopyProcess *process,
|
|
ChildProxy *child,
|
|
ChildProxy *before
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(process);
|
|
Check_Object(child);
|
|
Check_Object(before);
|
|
Verify(before->GetParentGroupProxy() == this);
|
|
|
|
STOP(("Not implemented"));
|
|
return NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
GroupProxy::FindNamedChildren(
|
|
DynamicArrayOf<ChildProxy*> *children,
|
|
const char* prefix,
|
|
bool matching
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(children);
|
|
Check_Pointer(prefix);
|
|
|
|
//
|
|
//----------------------
|
|
// Get the prefix length
|
|
//----------------------
|
|
//
|
|
int size = strlen(prefix);
|
|
|
|
//
|
|
//---------------------------------
|
|
// Find out how many children match
|
|
//---------------------------------
|
|
//
|
|
unsigned count = 0;
|
|
ChildProxy *child = UseFirstChildProxy();
|
|
while (child)
|
|
{
|
|
ChildProxy *next = child->UseNextSiblingProxy();
|
|
MString name;
|
|
if (child->GetName(&name))
|
|
{
|
|
if ((!_strnicmp(name, prefix, size)) == matching)
|
|
++count;
|
|
}
|
|
child->DetachReference();
|
|
child = next;
|
|
}
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// Set the array length, and if we have any matching children, fill in the
|
|
// array with those proxies
|
|
//------------------------------------------------------------------------
|
|
//
|
|
children->SetLength(count);
|
|
if (count > 0)
|
|
{
|
|
child = UseFirstChildProxy();
|
|
count = 0;
|
|
while (child)
|
|
{
|
|
ChildProxy *next = child->UseNextSiblingProxy();
|
|
|
|
//
|
|
//-----------------------------------------------------------------
|
|
// If the child has a name and it matches what we are looking for,
|
|
// store it in the array and bump the reference count so it doesn't
|
|
// go away
|
|
//-----------------------------------------------------------------
|
|
//
|
|
MString name;
|
|
if (child->GetName(&name))
|
|
{
|
|
if ((!_strnicmp(name, prefix, size)) == matching)
|
|
{
|
|
(*children)[count++] = child;
|
|
child->AttachReference();
|
|
}
|
|
}
|
|
child->DetachReference();
|
|
child = next;
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
GroupProxy::DetachChildProxy(ChildProxy* proxy)
|
|
{
|
|
Check_Object(this);
|
|
activeChildProxies.RemovePlug(proxy);
|
|
Verify(referenceCount > 1);
|
|
DetachReference();
|
|
}
|