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.
616 lines
16 KiB
C++
616 lines
16 KiB
C++
#include "ProxyHeaders.hpp"
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
FindErrorsProcess::FindErrorsProcess():
|
|
enableDuplicateCheck(true),
|
|
enableDegenerateCheck(true),
|
|
enableCoplanarCheck(true),
|
|
enableColinearCheck(true),
|
|
enableConvexCheck(true)
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
FindErrorsProcess::FindErrorsProcess(
|
|
Stuff::NotationFile *data_file,
|
|
bool bSuppress,
|
|
void* fcn
|
|
):
|
|
Process(data_file,bSuppress,fcn),
|
|
enableDuplicateCheck(true),
|
|
enableDegenerateCheck(true),
|
|
enableCoplanarCheck(true),
|
|
enableColinearCheck(true),
|
|
enableConvexCheck(true)
|
|
{
|
|
Check_Object(data_file);
|
|
|
|
Page *page = data_file->FindPage("FindErrors");
|
|
if (page)
|
|
{
|
|
page->GetEntry("DuplicateCheck", &enableDuplicateCheck);
|
|
page->GetEntry("DegenerateCheck", &enableDegenerateCheck);
|
|
page->GetEntry("CoplanarCheck", &enableCoplanarCheck);
|
|
page->GetEntry("ColinearCheck", &enableColinearCheck);
|
|
page->GetEntry("ConvexCheck", &enableConvexCheck);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
PolygonProxy::FindErrors(FindErrorsProcess *process)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(process);
|
|
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// Get the area of the polygon. This will be used to scale some of the
|
|
// error process so they fit with larger polygons
|
|
//---------------------------------------------------------------------
|
|
//
|
|
Scalar area = GetArea();
|
|
Scalar area_edge = Sqrt(area);
|
|
Scalar plane_tolerance = process->planeThicknessTolerance * area_edge;
|
|
Scalar duplicate_tolerance = process->duplicateVertexTolerance;
|
|
Scalar colinear_tolerance = process->colinearTolerance;
|
|
int total = 0;
|
|
|
|
//
|
|
//--------------------------------------------
|
|
// Delete all the error groups on this polygon
|
|
//--------------------------------------------
|
|
//
|
|
MStringChain group_list(NULL);
|
|
GetCollections(&group_list);
|
|
MStringChainIterator group_itr(&group_list);
|
|
PlugOf<MString> *group;
|
|
while ((group = group_itr.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(group);
|
|
const char* name = group->GetItem();
|
|
Check_Pointer(name);
|
|
if (!_strnicmp(name, "_ERROR_", 7))
|
|
RemoveFromCollection(name);
|
|
Unregister_Object(group);
|
|
delete group;
|
|
}
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// The first task we have is to find the two longest consecutive edges.
|
|
// We will use these edges to compute the desired polygon normal and plane
|
|
// equation
|
|
//------------------------------------------------------------------------
|
|
//
|
|
Point3D
|
|
position_a,
|
|
position_b = Point3D::Identity,
|
|
position_c = Point3D::Identity;
|
|
VertexProxy
|
|
*vertex_a = NULL,
|
|
*vertex_b = NULL,
|
|
*vertex_c = NULL;
|
|
Vector3D
|
|
edge_1,
|
|
edge_2 = Vector3D::Identity;
|
|
Plane
|
|
plane;
|
|
|
|
//
|
|
//-----------------------------------------------------------------
|
|
// Put in checks to make sure that the colors, normals, and uvs are
|
|
// compatible for all the vertices in this polygon
|
|
//-----------------------------------------------------------------
|
|
//
|
|
bool
|
|
uv_there = false,
|
|
color_there = false,
|
|
normal_there = false;
|
|
|
|
//
|
|
//-----------------------------------
|
|
// Spin through, testing the vertices
|
|
//-----------------------------------
|
|
//
|
|
DynamicArrayOf<IndexProxy*> indices;
|
|
unsigned index_count = UseIndexArray(&indices);
|
|
Verify(index_count == indices.GetLength());
|
|
Verify(index_count >= 3);
|
|
unsigned end=2;
|
|
for (unsigned i=0; i<index_count; ++i)
|
|
{
|
|
//
|
|
//-----------------------------------------------
|
|
// Generate all the information on the first pass
|
|
//-----------------------------------------------
|
|
//
|
|
if (!i)
|
|
{
|
|
Check_Object(indices[0]);
|
|
vertex_a = indices[0]->GetVertexProxy();
|
|
Check_Object(vertex_a);
|
|
|
|
Check_Object(indices[1]);
|
|
vertex_b = indices[1]->GetVertexProxy();
|
|
Check_Object(vertex_b);
|
|
|
|
Check_Object(indices[2]);
|
|
vertex_c = indices[2]->GetVertexProxy();
|
|
Check_Object(vertex_c);
|
|
|
|
vertex_a->GetPosition(&position_a);
|
|
vertex_b->GetPosition(&position_b);
|
|
vertex_c->GetPosition(&position_c);
|
|
|
|
edge_1.Subtract(position_b, position_a);
|
|
edge_2.Subtract(position_c, position_b);
|
|
Normal3D normal;
|
|
if (vertex_c->GetNormal(&normal))
|
|
{
|
|
if (!Close_Enough(normal.Vector3D::GetLengthSquared(), 1.0f, 2e-5f))
|
|
{
|
|
AddToCollection("_ERROR_Bad_Normal");
|
|
++total;
|
|
process->FindErrorsCallback(
|
|
this,
|
|
FindErrorsProcess::ERROR_Bad_Normal
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
//---------------------------------
|
|
// Set up the additional attributes
|
|
//---------------------------------
|
|
//
|
|
RGBAColor color;
|
|
color_there = vertex_c->GetColor(&color);
|
|
DynamicArrayOf<Vector2DOf<Scalar> > uv;
|
|
uv_there = vertex_c->GetUVs(&uv);
|
|
normal_there = vertex_c->GetNormal(&normal);
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------
|
|
// Get the index info. If this is not the first pass, copy the
|
|
// information from last pass
|
|
//--------------------------------------------------------------
|
|
//
|
|
else
|
|
{
|
|
Check_Object(vertex_b);
|
|
vertex_a = vertex_b;
|
|
Check_Object(vertex_c);
|
|
vertex_b = vertex_c;
|
|
if (++end >= index_count)
|
|
end -= index_count;
|
|
Check_Object(indices[end]);
|
|
vertex_c = indices[end]->GetVertexProxy();
|
|
Check_Object(vertex_c);
|
|
|
|
position_a = position_b;
|
|
position_b = position_c;
|
|
vertex_c->GetPosition(&position_c);
|
|
|
|
edge_1 = edge_2;
|
|
edge_2.Subtract(position_c, position_b);
|
|
|
|
//
|
|
//--------------------------------
|
|
// Check the additional attributes
|
|
//--------------------------------
|
|
//
|
|
RGBAColor color;
|
|
if (color_there != vertex_c->GetColor(&color))
|
|
{
|
|
AddToCollection("_ERROR_Mismatched_Vertex_Colors");
|
|
++total;
|
|
process->FindErrorsCallback(
|
|
this,
|
|
FindErrorsProcess::ERROR_Mismatched_Vertex_Colors
|
|
);
|
|
break;
|
|
}
|
|
DynamicArrayOf<Vector2DOf<Scalar> > uv;
|
|
if (uv_there != vertex_c->GetUVs(&uv))
|
|
{
|
|
AddToCollection("_ERROR_Mismatched_UVs");
|
|
++total;
|
|
process->FindErrorsCallback(
|
|
this,
|
|
FindErrorsProcess::ERROR_Mismatched_UVs
|
|
);
|
|
break;
|
|
}
|
|
Normal3D normal;
|
|
if (normal_there != vertex_c->GetNormal(&normal))
|
|
{
|
|
AddToCollection("_ERROR_Mismatched_Normals");
|
|
++total;
|
|
process->FindErrorsCallback(
|
|
this,
|
|
FindErrorsProcess::ERROR_Mismatched_Normals
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------
|
|
// Check the forward leg length to see if the polygon has duplicate
|
|
// points
|
|
//-----------------------------------------------------------------
|
|
//
|
|
Scalar length = edge_2.GetLengthSquared();
|
|
if (
|
|
Small_Enough(length, duplicate_tolerance)
|
|
&& process->enableDuplicateCheck
|
|
)
|
|
{
|
|
AddToCollection("_ERROR_Duplicate_Vertex");
|
|
++total;
|
|
process->FindErrorsCallback(
|
|
this,
|
|
FindErrorsProcess::ERROR_Duplicate_Vertex
|
|
);
|
|
break;
|
|
}
|
|
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// Compute the cross-product of the two legs and check for colinearness.
|
|
// This is not necessarily bad, as long as we are coplanar
|
|
//---------------------------------------------------------------------
|
|
//
|
|
Vector3D v;
|
|
v.Cross(edge_1, edge_2);
|
|
Scalar cross_len = v.GetLength();
|
|
if (Small_Enough(cross_len, colinear_tolerance))
|
|
{
|
|
if (!i && process->enableDegenerateCheck)
|
|
{
|
|
AddToCollection("_ERROR_Degenerate_Polygon");
|
|
++total;
|
|
process->FindErrorsCallback(
|
|
this,
|
|
FindErrorsProcess::ERROR_Degenerate_Polygon
|
|
);
|
|
break;
|
|
}
|
|
else if (
|
|
!Small_Enough(plane.GetDistanceTo(position_b), plane_tolerance)
|
|
&& process->enableCoplanarCheck
|
|
)
|
|
{
|
|
AddToCollection("_ERROR_Noncoplanar_Polygon");
|
|
++total;
|
|
process->FindErrorsCallback(
|
|
this,
|
|
FindErrorsProcess::ERROR_Noncoplanar_Polygon
|
|
);
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
//
|
|
//-------------------------------------------------------------------
|
|
// Normalize the cross. If this is the first pass, compute the plane
|
|
// equation for the polygon
|
|
//-------------------------------------------------------------------
|
|
//
|
|
cross_len = 1.0f / cross_len;
|
|
Normal3D edge_normal(v.x*cross_len, v.y*cross_len, v.z*cross_len);
|
|
if (!i)
|
|
{
|
|
plane.normal = edge_normal;
|
|
plane.offset = plane.normal * position_b;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
//--------------------------
|
|
// Check for non-coplanarity
|
|
//--------------------------
|
|
//
|
|
if (
|
|
!Small_Enough(plane.GetDistanceTo(position_b), plane_tolerance)
|
|
&& process->enableCoplanarCheck
|
|
)
|
|
{
|
|
AddToCollection("_ERROR_Noncoplanar_Polygon");
|
|
++total;
|
|
process->FindErrorsCallback(
|
|
this,
|
|
FindErrorsProcess::ERROR_Noncoplanar_Polygon
|
|
);
|
|
break;
|
|
}
|
|
|
|
//
|
|
//----------------------
|
|
// Check for concaveness
|
|
//----------------------
|
|
//
|
|
Scalar cosine = plane.normal*edge_normal;
|
|
if (cosine < colinear_tolerance && process->enableConvexCheck)
|
|
{
|
|
AddToCollection("_ERROR_Nonconvex_Polygon");
|
|
++total;
|
|
process->FindErrorsCallback(
|
|
this,
|
|
FindErrorsProcess::ERROR_Noncoplanar_Polygon
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
//
|
|
//--------------------------------
|
|
// Check for polygons w/o textures
|
|
//--------------------------------
|
|
//
|
|
if(stateArray.GetLength() < 1)
|
|
{
|
|
AddToCollection("_ERROR_Nontextured_Polygon");
|
|
++total;
|
|
process->FindErrorsCallback(
|
|
this,
|
|
FindErrorsProcess::ERROR_Nontextured_Polygon
|
|
);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
//-----------------------------
|
|
// Delete the remaining proxies
|
|
//-----------------------------
|
|
//
|
|
DetachArrayReferences(&indices);
|
|
return total;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
TextureProxy::FindErrors(FindErrorsProcess *process)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(process);
|
|
|
|
//
|
|
//------------------------------------------------------------
|
|
// Make sure that the process says its OK to check the texture
|
|
//------------------------------------------------------------
|
|
//
|
|
process->FindErrorsCallback(this, FindErrorsProcess::StatusCheck);
|
|
if (!process->continueProcess)
|
|
return 1;
|
|
|
|
//
|
|
//---------------------------------------------------------
|
|
// Make sure that the texture is between 32 and 256 in size
|
|
//---------------------------------------------------------
|
|
//
|
|
Vector2DOf<int> size;
|
|
GetImageSize(&size);
|
|
if (size.x<32 || size.x>512 || size.y<32 || size.y>512)
|
|
{
|
|
process->FindErrorsCallback(
|
|
this,
|
|
FindErrorsProcess::ERROR_Bad_Texture_Size
|
|
);
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------
|
|
// Make sure that we are dealing with a power of 2 texture
|
|
//--------------------------------------------------------
|
|
//
|
|
size.x ^= size.x&(-size.x);
|
|
size.y ^= size.y&(-size.y);
|
|
if (size.x || size.y)
|
|
{
|
|
process->FindErrorsCallback(
|
|
this,
|
|
FindErrorsProcess::ERROR_Bad_Texture_Size
|
|
);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
TextureLibrary::FindErrors(FindErrorsProcess *process)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(process);
|
|
|
|
//
|
|
//---------------------------
|
|
// Handle the texture library
|
|
//---------------------------
|
|
//
|
|
int total = 0;
|
|
TextureProxy *texture = UseFirstTextureProxy();
|
|
while (texture)
|
|
{
|
|
Check_Object(texture);
|
|
total += texture->FindErrors(process);
|
|
TextureProxy *next = texture->UseNextTextureProxyInLibrary();
|
|
texture->DetachReference();
|
|
if (!process->continueProcess)
|
|
{
|
|
if (next)
|
|
next->DetachReference();
|
|
return total;
|
|
}
|
|
texture = next;
|
|
}
|
|
return total;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
ChildProxy::FindErrors(FindErrorsProcess *process)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(process);
|
|
process->FindErrorsCallback(this, FindErrorsProcess::StatusCheck);
|
|
return (!process->continueProcess) ? 1 : 0;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
GroupProxy::FindErrors(FindErrorsProcess *process)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(process);
|
|
|
|
//
|
|
//---------------------------------------------------
|
|
// Make sure that the process says its OK to continue
|
|
//---------------------------------------------------
|
|
//
|
|
process->FindErrorsCallback(this, FindErrorsProcess::StatusCheck);
|
|
if (!process->continueProcess)
|
|
return 1;
|
|
|
|
//
|
|
//-----------------------------------------------------
|
|
// Go through each child and count the number of errors
|
|
//-----------------------------------------------------
|
|
//
|
|
int total = 0;
|
|
ChildProxy *child = UseFirstChildProxy();
|
|
while (child)
|
|
{
|
|
Check_Object(child);
|
|
total += child->FindErrors(process);
|
|
ChildProxy *next = child->UseNextSiblingProxy();
|
|
child->DetachReference();
|
|
if (!process->continueProcess)
|
|
{
|
|
if (next)
|
|
next->DetachReference();
|
|
return total;
|
|
}
|
|
child = next;
|
|
}
|
|
return total;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
PolygonMeshProxy::FindErrors(FindErrorsProcess *process)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(process);
|
|
|
|
//
|
|
//---------------------------------------------------
|
|
// Make sure that the process says its OK to continue
|
|
//---------------------------------------------------
|
|
//
|
|
process->FindErrorsCallback(this, FindErrorsProcess::StatusCheck);
|
|
if (!process->continueProcess)
|
|
return 1;
|
|
|
|
//
|
|
//-----------------------------------
|
|
// Count the number of polygon errors
|
|
//-----------------------------------
|
|
//
|
|
int total = 0;
|
|
DynamicArrayOf<PolygonProxy*> polygons;
|
|
unsigned polygon_count = UsePolygonArray(&polygons);
|
|
Verify(polygon_count == polygons.GetLength());
|
|
if (polygon_count)
|
|
{
|
|
for (unsigned i=0; i<polygon_count; ++i)
|
|
{
|
|
PolygonProxy *polygon = polygons[i];
|
|
Check_Object(polygon);
|
|
total += polygon->FindErrors(process);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
process->FindErrorsCallback(
|
|
this,
|
|
FindErrorsProcess::ERROR_Empty_Mesh
|
|
);
|
|
total = 1;
|
|
}
|
|
DetachArrayReferences(&polygons);
|
|
return total;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
SceneProxy::FindErrors(FindErrorsProcess *process)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(process);
|
|
|
|
//
|
|
//---------------------------------------------------
|
|
// Make sure that the process says its OK to continue
|
|
//---------------------------------------------------
|
|
//
|
|
process->FindErrorsCallback(this, FindErrorsProcess::StatusCheck);
|
|
if (!process->continueProcess)
|
|
return 1;
|
|
|
|
//
|
|
//-------------------
|
|
// Check the textures
|
|
//-------------------
|
|
//
|
|
int total=0;
|
|
StateLibrary *states = GetStateLibrary();
|
|
Check_Object(states);
|
|
TextureLibrary *textures = states->GetTextureLibrary();
|
|
Check_Object(textures);
|
|
total += textures->FindErrors(process);
|
|
if (!process->continueProcess)
|
|
return total;
|
|
|
|
//
|
|
//-----------------
|
|
// Check each child
|
|
//-----------------
|
|
//
|
|
ChildProxy *child = UseFirstChildProxy();
|
|
while (child)
|
|
{
|
|
Check_Object(child);
|
|
total += child->FindErrors(process);
|
|
ChildProxy *next = child->UseNextSiblingProxy();
|
|
child->DetachReference();
|
|
if (!process->continueProcess)
|
|
{
|
|
if (next)
|
|
next->DetachReference();
|
|
break;
|
|
}
|
|
child = next;
|
|
}
|
|
|
|
return total;
|
|
}
|