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.
7502 lines
173 KiB
C++
7502 lines
173 KiB
C++
#include <MLR\MLRHeaders.hpp>
|
|
#include <ElementRenderer\GridElement.hpp>
|
|
#include <ElementRenderer\GroupElement.hpp>
|
|
#include <ElementRenderer\ShapeElement.hpp>
|
|
|
|
#if !defined(HFSLIMMZ_HPP)
|
|
#include "HFslimMZ.hpp"
|
|
#include "terra\terra.hpp"
|
|
#endif
|
|
|
|
//#define NON_DEBUG_BUG 1
|
|
#define CHANGE_0625
|
|
|
|
const Scalar One_Over_Three = 1.0f/3.0f;
|
|
|
|
extern FILE *analyzeFile;
|
|
|
|
bool doWater = false;
|
|
Scalar waterLevel;
|
|
bool doBSP = false;
|
|
bool doPrecise = false;
|
|
bool doInterest = false;
|
|
bool doTileCap = false;
|
|
bool doTileCapYovin = false;
|
|
bool doDensityMap = false;
|
|
bool silentMode = false;
|
|
|
|
const Scalar smaller = SMALL;
|
|
|
|
FILE *daWaterObj = NULL;
|
|
static int vertexCountObj;
|
|
|
|
DynamicArrayOf<PointStruct> uniquePoints;
|
|
int usedUniquePoints;
|
|
|
|
PointStruct *TriangleStruct::points = NULL;
|
|
|
|
DynamicArrayOf<TriangleStruct> triangleIndices;
|
|
int usedTriangleIndices;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
template <class T> void Swap(T& t1, T& t2)
|
|
{
|
|
T t;
|
|
|
|
t = t1;
|
|
t1 = t2;
|
|
t2 = t;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool IsPowerOf2(int X)
|
|
{
|
|
return !( X & ( X - 1 ) );
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
FindPoint(Point3D& point)
|
|
{
|
|
for(int i=0;i<usedUniquePoints;i++)
|
|
{
|
|
if(Close_Enough(uniquePoints[i].p.x, point.x) && Close_Enough(uniquePoints[i].p.z, point.z))
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
FindAddPoint(Point3D& point)
|
|
{
|
|
int closest = -1;
|
|
float closestRadius = 10000000000000000000000000000000.0f;
|
|
|
|
for(int i=0;i<usedUniquePoints;i++)
|
|
{
|
|
Vector3D v(
|
|
uniquePoints[i].p.x-point.x,
|
|
uniquePoints[i].p.y-point.y,
|
|
uniquePoints[i].p.z-point.z
|
|
);
|
|
|
|
float radius = v.GetLengthSquared();
|
|
|
|
if(radius<SMALL)
|
|
{
|
|
if(radius<closestRadius)
|
|
{
|
|
closest = i;
|
|
closestRadius = radius;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(closest>=0)
|
|
{
|
|
return closest;
|
|
}
|
|
|
|
uniquePoints[usedUniquePoints++].p = point;
|
|
|
|
return (usedUniquePoints-1);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
RemoveTriangle(TriangleStruct *ts)
|
|
{
|
|
int i, j;
|
|
for(i=0;i<usedTriangleIndices;i++)
|
|
{
|
|
if(ts == &triangleIndices[i])
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(i>=usedTriangleIndices)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
PointStruct *point;
|
|
for(i=0;i<3;i++)
|
|
{
|
|
point = &ts->points[ts->v[i]];
|
|
|
|
do
|
|
{
|
|
for(j=0;j<point->connectedTo;j++)
|
|
{
|
|
if(point->myTri[j].tri==ts)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if(j<point->connectedTo)
|
|
{
|
|
for(;j<point->connectedTo-1;j++)
|
|
{
|
|
point->myTri[j].tri = point->myTri[j+1].tri;
|
|
point->myTri[j].angle = point->myTri[j+1].angle;
|
|
point->myTri[j].pos = point->myTri[j+1].pos;
|
|
}
|
|
point->connectedTo--;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
} while(point->connectedTo>0);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
RemoveTriangle(int i)
|
|
{
|
|
int j;
|
|
|
|
if(i>=usedTriangleIndices)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
TriangleStruct *ts = &triangleIndices[i];
|
|
|
|
PointStruct *point;
|
|
for(i=0;i<3;i++)
|
|
{
|
|
point = &ts->points[ts->v[i]];
|
|
|
|
do
|
|
{
|
|
for(j=0;j<point->connectedTo;j++)
|
|
{
|
|
if(point->myTri[j].tri==ts)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if(j<point->connectedTo)
|
|
{
|
|
for(;j<point->connectedTo-1;j++)
|
|
{
|
|
point->myTri[j].tri = point->myTri[j+1].tri;
|
|
point->myTri[j].angle = point->myTri[j+1].angle;
|
|
point->myTri[j].pos = point->myTri[j+1].pos;
|
|
}
|
|
point->connectedTo--;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
} while(point->connectedTo>0);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
float
|
|
GetAngle(Point3D& p0, Point3D& p1, Point3D& p2)
|
|
{
|
|
Vector3D v1, v2;
|
|
|
|
v1.Subtract(p0, p1);
|
|
v2.Subtract(p2, p1);
|
|
|
|
v1.y = 0.0f;
|
|
v2.y = 0.0f;
|
|
|
|
Scalar l1 = v1.GetLength(), l2 = v2.GetLength();
|
|
|
|
if(Small_Enough(l1*l2))
|
|
{
|
|
return 0.0f;
|
|
}
|
|
|
|
l1 = (v1*v2)/(l1*l2);
|
|
|
|
l1 = l1 > 1.0f ? 1.0f : l1;
|
|
l1 = l1 < -1.0f ? -1.0f : l1;
|
|
|
|
return static_cast<float> (acos(l1));
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
PointStruct::Add (TriangleStruct *ts, int pos)
|
|
{
|
|
Verify(Close_Enough(p.x, ts->GetPoint(pos).x) && Close_Enough(p.z, ts->GetPoint(pos).z));
|
|
myTri[connectedTo].tri = ts;
|
|
|
|
myTri[connectedTo].pos = pos;
|
|
myTri[connectedTo].angle = GetAngle(ts->GetPoint((pos-1+3)%3), ts->GetPoint(pos), ts->GetPoint((pos+1)%3));
|
|
|
|
Verify(myTri[connectedTo].angle<=Pi);
|
|
|
|
if(++connectedTo==myTri.GetLength())
|
|
{
|
|
myTri.SetLength(myTri.GetLength()+12);
|
|
}
|
|
|
|
Check_Object(this);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
PointStruct::CalculateAngles()
|
|
{
|
|
Check_Object(this);
|
|
|
|
for(int i=0;i<connectedTo;i++)
|
|
{
|
|
myTri[i].angle = GetAngle(
|
|
myTri[i].tri->GetPoint((myTri[i].pos-1+3)%3),
|
|
myTri[i].tri->GetPoint(myTri[i].pos),
|
|
myTri[i].tri->GetPoint((myTri[i].pos+1)%3)
|
|
);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
float
|
|
PointStruct::GetAngles()
|
|
{
|
|
Check_Object(this);
|
|
|
|
float angle = 0.0f;
|
|
|
|
if(connectedTo==0)
|
|
{
|
|
return angle;
|
|
}
|
|
|
|
for(int j=0;j<connectedTo;j++)
|
|
{
|
|
angle += myTri[j].angle;
|
|
}
|
|
|
|
return angle;
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
float
|
|
PointStruct::GetExpectedAngles(Scalar xMin, Scalar zMin, Scalar xMax, Scalar zMax)
|
|
{
|
|
if( (p.x == xMin || p.x==xMax) &&
|
|
(p.z == zMin || p.z==zMax) )
|
|
{
|
|
return Pi*0.5f;
|
|
}
|
|
else
|
|
if( (p.x == xMin || p.x==xMax) ||
|
|
(p.z == zMin || p.z==zMax) )
|
|
{
|
|
return Pi;
|
|
}
|
|
else
|
|
{
|
|
return 2*Pi;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
PointStruct::CheckAngles(Scalar xMin, Scalar zMin, Scalar xMax, Scalar zMax, Scalar dX, Scalar dZ)
|
|
{
|
|
Check_Object(this);
|
|
|
|
if(connectedTo==0)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
float angle = GetAngles();
|
|
|
|
|
|
if( (p.x == xMin || p.x==xMax) &&
|
|
(p.z == zMin || p.z==zMax) )
|
|
{
|
|
if(!Close_Enough(angle, Pi*0.5f, 0.005f))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
if( (p.x == xMin || p.x==xMax) ||
|
|
(p.z == zMin || p.z==zMax) )
|
|
{
|
|
if(!Close_Enough(angle, Pi, 0.005f))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!Close_Enough(angle, 2.0f*Pi, 0.005f))
|
|
{
|
|
if(p.z==zMax-dZ)
|
|
{
|
|
if(!Close_Enough(angle, Pi, 0.005f))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
PointStruct::CheckAngles()
|
|
{
|
|
for(int j=0;j<connectedTo;j++)
|
|
{
|
|
if(Close_Enough(myTri[j].angle, Pi))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
PointStruct::TestInstance() const
|
|
{
|
|
for(int i=0;i<connectedTo;i++)
|
|
{
|
|
Verify(myTri[i].tri->v[0] < usedUniquePoints);
|
|
Verify(myTri[i].tri->v[1] < usedUniquePoints);
|
|
Verify(myTri[i].tri->v[2] < usedUniquePoints);
|
|
}
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
TriangleAbstract::GetSurfaceAreaAndCentroid()
|
|
{
|
|
//
|
|
//---------------------
|
|
// Set up the variables
|
|
//---------------------
|
|
//
|
|
Point3D
|
|
position_a = Point3D::Identity,
|
|
position_b,
|
|
position_c = Point3D::Identity;
|
|
Vector3D
|
|
leg_1,
|
|
leg_2 = Vector3D::Identity;
|
|
|
|
//
|
|
//-----------------------------------
|
|
// Spin through, testing the vertices
|
|
//-----------------------------------
|
|
//
|
|
area = 0.0f;
|
|
center = GetPoint(0);
|
|
centerValid = true;
|
|
|
|
plane.normal.x = 0.0f;
|
|
plane.normal.y = 0.0f;
|
|
plane.normal.z = 1.0f;
|
|
plane.offset = 0.0f;
|
|
|
|
//
|
|
//-----------------------------------------------
|
|
// Generate all the information on the first pass
|
|
//-----------------------------------------------
|
|
//
|
|
position_a = GetPoint(2);
|
|
position_b = GetPoint(0);
|
|
position_c = GetPoint(1);
|
|
|
|
leg_1.Subtract(position_b, position_a);
|
|
leg_2.Subtract(position_c, position_a);
|
|
|
|
//
|
|
//-----------------------------------------------------------------
|
|
// Compute the cross-product of the two legs to get the area of the
|
|
// triangle
|
|
//-----------------------------------------------------------------
|
|
//
|
|
Vector3D vcp;
|
|
vcp.Cross(leg_1, leg_2);
|
|
|
|
//
|
|
//-------------------------------------------------------------------
|
|
// Add the three triangle points together and multiply by the area of
|
|
// the triangle to give a weighted sum for the polygon centroid
|
|
//-------------------------------------------------------------------
|
|
//
|
|
Point3D centroid;
|
|
centroid.Add(position_a, position_b);
|
|
centroid += position_c;
|
|
|
|
Scalar wedge_area = vcp.GetLength() * 0.5f;
|
|
|
|
if (area <= SMALL)
|
|
{
|
|
if (wedge_area > SMALL)
|
|
{
|
|
area += wedge_area;
|
|
centroid *= wedge_area;
|
|
}
|
|
center = centroid;
|
|
}
|
|
else
|
|
{
|
|
if (wedge_area > SMALL)
|
|
{
|
|
area += wedge_area;
|
|
centroid *= wedge_area;
|
|
center += centroid;
|
|
}
|
|
}
|
|
|
|
if(area > SMALL)
|
|
{
|
|
Point3D p0, p1, p2;
|
|
|
|
p0 = GetPoint(0);
|
|
p1 = GetPoint(2);
|
|
p2 = GetPoint(1);
|
|
Vector3D v1,v2;
|
|
v1.Subtract(p1, p0);
|
|
v2.Subtract(p2, p1);
|
|
|
|
Vector3D axis;
|
|
axis.Cross(v1, v2);
|
|
if(Small_Enough(axis.GetLength()))
|
|
{
|
|
area = 0.0f;
|
|
return false;
|
|
}
|
|
|
|
plane.normal = axis;
|
|
plane.offset = plane.normal * p0;
|
|
|
|
center *= (One_Over_Three/area);
|
|
|
|
if(plane.normal.y<=Stuff::SMALL)
|
|
{
|
|
area = 0.0f;
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
center *= One_Over_Three;
|
|
|
|
area = 0.0f;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
WaterPools::AddEdge(Stuff::Point3D& p0, Stuff::Point3D& p1, const
|
|
Stuff::Normal3D& normal)
|
|
{
|
|
int i, j;
|
|
Verify(p0.y==waterLevel);
|
|
Verify(p1.y==waterLevel);
|
|
|
|
int oe0 = OnWhatEdge(p0);
|
|
int oe1 = OnWhatEdge(p1);
|
|
|
|
if(Close_Enough(p0, p1, smaller))
|
|
{
|
|
return;
|
|
}
|
|
|
|
for(i=0;i<waterEdgePointCount;i++)
|
|
{
|
|
if(Close_Enough(waterEdgePoints[i].p, p0, smaller))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(i==waterEdgePointCount)
|
|
{
|
|
Verify(waterEdgePoints[waterEdgePointCount].toEdgeCount == 0);
|
|
waterEdgePoints[waterEdgePointCount].p = p0;
|
|
waterEdgePoints[waterEdgePointCount].toEdge[waterEdgePoints[waterEdgePointCount].toEdgeCount++]
|
|
= waterEdgeCount;
|
|
waterEdgePoints[waterEdgePointCount].onEdge = oe0;
|
|
|
|
waterEdgePointCount++;
|
|
}
|
|
else
|
|
{
|
|
Verify(waterEdgePoints[i].toEdgeCount < 8);
|
|
waterEdgePoints[i].toEdge[waterEdgePoints[i].toEdgeCount++] =
|
|
waterEdgeCount;
|
|
}
|
|
|
|
waterEdge[waterEdgeCount].p[0] = i;
|
|
|
|
for(j=0;j<waterEdgePointCount;j++)
|
|
{
|
|
if(Close_Enough(waterEdgePoints[j].p, p1, smaller))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(j==waterEdgePointCount)
|
|
{
|
|
Verify(waterEdgePoints[waterEdgePointCount].toEdgeCount == 0);
|
|
waterEdgePoints[waterEdgePointCount].p = p1;
|
|
waterEdgePoints[waterEdgePointCount].toEdge[waterEdgePoints[waterEdgePointCount].toEdgeCount++]
|
|
= waterEdgeCount;
|
|
waterEdgePoints[waterEdgePointCount].onEdge = oe1;
|
|
|
|
waterEdgePointCount++;
|
|
}
|
|
else
|
|
{
|
|
Verify(waterEdgePoints[j].toEdgeCount < 8);
|
|
waterEdgePoints[j].toEdge[waterEdgePoints[j].toEdgeCount++] =
|
|
waterEdgeCount;
|
|
}
|
|
|
|
waterEdge[waterEdgeCount].p[1] = j;
|
|
|
|
waterEdge[waterEdgeCount].normal = normal;
|
|
|
|
waterEdgeCount++;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MidLevelRenderer::MLRPrimitiveBase*
|
|
WaterPools::LinkEdges()
|
|
{
|
|
if(waterEdgePointCount==0)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
int i, j;
|
|
for(i=0;i<waterEdgePointCount;i++)
|
|
{
|
|
SPEW(("micgaert", "V%2d: %.12f %.12f", i, waterEdgePoints[i].p.x,
|
|
waterEdgePoints[i].p.z));
|
|
}
|
|
for(i=0;i<waterEdgeCount;i++)
|
|
{
|
|
SPEW(("micgaert", "E%2d: %d %d", i, waterEdge[i].p[0],
|
|
waterEdge[i].p[1]));
|
|
}
|
|
|
|
for(i=0;i<waterEdgePointCount;i++)
|
|
{
|
|
if(waterEdgePoints[i].toEdge[1] < 0 && waterEdgePoints[i].onEdge==0)
|
|
{
|
|
SPEW(("micgaert", "OH NO %d", i));
|
|
i = OnWhatEdge(waterEdgePoints[i]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
for(i=0;i<waterEdgePointCount;i++)
|
|
{
|
|
waterEdgePoints[i].used = false;
|
|
}
|
|
|
|
i = 0;
|
|
int pool = 1, edge = -1;
|
|
int usedPoints = 0;
|
|
bool island = false;
|
|
|
|
DynamicArrayOf<Point3D> polygon(2*waterEdgePointCount);
|
|
DynamicArrayOf<Normal3D> normals(2*waterEdgePointCount);
|
|
|
|
DynamicArrayOf<WaterEdgePoint> edgePoints[4];
|
|
int vertexCount;
|
|
// find the open pools
|
|
|
|
int edgePointCount[4] = { 0, 0, 0, 0};
|
|
int mask = 1;
|
|
for(j=0;j<4;j++)
|
|
{
|
|
edgePoints[j].SetLength(waterEdgePointCount);
|
|
for(i=0;i<waterEdgePointCount;i++)
|
|
{
|
|
if(waterEdgePoints[i].onEdge & mask && waterEdgePoints[i].toEdge[1]==-1)
|
|
{
|
|
edgePoints[j][edgePointCount[j]++] = waterEdgePoints[i];
|
|
}
|
|
}
|
|
mask <<= 1;
|
|
}
|
|
|
|
if(edgePointCount[0]>1)
|
|
{
|
|
for(i=edgePointCount[0]-1;i>=0;i--)
|
|
{
|
|
for(j=1;j<=i;j++)
|
|
{
|
|
if(edgePoints[0][j-1].p.z > edgePoints[0][j].p.z)
|
|
{
|
|
Swap(edgePoints[0][j-1], edgePoints[0][j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(edgePointCount[1]>1)
|
|
{
|
|
for(i=edgePointCount[1]-1;i>=0;i--)
|
|
{
|
|
for(j=1;j<=i;j++)
|
|
{
|
|
if(edgePoints[1][j-1].p.x > edgePoints[1][j].p.x)
|
|
{
|
|
Swap(edgePoints[1][j-1], edgePoints[1][j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(edgePointCount[2]>1)
|
|
{
|
|
for(i=edgePointCount[2]-1;i>=0;i--)
|
|
{
|
|
for(j=1;j<=i;j++)
|
|
{
|
|
if(edgePoints[2][j-1].p.z < edgePoints[2][j].p.z)
|
|
{
|
|
Swap(edgePoints[2][j-1], edgePoints[2][j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(edgePointCount[3]>1)
|
|
{
|
|
for(i=edgePointCount[3]-1;i>=0;i--)
|
|
{
|
|
for(j=1;j<=i;j++)
|
|
{
|
|
if(edgePoints[3][j-1].p.x < edgePoints[3][j].p.x)
|
|
{
|
|
Swap(edgePoints[3][j-1], edgePoints[3][j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(edgePointCount[0] + edgePointCount[1] + edgePointCount[2] +
|
|
edgePointCount[3] > 0)
|
|
|
|
do
|
|
{
|
|
for(i=0;i<waterEdgePointCount;i++)
|
|
{
|
|
if(waterEdgePoints[i].used == 0 && waterEdgePoints[i].toEdge[1]==-1)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if(i==waterEdgePointCount)
|
|
{
|
|
break;
|
|
}
|
|
|
|
vertexCount = 0;
|
|
|
|
int next;
|
|
do
|
|
{
|
|
while(waterEdgePoints[i].used == 0)
|
|
{
|
|
waterEdgePoints[i].used = pool;
|
|
usedPoints++;
|
|
polygon[vertexCount] = waterEdgePoints[i].p;
|
|
SPEW(("micgaert", "O: %6.1f %6.1f", polygon[vertexCount].x,
|
|
polygon[vertexCount].z));
|
|
|
|
if(waterEdgePoints[i].toEdge[0]==edge)
|
|
{
|
|
Verify(waterEdgePoints[i].toEdge[1]!=edge);
|
|
edge = waterEdgePoints[i].toEdge[1];
|
|
}
|
|
else
|
|
{
|
|
edge = waterEdgePoints[i].toEdge[0];
|
|
}
|
|
|
|
if(edge==-1)
|
|
{
|
|
normals[vertexCount++] = Normal3D::Down;
|
|
break;
|
|
}
|
|
normals[vertexCount++] = waterEdge[edge].normal;
|
|
|
|
if(waterEdge[edge].p[0] != i)
|
|
{
|
|
i = waterEdge[edge].p[0];
|
|
}
|
|
else
|
|
{
|
|
Verify(waterEdge[edge].p[1] != i);
|
|
i = waterEdge[edge].p[1];
|
|
}
|
|
if(i<0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// finding edges along the tile edge
|
|
|
|
int onWhatEdgeFirst = OnWhatEdge(polygon[0]);
|
|
int onWhatEdgeLast = OnWhatEdge(polygon[vertexCount-1]);
|
|
|
|
if(onWhatEdgeLast==0)
|
|
{
|
|
SPEW(("micgaert", "OH NO %d", edge));
|
|
}
|
|
|
|
mask = 1;
|
|
|
|
//
|
|
// i mask inD s nx nz ns
|
|
//
|
|
// 0 1 1 + 1 0 +
|
|
// 1 2 0 + 0 1 -
|
|
// 2 4 1 - 1 0 -
|
|
// 3 8 0 - 0 1 +
|
|
//
|
|
//
|
|
for(i=0;i<4;i++,mask<<=1)
|
|
{
|
|
if(onWhatEdgeLast & mask)
|
|
{
|
|
break;
|
|
Verify(edgePointCount[i] > 0);
|
|
}
|
|
}
|
|
// Verify(i<4);
|
|
|
|
bool cloakWise = false;
|
|
int edgePoint = -1;
|
|
|
|
if(i<4)
|
|
do
|
|
{
|
|
int sign = (i>1)?-1:1;
|
|
|
|
Scalar inDir[2];
|
|
Vector3D vx(1.0f, 0.0f, 0.0f);
|
|
inDir[0] = normals[vertexCount-2]*vx;
|
|
|
|
Vector3D vz(0.0f, 0.0f, 1.0f);
|
|
inDir[1] = normals[vertexCount-2]*vz;
|
|
|
|
cloakWise = sign*inDir[(i+1)&1]>0.0f;
|
|
|
|
if(polygon[vertexCount-1].x == x0 && polygon[vertexCount-1].z == z0)
|
|
{
|
|
edgePoint = 0;
|
|
Verify(((i==0)&&(cloakWise==true)) || ((i==3)&&(cloakWise==false)));
|
|
}
|
|
else
|
|
{
|
|
if(polygon[vertexCount-1].x == x0 && polygon[vertexCount-1].z == z1)
|
|
{
|
|
edgePoint = 1;
|
|
Verify(((i==1)&&(cloakWise==true)) || ((i==0)&&(cloakWise==false)));
|
|
}
|
|
else
|
|
{
|
|
if(polygon[vertexCount-1].x == x1 && polygon[vertexCount-1].z == z1)
|
|
{
|
|
edgePoint = 2;
|
|
Verify(((i==2)&&(cloakWise==true)) || ((i==1)&&(cloakWise==false)));
|
|
}
|
|
else
|
|
{
|
|
if(polygon[vertexCount-1].x == x1 && polygon[vertexCount-1].z == z0)
|
|
{
|
|
edgePoint = 3;
|
|
Verify(((i==3)&&(cloakWise==true)) || ((i==2)&&(cloakWise==false)));
|
|
}
|
|
else
|
|
{
|
|
edgePoint = -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
normals[vertexCount-1] = Normal3D(
|
|
(((i+3)&3)>1?1:-1)*((i+1)&1)*1.0f,
|
|
0.0f,
|
|
(((i+3)&3)>1?1:-1)*(i&1)*1.0f
|
|
);
|
|
Verify(Close_Enough(normals[vertexCount-1].GetLengthSquared(), 1.0f));
|
|
|
|
Verify(mask & onWhatEdgeLast);
|
|
|
|
int same = -1;
|
|
if(edgePointCount[i]>0)
|
|
{
|
|
for(j=0;j<edgePointCount[i];j++)
|
|
{
|
|
if(Close_Enough(polygon[vertexCount-1], edgePoints[i][j].p, smaller))
|
|
{
|
|
same = j;
|
|
break;
|
|
}
|
|
|
|
|
|
}
|
|
if(j<edgePointCount[i])
|
|
{
|
|
}
|
|
else
|
|
{
|
|
Verify(edgePoint>=0);
|
|
next = cloakWise? 0 : edgePointCount[i]-1;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
}
|
|
|
|
if(edgePointCount[i]==0)
|
|
{
|
|
}
|
|
|
|
bool allOurs = j==edgePointCount[i];
|
|
|
|
|
|
// SPEW(("micgaert", "%d %f %f: %.1f %.1f %.1f",
|
|
// onWhatEdgeLast, inDir[0], inDir[1],
|
|
// normals[vertexCount-1].x, normals[vertexCount-1].y,
|
|
// normals[vertexCount-1].z
|
|
// ));
|
|
|
|
int whereTo = 0;
|
|
Point3D newPoint;
|
|
if(sign*inDir[(i+1)&1] > 0.0f)
|
|
{
|
|
if(j>=edgePointCount[i]-1)
|
|
{
|
|
newPoint = Point3D(
|
|
(i==0) ? x0 :
|
|
(i==1) ? (inDir[0]>0.0)? x1:x0 :
|
|
(i==2) ? x1 : (inDir[0]>0.0)? x1:x0,
|
|
|
|
waterLevel,
|
|
(i==0) ? (inDir[1]>0.0)? z1:z0 :
|
|
(i==1) ? z1 :
|
|
(i==2) ? (inDir[1]>0.0)? z1:z0 : z0
|
|
);
|
|
SPEW(("micgaert", "O: %6.1f %6.1f", newPoint.x, newPoint.z));
|
|
|
|
int k;
|
|
for(k=0;k<vertexCount;k++)
|
|
{
|
|
if(Close_Enough(polygon[k], newPoint, smaller))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
Verify(k==vertexCount);
|
|
polygon[vertexCount++] = newPoint;
|
|
onWhatEdgeLast = OnWhatEdge(polygon[vertexCount-1]);
|
|
}
|
|
else
|
|
{
|
|
next = j+1;
|
|
Verify(next<edgePointCount[i]);
|
|
break;
|
|
}
|
|
whereTo = 1;
|
|
mask<<=1;
|
|
if(mask>8)
|
|
{
|
|
mask = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(j==0 || j>=edgePointCount[i])
|
|
{
|
|
newPoint = Point3D(
|
|
(i==0) ? x0 :
|
|
(i==1) ? (inDir[0]>0.0)? x1:x0 :
|
|
(i==2) ? x1 : (inDir[0]>0.0)? x1:x0,
|
|
|
|
waterLevel,
|
|
(i==0) ? (inDir[1]>0.0)? z1:z0 :
|
|
(i==1) ? z1 :
|
|
(i==2) ? (inDir[1]>0.0)? z1:z0 : z0
|
|
);
|
|
|
|
SPEW(("micgaert", "O: %6.1f %6.1f", newPoint.x, newPoint.z));
|
|
|
|
int k;
|
|
for(k=0;k<vertexCount;k++)
|
|
{
|
|
if(Close_Enough(polygon[k], newPoint, smaller))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
Verify(k==vertexCount);
|
|
polygon[vertexCount++] = newPoint;
|
|
onWhatEdgeLast = OnWhatEdge(polygon[vertexCount-1]);
|
|
}
|
|
else
|
|
{
|
|
next = j-1;
|
|
Verify(next<edgePointCount[i]);
|
|
break;
|
|
}
|
|
whereTo = -1;
|
|
mask>>=1;
|
|
if(mask<=0)
|
|
{
|
|
mask = 8;
|
|
}
|
|
}
|
|
Verify(mask>0 && mask<16);
|
|
Verify(onWhatEdgeLast!=0);
|
|
|
|
i = (i+4+whereTo)&3;
|
|
} while(1);
|
|
|
|
int hello;
|
|
for(hello=0;hello<waterEdgePointCount;hello++)
|
|
{
|
|
if(Close_Enough(waterEdgePoints[hello].p, edgePoints[i][next].p,
|
|
smaller))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(waterEdgePoints[hello].used>0)
|
|
{
|
|
Verify(waterEdgePoints[hello].toEdge[1]==-1);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
Verify(hello<waterEdgePointCount);
|
|
i = hello;
|
|
};
|
|
} while (1);
|
|
|
|
// Verify(vertexCount>2);
|
|
|
|
pool++;
|
|
|
|
|
|
int j, up=0, down=0;
|
|
int upVC=0, downVC=0;
|
|
int bigA = -1;
|
|
Scalar axisL = 1000000.0f ;
|
|
for(j=0;j<vertexCount;j++)
|
|
{
|
|
if(daWaterObj!=NULL && vertexCount>2)
|
|
{
|
|
fprintf(daWaterObj, "v %.5f %.5f %.5f\n", polygon[j].x, waterLevel,
|
|
polygon[j].z);
|
|
}
|
|
|
|
int next = (j+1)%vertexCount;
|
|
|
|
Normal3D n(normals[j]);
|
|
n.y = 0.0f;
|
|
n.Normalize(n);
|
|
|
|
Vector3D v;
|
|
v.Cross(normals[j], normals[next]);
|
|
|
|
Scalar l = v.GetLengthSquared();
|
|
|
|
if(l>0.0f)
|
|
{
|
|
up++;
|
|
if(l<axisL)
|
|
{
|
|
bigA = j;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
down++;
|
|
}
|
|
|
|
v.Cross(polygon[j], polygon[next], polygon[(j+2)%vertexCount]);
|
|
|
|
if(v.y>0.0f)
|
|
{
|
|
upVC++;
|
|
}
|
|
else
|
|
{
|
|
downVC++;
|
|
}
|
|
}
|
|
if(daWaterObj!=NULL && vertexCount>2)
|
|
{
|
|
fprintf(daWaterObj, "f");
|
|
if(upVC>downVC)
|
|
{
|
|
for(j=0;j<vertexCount;j++)
|
|
{
|
|
fprintf(daWaterObj, " %d", j+vertexCountObj);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(j=vertexCount-1;j>=0;j--)
|
|
{
|
|
fprintf(daWaterObj, " %d", j+vertexCountObj);
|
|
}
|
|
}
|
|
fprintf(daWaterObj, "\n\n");
|
|
vertexCountObj += vertexCount;
|
|
}
|
|
|
|
SPEW(("micgaert", "==="));
|
|
// SPEW(("micgaert", "%d %d", up, down));
|
|
|
|
/* if(down==0)
|
|
{
|
|
for(j=0;j<vertexCount;j++)
|
|
{
|
|
(*coords)[cCount+j] = polygon[(j+bigA)%vertexCount];
|
|
(*index)[cCount+j] = cCount+j;
|
|
}
|
|
|
|
(*lengths)[pCount++] = vertexCount;
|
|
|
|
cCount += j;
|
|
}
|
|
*/
|
|
} while(usedPoints < waterEdgePointCount);
|
|
|
|
// find the closed pools
|
|
if(usedPoints < waterEdgePointCount)
|
|
{
|
|
do
|
|
{
|
|
for(i=0;i<waterEdgePointCount;i++)
|
|
{
|
|
if(waterEdgePoints[i].used == 0 && waterEdgePoints[i].toEdge[1]>=0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if(i==waterEdgePointCount)
|
|
{
|
|
break;
|
|
}
|
|
|
|
vertexCount = 0;
|
|
while(waterEdgePoints[i].used == 0)
|
|
{
|
|
waterEdgePoints[i].used = pool;
|
|
usedPoints++;
|
|
polygon[vertexCount] = waterEdgePoints[i].p;
|
|
|
|
if(waterEdgePoints[i].toEdge[0]==edge)
|
|
{
|
|
Verify(waterEdgePoints[i].toEdge[1]!=edge);
|
|
edge = waterEdgePoints[i].toEdge[1];
|
|
}
|
|
else
|
|
{
|
|
edge = waterEdgePoints[i].toEdge[0];
|
|
}
|
|
|
|
if(edge==-1)
|
|
{
|
|
normals[vertexCount++] = Normal3D::Down;
|
|
break;
|
|
}
|
|
normals[vertexCount++] = waterEdge[edge].normal;
|
|
|
|
if(waterEdge[edge].p[0] != i)
|
|
{
|
|
i = waterEdge[edge].p[0];
|
|
}
|
|
else
|
|
{
|
|
Verify(waterEdge[edge].p[1] != i);
|
|
i = waterEdge[edge].p[1];
|
|
}
|
|
if(i<0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
pool++;
|
|
|
|
// island or pool
|
|
Verify(vertexCount>2);
|
|
|
|
int j, up=0, down=0;
|
|
int upVC=0, downVC=0;
|
|
int bigA = -1;
|
|
Scalar axisL = 1000000.0f ;
|
|
|
|
for(j=0;j<vertexCount;j++)
|
|
{
|
|
if(daWaterObj!=NULL)
|
|
{
|
|
fprintf(daWaterObj, "v %.5f %.5f %.5f\n", polygon[j].x, waterLevel,
|
|
polygon[j].z);
|
|
}
|
|
|
|
int next = (j+1)%vertexCount;
|
|
|
|
Normal3D n(normals[j]);
|
|
n.y = 0.0f;
|
|
n.Normalize(n);
|
|
|
|
SPEW(("micgaert", "C: %6.1f %6.1f %6.1f %6.1f", polygon[j].x,
|
|
polygon[j].z, n.x, n.z));
|
|
|
|
Vector3D v;
|
|
v.Cross(normals[j], normals[next]);
|
|
|
|
Scalar l = v.GetLengthSquared();
|
|
|
|
if(l>0.0f)
|
|
{
|
|
up++;
|
|
if(l<axisL)
|
|
{
|
|
bigA = j;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
down++;
|
|
}
|
|
|
|
v.Cross(polygon[j], polygon[next], polygon[(j+2)%vertexCount]);
|
|
|
|
if(v.y>0.0f)
|
|
{
|
|
upVC++;
|
|
}
|
|
else
|
|
{
|
|
downVC++;
|
|
}
|
|
}
|
|
SPEW(("micgaert", "==="));
|
|
// SPEW(("micgaert", "%d %d", up, down));
|
|
|
|
/* if(down==0)
|
|
{
|
|
|
|
for(j=0;j<vertexCount;j++)
|
|
{
|
|
(*coords)[cCount+j] = polygon[(j+bigA)%vertexCount];
|
|
(*index)[cCount+j] = cCount+j;
|
|
}
|
|
|
|
(*lengths)[pCount++] = vertexCount;
|
|
|
|
cCount += j;
|
|
}
|
|
*/
|
|
if(daWaterObj!=NULL)
|
|
{
|
|
fprintf(daWaterObj, "f");
|
|
|
|
if(upVC>downVC)
|
|
{
|
|
for(j=0;j<vertexCount;j++)
|
|
{
|
|
fprintf(daWaterObj, " %d", j+vertexCountObj);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(j=vertexCount-1;j>=0;j--)
|
|
{
|
|
fprintf(daWaterObj, " %d", j+vertexCountObj);
|
|
}
|
|
}
|
|
fprintf(daWaterObj, "\n\n");
|
|
vertexCountObj += vertexCount;
|
|
}
|
|
|
|
} while(usedPoints < waterEdgePointCount);
|
|
}
|
|
SPEW(("micgaert", "==="));
|
|
Verify(usedPoints == waterEdgePointCount);
|
|
return NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
WaterPools::OnWhatEdge(WaterEdgePoint& wep)
|
|
{
|
|
return OnWhatEdge(wep.p);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int
|
|
WaterPools::OnWhatEdge(Point3D& p)
|
|
{
|
|
int onWhatEdge = 0;
|
|
if(Close_Enough(p.x, x0, 100.0f*smaller))
|
|
{
|
|
Verify(!Close_Enough(p.x, x1, 100.0f*smaller));
|
|
p.x = x0;
|
|
onWhatEdge |= 1;
|
|
}
|
|
else
|
|
{
|
|
if(Close_Enough(p.x, x1, 100.0f*smaller))
|
|
{
|
|
p.x = x1;
|
|
onWhatEdge |= 4;
|
|
}
|
|
}
|
|
if(Close_Enough(p.z, z0, 100.0f*smaller))
|
|
{
|
|
Verify(!Close_Enough(p.z, z1, 100.0f*smaller));
|
|
p.z = z0;
|
|
onWhatEdge |= 8;
|
|
}
|
|
else
|
|
{
|
|
if(Close_Enough(p.z, z1, 100.0f*smaller))
|
|
{
|
|
p.z = z1;
|
|
onWhatEdge |= 2;
|
|
}
|
|
}
|
|
|
|
return onWhatEdge;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
HFSlimMZ::HFSlimMZ()
|
|
{
|
|
X = (int)0.0f;
|
|
Z = (int)0.0f;
|
|
|
|
dX = 2.0f;
|
|
dY = 0.15f;
|
|
dZ = 2.0f;
|
|
|
|
Offset = 0.0f;
|
|
visHeight = 0;
|
|
|
|
simpleTerrainGroup.SetLength(0);
|
|
waterGroup.SetLength(0);
|
|
|
|
borderPixelFun = 0.0f;
|
|
|
|
waterTextureName = NULL;
|
|
waterTextureRatio = 4.0f;
|
|
waterMovieFrames = 1;
|
|
waterDetailMovieFrames = 1;
|
|
|
|
xCenterOffset = 0.0f;
|
|
zCenterOffset = 0.0f;
|
|
|
|
culturalFadeIn = 50.0f;
|
|
culturalFadeOut = 80.0f;
|
|
|
|
interestData = NULL;
|
|
|
|
mesh = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
HFSlimMZ::~HFSlimMZ()
|
|
{
|
|
for(int i=0;i<simpleTerrainGroup.GetLength();i++)
|
|
{
|
|
Unregister_Object(simpleTerrainGroup[i]);
|
|
delete simpleTerrainGroup[i];
|
|
simpleTerrainGroup[i] = NULL;
|
|
|
|
Unregister_Object(waterGroup[i]);
|
|
delete waterGroup[i];
|
|
waterGroup[i] = NULL;
|
|
}
|
|
simpleTerrainGroup.SetLength(0);
|
|
waterGroup.SetLength(0);
|
|
|
|
interestData.SetLength(0);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Stuff::ExtentBox
|
|
HFSlimMZ::GetExtents()
|
|
{
|
|
Stuff::ExtentBox ebox;
|
|
|
|
ebox.minX = GetX(0);
|
|
ebox.minZ = GetZ(0);
|
|
|
|
// ebox.maxX = GetX(X-1);
|
|
// ebox.maxZ = GetZ(Z-1);
|
|
|
|
ebox.maxX = GetX(xDim*256-1);
|
|
ebox.maxZ = GetZ(zDim*256-1);
|
|
|
|
int i, j;
|
|
Scalar h;
|
|
ebox.maxY = ebox.minY = GetHeight(0, 0);
|
|
|
|
for (j=1;j<Z;j++)
|
|
for (i=1;i<X;i++)
|
|
{
|
|
h = GetHeight(i, j);
|
|
if(ebox.maxY < h)
|
|
{
|
|
ebox.maxY = h;
|
|
}
|
|
if(ebox.minY > h)
|
|
{
|
|
ebox.minY = h;
|
|
}
|
|
}
|
|
|
|
return ebox;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
void
|
|
HFSlimMZ::Blur2D (int smooth)
|
|
{
|
|
|
|
// Precondition for stability: 0 < scale < exp(0.25)
|
|
// Good choice for iterative blurring is scale = exp(0.125)
|
|
float scale = static_cast<float>(exp(0.125));
|
|
float** temp = new float*[Z];
|
|
int x, y;
|
|
for (y = 0; y < Z; y++)
|
|
temp[y] = new float[X];
|
|
|
|
for(int i=0;i<smooth;i++)
|
|
{
|
|
float logscale = float(log(scale));
|
|
|
|
for (y = 0; y < Z; y++)
|
|
{
|
|
float ryp = y+scale, rym = y-scale;
|
|
int yp = (int) floor(ryp), ym = (int) ceil(rym);
|
|
|
|
for (x = 0; x < X; x++)
|
|
{
|
|
float rxp = x+scale, rxm = x-scale;
|
|
int xp = (int) floor(rxp), xm = (int) ceil(rxm);
|
|
|
|
// x portion of second central difference
|
|
float xsum = -2*field[y*X+x];
|
|
if ( xp >= X-1 ) // use boundary value
|
|
xsum += field[y*X+X-1];
|
|
else // linearly interpolate
|
|
xsum += field[y*X+xp]+(rxp-xp)*(field[y*X+xp+1]-field[y*X+xp]);
|
|
if ( xm <= 0 ) // use boundary value
|
|
xsum += field[y*X+0];
|
|
else // linearly interpolate
|
|
xsum += field[y*X+xm]+(rxm-xm)*(field[y*X+xm]-field[y*X+xm-1]);
|
|
|
|
// y portion of second central difference
|
|
float ysum = -2*field[y*X+x];
|
|
if ( yp >= Z-1 ) // use boundary value
|
|
ysum += field[(Z-1)*X+x];
|
|
else // linearly interpolate
|
|
ysum += field[yp*X+x]+(ryp-yp)*(field[(yp+1)*X+x]-field[yp*X+x]);
|
|
if ( ym <= 0 ) // use boundary value
|
|
ysum += field[0*X+x];
|
|
else // linearly interpolate
|
|
ysum += field[ym*X+x]+(rym-ym)*(field[ym*X+x]-field[(ym-1)*X+x]);
|
|
|
|
temp[y][x] = field[y*X+x]+logscale*(xsum+ysum);
|
|
}
|
|
}
|
|
|
|
for (y = 0; y < Z; y++)
|
|
for (x = 0; x < X; x++)
|
|
field[y*X+x] = temp[y][x];
|
|
}
|
|
|
|
for (y = 0; y < Z; y++)
|
|
delete[] temp[y];
|
|
delete[] temp;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
HFSlimMZ::FillFromImage(Image &image, int smooth)
|
|
{
|
|
Verify(image.GetBpp()==8);
|
|
|
|
int
|
|
imgX = image.GetWidth(),
|
|
imgZ = image.GetHeight();
|
|
|
|
if((imgX%256 != 0) || (imgZ%256 != 0))
|
|
{
|
|
if(silentMode==true)
|
|
{
|
|
fprintf(stderr, "Image width and height has to be a multiple of 256. Program exits !\n");
|
|
exit(-1);
|
|
}
|
|
else
|
|
{
|
|
STOP(("Image width and height has to be a multiple of 256"));
|
|
}
|
|
}
|
|
|
|
xDim = imgX/256;
|
|
zDim = imgZ/256;
|
|
|
|
int xb = 0, zb = 0;
|
|
if(!IsPowerOf2(xDim) && xDim!=1)
|
|
{
|
|
xb = 2*( (xDim/2) + ((xDim%2) ? 1 : 0));
|
|
}
|
|
else
|
|
{
|
|
xb = xDim;
|
|
}
|
|
|
|
if(!IsPowerOf2(zDim) && zDim!=1)
|
|
{
|
|
zb = 2*( (zDim/2) + ((zDim%2) ? 1 : 0));
|
|
}
|
|
else
|
|
{
|
|
zb = zDim;
|
|
}
|
|
|
|
if(xb>zb)
|
|
{
|
|
X = xb*256 + 1;
|
|
Z = xb*256 + 1;
|
|
}
|
|
else
|
|
{
|
|
X = zb*256 + 1;
|
|
Z = zb*256 + 1;
|
|
}
|
|
|
|
Xoffset = (xb>xDim) ? 256 : 0;
|
|
Zoffset = (zb>zDim) ? 256 : 0;
|
|
|
|
field.SetLength(X*Z);
|
|
|
|
BYTE *ptr;
|
|
ptr = (BYTE *)image.Lock();
|
|
|
|
int i, j;
|
|
BYTE c;
|
|
|
|
#if 1
|
|
for(i=0;i<imgZ;i++)
|
|
{
|
|
for(j=0;j<imgX;j++)
|
|
{
|
|
field[(i+Zoffset)*X+j+Xoffset] = ptr[(imgZ-i-1)*imgX + imgX-j-1];
|
|
}
|
|
}
|
|
|
|
//============== filling in the corners ====================
|
|
c = ptr[(imgZ-1)*imgX + imgX-1];
|
|
for(i=0;i<Zoffset;i++)
|
|
{
|
|
for(j=0;j<Xoffset;j++)
|
|
{
|
|
field[i*X+j] = c;
|
|
}
|
|
}
|
|
c = ptr[(imgZ-1)*imgX + 0];
|
|
for(i=0;i<Zoffset;i++)
|
|
{
|
|
for(j=Xoffset+imgX;j<X;j++)
|
|
{
|
|
field[i*X+j] = c;
|
|
}
|
|
}
|
|
c = ptr[imgX-1];
|
|
for(i=Zoffset+imgZ;i<Z;i++)
|
|
{
|
|
for(j=0;j<Xoffset;j++)
|
|
{
|
|
field[i*X+j] = c;
|
|
}
|
|
}
|
|
c = ptr[0];
|
|
for(i=Zoffset+imgZ;i<Z;i++)
|
|
{
|
|
for(j=Xoffset+imgX;j<X;j++)
|
|
{
|
|
field[i*X+j] = c;
|
|
}
|
|
}
|
|
|
|
//============== filling in the sides ====================
|
|
for(i=Zoffset;i<Zoffset+imgZ;i++)
|
|
{
|
|
c = ptr[(imgZ-1-i+Zoffset)*imgX + imgX-1];
|
|
for(j=0;j<Xoffset;j++)
|
|
{
|
|
field[i*X+j] = c;
|
|
}
|
|
}
|
|
for(j=Xoffset;j<Xoffset+imgX;j++)
|
|
{
|
|
c = ptr[(imgZ-1)*imgX + imgX-1-j+Xoffset];
|
|
for(i=0;i<Zoffset;i++)
|
|
{
|
|
field[i*X+j] = c;
|
|
}
|
|
}
|
|
for(i=Zoffset;i<Zoffset+imgZ;i++)
|
|
{
|
|
c = ptr[(imgZ-1-i+Zoffset)*imgX];
|
|
for(j=Xoffset+imgX;j<X;j++)
|
|
{
|
|
field[i*X+j] = c;
|
|
}
|
|
}
|
|
for(j=Xoffset;j<Xoffset+imgX;j++)
|
|
{
|
|
c = ptr[imgX-1-j+Xoffset];
|
|
for(i=Zoffset+imgZ;i<Z;i++)
|
|
{
|
|
field[i*X+j] = c;
|
|
}
|
|
}
|
|
#else
|
|
for(i=0;i<Z-1;i++)
|
|
{
|
|
for(j=0;j<X-1;j++)
|
|
{
|
|
field[i*X+j] = ptr[(image.GetHeight()-i-1)*(X-1)+image.GetWidth()-j-1];
|
|
}
|
|
field[i*X+j] = field[i*X+j-1];
|
|
}
|
|
for(j=0;j<X-1;j++)
|
|
{
|
|
field[i*X+j] = field[(i-1)*X+j];
|
|
}
|
|
field[i*X+j] = field[i*X+j-1];
|
|
#endif
|
|
|
|
image.UnLock();
|
|
|
|
Blur2D(smooth);
|
|
/*
|
|
Image testImage(X, Z, ITYPE_INDEXED);;
|
|
testImage.MakeGrayscalePalette();
|
|
ptr = testImage.Lock();
|
|
|
|
for(i=0;i<X*Z;i++)
|
|
{
|
|
ptr[i] = field[i];
|
|
}
|
|
testImage.UnLock();
|
|
testImage.SaveGif("c:\\test1.gif");
|
|
*/
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
HFSlimMZ::FillInterestDataFromImage(Image &image)
|
|
{
|
|
Verify(image.GetBpp()>8);
|
|
|
|
int
|
|
imgX = image.GetWidth(),
|
|
imgZ = image.GetHeight();
|
|
|
|
if((imgX%256 != 0) || (imgZ%256 != 0))
|
|
{
|
|
if(silentMode==true)
|
|
{
|
|
fprintf(stderr, "Interest data image width and height has to be a multiple of 256. Program exits !\n");
|
|
exit(-1);
|
|
}
|
|
else
|
|
{
|
|
STOP(("Interest data image width and height has to be a multiple of 256"));
|
|
}
|
|
}
|
|
|
|
xDim = imgX/256;
|
|
zDim = imgZ/256;
|
|
|
|
int xb = 0, zb = 0;
|
|
if(!IsPowerOf2(xDim) && xDim!=1)
|
|
{
|
|
xb = 2*( (xDim/2) + ((xDim%2) ? 1 : 0));
|
|
}
|
|
else
|
|
{
|
|
xb = xDim;
|
|
}
|
|
|
|
if(!IsPowerOf2(zDim) && zDim!=1)
|
|
{
|
|
zb = 2*( (zDim/2) + ((zDim%2) ? 1 : 0));
|
|
}
|
|
else
|
|
{
|
|
zb = zDim;
|
|
}
|
|
|
|
if(xb>zb)
|
|
{
|
|
X = xb*256 + 1;
|
|
Z = xb*256 + 1;
|
|
}
|
|
else
|
|
{
|
|
X = zb*256 + 1;
|
|
Z = zb*256 + 1;
|
|
}
|
|
|
|
Xoffset = (xb>xDim) ? 256 : 0;
|
|
Zoffset = (zb>zDim) ? 256 : 0;
|
|
|
|
interestData.SetLength(X*Z);
|
|
|
|
BYTE *ptr;
|
|
ptr = (BYTE *)image.Lock();
|
|
|
|
int i, j;
|
|
BYTE c;
|
|
int cd = image.GetBpp()>>3;
|
|
|
|
#if 1
|
|
for(i=0;i<imgZ;i++)
|
|
{
|
|
for(j=0;j<imgX;j++)
|
|
{
|
|
interestData[(i+Zoffset)*X+j+Xoffset] = ptr[cd*((imgZ-i-1)*imgX +
|
|
imgX-j-1)+1];
|
|
}
|
|
}
|
|
|
|
//============== filling in the corners ====================
|
|
c = ptr[cd*((imgZ-1)*imgX + imgX-1)+1];
|
|
for(i=0;i<Zoffset;i++)
|
|
{
|
|
for(j=0;j<Xoffset;j++)
|
|
{
|
|
interestData[i*X+j] = c;
|
|
}
|
|
}
|
|
c = ptr[cd*((imgZ-1)*imgX + 0)+1];
|
|
for(i=0;i<Zoffset;i++)
|
|
{
|
|
for(j=Xoffset+imgX;j<X;j++)
|
|
{
|
|
interestData[i*X+j] = c;
|
|
}
|
|
}
|
|
c = ptr[cd*(imgX-1)+1];
|
|
for(i=Zoffset+imgZ;i<Z;i++)
|
|
{
|
|
for(j=0;j<Xoffset;j++)
|
|
{
|
|
interestData[i*X+j] = c;
|
|
}
|
|
}
|
|
c = ptr[cd*(0)+1];
|
|
for(i=Zoffset+imgZ;i<Z;i++)
|
|
{
|
|
for(j=Xoffset+imgX;j<X;j++)
|
|
{
|
|
interestData[i*X+j] = c;
|
|
}
|
|
}
|
|
|
|
//============== filling in the sides ====================
|
|
for(i=Zoffset;i<Zoffset+imgZ;i++)
|
|
{
|
|
c = ptr[cd*((imgZ-1-i+Zoffset)*imgX + imgX-1)+1];
|
|
for(j=0;j<Xoffset;j++)
|
|
{
|
|
interestData[i*X+j] = c;
|
|
}
|
|
}
|
|
for(j=Xoffset;j<Xoffset+imgX;j++)
|
|
{
|
|
c = ptr[cd*((imgZ-1)*imgX + imgX-1-j+Xoffset)+1];
|
|
for(i=0;i<Zoffset;i++)
|
|
{
|
|
interestData[i*X+j] = c;
|
|
}
|
|
}
|
|
for(i=Zoffset;i<Zoffset+imgZ;i++)
|
|
{
|
|
c = ptr[cd*((imgZ-1-i+Zoffset)*imgX)+1];
|
|
for(j=Xoffset+imgX;j<X;j++)
|
|
{
|
|
interestData[i*X+j] = c;
|
|
}
|
|
}
|
|
for(j=Xoffset;j<Xoffset+imgX;j++)
|
|
{
|
|
c = ptr[cd*(imgX-1-j+Xoffset)+1];
|
|
for(i=Zoffset+imgZ;i<Z;i++)
|
|
{
|
|
interestData[i*X+j] = c;
|
|
}
|
|
}
|
|
#else
|
|
for(i=0;i<Z-1;i++)
|
|
{
|
|
for(j=0;j<X-1;j++)
|
|
{
|
|
interestData[i*X+j] =
|
|
ptr[cd*((image.GetHeight()-i-1)*(X-1)+image.GetWidth()-j-1];
|
|
}
|
|
interestData[i*X+j] = interestData[i*X+j-1];
|
|
}
|
|
for(j=0;j<X-1;j++)
|
|
{
|
|
interestData[i*X+j] = interestData[(i-1)*X+j];
|
|
}
|
|
interestData[i*X+j] = interestData[i*X+j-1];
|
|
#endif
|
|
|
|
image.UnLock();
|
|
/*
|
|
Image testImage(X, Z, ITYPE_INDEXED);;
|
|
testImage.MakeGrayscalePalette();
|
|
ptr = testImage.Lock();
|
|
|
|
for(i=0;i<X*Z;i++)
|
|
{
|
|
ptr[i] = interestData[i];
|
|
}
|
|
testImage.UnLock();
|
|
testImage.SaveGif("c:\\test_id.gif");
|
|
*/
|
|
}
|
|
|
|
int triangleCounter = 0;
|
|
|
|
Scalar xGridSize, zGridSize;
|
|
int tX, tY;
|
|
|
|
void GetFacesCB(Triangle &tri,void *cbp)
|
|
{
|
|
ToDrawTriangle *tdtrilist = (ToDrawTriangle *)cbp;
|
|
tdtrilist[triangleCounter].SetPoint(0,(float)tri.point1()[0],0.0f,(float)tri.point1()[1]);
|
|
tdtrilist[triangleCounter].SetPoint(1,(float)tri.point2()[0],0.0f,(float)tri.point2()[1]);
|
|
tdtrilist[triangleCounter].SetPoint(2,(float)tri.point3()[0],0.0f,(float)tri.point3()[1]);
|
|
|
|
triangleCounter++;
|
|
}
|
|
|
|
void GetFacesCBPrecise(Triangle &tri, void*)
|
|
{
|
|
Point3D point;
|
|
|
|
point.x = (float)tri.point1()[0];
|
|
point.y = 0.0f;
|
|
point.z = (float)tri.point1()[1];
|
|
|
|
triangleIndices[usedTriangleIndices].v[0] = FindAddPoint(point);
|
|
|
|
point.x = (float)tri.point3()[0];
|
|
point.y = 0.0f;
|
|
point.z = (float)tri.point3()[1];
|
|
|
|
triangleIndices[usedTriangleIndices].v[2] = FindAddPoint(point);
|
|
|
|
point.x = (float)tri.point2()[0];
|
|
point.y = 0.0f;
|
|
point.z = (float)tri.point2()[1];
|
|
|
|
triangleIndices[usedTriangleIndices].v[1] = FindAddPoint(point);
|
|
|
|
usedTriangleIndices++;
|
|
}
|
|
|
|
#define TERRAIN2_TEST
|
|
|
|
bool
|
|
HFSlimMZ::CreateMesh(
|
|
ElementRenderer::ListElement *parent,
|
|
int listIndex,
|
|
int diffLevel,
|
|
DynamicArrayOf<TriangleAbstract*>& tdtrilist,
|
|
frameArray *frame,
|
|
MLRState *state
|
|
)
|
|
{
|
|
int polygon_count = tdtrilist.GetLength();
|
|
if(polygon_count==0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
gos_PushCurrentHeap(MLR_Terrain2::PrimitiveHeap);
|
|
MLR_Terrain2 *erf_mesh = new MLR_Terrain2;
|
|
gos_PopCurrentHeap();
|
|
|
|
erf_mesh->SetDepthData(maxAllDepth-diffLevel, maxAllDepth);
|
|
erf_mesh->SetTileData(tX, tY);
|
|
#ifdef BORDERPIXEL
|
|
erf_mesh->SetBorderPixel(borderPixelFun);
|
|
#endif
|
|
|
|
// erf_mesh->SetOffset(xOffset, zOffset);
|
|
// erf_mesh->SetGrid(xGridSize, zGridSize);
|
|
for(int ii=0;ii<8;ii++)
|
|
{
|
|
erf_mesh->SetFrame(
|
|
ii,
|
|
(*frame)[ii][0] - xCenterOffset - Xoffset*dX,
|
|
(*frame)[ii][1] - zCenterOffset - Zoffset*dZ,
|
|
(*frame)[ii][2] - xCenterOffset - Xoffset*dX,
|
|
(*frame)[ii][3] - zCenterOffset - Zoffset*dZ
|
|
);
|
|
}
|
|
|
|
Register_Object(erf_mesh);
|
|
|
|
erf_mesh->SetDetailData(
|
|
detailInfo.xOff,
|
|
detailInfo.zOff,
|
|
detailInfo.xFac*(1<<diffLevel),
|
|
detailInfo.zFac*(1<<diffLevel),
|
|
detailInfo.dStart,
|
|
detailInfo.dEnd
|
|
);
|
|
|
|
DynamicArrayOf<int> vert_id(X*Z);
|
|
memset(vert_id.GetData(), 0, vert_id.GetSize());
|
|
|
|
int i, j, x, z, point_count = 0;
|
|
|
|
int minX[2]={0,0},
|
|
maxX[2]={0,0},
|
|
minY[2]={0,0},
|
|
maxY[2]={0,0},
|
|
minZ[2]={0,0},
|
|
maxZ[2]={0,0};
|
|
Scalar
|
|
minx=tdtrilist[0]->GetPoint(0).x,
|
|
maxx=tdtrilist[0]->GetPoint(0).x,
|
|
miny=tdtrilist[0]->GetPoint(0).y,
|
|
maxy=tdtrilist[0]->GetPoint(0).y,
|
|
minz=tdtrilist[0]->GetPoint(0).z,
|
|
maxz=tdtrilist[0]->GetPoint(0).z;
|
|
|
|
Point3D
|
|
center0 = Point3D::Identity,
|
|
center1 = Point3D::Identity,
|
|
center2 = Point3D::Identity,
|
|
center3 = Point3D::Identity;
|
|
|
|
for(i=0;i<polygon_count;++i)
|
|
{
|
|
if(tdtrilist[i]->centerValid==false)
|
|
{
|
|
SPEWALWAYS(("micgaert", "Found invalid center!"));
|
|
if(false==tdtrilist[i]->GetSurfaceAreaAndCentroid())
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
center3 += tdtrilist[i]->center;
|
|
|
|
if(tdtrilist[i]->GetPoint(0).x < minx)
|
|
{
|
|
minX[0] = i;
|
|
minX[1] = 0;
|
|
minx = tdtrilist[i]->GetPoint(0).x;
|
|
} else if(tdtrilist[i]->GetPoint(0).x > maxx)
|
|
{
|
|
maxX[0] = i;
|
|
maxX[1] = 0;
|
|
maxx = tdtrilist[i]->GetPoint(0).x;
|
|
}
|
|
if(tdtrilist[i]->GetPoint(0).y < miny)
|
|
{
|
|
minY[0] = i;
|
|
minY[1] = 0;
|
|
miny = tdtrilist[i]->GetPoint(0).y;
|
|
} else if(tdtrilist[i]->GetPoint(0).y > maxy)
|
|
{
|
|
maxY[0] = i;
|
|
maxY[1] = 0;
|
|
maxy = tdtrilist[i]->GetPoint(0).y;
|
|
}
|
|
if(tdtrilist[i]->GetPoint(0).z < minz)
|
|
{
|
|
minZ[0] = i;
|
|
minZ[1] = 0;
|
|
minz = tdtrilist[i]->GetPoint(0).z;
|
|
} else if(tdtrilist[i]->GetPoint(0).z > maxz)
|
|
{
|
|
maxZ[0] = i;
|
|
maxZ[1] = 0;
|
|
maxz = tdtrilist[i]->GetPoint(0).z;
|
|
}
|
|
|
|
x = (int)(tdtrilist[i]->GetPoint(0).x/dX);
|
|
z = (int)(tdtrilist[i]->GetPoint(0).z/dZ);
|
|
|
|
vert_id[x + X*z]++;
|
|
if(vert_id[x + X*z]==1)
|
|
{
|
|
center0 += tdtrilist[i]->GetPoint(0);
|
|
point_count++;
|
|
}
|
|
|
|
if(tdtrilist[i]->GetPoint(2).x < minx)
|
|
{
|
|
minX[0] = i;
|
|
minX[1] = 2;
|
|
minx = tdtrilist[i]->GetPoint(2).x;
|
|
} else if(tdtrilist[i]->GetPoint(2).x > maxx)
|
|
{
|
|
maxX[0] = i;
|
|
maxX[1] = 2;
|
|
maxx = tdtrilist[i]->GetPoint(2).x;
|
|
}
|
|
if(tdtrilist[i]->GetPoint(2).y < miny)
|
|
{
|
|
minY[0] = i;
|
|
minY[1] = 2;
|
|
miny = tdtrilist[i]->GetPoint(2).y;
|
|
} else if(tdtrilist[i]->GetPoint(2).y > maxy)
|
|
{
|
|
maxY[0] = i;
|
|
maxY[1] = 2;
|
|
maxy = tdtrilist[i]->GetPoint(2).y;
|
|
}
|
|
if(tdtrilist[i]->GetPoint(2).z < minz)
|
|
{
|
|
minZ[0] = i;
|
|
minZ[1] = 2;
|
|
minz = tdtrilist[i]->GetPoint(2).z;
|
|
} else if(tdtrilist[i]->GetPoint(2).z > maxz)
|
|
{
|
|
maxZ[0] = i;
|
|
maxZ[1] = 2;
|
|
maxz = tdtrilist[i]->GetPoint(2).z;
|
|
}
|
|
x = (int)(tdtrilist[i]->GetPoint(2).x/dX);
|
|
z = (int)(tdtrilist[i]->GetPoint(2).z/dZ);
|
|
vert_id[x + X*z]++;
|
|
if(vert_id[x + X*z]==1)
|
|
{
|
|
center0 += tdtrilist[i]->GetPoint(1);
|
|
point_count++;
|
|
}
|
|
|
|
if(tdtrilist[i]->GetPoint(1).x < minx)
|
|
{
|
|
minX[0] = i;
|
|
minX[1] = 1;
|
|
minx = tdtrilist[i]->GetPoint(1).x;
|
|
} else if(tdtrilist[i]->GetPoint(1).x > maxx)
|
|
{
|
|
maxX[0] = i;
|
|
maxX[1] = 1;
|
|
maxx = tdtrilist[i]->GetPoint(1).x;
|
|
}
|
|
if(tdtrilist[i]->GetPoint(1).y < miny)
|
|
{
|
|
minY[0] = i;
|
|
minY[1] = 1;
|
|
miny = tdtrilist[i]->GetPoint(1).y;
|
|
} else if(tdtrilist[i]->GetPoint(1).y > maxy)
|
|
{
|
|
maxY[0] = i;
|
|
maxY[1] = 1;
|
|
maxy = tdtrilist[i]->GetPoint(1).y;
|
|
}
|
|
if(tdtrilist[i]->GetPoint(1).z < minz)
|
|
{
|
|
minZ[0] = i;
|
|
minZ[1] = 1;
|
|
minz = tdtrilist[i]->GetPoint(1).z;
|
|
} else if(tdtrilist[i]->GetPoint(1).z > maxz)
|
|
{
|
|
maxZ[0] = i;
|
|
maxZ[1] = 1;
|
|
maxz = tdtrilist[i]->GetPoint(1).z;
|
|
}
|
|
x = (int)(tdtrilist[i]->GetPoint(1).x/dX);
|
|
z = (int)(tdtrilist[i]->GetPoint(1).z/dZ);
|
|
vert_id[x + X*z]++;
|
|
if(vert_id[x + X*z]==1)
|
|
{
|
|
center0 += tdtrilist[i]->GetPoint(2);
|
|
point_count++;
|
|
}
|
|
}
|
|
|
|
center0 *= 1.0f/point_count;
|
|
center0.x = GetX(center0.x);
|
|
center0.y += Offset;
|
|
center0.z = GetZ(center0.z);
|
|
|
|
center3 *= 1.0f/polygon_count;
|
|
center3.x = GetX(center3.x);
|
|
center3.y += Offset;
|
|
center3.z = GetZ(center3.z);
|
|
|
|
Vector3D v3;
|
|
Scalar d[3];
|
|
|
|
v3.Subtract(tdtrilist[maxX[0]]->GetPoint(maxX[1]), tdtrilist[minX[0]]->GetPoint(minX[1]));
|
|
d[0] = v3.GetLengthSquared();
|
|
|
|
v3.Subtract(tdtrilist[maxY[0]]->GetPoint(maxY[1]), tdtrilist[minY[0]]->GetPoint(minY[1]));
|
|
d[1] = v3.GetLengthSquared();
|
|
|
|
v3.Subtract(tdtrilist[maxZ[0]]->GetPoint(maxZ[1]), tdtrilist[minZ[0]]->GetPoint(minZ[1]));
|
|
d[2] = v3.GetLengthSquared();
|
|
|
|
if(d[0] > d[1])
|
|
{
|
|
if(d[0]>d[2])
|
|
{
|
|
center1 = tdtrilist[maxX[0]]->GetPoint(maxX[1]);
|
|
center1 += tdtrilist[minX[0]]->GetPoint(minX[1]);
|
|
center1 *= 0.5f;
|
|
}
|
|
else
|
|
{
|
|
center1 = tdtrilist[maxZ[0]]->GetPoint(maxZ[1]);
|
|
center1 += tdtrilist[minZ[0]]->GetPoint(minZ[1]);
|
|
center1 *= 0.5f;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(d[1]>d[2])
|
|
{
|
|
center1 = tdtrilist[maxY[0]]->GetPoint(maxY[1]);
|
|
center1 += tdtrilist[minY[0]]->GetPoint(minY[1]);
|
|
center1 *= 0.5f;
|
|
}
|
|
else
|
|
{
|
|
center1 = tdtrilist[maxZ[0]]->GetPoint(maxZ[1]);
|
|
center1 += tdtrilist[minZ[0]]->GetPoint(minZ[1]);
|
|
center1 *= 0.5f;
|
|
}
|
|
}
|
|
|
|
center1.x = GetX(center1.x);
|
|
center1.y += Offset;
|
|
center1.z = GetZ(center1.z);
|
|
|
|
center2.x = GetX((maxx+minx)*0.5f);
|
|
center2.y = (maxy+miny)*0.5f;
|
|
center2.z = GetZ((maxz+minz)*0.5f);
|
|
|
|
center2.y += Offset;
|
|
|
|
Point3D *coords = new Point3D [point_count];
|
|
Vector2DScalar *texCoords = new Vector2DScalar[point_count];
|
|
|
|
UnitVector3D sun;
|
|
sun = Vector3D(-1.0f, -1.0f, 0.0f);
|
|
|
|
int nrOfPoints = 0;
|
|
Scalar radiusSquared,
|
|
maxRadius0 = 0.0f,
|
|
maxRadius1 = 0.0f,
|
|
maxRadius2 = 0.0f,
|
|
maxRadius3 = 0.0f;
|
|
|
|
for(z=0;z<Z;z++)
|
|
for(x=0;x<X;x++)
|
|
{
|
|
if( vert_id[x + X*z] > 0 )
|
|
{
|
|
Verify(nrOfPoints<point_count);
|
|
vert_id[z*X+x] = nrOfPoints;
|
|
|
|
Verify(GetX(x)<=(*frame)[maxAllDepth][2] &&
|
|
GetX(x)>=(*frame)[maxAllDepth][0]);
|
|
Verify(GetZ(z)<=(*frame)[maxAllDepth][3] &&
|
|
GetZ(z)>=(*frame)[maxAllDepth][1]);
|
|
|
|
coords[nrOfPoints].x = GetX(x);
|
|
coords[nrOfPoints].y = GetHeight(x, z);
|
|
coords[nrOfPoints].z = GetZ(z);
|
|
|
|
v3.Subtract(coords[nrOfPoints], center0);
|
|
|
|
radiusSquared = v3.GetLengthSquared();
|
|
maxRadius0 = radiusSquared>maxRadius0 ? radiusSquared:maxRadius0;
|
|
|
|
v3.Subtract(coords[nrOfPoints], center1);
|
|
|
|
radiusSquared = v3.GetLengthSquared();
|
|
maxRadius1 = radiusSquared>maxRadius1 ? radiusSquared:maxRadius1;
|
|
|
|
v3.Subtract(coords[nrOfPoints], center2);
|
|
|
|
radiusSquared = v3.GetLengthSquared();
|
|
maxRadius2 = radiusSquared>maxRadius2 ? radiusSquared:maxRadius2;
|
|
|
|
v3.Subtract(coords[nrOfPoints], center3);
|
|
|
|
radiusSquared = v3.GetLengthSquared();
|
|
maxRadius3 = radiusSquared>maxRadius3 ? radiusSquared:maxRadius3;
|
|
|
|
#ifndef TERRAIN2_TEST
|
|
texCoords[nrOfPoints][0] =
|
|
borderPixelFun + (1.0f-2*borderPixelFun)*((uvFrame->maxX -
|
|
coords[nrOfPoints).x)/(uvFrame->maxX-uvFrame->minX));
|
|
texCoords[nrOfPoints][1] =
|
|
borderPixelFun + (1.0f-2*borderPixelFun)*((uvFrame->maxZ -
|
|
coords[nrOfPoints).z)/(uvFrame->maxZ-uvFrame->minZ));
|
|
#endif
|
|
nrOfPoints++;
|
|
}
|
|
else
|
|
vert_id[z*X+x] = -1;
|
|
}
|
|
|
|
if(nrOfPoints >= Limits::Max_Number_Vertices_Per_Mesh)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
maxRadius0 = static_cast<Scalar>(sqrt(maxRadius0));
|
|
maxRadius1 = static_cast<Scalar>(sqrt(maxRadius1));
|
|
maxRadius2 = static_cast<Scalar>(sqrt(maxRadius2));
|
|
maxRadius3 = static_cast<Scalar>(sqrt(maxRadius3));
|
|
|
|
Point3D center;
|
|
Scalar maxRadius;
|
|
|
|
if(maxRadius0<maxRadius1)
|
|
{
|
|
if(maxRadius0<maxRadius2)
|
|
{
|
|
if(maxRadius0<maxRadius3)
|
|
{
|
|
maxRadius = maxRadius0;
|
|
center = center0;
|
|
}
|
|
else
|
|
{
|
|
maxRadius = maxRadius3;
|
|
center = center3;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(maxRadius2<maxRadius3)
|
|
{
|
|
maxRadius = maxRadius2;
|
|
center = center2;
|
|
}
|
|
else
|
|
{
|
|
maxRadius = maxRadius3;
|
|
center = center3;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(maxRadius1<maxRadius2)
|
|
{
|
|
if(maxRadius1<maxRadius3)
|
|
{
|
|
maxRadius = maxRadius1;
|
|
center = center1;
|
|
}
|
|
else
|
|
{
|
|
maxRadius = maxRadius3;
|
|
center = center3;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(maxRadius2<maxRadius3)
|
|
{
|
|
maxRadius = maxRadius2;
|
|
center = center2;
|
|
}
|
|
else
|
|
{
|
|
maxRadius = maxRadius3;
|
|
center = center3;
|
|
}
|
|
}
|
|
}
|
|
|
|
BYTE *index = new BYTE [polygon_count*3];
|
|
|
|
int k, l;
|
|
|
|
for(i=0,l=0;i<polygon_count;i++)
|
|
{
|
|
k = 0;
|
|
|
|
x = (int)(tdtrilist[i]->GetPoint(0).x/dX);
|
|
z = (int)(tdtrilist[i]->GetPoint(0).z/dZ);
|
|
j = x + X*z;
|
|
Verify(vert_id[j]>=0);
|
|
index[l++] = vert_id[j];
|
|
|
|
if(z==Z-1)
|
|
k++;
|
|
|
|
x = (int)(tdtrilist[i]->GetPoint(2).x/dX);
|
|
z = (int)(tdtrilist[i]->GetPoint(2).z/dZ);
|
|
j = x + X*z;
|
|
Verify(vert_id[j]>=0);
|
|
index[l++] = vert_id[j];
|
|
if(z==Z-1)
|
|
k++;
|
|
|
|
x = (int)(tdtrilist[i]->GetPoint(1).x/dX);
|
|
z = (int)(tdtrilist[i]->GetPoint(1).z/dZ);
|
|
j = x + X*z;
|
|
Verify(vert_id[j]>=0);
|
|
index[l++] = vert_id[j];
|
|
if(z==Z-1)
|
|
k++;
|
|
|
|
if(k>=2)
|
|
{
|
|
j = 0;
|
|
}
|
|
|
|
if(
|
|
index[l-3]==index[l-2] ||
|
|
index[l-2]==index[l-1] ||
|
|
index[l-1]==index[l-3]
|
|
)
|
|
{
|
|
l-=3;
|
|
continue;
|
|
}
|
|
|
|
Vector3D vCross;
|
|
vCross.Cross(
|
|
coords[index[l-1]],
|
|
coords[index[l-2]],
|
|
coords[index[l-3]]
|
|
);
|
|
|
|
if(Small_Enough(vCross) || vCross.y<=SMALL)
|
|
{
|
|
l-=3;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if(l<3)
|
|
{
|
|
erf_mesh->DetachReference();
|
|
return false;
|
|
}
|
|
|
|
gos_PushCurrentHeap(MLR_Terrain2::PrimitiveHeap);
|
|
erf_mesh->SetSubprimitiveLengths(NULL, l/3);
|
|
|
|
Scalar xOffset2 = xCenterOffset + Xoffset*dX;
|
|
Scalar zOffset2 = zCenterOffset + Zoffset*dZ;
|
|
for(i=0;i<nrOfPoints;i++)
|
|
{
|
|
coords[i].x -= xOffset2;
|
|
coords[i].z -= zOffset2;
|
|
}
|
|
|
|
erf_mesh->SetCoordData(coords, nrOfPoints);
|
|
|
|
#ifdef TERRAIN2_TEST
|
|
erf_mesh->SetCurrentDepth(maxAllDepth-diffLevel);
|
|
#else
|
|
erf_mesh->SetTexCoordData(texCoords, nrOfPoints);
|
|
#endif
|
|
|
|
erf_mesh->SetIndexData(index, l);
|
|
gos_PopCurrentHeap();
|
|
|
|
// delete [] coords;
|
|
// delete [] texCoords;
|
|
// delete [] index;
|
|
|
|
erf_mesh->FindFacePlanes();
|
|
|
|
if(state)
|
|
{
|
|
erf_mesh->SetReferenceState(*state);
|
|
}
|
|
else
|
|
{
|
|
erf_mesh->SetReferenceState(state0);
|
|
}
|
|
|
|
erf_mesh->SetReferenceState(state1, 1);
|
|
|
|
gos_PushCurrentHeap(ElementRenderer::ShapeElement::s_Heap);
|
|
ElementRenderer::ShapeElement* Shape = new ElementRenderer::ShapeElement;
|
|
Register_Object(Shape);
|
|
gos_PopCurrentHeap();
|
|
|
|
gos_PushCurrentHeap(MidLevelRenderer::ShapeHeap);
|
|
MLRShape *shape = new MLRShape(1);
|
|
Register_Object(shape);
|
|
gos_PopCurrentHeap();
|
|
|
|
shape->Add(erf_mesh);
|
|
erf_mesh->DetachReference();
|
|
|
|
Shape->SetMLRShape(shape);
|
|
|
|
const Point3D *p = NULL;
|
|
int nr_of_points = 0;
|
|
erf_mesh->GetCoordData(&p, &nr_of_points);
|
|
ReadOnlyArrayOf<Point3D> p_array;
|
|
p_array.AssignData(p, nr_of_points);
|
|
Shape->m_localOBB.ComputeBounds(p_array);
|
|
Shape->SetOBBMode();
|
|
|
|
/*
|
|
.localToParent = LinearMatrix4D::Identity;
|
|
|
|
center.x -= xCenterOffset + Xoffset*dX;
|
|
center.z -= zCenterOffset + Zoffset*dZ;
|
|
|
|
Shape->m_localOBB.localToParent.BuildTranslation(center);
|
|
|
|
Shape->m_localOBB.sphereRadius = maxRadius;
|
|
*/
|
|
parent->AttachIndexedChild(listIndex, Shape);
|
|
Shape->SetVolumeCullMode();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
HFSlimMZ::CreateMesh2(
|
|
ElementRenderer::ListElement *parent,
|
|
int listIndex,
|
|
int diffLevel,
|
|
DynamicArrayOf<TriangleAbstract*>& tdtrilist,
|
|
frameArray *frame,
|
|
MLRState *state,
|
|
bool underWater
|
|
)
|
|
{
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\nCreateMesh2 parameters: parent = 0x%08X, listIndex = %d, diffLevel = %d,"
|
|
"\n &tdtrilist=0x%08X, frame = 0x%08X, MLRState = 0x%08X, underwater = %s",
|
|
(DWORD)(void*)parent, listIndex, diffLevel, (DWORD)(void*)&tdtrilist,
|
|
(DWORD)(void*)frame, (DWORD)(void*)state, underWater ? "TRUE" : "FALSE");
|
|
#endif
|
|
//#undef NON_DEBUG_BUG
|
|
int polygon_count = tdtrilist.GetLength();
|
|
if(polygon_count==0)
|
|
{
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\nReturning right away with false");
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
// SPEWALWAYS(("micgaert", "#cm0"));
|
|
|
|
gos_PushCurrentHeap(MLR_Terrain2::PrimitiveHeap);
|
|
MLR_Terrain2 *erf_mesh = new MLR_Terrain2;
|
|
gos_PopCurrentHeap();
|
|
|
|
erf_mesh->SetDepthData(maxAllDepth-diffLevel, maxAllDepth);
|
|
erf_mesh->SetTileData(tX, tY);
|
|
#ifdef BORDERPIXEL
|
|
erf_mesh->SetBorderPixel(borderPixelFun);
|
|
#endif
|
|
|
|
// erf_mesh->SetOffset(xOffset, zOffset);
|
|
// erf_mesh->SetGrid(xGridSize, zGridSize);
|
|
for(int ii=0;ii<8;ii++)
|
|
{
|
|
erf_mesh->SetFrame(
|
|
ii,
|
|
(*frame)[ii][0] - xCenterOffset - Xoffset*dX,
|
|
(*frame)[ii][1] - zCenterOffset - Zoffset*dZ,
|
|
(*frame)[ii][2] - xCenterOffset - Xoffset*dX,
|
|
(*frame)[ii][3] - zCenterOffset - Zoffset*dZ
|
|
);
|
|
|
|
}
|
|
|
|
Register_Object(erf_mesh);
|
|
|
|
erf_mesh->SetDetailData(
|
|
detailInfo.xOff,
|
|
detailInfo.zOff,
|
|
detailInfo.xFac*(1<<diffLevel),
|
|
detailInfo.zFac*(1<<diffLevel),
|
|
detailInfo.dStart,
|
|
detailInfo.dEnd
|
|
);
|
|
|
|
DynamicArrayOf<int> vert_id(X*Z);
|
|
DynamicArrayOf<Point3D> l_uniquePoints(Limits::Max_Number_Vertices_Per_Mesh);
|
|
|
|
BYTE *index = new BYTE [polygon_count*3];
|
|
|
|
int nrOfUniquePoints = 0;
|
|
|
|
// SPEWALWAYS(("micgaert", "#cm1"));
|
|
memset(vert_id.GetData(), 0, vert_id.GetSize());
|
|
|
|
int i, j, k;
|
|
|
|
int minX[2]={0,0},
|
|
maxX[2]={0,0},
|
|
minY[2]={0,0},
|
|
maxY[2]={0,0},
|
|
minZ[2]={0,0},
|
|
maxZ[2]={0,0};
|
|
Scalar
|
|
minx=tdtrilist[0]->GetPoint(0).x,
|
|
maxx=tdtrilist[0]->GetPoint(0).x,
|
|
miny=tdtrilist[0]->GetPoint(0).y,
|
|
maxy=tdtrilist[0]->GetPoint(0).y,
|
|
minz=tdtrilist[0]->GetPoint(0).z,
|
|
maxz=tdtrilist[0]->GetPoint(0).z;
|
|
|
|
Point3D
|
|
center0 = Point3D::Identity,
|
|
center1 = Point3D::Identity,
|
|
center2 = Point3D::Identity,
|
|
center3 = Point3D::Identity;
|
|
|
|
int indexCount = 0;
|
|
for(i=0;i<polygon_count;++i)
|
|
{
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\nPolygon count %d", i);
|
|
#endif
|
|
if(tdtrilist[i]->centerValid==false)
|
|
{
|
|
SPEWALWAYS(("micgaert", "Found invalid center"));
|
|
}
|
|
|
|
if(!tdtrilist[i]->GetSurfaceAreaAndCentroid())
|
|
{
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\ncontinue %d", i);
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
// SPEWALWAYS(("micgaert", "#cmZ.%d %f %f %f", i , tdtrilist[i]->center.x,
|
|
//tdtrilist[i]->center.y, tdtrilist[i]->center.z));
|
|
center3 += tdtrilist[i]->center;
|
|
|
|
for(j=0;j<3;j++)
|
|
{
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\nBegin loop j %d", j);
|
|
#endif
|
|
if(tdtrilist[i]->GetPoint(j).x < minx)
|
|
{
|
|
minX[0] = i;
|
|
minX[1] = 0;
|
|
minx = tdtrilist[i]->GetPoint(j).x;
|
|
} else if(tdtrilist[i]->GetPoint(j).x > maxx)
|
|
{
|
|
maxX[0] = i;
|
|
maxX[1] = 0;
|
|
maxx = tdtrilist[i]->GetPoint(j).x;
|
|
}
|
|
if(tdtrilist[i]->GetPoint(j).y < miny)
|
|
{
|
|
minY[0] = i;
|
|
minY[1] = 0;
|
|
miny = tdtrilist[i]->GetPoint(j).y;
|
|
} else if(tdtrilist[i]->GetPoint(j).y > maxy)
|
|
{
|
|
maxY[0] = i;
|
|
maxY[1] = 0;
|
|
maxy = tdtrilist[i]->GetPoint(j).y;
|
|
}
|
|
if(tdtrilist[i]->GetPoint(j).z < minz)
|
|
{
|
|
minZ[0] = i;
|
|
minZ[1] = 0;
|
|
minz = tdtrilist[i]->GetPoint(j).z;
|
|
} else if(tdtrilist[i]->GetPoint(j).z > maxz)
|
|
{
|
|
maxZ[0] = i;
|
|
maxZ[1] = 0;
|
|
maxz = tdtrilist[i]->GetPoint(j).z;
|
|
}
|
|
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\nSearching on k for unique points");
|
|
#endif
|
|
for(k=0;k<nrOfUniquePoints;k++)
|
|
{
|
|
if(Close_Enough(l_uniquePoints[k], tdtrilist[i]->GetPoint(j)))
|
|
{
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\nBreaking %d", k);
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(k==nrOfUniquePoints)
|
|
{
|
|
center0 += tdtrilist[i]->GetPoint(j);
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\nAdding unique point before %d", k);
|
|
fprintf(stdout, "\n {%f, %f, %f}", tdtrilist[i]->GetPoint(j).x, tdtrilist[i]->GetPoint(j).y, tdtrilist[i]->GetPoint(j).z );
|
|
#endif
|
|
l_uniquePoints[nrOfUniquePoints++] = tdtrilist[i]->GetPoint(j);
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\nAdding unique point after %d", k);
|
|
fprintf(stdout, "\n {%f, %f, %f}", l_uniquePoints[k].x, l_uniquePoints[k].y, l_uniquePoints[k].z );
|
|
#endif
|
|
|
|
// SPEWALWAYS(("micgaert", "#cm#.%d %f %f %f", nrOfUniquePoints-1,
|
|
//l_uniquePoints[nrOfUniquePoints-1].x, l_uniquePoints[nrOfUniquePoints-1].y,
|
|
//l_uniquePoints[nrOfUniquePoints-1].z));
|
|
|
|
}
|
|
|
|
index[indexCount+j] = k;
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\nEnd loop j %d", j);
|
|
#endif
|
|
|
|
}
|
|
|
|
if(
|
|
index[indexCount]!=index[indexCount+1] &&
|
|
index[indexCount]!=index[indexCount+2] &&
|
|
index[indexCount+1]!=index[indexCount+2]
|
|
)
|
|
{
|
|
Swap(index[indexCount+1], index[indexCount+2]);
|
|
|
|
indexCount+=3;
|
|
}
|
|
}
|
|
|
|
if(nrOfUniquePoints==0 || nrOfUniquePoints >= Limits::Max_Number_Vertices_Per_Mesh)
|
|
{
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\nReturning (no unique points) with false");
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
// SPEWALWAYS(("micgaert", "#cm2"));
|
|
center0 *= 1.0f/nrOfUniquePoints;
|
|
center0.x = GetX(center0.x);
|
|
center0.y += Offset;
|
|
center0.z = GetZ(center0.z);
|
|
|
|
// SPEWALWAYS(("micgaert", "#cmB.%f %f %f", center3.x, center3.y,
|
|
//center3.z));
|
|
|
|
center3 *= 1.0f/polygon_count;
|
|
center3.x = GetX(center3.x);
|
|
center3.y += Offset;
|
|
center3.z = GetZ(center3.z);
|
|
|
|
Vector3D v3;
|
|
Scalar d[3];
|
|
|
|
v3.Subtract(tdtrilist[maxX[0]]->GetPoint(maxX[1]),
|
|
tdtrilist[minX[0]]->GetPoint(minX[1]));
|
|
d[0] = v3.GetLengthSquared();
|
|
|
|
v3.Subtract(tdtrilist[maxY[0]]->GetPoint(maxY[1]),
|
|
tdtrilist[minY[0]]->GetPoint(minY[1]));
|
|
d[1] = v3.GetLengthSquared();
|
|
|
|
v3.Subtract(tdtrilist[maxZ[0]]->GetPoint(maxZ[1]),
|
|
tdtrilist[minZ[0]]->GetPoint(minZ[1]));
|
|
d[2] = v3.GetLengthSquared();
|
|
|
|
if(d[0] > d[1])
|
|
{
|
|
if(d[0]>d[2])
|
|
{
|
|
center1 = tdtrilist[maxX[0]]->GetPoint(maxX[1]);
|
|
center1 += tdtrilist[minX[0]]->GetPoint(minX[1]);
|
|
center1 *= 0.5f;
|
|
}
|
|
else
|
|
{
|
|
center1 = tdtrilist[maxZ[0]]->GetPoint(maxZ[1]);
|
|
center1 += tdtrilist[minZ[0]]->GetPoint(minZ[1]);
|
|
center1 *= 0.5f;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(d[1]>d[2])
|
|
{
|
|
center1 = tdtrilist[maxY[0]]->GetPoint(maxY[1]);
|
|
center1 += tdtrilist[minY[0]]->GetPoint(minY[1]);
|
|
center1 *= 0.5f;
|
|
}
|
|
else
|
|
{
|
|
center1 = tdtrilist[maxZ[0]]->GetPoint(maxZ[1]);
|
|
center1 += tdtrilist[minZ[0]]->GetPoint(minZ[1]);
|
|
center1 *= 0.5f;
|
|
}
|
|
}
|
|
|
|
center1.x = GetX(center1.x);
|
|
center1.y += Offset;
|
|
center1.z = GetZ(center1.z);
|
|
|
|
center2.x = GetX((maxx+minx)*0.5f);
|
|
center2.y = (maxy+miny)*0.5f;
|
|
center2.z = GetZ((maxz+minz)*0.5f);
|
|
|
|
center2.y += Offset;
|
|
|
|
Vector2DScalar *texCoords = new Vector2DScalar[nrOfUniquePoints];
|
|
Point3D *coords = new Point3D [nrOfUniquePoints];
|
|
|
|
UnitVector3D sun;
|
|
sun = Vector3D(-1.0f, -1.0f, 0.0f);
|
|
|
|
Scalar radiusSquared = 0.0f,
|
|
maxRadius0 = 0.0f,
|
|
maxRadius1 = 0.0f,
|
|
maxRadius2 = 0.0f,
|
|
maxRadius3 = 0.0f;
|
|
|
|
// SPEWALWAYS(("micgaert", "#cm4 %d", nrOfUniquePoints));
|
|
for(i=0;i<nrOfUniquePoints;i++)
|
|
{
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\nnrOfUniquePoints loop %d of %d", i, nrOfUniquePoints);
|
|
#endif
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\nnrOfUniquePoints, coords[i].x, y, z {%f, %f, %f} before", l_uniquePoints[i].x, l_uniquePoints[i].y, l_uniquePoints[i].z );
|
|
#endif
|
|
#ifdef NON_DEBUG_BUG
|
|
{
|
|
float testfloat1 = 5.0f;
|
|
float testfloat2 = testfloat1 + coords[i].x;
|
|
fprintf(stdout, "\nTest floating point 1 (%f)", testfloat2);
|
|
}
|
|
#endif
|
|
|
|
coords[i] = l_uniquePoints[i];
|
|
coords[i].y += Offset;
|
|
|
|
v3.Subtract(coords[i], center0);
|
|
|
|
#ifdef NON_DEBUG_BUG
|
|
{
|
|
float testfloat1 = 5.0f;
|
|
float testfloat2 = testfloat1 + coords[i].x;
|
|
fprintf(stdout, "\nTest floating point 2 (%f)", testfloat2);
|
|
}
|
|
#endif
|
|
radiusSquared = v3.GetLengthSquared();
|
|
maxRadius0 = radiusSquared>maxRadius0 ? radiusSquared:maxRadius0;
|
|
|
|
v3.Subtract(coords[i], center1);
|
|
|
|
#ifdef NON_DEBUG_BUG
|
|
{
|
|
float testfloat1 = 5.0f;
|
|
float testfloat2 = testfloat1 + coords[i].x;
|
|
fprintf(stdout, "\nTest floating point 3 (%f)", testfloat2);
|
|
}
|
|
#endif
|
|
radiusSquared = v3.GetLengthSquared();
|
|
maxRadius1 = radiusSquared>maxRadius1 ? radiusSquared:maxRadius1;
|
|
|
|
v3.Subtract(coords[i], center2);
|
|
|
|
#ifdef NON_DEBUG_BUG
|
|
{
|
|
float testfloat1 = 5.0f;
|
|
float testfloat2 = testfloat1 + coords[i].x;
|
|
fprintf(stdout, "\nTest floating point 4 (%f)", testfloat2);
|
|
}
|
|
#endif
|
|
radiusSquared = v3.GetLengthSquared();
|
|
maxRadius2 = radiusSquared>maxRadius2 ? radiusSquared:maxRadius2;
|
|
|
|
v3.Subtract(coords[i], center3);
|
|
|
|
#ifdef NON_DEBUG_BUG
|
|
{
|
|
float testfloat1 = 5.0f;
|
|
float testfloat2 = testfloat1 + coords[i].x;
|
|
fprintf(stdout, "\nTest floating point 5 (%f)", testfloat2);
|
|
}
|
|
#endif
|
|
radiusSquared = v3.GetLengthSquared();
|
|
maxRadius3 = radiusSquared>maxRadius3 ? radiusSquared:maxRadius3;
|
|
|
|
#ifndef TERRAIN2_TEST
|
|
texCoords[nrOfPoints][0] =
|
|
borderPixelFun + (1.0f-2*borderPixelFun)*((uvFrame->maxX -
|
|
coords[nrOfPoints].x)/(uvFrame->maxX-uvFrame->minX));
|
|
texCoords[nrOfPoints][1] =
|
|
borderPixelFun + (1.0f-2*borderPixelFun)*((uvFrame->maxZ -
|
|
coords[nrOfPoints].z)/(uvFrame->maxZ-uvFrame->minZ));
|
|
#endif
|
|
#ifdef NON_DEBUG_BUG
|
|
{
|
|
float testfloat1 = 5.0f;
|
|
float testfloat2 = testfloat1 + coords[i].x;
|
|
fprintf(stdout, "\nTest floating point 6 (%f)", testfloat2);
|
|
}
|
|
#endif
|
|
}
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\nCalculating radius");
|
|
#endif
|
|
|
|
maxRadius0 = static_cast<Scalar>(sqrt(maxRadius0));
|
|
maxRadius1 = static_cast<Scalar>(sqrt(maxRadius1));
|
|
maxRadius2 = static_cast<Scalar>(sqrt(maxRadius2));
|
|
maxRadius3 = static_cast<Scalar>(sqrt(maxRadius3));
|
|
|
|
Point3D center;
|
|
Scalar maxRadius;
|
|
|
|
// SPEWALWAYS(("micgaert", "#cm5"));
|
|
if(maxRadius0<maxRadius1)
|
|
{
|
|
if(maxRadius0<maxRadius2)
|
|
{
|
|
if(maxRadius0<maxRadius3)
|
|
{
|
|
maxRadius = maxRadius0;
|
|
center = center0;
|
|
}
|
|
else
|
|
{
|
|
maxRadius = maxRadius3;
|
|
center = center3;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(maxRadius2<maxRadius3)
|
|
{
|
|
maxRadius = maxRadius2;
|
|
center = center2;
|
|
}
|
|
else
|
|
{
|
|
maxRadius = maxRadius3;
|
|
center = center3;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(maxRadius1<maxRadius2)
|
|
{
|
|
if(maxRadius1<maxRadius3)
|
|
{
|
|
maxRadius = maxRadius1;
|
|
center = center1;
|
|
}
|
|
else
|
|
{
|
|
maxRadius = maxRadius3;
|
|
center = center3;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(maxRadius2<maxRadius3)
|
|
{
|
|
maxRadius = maxRadius2;
|
|
center = center2;
|
|
}
|
|
else
|
|
{
|
|
maxRadius = maxRadius3;
|
|
center = center3;
|
|
}
|
|
}
|
|
}
|
|
// SPEWALWAYS(("micgaert", "#cm6"));
|
|
|
|
if(indexCount<3)
|
|
{
|
|
erf_mesh->DetachReference();
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\nReturning (indexCount < 3) with false");
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
gos_PushCurrentHeap(MLR_Terrain2::PrimitiveHeap);
|
|
erf_mesh->SetSubprimitiveLengths(NULL, indexCount/3);
|
|
|
|
Scalar xOffset2 = xCenterOffset + Xoffset*dX;
|
|
Scalar zOffset2 = zCenterOffset + Zoffset*dZ;
|
|
for(i=0;i<nrOfUniquePoints;i++)
|
|
{
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\nnrOfUniquePoints loop %d or %d, coords[i].x, y, z {%f, %f, %f} before", i, nrOfUniquePoints, coords[i].x , coords[i].y , coords[i].z );
|
|
#endif
|
|
|
|
coords[i].x -= xOffset2;
|
|
coords[i].z -= zOffset2;
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\nnrOfUniquePoints loop %d or %d, coords[i].x, y, z {%f, %f, %f} after", i, nrOfUniquePoints, coords[i].x , coords[i].y , coords[i].z );
|
|
#endif
|
|
}
|
|
|
|
erf_mesh->SetCoordData(coords, nrOfUniquePoints);
|
|
|
|
#ifdef TERRAIN2_TEST
|
|
erf_mesh->SetCurrentDepth(maxAllDepth-diffLevel);
|
|
#else
|
|
erf_mesh->SetTexCoordData(texCoords, nrOfPoints);
|
|
#endif
|
|
|
|
erf_mesh->SetIndexData(index, indexCount);
|
|
gos_PopCurrentHeap();
|
|
|
|
// delete [] texCoords;
|
|
// delete [] index;
|
|
|
|
// SPEWALWAYS(("micgaert", "#cm7"));
|
|
erf_mesh->FindFacePlanes();
|
|
|
|
for(i=0;i<indexCount/3;i++)
|
|
{
|
|
Verify(erf_mesh->GetTrianglePlane(i)->normal.y > Stuff::SMALL);
|
|
}
|
|
|
|
if(state)
|
|
{
|
|
erf_mesh->SetReferenceState(*state);
|
|
}
|
|
else
|
|
{
|
|
erf_mesh->SetReferenceState(state0);
|
|
}
|
|
|
|
if(underWater==true)
|
|
{
|
|
erf_mesh->SetReferenceState(state2, 1);
|
|
}
|
|
else
|
|
{
|
|
erf_mesh->SetReferenceState(state1, 1);
|
|
}
|
|
|
|
// SPEWALWAYS(("micgaert", "#cm8"));
|
|
gos_PushCurrentHeap(ElementRenderer::ShapeElement::s_Heap);
|
|
ElementRenderer::ShapeElement* Shape = new ElementRenderer::ShapeElement;
|
|
Register_Object(Shape);
|
|
gos_PopCurrentHeap();
|
|
|
|
gos_PushCurrentHeap(MidLevelRenderer::ShapeHeap);
|
|
MLRShape *shape = new MLRShape(1);
|
|
Register_Object(shape);
|
|
gos_PopCurrentHeap();
|
|
|
|
shape->Add(erf_mesh);
|
|
erf_mesh->DetachReference();
|
|
|
|
Shape->SetMLRShape(shape);
|
|
|
|
const Point3D *p = NULL;
|
|
int nr_of_points = 0;
|
|
erf_mesh->GetCoordData(&p, &nr_of_points);
|
|
ReadOnlyArrayOf<Point3D> p_array;
|
|
p_array.AssignData(p, nr_of_points);
|
|
Shape->m_localOBB.ComputeBounds(p_array);
|
|
Shape->SetOBBMode();
|
|
|
|
/*
|
|
.localToParent = LinearMatrix4D::Identity;
|
|
|
|
center.x -= xCenterOffset + Xoffset*dX;
|
|
center.z -= zCenterOffset + Zoffset*dZ;
|
|
|
|
Shape->m_localOBB.localToParent.BuildTranslation(center);
|
|
|
|
Shape->m_localOBB.sphereRadius = maxRadius;
|
|
*/
|
|
parent->AttachIndexedChild(listIndex, Shape);
|
|
Shape->SetVolumeCullMode();
|
|
//#define NON_DEBUG_BUG 1
|
|
#ifdef NON_DEBUG_BUG
|
|
fprintf(stdout, "\nReturning true");
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
MLRPrimitiveBase*
|
|
HFSlimMZ::CreateWater(
|
|
Scalar x0, Scalar x1,
|
|
Scalar z0, Scalar z1,
|
|
Scalar waterLevel
|
|
)
|
|
{
|
|
gos_PushCurrentHeap(MLR_Water::PrimitiveHeap);
|
|
MLR_Water *ret = new MLR_Water;
|
|
|
|
DynamicArrayOf<Point3D> *coords = &ret->dataStore->coords;
|
|
Check_Object(coords);
|
|
coords->SetLength(25);
|
|
|
|
DynamicArrayOf<Vector2DScalar> *texCoords = &ret->dataStore->texCoords;
|
|
Check_Object(texCoords);
|
|
texCoords->SetLength(25);
|
|
|
|
DynamicArrayOf<ColorType> *colors = &ret->dataStore->colors;
|
|
Check_Object(colors);
|
|
colors->SetLength(25);
|
|
|
|
DynamicArrayOf<BYTE> *index = &ret->dataStore->index;
|
|
Check_Object(index);
|
|
index->SetLength(16*2*3);
|
|
|
|
int i, j;
|
|
for(i=0;i<5;i++)
|
|
{
|
|
for(j=0;j<5;j++)
|
|
{
|
|
int offset = i*5+j;
|
|
(*coords)[offset] = Point3D( x0+(i*(x1-x0))/4.0f, waterLevel, z0+(j*(z1-z0))/4.0f );
|
|
#if COLOR_AS_DWORD>0
|
|
(*colors)[offset] = 0xffffffff;
|
|
#else
|
|
(*colors)[offset] = RGBAColor::White;
|
|
#endif
|
|
|
|
(*texCoords)[offset] = Vector2DScalar(
|
|
((*coords)[offset].x-(x1+x0)/2.0f)*(waterTextureRatio/(x1-x0)),
|
|
((*coords)[offset].z-(z1+z0)/2.0f)*(waterTextureRatio/(z1-z0))
|
|
);
|
|
|
|
Verify((*texCoords)[offset][0] >= -waterTextureRatio && (*texCoords)[offset][0] <= waterTextureRatio);
|
|
Verify((*texCoords)[offset][1] >= -waterTextureRatio && (*texCoords)[offset][0] <= waterTextureRatio);
|
|
}
|
|
}
|
|
|
|
int k = 0;
|
|
for(i=0;i<4;i++)
|
|
{
|
|
for(j=0;j<4;j++)
|
|
{
|
|
// if((i+j)&1)
|
|
{
|
|
(*index)[k++] = i*5+j;
|
|
(*index)[k++] = (i+1)*5+j;
|
|
(*index)[k++] = i*5+j+1;
|
|
|
|
(*index)[k++] = i*5+j+1;
|
|
(*index)[k++] = (i+1)*5+j;
|
|
(*index)[k++] = (i+1)*5+j+1;
|
|
}
|
|
/*
|
|
else
|
|
{
|
|
(*index)[k++] = i*5+j;
|
|
(*index)[k++] = (i+1)*5+j;
|
|
(*index)[k++] = (i+1)*5+j+1;
|
|
|
|
(*index)[k++] = i*5+j+1;
|
|
(*index)[k++] = (i+1)*5+j+1;
|
|
(*index)[k++] = i*5+j+1;
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|
|
ret->SetSubprimitiveLengths(NULL, 16*2);
|
|
|
|
Scalar xOffset2 = xCenterOffset + Xoffset*dX;
|
|
Scalar zOffset2 = zCenterOffset + Zoffset*dZ;
|
|
for(i=0;i<25;i++)
|
|
{
|
|
(*coords)[i].x -= xOffset2;
|
|
(*coords)[i].z -= zOffset2;
|
|
}
|
|
|
|
ret->SetCoordData(coords->GetData(), 25);
|
|
ret->SetColorData(colors->GetData(), 25);
|
|
ret->SetIndexData(index->GetData(), 16*2*3);
|
|
ret->SetTexCoordData(texCoords->GetData(), 25);
|
|
ret->FindFacePlanes();
|
|
|
|
MLRState state, detState;
|
|
|
|
MLRTexture *texture = NULL;
|
|
if(waterMovieFrames>1)
|
|
{
|
|
texture = MLRTexturePool::Instance->AddMovie(waterTextureName, waterMovieFrames, 0.01f);
|
|
state.SetMovieTextureOn();
|
|
}
|
|
else
|
|
{
|
|
texture = MLRTexturePool::Instance->Add(waterTextureName);
|
|
}
|
|
|
|
Check_Object(texture);
|
|
state.SetTextureHandle(texture->GetTextureHandle());
|
|
|
|
state.SetBackFaceOff();
|
|
state.SetDitherOn();
|
|
state.SetTextureCorrectionOn();
|
|
state.SetZBufferCompareOn();
|
|
state.SetZBufferWriteOff();
|
|
state.SetAlphaMode(MLRState::AlphaInvAlphaMode);
|
|
state.SetPriority(MLRState::AlphaPriority);
|
|
|
|
ret->SetReferenceState(state);
|
|
|
|
detState = state;
|
|
detState.SetPriority(state.GetPriority()+1);
|
|
|
|
if(waterDetailInfo.movieFrames>1)
|
|
{
|
|
texture = MLRTexturePool::Instance->AddMovie(waterDetailInfo.name, waterDetailInfo.movieFrames, 0.01f);
|
|
detState.SetMovieTextureOn();
|
|
}
|
|
else
|
|
{
|
|
texture = MLRTexturePool::Instance->Add(waterDetailInfo.name);
|
|
}
|
|
|
|
Check_Object(texture);
|
|
detState.SetTextureHandle(texture->GetTextureHandle());
|
|
|
|
ret->SetDetailData(
|
|
waterDetailInfo.xOff,
|
|
waterDetailInfo.zOff,
|
|
waterDetailInfo.xFac,
|
|
waterDetailInfo.zFac,
|
|
waterDetailInfo.dStart,
|
|
waterDetailInfo.dEnd
|
|
);
|
|
|
|
ret->SetReferenceState(detState, 1);
|
|
|
|
gos_PopCurrentHeap();
|
|
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
primCounter, maxPrims;
|
|
|
|
bool
|
|
HFSlimMZ::BinSort(
|
|
ElementRenderer::ListElement *parent,
|
|
int index,
|
|
int levDiff,
|
|
DynamicArrayOf<TriangleAbstract*>& tdtrilist,
|
|
int binSize,
|
|
frameArray *frame,
|
|
MLRState *state
|
|
)
|
|
{
|
|
int polygon_count = tdtrilist.GetLength();
|
|
|
|
if (polygon_count==0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
//---------------------------------------------------------
|
|
// If the polygon mesh is already small enough, just return
|
|
//---------------------------------------------------------
|
|
//
|
|
if (polygon_count <= binSize)
|
|
{
|
|
return CreateMesh(parent, index, levDiff, tdtrilist, frame, state);
|
|
}
|
|
|
|
DynamicArrayOf<Point3D> centroids(polygon_count);
|
|
unsigned i;
|
|
for (i=0; i<polygon_count; ++i)
|
|
{
|
|
centroids[i] = tdtrilist[i]->center;
|
|
}
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// Calculate the dividing plane, and if none can be found, don't do nothin
|
|
//------------------------------------------------------------------------
|
|
//
|
|
Plane plane;
|
|
if (!plane.ComputeBestDividingPlane(centroids))
|
|
{
|
|
return CreateMesh(parent, index, levDiff, tdtrilist, frame, state);
|
|
}
|
|
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
// The mesh is too big, so we have to cut it up. Make a group proxy to
|
|
// hold the new mesh collection
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
Check_Object(parent);
|
|
gos_PushCurrentHeap(ElementRenderer::ListElement::s_Heap);
|
|
ElementRenderer::ListElement *group = new ElementRenderer::ListElement;
|
|
Register_Object(group);
|
|
group->SetSize(2);
|
|
gos_PopCurrentHeap();
|
|
//
|
|
//----------------------------------
|
|
// Set the position of the group
|
|
//----------------------------------
|
|
//
|
|
LinearMatrix4D m;
|
|
m = parent->GetLocalToParent();
|
|
|
|
parent->SetLocalToParent(LinearMatrix4D::Identity);
|
|
group->SetLocalToParent(m);
|
|
|
|
#if 0
|
|
const char *name;
|
|
if ((name=parent->GetName())!=NULL)
|
|
{
|
|
parent->SetName(NULL);
|
|
group->SetName(name);
|
|
}
|
|
#endif
|
|
|
|
DynamicArrayOf<TriangleAbstract*>
|
|
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)
|
|
{
|
|
if (plane.GetDistanceTo(centroids[i]) < 0.0f)
|
|
group_b[count_b++] = tdtrilist[i];
|
|
else
|
|
group_a[count_a++] = tdtrilist[i];
|
|
}
|
|
|
|
//
|
|
//---------------------------------
|
|
// Now add the polygons to each bin
|
|
//---------------------------------
|
|
//
|
|
Verify(count_a>0);
|
|
group_a.SetLength(count_a);
|
|
// bin_a->AddPolygons(process, group_a);
|
|
Verify(count_b>0);
|
|
group_b.SetLength(count_b);
|
|
// bin_b->AddPolygons(process, group_b);
|
|
|
|
//
|
|
//-------------------------------------------------------------------
|
|
// Now that the mesh has been split up, Bin_Sort each smaller mesh and
|
|
// destroy this mesh
|
|
//-------------------------------------------------------------------
|
|
//
|
|
int worked = 0;
|
|
|
|
if (BinSort(
|
|
group,
|
|
0,
|
|
levDiff,
|
|
group_a,
|
|
binSize,
|
|
frame,
|
|
state))
|
|
{
|
|
Verify(group->GetIndexedElement(0) != NULL);
|
|
worked |= 1;
|
|
}
|
|
|
|
if (BinSort(
|
|
group,
|
|
1,
|
|
levDiff,
|
|
group_b,
|
|
binSize,
|
|
frame,
|
|
state))
|
|
{
|
|
Verify(group->GetIndexedElement(1) != NULL);
|
|
worked |= 2;
|
|
}
|
|
|
|
if(worked != 3)
|
|
{
|
|
if(worked == 0)
|
|
return false;
|
|
|
|
ElementRenderer::ListElement *smallgroup = new
|
|
ElementRenderer::ListElement;
|
|
Register_Object(smallgroup);
|
|
smallgroup->SetSize(1);
|
|
|
|
ElementRenderer::Element *element;
|
|
if(worked==1)
|
|
{
|
|
element = group->GetIndexedElement(0);
|
|
element->DetachFromParent();
|
|
}
|
|
else
|
|
{
|
|
element = group->GetIndexedElement(1);
|
|
element->DetachFromParent();
|
|
}
|
|
delete group;
|
|
|
|
smallgroup->AttachIndexedChild(0, element);
|
|
Check_Object(smallgroup);
|
|
parent->AttachIndexedChild(index, smallgroup);
|
|
|
|
smallgroup->NeedNewBounds();
|
|
smallgroup->SetVolumeCullMode();
|
|
}
|
|
else
|
|
{
|
|
Check_Object(group);
|
|
parent->AttachIndexedChild(index, group);
|
|
|
|
group->NeedNewBounds();
|
|
group->SetVolumeCullMode();
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------
|
|
// Now set the bounding sphere of the group
|
|
//-----------------------------------------
|
|
//
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
HFSlimMZ::BinSort2(
|
|
ElementRenderer::ListElement *parent,
|
|
int index,
|
|
int levDiff,
|
|
DynamicArrayOf<TriangleAbstract*>& tdtrilist,
|
|
int binSize,
|
|
frameArray *frame,
|
|
MLRState *state,
|
|
bool underWater
|
|
)
|
|
{
|
|
int polygon_count = tdtrilist.GetLength();
|
|
|
|
if (polygon_count==0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
//---------------------------------------------------------
|
|
// If the polygon mesh is already small enough, just return
|
|
//---------------------------------------------------------
|
|
//
|
|
// SPEWALWAYS(("micgaert", "#bs0"));
|
|
if (polygon_count <= binSize)
|
|
{
|
|
return CreateMesh2(parent, index, levDiff, tdtrilist, frame, state,
|
|
underWater);
|
|
}
|
|
|
|
DynamicArrayOf<Point3D> centroids(polygon_count);
|
|
unsigned i;
|
|
for (i=0; i<polygon_count; ++i)
|
|
{
|
|
if(tdtrilist[i]->centerValid==false)
|
|
{
|
|
SPEWALWAYS(("micgaert", "Found invalid center!"));
|
|
}
|
|
|
|
centroids[i] = tdtrilist[i]->center;
|
|
}
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// Calculate the dividing plane, and if none can be found, don't do nothin
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// SPEWALWAYS(("micgaert", "#bs1"));
|
|
|
|
Plane plane;
|
|
if (!plane.ComputeBestDividingPlane(centroids))
|
|
{
|
|
return CreateMesh2(parent, index, levDiff, tdtrilist, frame, state,
|
|
underWater);
|
|
}
|
|
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
// The mesh is too big, so we have to cut it up. Make a group proxy to
|
|
// hold the new mesh collection
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
// SPEWALWAYS(("micgaert", "#bs2"));
|
|
Check_Object(parent);
|
|
gos_PushCurrentHeap(ElementRenderer::ListElement::s_Heap);
|
|
ElementRenderer::ListElement *group = new ElementRenderer::ListElement;
|
|
Register_Object(group);
|
|
group->SetSize(2);
|
|
gos_PopCurrentHeap();
|
|
//
|
|
//----------------------------------
|
|
// Set the position of the group
|
|
//----------------------------------
|
|
//
|
|
LinearMatrix4D m;
|
|
m = parent->GetLocalToParent();
|
|
|
|
parent->SetLocalToParent(LinearMatrix4D::Identity);
|
|
group->SetLocalToParent(m);
|
|
|
|
// SPEWALWAYS(("micgaert", "#bs3"));
|
|
#if 0
|
|
const char *name;
|
|
if ((name=parent->GetName())!=NULL)
|
|
{
|
|
parent->SetName(NULL);
|
|
group->SetName(name);
|
|
}
|
|
#endif
|
|
|
|
DynamicArrayOf<TriangleAbstract*>
|
|
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
|
|
//------------------------------------------------------------------
|
|
//
|
|
// SPEWALWAYS(("micgaert", "#bs4"));
|
|
for (i=0; i<polygon_count; ++i)
|
|
{
|
|
if (plane.GetDistanceTo(centroids[i]) < 0.0f)
|
|
group_b[count_b++] = tdtrilist[i];
|
|
else
|
|
group_a[count_a++] = tdtrilist[i];
|
|
}
|
|
|
|
//
|
|
//---------------------------------
|
|
// Now add the polygons to each bin
|
|
//---------------------------------
|
|
//
|
|
Verify(count_a>0);
|
|
group_a.SetLength(count_a);
|
|
// bin_a->AddPolygons(process, group_a);
|
|
Verify(count_b>0);
|
|
group_b.SetLength(count_b);
|
|
// bin_b->AddPolygons(process, group_b);
|
|
// SPEWALWAYS(("micgaert", "#bs5"));
|
|
|
|
//
|
|
//-------------------------------------------------------------------
|
|
// Now that the mesh has been split up, Bin_Sort each smaller mesh and
|
|
// destroy this mesh
|
|
//-------------------------------------------------------------------
|
|
//
|
|
int worked = 0;
|
|
|
|
if (BinSort2(
|
|
group,
|
|
0,
|
|
levDiff,
|
|
group_a,
|
|
binSize,
|
|
frame,
|
|
state,
|
|
underWater))
|
|
{
|
|
worked |= 1;
|
|
}
|
|
// SPEWALWAYS(("micgaert", "#bs6"));
|
|
if (BinSort2(
|
|
group,
|
|
1,
|
|
levDiff,
|
|
group_b,
|
|
binSize,
|
|
frame,
|
|
state,
|
|
underWater))
|
|
{
|
|
worked |= 2;
|
|
}
|
|
|
|
// SPEWALWAYS(("micgaert", "#bs7"));
|
|
if(worked != 3)
|
|
{
|
|
if(worked == 0)
|
|
return false;
|
|
|
|
ElementRenderer::ListElement *smallgroup = new ElementRenderer::ListElement;
|
|
Register_Object(smallgroup);
|
|
smallgroup->SetSize(1);
|
|
|
|
ElementRenderer::Element *element;
|
|
if(worked==1)
|
|
{
|
|
element = group->GetIndexedElement(0);
|
|
element->DetachFromParent();
|
|
}
|
|
else
|
|
{
|
|
element = group->GetIndexedElement(1);
|
|
element->DetachFromParent();
|
|
}
|
|
delete group;
|
|
|
|
smallgroup->AttachIndexedChild(0, element);
|
|
Check_Object(smallgroup);
|
|
parent->AttachIndexedChild(index, smallgroup);
|
|
|
|
group = smallgroup;
|
|
}
|
|
else
|
|
{
|
|
Check_Object(group);
|
|
parent->AttachIndexedChild(index, group);
|
|
}
|
|
// SPEWALWAYS(("micgaert", "#bs8"));
|
|
//
|
|
//-----------------------------------------
|
|
// Now set the bounding sphere of the group
|
|
//-----------------------------------------
|
|
//
|
|
group->NeedNewBounds();
|
|
group->SetVolumeCullMode();
|
|
|
|
return true;
|
|
}
|
|
|
|
void
|
|
HFSlimMZ::OptimizeHField(int depth, int binSize, const char *imagename)
|
|
{
|
|
if(X*Z == 0)
|
|
{
|
|
return;
|
|
}
|
|
fprintf(stdout, "Going to optimize the terrain: MaxNr.Of Points: %d BinSize: %d\n", depth, binSize);
|
|
|
|
tdtrilist.SetLength((X-1)*(Z-1));
|
|
map = new DirectMap<real>(X,Z);
|
|
|
|
int i, j;
|
|
|
|
float maxY = 0;
|
|
for(j=0;j<Z;j++)
|
|
for(i=0;i<X;i++)
|
|
{
|
|
map->ref(i,j) = field[j*X + i];
|
|
}
|
|
Offset = 0.0;
|
|
|
|
MASK = new ImportMask;
|
|
MASK->width=X;
|
|
MASK->height=Z;
|
|
|
|
Scalar percentage = (Scalar)depth / (X*Z);
|
|
|
|
mesh = new GreedySubdivision(map, percentage);
|
|
|
|
if(doInterest==true)
|
|
{
|
|
Verify(X*Z == interestData.GetLength());
|
|
mesh->interest_data.init(X, Z, interestData.GetData());
|
|
}
|
|
mesh->SetInterestMethod(doInterest);
|
|
mesh->SetSquareMethod(doTileCap);
|
|
mesh->SetBiggerSquareMethod(doTileCapYovin);
|
|
|
|
point_limit = depth;
|
|
|
|
triangleCounter = 0;
|
|
int count = 1;
|
|
while(mesh->pointCount()<point_limit && mesh->maxError() > error_threshold)
|
|
{
|
|
mesh->greedyInsert();
|
|
}
|
|
fprintf(stdout, "The mesh was greedy.\n");
|
|
|
|
if(doDensityMap==true && imagename!=NULL)
|
|
{
|
|
Image img;
|
|
|
|
img.CreateBlank(X, Z);
|
|
|
|
BYTE *ptr = img.Lock();
|
|
for(j=0;j<Z;j++)
|
|
{
|
|
for(i=0;i<X;i++)
|
|
{
|
|
ptr[3*(j*X+i)] = mesh->areUsed(Z-j-1, X-i-1);
|
|
ptr[3*(j*X+i)+1] = mesh->is_used(X-i-1, Z-j-1);
|
|
ptr[3*(j*X+i)+2] = mesh->are_used_32((X-i-1)>>5, (Z-j-1)>>5);
|
|
}
|
|
}
|
|
img.UnLock();
|
|
|
|
img.SaveTga((LPSTR)imagename);
|
|
|
|
exit(-1);
|
|
}
|
|
|
|
if(!doPrecise)
|
|
{
|
|
fprintf(stdout, "You don't care about precision !\n");
|
|
|
|
mesh->overFaces(GetFacesCB, tdtrilist.GetData());
|
|
|
|
for(i=0;i<triangleCounter;i++)
|
|
{
|
|
tdtrilist[i].v[0].y = Offset + static_cast<float>(dY*mesh->eval(
|
|
(int)(tdtrilist[i].v[0].x),
|
|
(int)(tdtrilist[i].v[0].z)
|
|
));
|
|
|
|
tdtrilist[i].v[1].y = Offset + static_cast<float>(dY*mesh->eval(
|
|
(int)(tdtrilist[i].v[1].x),
|
|
(int)(tdtrilist[i].v[1].z)
|
|
));
|
|
|
|
tdtrilist[i].v[2].y = Offset + static_cast<float>(dY*mesh->eval(
|
|
(int)(tdtrilist[i].v[2].x),
|
|
(int)(tdtrilist[i].v[2].z)
|
|
));
|
|
|
|
tdtrilist[i].v[0].x *= dX;
|
|
tdtrilist[i].v[0].z *= dZ;
|
|
|
|
tdtrilist[i].v[1].x *= dX;
|
|
tdtrilist[i].v[1].z *= dZ;
|
|
|
|
tdtrilist[i].v[2].x *= dX;
|
|
tdtrilist[i].v[2].z *= dZ;
|
|
|
|
if(tdtrilist[i].GetSurfaceAreaAndCentroid()!=true)
|
|
{
|
|
if(silentMode==true)
|
|
{
|
|
fprintf(stderr, "Found a triangle with a face normal not pointing up, consider revising map ! Program exits !\n");
|
|
exit(-1);
|
|
}
|
|
else
|
|
{
|
|
STOP(("Found a triangle with a face normal not pointing up, consider revising map !"));
|
|
}
|
|
}
|
|
}
|
|
|
|
OptPolyCount = triangleCounter;
|
|
|
|
if(triangleCounter == 0 || mesh->pointCount() == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
toSortTriangles.SetLength(triangleCounter);
|
|
|
|
for(i=0,j=0;i<triangleCounter;++i)
|
|
{
|
|
if(! (tdtrilist[i].plane.normal.y > Stuff::SMALL) )
|
|
{
|
|
if(silentMode==true)
|
|
{
|
|
fprintf(stderr, "Found a triangle with a face normal not pointing up, consider revising map ! Program exits !\n");
|
|
exit(-1);
|
|
}
|
|
else
|
|
{
|
|
STOP(("Found a triangle with a face normal not pointing up, consider revising map !"));
|
|
}
|
|
}
|
|
|
|
/*
|
|
if( !(tdtrilist[i].GetV0().x==0.0f && tdtrilist[i].GetV0().z==GetZinM())
|
|
&&
|
|
!(tdtrilist[i].GetV1().x==0.0f && tdtrilist[i].GetV1().z==GetZinM()) &&
|
|
!(tdtrilist[i].GetV2().x==0.0f && tdtrilist[i].GetV2().z==GetZinM())
|
|
)
|
|
*/
|
|
{
|
|
toSortTriangles[j++] = &tdtrilist[i];
|
|
}
|
|
}
|
|
toSortTriangles.SetLength(j);
|
|
|
|
fprintf(stdout, "optimized to %d triangles.\n", j);
|
|
|
|
}
|
|
else
|
|
{
|
|
fprintf(stdout, "You wanted it precise !");
|
|
usedUniquePoints = 0;
|
|
usedTriangleIndices = 0;
|
|
|
|
uniquePoints.SetLength(4*mesh->pointCount());
|
|
TriangleStruct::points = uniquePoints.GetData();
|
|
|
|
triangleIndices.SetLength(8*mesh->pointCount());
|
|
|
|
mesh->overFaces(GetFacesCBPrecise, NULL);
|
|
|
|
for(i=0;i<usedUniquePoints;i++)
|
|
{
|
|
uniquePoints[i].p.y = Offset + static_cast<float>(dY*mesh->eval(
|
|
(int)(uniquePoints[i].p.x),
|
|
(int)(uniquePoints[i].p.z)
|
|
));
|
|
|
|
uniquePoints[i].p.x *= dX;
|
|
uniquePoints[i].p.z *= dZ;
|
|
}
|
|
|
|
for(i=0;i<usedTriangleIndices;i++)
|
|
{
|
|
triangleIndices[i].GetSurfaceAreaAndCentroid();
|
|
}
|
|
|
|
OptPolyCount = usedTriangleIndices;
|
|
|
|
if(usedTriangleIndices == 0 || mesh->pointCount() == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for(i=0;i<usedTriangleIndices;++i)
|
|
{
|
|
if(! (triangleIndices[i].plane.normal.y > Stuff::SMALL) )
|
|
{
|
|
if(silentMode==true)
|
|
{
|
|
fprintf(stderr, "Found a triangle with a face normal not pointing up, consider revising map ! Program exits !\n");
|
|
exit(-1);
|
|
}
|
|
else
|
|
{
|
|
STOP(("Found a triangle with a face normal not pointing up, consider revising map !"));
|
|
}
|
|
}
|
|
}
|
|
|
|
fprintf(stdout, "optimized to %d triangles.\n", usedTriangleIndices);
|
|
}
|
|
}
|
|
|
|
int brokenTriangles;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
AnalyzeThis(
|
|
DynamicArrayOf<TriangleAbstract*> &tempTrianglesPtr,
|
|
Scalar x0,
|
|
Scalar z0,
|
|
Scalar x1,
|
|
Scalar z1
|
|
)
|
|
{
|
|
int i, j, k, l, len = tempTrianglesPtr.GetLength();
|
|
int divide = 2;
|
|
Scalar x0n, z0n, x1n, z1n;
|
|
|
|
fprintf(analyzeFile, "%d ", len);
|
|
|
|
int in, out;
|
|
|
|
for(i=0;i<divide;i++)
|
|
{
|
|
for(j=0;j<divide;j++)
|
|
{
|
|
x0n = x0 + j*(x1-x0)/divide;
|
|
x1n = x0 + (j+1)*(x1-x0)/divide;
|
|
z0n = z0 + i*(z1-z0)/divide;
|
|
z1n = z0 + (i+1)*(z1-z0)/divide;
|
|
|
|
in = 0;
|
|
out = 0;
|
|
for(k=0;k<len;k++)
|
|
{
|
|
l = 0;
|
|
if( tempTrianglesPtr[k]->GetPoint(0).x >= x0n &&
|
|
tempTrianglesPtr[k]->GetPoint(0).x <= x1n &&
|
|
tempTrianglesPtr[k]->GetPoint(0).z >= z0n &&
|
|
tempTrianglesPtr[k]->GetPoint(0).z < z1n
|
|
)
|
|
{
|
|
l++;
|
|
}
|
|
if( tempTrianglesPtr[k]->GetPoint(1).x >= x0n &&
|
|
tempTrianglesPtr[k]->GetPoint(1).x <= x1n &&
|
|
tempTrianglesPtr[k]->GetPoint(1).z >= z0n &&
|
|
tempTrianglesPtr[k]->GetPoint(1).z <= z1n
|
|
)
|
|
{
|
|
l++;
|
|
}
|
|
if( tempTrianglesPtr[k]->GetPoint(2).x >= x0n &&
|
|
tempTrianglesPtr[k]->GetPoint(2).x <= x1n &&
|
|
tempTrianglesPtr[k]->GetPoint(2).z >= z0n &&
|
|
tempTrianglesPtr[k]->GetPoint(2).z <= z1n
|
|
)
|
|
{
|
|
l++;
|
|
}
|
|
|
|
if(l==3)
|
|
{
|
|
in++;
|
|
}
|
|
else if(l>0)
|
|
{
|
|
if(tempTrianglesPtr[k]->centerValid==false)
|
|
{
|
|
SPEWALWAYS(("micgaert", "Found invalid center!"));
|
|
}
|
|
|
|
if( tempTrianglesPtr[k]->center.x >= x0n &&
|
|
tempTrianglesPtr[k]->center.x <= x1n &&
|
|
tempTrianglesPtr[k]->center.z >= z0n && tempTrianglesPtr[k]->center.z
|
|
<= z1n
|
|
)
|
|
{
|
|
out++;
|
|
}
|
|
}
|
|
}
|
|
|
|
fprintf(analyzeFile, "%d %d ", in, out);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
fprintf(analyzeFile, "\n");
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
HFSlimMZ::BuildTile(
|
|
DynamicArrayOf<TriangleStruct*>& tempTrianglesPtr,
|
|
int index,
|
|
int depth, int maxdepth,
|
|
int numOfTriangles,
|
|
DynamicArrayOf<unsigned char>& onOffPoints,
|
|
int maxNumOfTrianglesPerMesh,
|
|
Scalar xGridOffset,
|
|
Scalar zGridOffset,
|
|
Scalar xGrid,
|
|
Scalar zGrid,
|
|
int tileX,
|
|
int tileZ
|
|
)
|
|
{
|
|
int orgUsedTriangleIndices = usedTriangleIndices;
|
|
|
|
int i, j, inCount, newCount = 0, extraTriangles = 0, refused = 0;
|
|
int k, l, m;
|
|
|
|
Scalar x0, z0, x1, z1;
|
|
|
|
x0 = xGridOffset + tileX*xGrid;
|
|
z0 = zGridOffset + tileZ*zGrid;
|
|
x1 = x0 + xGrid;
|
|
z1 = z0 + zGrid;
|
|
|
|
for(i=0,j=0;i<numOfTriangles;j+=3,++i)
|
|
{
|
|
Verify(i<numOfTriangles);
|
|
Verify(j<3*numOfTriangles);
|
|
|
|
/* m = 0;
|
|
for(k=0;k<3;k++)
|
|
{
|
|
if(triangleIndices[i].v[k]==2)
|
|
{
|
|
m++;
|
|
}
|
|
}
|
|
|
|
if(m==1 && (z0==800.0f || z1==800.0f))
|
|
{
|
|
m--;
|
|
}
|
|
*/
|
|
if(onOffPoints[i] == 0)
|
|
{
|
|
inCount = 0;
|
|
int clipIt[3] = {0, 0, 0}, orIt = 0, addIt = 0xf;
|
|
|
|
for(k=0;k<3;k++)
|
|
{
|
|
if(triangleIndices[i].GetPoint(k).x < x0)
|
|
{
|
|
clipIt[k] |= 1;
|
|
}
|
|
if(triangleIndices[i].GetPoint(k).x > x1)
|
|
{
|
|
clipIt[k] |= 4;
|
|
}
|
|
if(triangleIndices[i].GetPoint(k).z < z0)
|
|
{
|
|
clipIt[k] |= 8;
|
|
}
|
|
if(triangleIndices[i].GetPoint(k).z > z1)
|
|
{
|
|
clipIt[k] |= 2;
|
|
}
|
|
|
|
orIt |= clipIt[k];
|
|
addIt &= clipIt[k];
|
|
}
|
|
|
|
if(orIt == 0)
|
|
{
|
|
onOffPoints[i] = 1;
|
|
|
|
tempTrianglesPtr[newCount++] = &triangleIndices[i];
|
|
|
|
uniquePoints[triangleIndices[i].v[0]].Add(&triangleIndices[i], 0);
|
|
uniquePoints[triangleIndices[i].v[1]].Add(&triangleIndices[i], 1);
|
|
uniquePoints[triangleIndices[i].v[2]].Add(&triangleIndices[i], 2);
|
|
}
|
|
else if(addIt==0)
|
|
{
|
|
if(orIt==1 || orIt==2 || orIt==4 || orIt==8)
|
|
{
|
|
Point3D triangle[3], clipPoints[8];
|
|
int index[8];
|
|
float angles[8];
|
|
|
|
for(k=0;k<3;k++)
|
|
{
|
|
triangle[k] = triangleIndices[i].GetPoint(k);
|
|
}
|
|
|
|
l = 0;
|
|
for(k=0;k<3;k++)
|
|
{
|
|
int next = k+1>2?0:k+1;
|
|
if(clipIt[k]==0)
|
|
{
|
|
clipPoints[l++] = triangle[k];
|
|
if(clipIt[next]==0)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(clipIt[next]!=0)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
//
|
|
//-----------------------------------------------------
|
|
// Find the boundary conditions that match our clipping
|
|
// plane
|
|
//-----------------------------------------------------
|
|
//
|
|
int mask = 1;
|
|
for (m=0; m<4; m++)
|
|
{
|
|
if((clipIt[k] | clipIt[next]) & mask)
|
|
{
|
|
switch(m)
|
|
{
|
|
case 0:
|
|
clipPoints[l].AddScaled(
|
|
triangle[k],
|
|
Vector3D(
|
|
triangle[next].x - triangle[k].x,
|
|
triangle[next].y - triangle[k].y,
|
|
triangle[next].z - triangle[k].z
|
|
),
|
|
(x0-triangle[k].x)/(triangle[next].x-triangle[k].x)
|
|
|
|
);
|
|
clipPoints[l++].x = x0;
|
|
break;
|
|
case 1:
|
|
clipPoints[l].AddScaled(
|
|
triangle[k],
|
|
Vector3D(
|
|
triangle[next].x - triangle[k].x,
|
|
triangle[next].y - triangle[k].y,
|
|
triangle[next].z - triangle[k].z
|
|
),
|
|
(z1-triangle[k].z)/(triangle[next].z-triangle[k].z)
|
|
);
|
|
clipPoints[l++].z = z1;
|
|
break;
|
|
case 2:
|
|
clipPoints[l].AddScaled(
|
|
triangle[k],
|
|
Vector3D(
|
|
triangle[next].x - triangle[k].x,
|
|
triangle[next].y - triangle[k].y,
|
|
triangle[next].z - triangle[k].z
|
|
),
|
|
(x1-triangle[k].x)/(triangle[next].x-triangle[k].x)
|
|
);
|
|
clipPoints[l++].x = x1;
|
|
break;
|
|
case 3:
|
|
clipPoints[l].AddScaled(
|
|
triangle[k],
|
|
Vector3D(
|
|
triangle[next].x - triangle[k].x,
|
|
triangle[next].y - triangle[k].y,
|
|
triangle[next].z - triangle[k].z
|
|
),
|
|
(z0-triangle[k].z)/(triangle[next].z-triangle[k].z)
|
|
);
|
|
clipPoints[l++].z = z0;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
mask <<= 1;
|
|
}
|
|
}
|
|
Verify(l>2);
|
|
|
|
for(m=0;m<l;m++)
|
|
{
|
|
index[m] = FindAddPoint(clipPoints[m]);
|
|
}
|
|
|
|
int ba = -1;
|
|
float a = -360.0f;
|
|
for(m=0;m<l;m++)
|
|
{
|
|
angles[m] = GetAngle(
|
|
uniquePoints[index[(m-1+l)%l]].p,
|
|
uniquePoints[index[m]].p,
|
|
uniquePoints[index[(m+l)%l]].p
|
|
);
|
|
|
|
if(angles[m] > a)
|
|
{
|
|
a = angles[m];
|
|
ba = m;
|
|
}
|
|
}
|
|
|
|
for(m=1;m<l-1;m++)
|
|
{
|
|
triangleIndices[usedTriangleIndices].v[0] = index[ba];
|
|
triangleIndices[usedTriangleIndices].v[1] = index[(ba+m)%l];
|
|
triangleIndices[usedTriangleIndices].v[2] = index[(ba+m+1)%l];
|
|
|
|
if( (triangleIndices[usedTriangleIndices].v[0] !=
|
|
triangleIndices[usedTriangleIndices].v[1]) &&
|
|
(triangleIndices[usedTriangleIndices].v[0] !=
|
|
triangleIndices[usedTriangleIndices].v[2]) &&
|
|
(triangleIndices[usedTriangleIndices].v[1] !=
|
|
triangleIndices[usedTriangleIndices].v[2]) )
|
|
{
|
|
uniquePoints[triangleIndices[usedTriangleIndices].v[0]].Add(&triangleIndices[usedTriangleIndices],
|
|
0);
|
|
uniquePoints[triangleIndices[usedTriangleIndices].v[1]].Add(&triangleIndices[usedTriangleIndices],
|
|
1);
|
|
uniquePoints[triangleIndices[usedTriangleIndices].v[2]].Add(&triangleIndices[usedTriangleIndices],
|
|
2);
|
|
|
|
triangleIndices[usedTriangleIndices++].GetSurfaceAreaAndCentroid();
|
|
}
|
|
else
|
|
{
|
|
refused++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int key=0, len[2] = {0, 0};
|
|
Point3D clipPoints[2][8];
|
|
int index[8];
|
|
float angles[8];
|
|
int clipMeToo[2][8];
|
|
|
|
for(k=0;k<3;k++)
|
|
{
|
|
clipPoints[key][k] = triangleIndices[i].GetPoint(k);
|
|
}
|
|
|
|
clipMeToo[key][0] = clipIt[0];
|
|
clipMeToo[key][1] = clipIt[1];
|
|
clipMeToo[key][2] = clipIt[2];
|
|
|
|
len[key] = 3;
|
|
|
|
int next, mask = 1;
|
|
for(m=0;m<4;++m)
|
|
{
|
|
if(orIt & mask)
|
|
{
|
|
for(k=0;k<len[key];k++)
|
|
{
|
|
next = (k+1) < len[key] ? k+1 : 0;
|
|
|
|
if(!(clipMeToo[key][k] & mask))
|
|
{
|
|
clipPoints[!key][len[!key]++] = clipPoints[key][k];
|
|
if(!(clipMeToo[key][next] & mask))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(clipMeToo[key][next] & mask)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
switch(m)
|
|
{
|
|
case 0:
|
|
clipPoints[!key][len[!key]].AddScaled(
|
|
clipPoints[key][k],
|
|
Vector3D(
|
|
clipPoints[key][next].x - clipPoints[key][k].x,
|
|
clipPoints[key][next].y - clipPoints[key][k].y,
|
|
clipPoints[key][next].z - clipPoints[key][k].z
|
|
),
|
|
(x0-clipPoints[key][k].x)/(clipPoints[key][next].x-clipPoints[key][k].x)
|
|
);
|
|
Verify(len[!key]<7);
|
|
clipPoints[!key][len[!key]++].x = x0;
|
|
break;
|
|
case 1:
|
|
clipPoints[!key][len[!key]].AddScaled(
|
|
clipPoints[key][k],
|
|
Vector3D(
|
|
clipPoints[key][next].x - clipPoints[key][k].x,
|
|
clipPoints[key][next].y - clipPoints[key][k].y,
|
|
clipPoints[key][next].z - clipPoints[key][k].z
|
|
),
|
|
(z1-clipPoints[key][k].z)/(clipPoints[key][next].z-clipPoints[key][k].z)
|
|
);
|
|
Verify(len[!key]<7);
|
|
clipPoints[!key][len[!key]++].z = z1;
|
|
break;
|
|
case 2:
|
|
clipPoints[!key][len[!key]].AddScaled(
|
|
clipPoints[key][k],
|
|
Vector3D(
|
|
clipPoints[key][next].x - clipPoints[key][k].x,
|
|
clipPoints[key][next].y - clipPoints[key][k].y,
|
|
clipPoints[key][next].z - clipPoints[key][k].z
|
|
),
|
|
(x1-clipPoints[key][k].x)/(clipPoints[key][next].x-clipPoints[key][k].x)
|
|
);
|
|
Verify(len[!key]<7);
|
|
clipPoints[!key][len[!key]++].x = x1;
|
|
break;
|
|
case 3:
|
|
clipPoints[!key][len[!key]].AddScaled(
|
|
clipPoints[key][k],
|
|
Vector3D(
|
|
clipPoints[key][next].x - clipPoints[key][k].x,
|
|
clipPoints[key][next].y - clipPoints[key][k].y,
|
|
clipPoints[key][next].z - clipPoints[key][k].z
|
|
),
|
|
(z0-clipPoints[key][k].z)/(clipPoints[key][next].z-clipPoints[key][k].z)
|
|
);
|
|
Verify(len[!key]<7);
|
|
clipPoints[!key][len[!key]++].z = z0;
|
|
break;
|
|
}
|
|
}
|
|
key = !key;
|
|
for(k=0;k<len[key];k++)
|
|
{
|
|
clipMeToo[key][k] = 0;
|
|
if(clipPoints[key][k].x < x0)
|
|
{
|
|
clipMeToo[key][k] |= 1;
|
|
}
|
|
if(clipPoints[key][k].x > x1)
|
|
{
|
|
clipMeToo[key][k] |= 4;
|
|
}
|
|
if(clipPoints[key][k].z < z0)
|
|
{
|
|
clipMeToo[key][k] |= 8;
|
|
}
|
|
if(clipPoints[key][k].z > z1)
|
|
{
|
|
clipMeToo[key][k] |= 2;
|
|
}
|
|
}
|
|
len[!key] = 0;
|
|
}
|
|
mask <<= 1;
|
|
}
|
|
|
|
for(m=0;m<len[key];m++)
|
|
{
|
|
index[m] = FindAddPoint(clipPoints[key][m]);
|
|
}
|
|
|
|
int ba = -1;
|
|
float a = -360.0f;
|
|
for(m=0;m<len[key];m++)
|
|
{
|
|
angles[m] = GetAngle(
|
|
uniquePoints[index[(m-1+len[key])%len[key]]].p,
|
|
uniquePoints[index[m]].p,
|
|
uniquePoints[index[(m+len[key])%len[key]]].p
|
|
);
|
|
|
|
if(angles[m] > a)
|
|
{
|
|
a = angles[m];
|
|
ba = m;
|
|
}
|
|
}
|
|
|
|
for(m=1;m<len[key]-1;m++)
|
|
{
|
|
triangleIndices[usedTriangleIndices].v[0] = index[ba];
|
|
triangleIndices[usedTriangleIndices].v[1] = index[(ba+m)%len[key]];
|
|
triangleIndices[usedTriangleIndices].v[2] = index[(ba+m+1)%len[key]];
|
|
|
|
if( (triangleIndices[usedTriangleIndices].v[0] !=
|
|
triangleIndices[usedTriangleIndices].v[1]) &&
|
|
(triangleIndices[usedTriangleIndices].v[0] !=
|
|
triangleIndices[usedTriangleIndices].v[2]) &&
|
|
(triangleIndices[usedTriangleIndices].v[1] !=
|
|
triangleIndices[usedTriangleIndices].v[2]) )
|
|
{
|
|
uniquePoints[triangleIndices[usedTriangleIndices].v[0]].Add(&triangleIndices[usedTriangleIndices],
|
|
0);
|
|
uniquePoints[triangleIndices[usedTriangleIndices].v[1]].Add(&triangleIndices[usedTriangleIndices],
|
|
1);
|
|
uniquePoints[triangleIndices[usedTriangleIndices].v[2]].Add(&triangleIndices[usedTriangleIndices],
|
|
2);
|
|
|
|
triangleIndices[usedTriangleIndices++].GetSurfaceAreaAndCentroid();
|
|
}
|
|
else
|
|
{
|
|
refused++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for(i=orgUsedTriangleIndices;i<usedTriangleIndices;i++)
|
|
{
|
|
tempTrianglesPtr[newCount++] = &triangleIndices[i];
|
|
}
|
|
|
|
tempTrianglesPtr.SetLength(newCount);
|
|
|
|
#if _ARMOR
|
|
for(i=0,j=0;i<newCount;++i)
|
|
{
|
|
if(onOffPoints[i] == 0)
|
|
{
|
|
Verify(tempTrianglesPtr[i]->GetPoint(0).x >= x0);
|
|
Verify(tempTrianglesPtr[i]->GetPoint(0).x <= x1);
|
|
Verify(tempTrianglesPtr[i]->GetPoint(0).z >= z0);
|
|
Verify(tempTrianglesPtr[i]->GetPoint(0).z <= z1);
|
|
|
|
Verify(tempTrianglesPtr[i]->GetPoint(1).x >= x0);
|
|
Verify(tempTrianglesPtr[i]->GetPoint(1).x <= x1);
|
|
Verify(tempTrianglesPtr[i]->GetPoint(1).z >= z0);
|
|
Verify(tempTrianglesPtr[i]->GetPoint(1).z <= z1);
|
|
|
|
Verify(tempTrianglesPtr[i]->GetPoint(2).x >= x0);
|
|
Verify(tempTrianglesPtr[i]->GetPoint(2).x <= x1);
|
|
Verify(tempTrianglesPtr[i]->GetPoint(2).z >= z0);
|
|
Verify(tempTrianglesPtr[i]->GetPoint(2).z <= z1);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
brokenTriangles += newCount;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
HFSlimMZ::CreateTile(
|
|
ElementRenderer::ListElement *list,
|
|
ElementRenderer::GroupElement *waterList,
|
|
DynamicArrayOf<TriangleStruct*>& tempTrianglesPtr,
|
|
int index,
|
|
int depth, int maxdepth,
|
|
int maxNumOfTrianglesPerMesh,
|
|
Scalar xGridOffset,
|
|
Scalar zGridOffset,
|
|
Scalar xGrid,
|
|
Scalar zGrid,
|
|
int tileX,
|
|
int tileZ,
|
|
const char *texRoot
|
|
)
|
|
{
|
|
char textureName[1024];
|
|
Scalar x0, z0, x1, z1;
|
|
|
|
x0 = xGridOffset + tileX*xGrid;
|
|
z0 = zGridOffset + tileZ*zGrid;
|
|
x1 = x0 + xGrid;
|
|
z1 = z0 + zGrid;
|
|
|
|
MLRState state;
|
|
|
|
gos_PushCurrentHeap(ElementRenderer::GroupElement::s_Heap);
|
|
ElementRenderer::GroupElement *group = new ElementRenderer::GroupElement;
|
|
Register_Object(group);
|
|
|
|
list->AttachIndexedChild(index, group);
|
|
group->NeedNewBounds();
|
|
group->SetVolumeCullMode();
|
|
ElementRenderer::ListElement *subList = new ElementRenderer::ListElement;
|
|
Register_Object(subList);
|
|
subList->SetSize(1);
|
|
group->AttachChild(subList);
|
|
subList->NeedNewBounds();
|
|
subList->SetVolumeCullMode();
|
|
gos_PopCurrentHeap();
|
|
|
|
/*
|
|
state.SetBackFaceOn();
|
|
state.SetDitherOff();
|
|
state.SetTextureCorrectionOn();
|
|
state.SetZBufferCompareOn();
|
|
state.SetZBufferWriteOn();
|
|
|
|
state.SetFilterMode(MLRState::BiLinearFilterMode);
|
|
|
|
state.SetFogMode(MLRState::OverrideFogMode);
|
|
state.SetFogData(
|
|
0xff9090f0,
|
|
0.0f,
|
|
700.0f,
|
|
1000.0f
|
|
);
|
|
*/
|
|
state.SetPriority(MLRState::DefaultPriority);
|
|
|
|
#if 0
|
|
sprintf(textureName, "%s_%1d_%02x%02x",
|
|
texRoot,
|
|
depth,
|
|
(1<<depth) - tileX/(1<<(maxdepth-depth)) - 1,
|
|
(1<<depth) - tileZ/(1<<(maxdepth-depth)) - 1
|
|
);
|
|
#else
|
|
sprintf(textureName, "%s_0_0000", texRoot);
|
|
#endif
|
|
|
|
MLRTexture *texture = MLRTexturePool::Instance->Add(textureName);
|
|
texture->SetHint(gosHint_AGPMemory | gosHint_DontShrink);
|
|
state.SetTextureHandle(texture->GetTextureHandle());
|
|
state.SetTextureWrapMode(MLRState::TextureClamp);
|
|
|
|
/* AnalyzeThis(
|
|
tempTrianglesPtr,
|
|
x0,
|
|
z0,
|
|
x1,
|
|
z1
|
|
);
|
|
*/
|
|
int i, j;
|
|
|
|
|
|
Scalar frame[8][4];
|
|
|
|
frame[0][0] = xGridOffset;
|
|
frame[0][1] = zGridOffset;
|
|
frame[0][2] = xGridOffset + 8*xGrid;
|
|
frame[0][3] = zGridOffset + 8*zGrid;
|
|
|
|
frame[1][0] = xGridOffset + 4*(tileX/4)*xGrid;
|
|
frame[1][1] = zGridOffset + 4*(tileZ/4)*zGrid;
|
|
frame[1][2] = frame[1][0] + 4*xGrid;
|
|
frame[1][3] = frame[1][1] + 4*zGrid;
|
|
|
|
for(i=2;i<8;i++)
|
|
{
|
|
frame[i][0] = xGridOffset + tileX*xGrid;
|
|
frame[i][1] = zGridOffset + tileZ*zGrid;
|
|
frame[i][2] = frame[i][0] + xGrid;
|
|
frame[i][3] = frame[i][1] + zGrid;
|
|
}
|
|
|
|
DynamicArrayOf<TriangleAbstract*> group_a;
|
|
|
|
int usable = tempTrianglesPtr.GetLength();
|
|
|
|
if(doWater==true)
|
|
{
|
|
DynamicArrayOf<TriangleStruct> underWaterTriangles(2*usable);
|
|
DynamicArrayOf<TriangleStruct> aboveWaterTriangles(2*usable);
|
|
|
|
WaterPools waterPools(usable, waterLevel);
|
|
waterPools.SetTileEdges(x0, x1, z0, z1);
|
|
|
|
int org=0, aw=0, uw=0;
|
|
|
|
for(i=0;i<usable;i++)
|
|
{
|
|
int ac=0, uc=0, ec=0;
|
|
|
|
for(j=0;j<3;j++)
|
|
{
|
|
if(tempTrianglesPtr[i]->GetPoint(j).y < waterLevel)
|
|
{
|
|
uc++;
|
|
}
|
|
else
|
|
{
|
|
if(tempTrianglesPtr[i]->GetPoint(j).y > waterLevel)
|
|
{
|
|
ac++;
|
|
}
|
|
else
|
|
{
|
|
ec++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(uc==0)
|
|
{
|
|
for(int q=0;q<3;q++)
|
|
{
|
|
Verify(tempTrianglesPtr[i]->v[q]<usedUniquePoints);
|
|
aboveWaterTriangles[aw].v[q] = tempTrianglesPtr[i]->v[q];
|
|
}
|
|
aw++;
|
|
}
|
|
else
|
|
{
|
|
if(ac==0)
|
|
{
|
|
for(int q=0;q<3;q++)
|
|
{
|
|
Verify(tempTrianglesPtr[i]->v[q]<usedUniquePoints);
|
|
underWaterTriangles[uw].v[q] = tempTrianglesPtr[i]->v[q];
|
|
}
|
|
if(underWaterTriangles[uw].GetSurfaceAreaAndCentroid()==true)
|
|
{
|
|
uw++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Verify(ec<2);
|
|
|
|
if(ec==0)
|
|
{
|
|
Point3D v[4];
|
|
Vector3D vc;
|
|
Scalar l[4];
|
|
|
|
if(ac>uc)
|
|
{
|
|
for(j=0;j<3;j++)
|
|
{
|
|
if(tempTrianglesPtr[i]->GetPoint(j).y < waterLevel)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
Verify(j<3);
|
|
|
|
int next = (j+1)%3;
|
|
int prev = (j+2)%3;
|
|
int now = j;
|
|
|
|
v[0].Lerp(
|
|
tempTrianglesPtr[i]->GetPoint(next),
|
|
tempTrianglesPtr[i]->GetPoint(j),
|
|
(waterLevel-tempTrianglesPtr[i]->GetPoint(next).y)/
|
|
(tempTrianglesPtr[i]->GetPoint(j).y-tempTrianglesPtr[i]->GetPoint(next).y)
|
|
);
|
|
Verify(Close_Enough(waterLevel, v[0].y));
|
|
v[0].y = waterLevel;
|
|
|
|
v[1] = tempTrianglesPtr[i]->GetPoint(next);
|
|
|
|
v[2] = tempTrianglesPtr[i]->GetPoint(prev);
|
|
|
|
v[3].Lerp(
|
|
tempTrianglesPtr[i]->GetPoint(prev),
|
|
tempTrianglesPtr[i]->GetPoint(j),
|
|
(waterLevel-tempTrianglesPtr[i]->GetPoint(prev).y)/
|
|
(tempTrianglesPtr[i]->GetPoint(j).y-tempTrianglesPtr[i]->GetPoint(prev).y)
|
|
);
|
|
Verify(Close_Enough(waterLevel, v[3].y));
|
|
v[3].y = waterLevel;
|
|
|
|
waterPools.AddEdge(v[0], v[3], tempTrianglesPtr[i]->plane.normal);
|
|
|
|
vc.Cross(v[1], v[0], v[3]);
|
|
l[0] = vc.GetLengthSquared();
|
|
|
|
vc.Cross(v[2], v[1], v[0]);
|
|
l[1] = vc.GetLengthSquared();
|
|
|
|
vc.Cross(v[3], v[2], v[1]);
|
|
l[2] = vc.GetLengthSquared();
|
|
|
|
vc.Cross(v[0], v[3], v[2]);
|
|
l[3] = vc.GetLengthSquared();
|
|
|
|
int biggest = 0;
|
|
for(j=1;j<4;j++)
|
|
{
|
|
if(l[biggest]<l[j])
|
|
{
|
|
biggest = j;
|
|
}
|
|
}
|
|
|
|
aboveWaterTriangles[aw].v[0] = FindAddPoint(v[biggest]);
|
|
aboveWaterTriangles[aw].v[1] = FindAddPoint(v[(biggest+1)%4]);
|
|
aboveWaterTriangles[aw].v[2] = FindAddPoint(v[(biggest+2)%4]);
|
|
if(aboveWaterTriangles[aw].GetSurfaceAreaAndCentroid()==true)
|
|
{
|
|
aw++;
|
|
}
|
|
|
|
aboveWaterTriangles[aw].v[0] = FindAddPoint(v[biggest]);
|
|
aboveWaterTriangles[aw].v[1] = FindAddPoint(v[(biggest+2)%4]);
|
|
aboveWaterTriangles[aw].v[2] = FindAddPoint(v[(biggest+3)%4]);
|
|
if(aboveWaterTriangles[aw].GetSurfaceAreaAndCentroid()==true)
|
|
{
|
|
aw++;
|
|
}
|
|
|
|
underWaterTriangles[uw].v[0] = tempTrianglesPtr[i]->v[now];
|
|
Verify(underWaterTriangles[uw].v[0]<usedUniquePoints);
|
|
|
|
underWaterTriangles[uw].v[1] = FindAddPoint(v[0]);
|
|
Verify(underWaterTriangles[uw].v[1]<usedUniquePoints);
|
|
|
|
underWaterTriangles[uw].v[2] = FindAddPoint(v[3]);
|
|
Verify(underWaterTriangles[uw].v[2]<usedUniquePoints);
|
|
|
|
if(underWaterTriangles[uw].GetSurfaceAreaAndCentroid()==true)
|
|
{
|
|
uw++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(j=0;j<3;j++)
|
|
{
|
|
if(tempTrianglesPtr[i]->GetPoint(j).y > waterLevel)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
Verify(j<3);
|
|
|
|
int next = (j+1)%3;
|
|
int prev = (j+2)%3;
|
|
int now = j;
|
|
|
|
v[0].Lerp(
|
|
tempTrianglesPtr[i]->GetPoint(next),
|
|
tempTrianglesPtr[i]->GetPoint(j),
|
|
(waterLevel-tempTrianglesPtr[i]->GetPoint(next).y)/
|
|
(tempTrianglesPtr[i]->GetPoint(j).y-tempTrianglesPtr[i]->GetPoint(next).y)
|
|
);
|
|
Verify(Close_Enough(waterLevel, v[0].y));
|
|
v[0].y = waterLevel;
|
|
|
|
v[1] = tempTrianglesPtr[i]->GetPoint(next);
|
|
|
|
v[2] = tempTrianglesPtr[i]->GetPoint(prev);
|
|
|
|
v[3].Lerp(
|
|
tempTrianglesPtr[i]->GetPoint(prev),
|
|
tempTrianglesPtr[i]->GetPoint(j),
|
|
(waterLevel-tempTrianglesPtr[i]->GetPoint(prev).y)/
|
|
(tempTrianglesPtr[i]->GetPoint(j).y-tempTrianglesPtr[i]->GetPoint(prev).y)
|
|
);
|
|
Verify(Close_Enough(waterLevel, v[3].y));
|
|
v[3].y = waterLevel;
|
|
|
|
waterPools.AddEdge(v[0], v[3], tempTrianglesPtr[i]->plane.normal);
|
|
|
|
vc.Cross(v[1], v[0], v[3]);
|
|
l[0] = vc.GetLengthSquared();
|
|
|
|
vc.Cross(v[2], v[1], v[0]);
|
|
l[1] = vc.GetLengthSquared();
|
|
|
|
vc.Cross(v[3], v[2], v[1]);
|
|
l[2] = vc.GetLengthSquared();
|
|
|
|
vc.Cross(v[0], v[3], v[2]);
|
|
l[3] = vc.GetLengthSquared();
|
|
|
|
int biggest = 0;
|
|
for(j=1;j<4;j++)
|
|
{
|
|
if(l[biggest]<l[j])
|
|
{
|
|
biggest = j;
|
|
}
|
|
}
|
|
|
|
underWaterTriangles[uw].v[0] = FindAddPoint(v[biggest]);
|
|
Verify(underWaterTriangles[uw].v[0]<usedUniquePoints);
|
|
|
|
underWaterTriangles[uw].v[1] = FindAddPoint(v[(biggest+1)%4]);
|
|
Verify(underWaterTriangles[uw].v[1]<usedUniquePoints);
|
|
|
|
underWaterTriangles[uw].v[2] = FindAddPoint(v[(biggest+2)%4]);
|
|
Verify(underWaterTriangles[uw].v[2]<usedUniquePoints);
|
|
|
|
if(underWaterTriangles[uw].GetSurfaceAreaAndCentroid()==true)
|
|
{
|
|
uw++;
|
|
}
|
|
|
|
underWaterTriangles[uw].v[0] = FindAddPoint(v[biggest]);
|
|
Verify(underWaterTriangles[uw].v[0]<usedUniquePoints);
|
|
|
|
underWaterTriangles[uw].v[1] = FindAddPoint(v[(biggest+2)%4]);
|
|
Verify(underWaterTriangles[uw].v[1]<usedUniquePoints);
|
|
|
|
underWaterTriangles[uw].v[2] = FindAddPoint(v[(biggest+3)%4]);
|
|
Verify(underWaterTriangles[uw].v[2]<usedUniquePoints);
|
|
|
|
if(underWaterTriangles[uw].GetSurfaceAreaAndCentroid())
|
|
{
|
|
uw++;
|
|
}
|
|
|
|
aboveWaterTriangles[aw].v[0] = tempTrianglesPtr[i]->v[now];
|
|
aboveWaterTriangles[aw].v[1] = FindAddPoint(v[0]);
|
|
aboveWaterTriangles[aw].v[2] = FindAddPoint(v[3]);
|
|
if(aboveWaterTriangles[aw].GetSurfaceAreaAndCentroid()==true)
|
|
{
|
|
aw++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(j=0;j<3;j++)
|
|
{
|
|
if(!(tempTrianglesPtr[i]->GetPoint(j).y < waterLevel) &&
|
|
!(tempTrianglesPtr[i]->GetPoint(j).y > waterLevel))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
Verify(j<3);
|
|
|
|
int next = (j+1)%3;
|
|
int prev = (j+2)%3;
|
|
Point3D tempPoint;
|
|
|
|
if(tempTrianglesPtr[i]->GetPoint(next).y < waterLevel)
|
|
{
|
|
underWaterTriangles[uw].v[0] = tempTrianglesPtr[i]->v[j];
|
|
underWaterTriangles[uw].v[1] = tempTrianglesPtr[i]->v[next];
|
|
|
|
tempPoint.Lerp(
|
|
tempTrianglesPtr[i]->GetPoint(prev),
|
|
tempTrianglesPtr[i]->GetPoint(next),
|
|
(waterLevel-tempTrianglesPtr[i]->GetPoint(prev).y)/
|
|
(tempTrianglesPtr[i]->GetPoint(next).y-tempTrianglesPtr[i]->GetPoint(prev).y)
|
|
);
|
|
Verify(Close_Enough(waterLevel, tempPoint.y));
|
|
tempPoint.y = waterLevel;
|
|
|
|
underWaterTriangles[uw].v[2] = FindAddPoint(tempPoint);
|
|
|
|
waterPools.AddEdge(
|
|
underWaterTriangles[uw].GetPoint(0),
|
|
underWaterTriangles[uw].GetPoint(2),
|
|
tempTrianglesPtr[i]->plane.normal
|
|
);
|
|
|
|
if(underWaterTriangles[uw].GetSurfaceAreaAndCentroid()==true)
|
|
{
|
|
uw++;
|
|
}
|
|
|
|
|
|
aboveWaterTriangles[aw].v[0] = tempTrianglesPtr[i]->v[j];
|
|
aboveWaterTriangles[aw].v[1] = underWaterTriangles[uw-1].v[2];
|
|
aboveWaterTriangles[aw].v[2] = tempTrianglesPtr[i]->v[prev];
|
|
|
|
if(aboveWaterTriangles[aw].GetSurfaceAreaAndCentroid()==true)
|
|
{
|
|
aw++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aboveWaterTriangles[aw].v[0] = tempTrianglesPtr[i]->v[j];
|
|
aboveWaterTriangles[aw].v[1] = tempTrianglesPtr[i]->v[next];
|
|
|
|
tempPoint.Lerp(
|
|
tempTrianglesPtr[i]->GetPoint(prev),
|
|
tempTrianglesPtr[i]->GetPoint(next),
|
|
(waterLevel-tempTrianglesPtr[i]->GetPoint(prev).y)/
|
|
(tempTrianglesPtr[i]->GetPoint(next).y-tempTrianglesPtr[i]->GetPoint(prev).y)
|
|
);
|
|
Verify(Close_Enough(waterLevel, tempPoint.y));
|
|
tempPoint.y = waterLevel;
|
|
|
|
aboveWaterTriangles[aw].v[2] = FindAddPoint(tempPoint);
|
|
|
|
waterPools.AddEdge(
|
|
aboveWaterTriangles[aw].GetPoint(0),
|
|
aboveWaterTriangles[aw].GetPoint(2),
|
|
tempTrianglesPtr[i]->plane.normal
|
|
);
|
|
|
|
if(aboveWaterTriangles[aw].GetSurfaceAreaAndCentroid()==true)
|
|
{
|
|
aw++;
|
|
}
|
|
|
|
underWaterTriangles[uw].v[0] = tempTrianglesPtr[i]->v[j];
|
|
underWaterTriangles[uw].v[1] = aboveWaterTriangles[aw-1].v[2];
|
|
underWaterTriangles[uw].v[2] = tempTrianglesPtr[i]->v[prev];
|
|
|
|
if(underWaterTriangles[uw].GetSurfaceAreaAndCentroid()==true)
|
|
{
|
|
uw++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Verify(uw+aw >= usable);
|
|
|
|
if( (uw==0 && aw==usable) || (aw==0 && uw==usable) )
|
|
{
|
|
if(uw==usable)
|
|
{
|
|
gos_PushCurrentHeap(ElementRenderer::ListElement::s_Heap);
|
|
subList->SetSize(2);
|
|
gos_PopCurrentHeap();
|
|
}
|
|
|
|
group_a.SetLength(tempTrianglesPtr.GetLength());
|
|
for (i=0; i<tempTrianglesPtr.GetLength(); ++i)
|
|
{
|
|
group_a[i] = tempTrianglesPtr[i];
|
|
}
|
|
|
|
if(!BinSort2(
|
|
subList,
|
|
0,
|
|
maxdepth - depth,
|
|
group_a,
|
|
maxNumOfTrianglesPerMesh,
|
|
&frame,
|
|
&state,
|
|
uw==usable
|
|
)
|
|
)
|
|
{
|
|
if(silentMode==true)
|
|
{
|
|
fprintf(stderr, "Unstable triangle mesh created!");
|
|
}
|
|
else
|
|
{
|
|
PAUSE(("Unstable triangle mesh created!"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(uw==usable)
|
|
{
|
|
gos_PushCurrentHeap(ElementRenderer::ShapeElement::s_Heap);
|
|
|
|
ElementRenderer::ShapeElement* Shape = new ElementRenderer::ShapeElement;
|
|
Register_Object(Shape);
|
|
gos_PopCurrentHeap();
|
|
|
|
gos_PushCurrentHeap(MidLevelRenderer::ShapeHeap);
|
|
MLRShape *shape = new MLRShape(1);
|
|
Register_Object(shape);
|
|
gos_PopCurrentHeap();
|
|
|
|
MLRPrimitiveBase *prim = CreateWater( x0, x1, z0, z1, waterLevel);
|
|
Check_Object(prim);
|
|
shape->Add(prim);
|
|
|
|
prim->DetachReference();
|
|
|
|
Shape->SetMLRShape(shape);
|
|
|
|
const Point3D *p = NULL;
|
|
int nr_of_points = 0;
|
|
prim->GetCoordData(&p, &nr_of_points);
|
|
ReadOnlyArrayOf<Point3D> p_array;
|
|
p_array.AssignData(p, nr_of_points);
|
|
Shape->m_localOBB.ComputeBounds(p_array);
|
|
Shape->SetOBBMode();
|
|
|
|
/*
|
|
Shape->m_localOBB.localToParent = LinearMatrix4D::Identity;
|
|
Shape->m_localOBB.localToParent.BuildTranslation(
|
|
Point3D(
|
|
(x1+x0)*0.5f - xCenterOffset - Xoffset*dX,
|
|
waterLevel,
|
|
(z1+z0)*0.5f - zCenterOffset - Zoffset*dZ
|
|
)
|
|
);
|
|
|
|
Shape->m_localOBB.sphereRadius = 0.5f*xGrid*static_cast<Scalar>(sqrt(2.0f));
|
|
Check_Object(Shape);
|
|
*/
|
|
waterList->AttachChild(Shape);
|
|
Shape->SetVolumeCullMode();
|
|
|
|
subList->AttachIndexedChild(1, Shape);
|
|
}
|
|
brokenTriangles += usable;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// MLRPrimitiveBase *prim = waterPools.LinkEdges();
|
|
|
|
gos_PushCurrentHeap(ElementRenderer::ListElement::s_Heap);
|
|
subList->SetSize(3);
|
|
gos_PopCurrentHeap();
|
|
|
|
tempTrianglesPtr.SetLength(uw);
|
|
underWaterTriangles.SetLength(uw);
|
|
|
|
group_a.SetLength(uw);
|
|
for(i=0;i<uw;i++)
|
|
{
|
|
group_a[i] = &underWaterTriangles[i];
|
|
|
|
}
|
|
|
|
if(!BinSort2(
|
|
subList,
|
|
0,
|
|
maxdepth - depth,
|
|
group_a,
|
|
maxNumOfTrianglesPerMesh,
|
|
&frame,
|
|
&state,
|
|
true
|
|
)
|
|
)
|
|
{
|
|
if(silentMode==true)
|
|
{
|
|
fprintf(stderr, "Unstable triangle mesh created!");
|
|
}
|
|
else
|
|
{
|
|
PAUSE(("Unstable triangle mesh created!"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
brokenTriangles += uw;
|
|
}
|
|
|
|
tempTrianglesPtr.SetLength(aw);
|
|
aboveWaterTriangles.SetLength(aw);
|
|
|
|
group_a.SetLength(aw);
|
|
for(i=0;i<aw;i++)
|
|
{
|
|
group_a[i] = &aboveWaterTriangles[i];
|
|
|
|
}
|
|
|
|
if(!BinSort2(
|
|
subList,
|
|
1,
|
|
maxdepth - depth,
|
|
group_a,
|
|
maxNumOfTrianglesPerMesh,
|
|
&frame,
|
|
&state,
|
|
false
|
|
)
|
|
)
|
|
{
|
|
if(silentMode==true)
|
|
{
|
|
fprintf(stderr, "Unstable triangle mesh created!");
|
|
}
|
|
else
|
|
{
|
|
PAUSE(("Unstable triangle mesh created!"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
brokenTriangles += aw;
|
|
}
|
|
|
|
gos_PushCurrentHeap(ElementRenderer::ShapeElement::s_Heap);
|
|
|
|
ElementRenderer::ShapeElement* Shape = new ElementRenderer::ShapeElement;
|
|
Register_Object(Shape);
|
|
gos_PopCurrentHeap();
|
|
|
|
gos_PushCurrentHeap(MidLevelRenderer::ShapeHeap);
|
|
MLRShape *shape = new MLRShape(1);
|
|
Register_Object(shape);
|
|
gos_PopCurrentHeap();
|
|
|
|
MLRPrimitiveBase *prim = CreateWater( x0, x1, z0, z1, waterLevel);;
|
|
Check_Object(prim);
|
|
shape->Add(prim);
|
|
|
|
prim->DetachReference();
|
|
|
|
Shape->SetMLRShape(shape);
|
|
|
|
const Point3D *p = NULL;
|
|
int nr_of_points = 0;
|
|
prim->GetCoordData(&p, &nr_of_points);
|
|
ReadOnlyArrayOf<Point3D> p_array;
|
|
p_array.AssignData(p, nr_of_points);
|
|
Shape->m_localOBB.ComputeBounds(p_array);
|
|
Shape->SetOBBMode();
|
|
|
|
/*
|
|
Shape->m_localOBB.localToParent = LinearMatrix4D::Identity;
|
|
Shape->m_localOBB.localToParent.BuildTranslation(
|
|
Point3D(
|
|
(x1+x0)*0.5f - xCenterOffset - Xoffset*dX,
|
|
waterLevel,
|
|
(z1+z0)*0.5f - zCenterOffset - Zoffset*dZ
|
|
)
|
|
);
|
|
|
|
Shape->m_localOBB.sphereRadius = 0.5f*xGrid*static_cast<Scalar>(sqrt(2.0f));
|
|
Check_Object(Shape);
|
|
*/
|
|
waterList->AttachChild(Shape);
|
|
Shape->SetVolumeCullMode();
|
|
|
|
subList->AttachIndexedChild(2, Shape);
|
|
}
|
|
|
|
/*
|
|
bool px0z0, px0z1, px1z0, px1z1;
|
|
|
|
px0z0 = waterLevel < mesh->eval( (int)(x0/dX), (int)(z0/dZ) );
|
|
px0z1 = waterLevel < mesh->eval( (int)(x0/dX), (int)(z1/dZ) );
|
|
px1z0 = waterLevel < mesh->eval( (int)(x1/dX), (int)(z0/dZ) );
|
|
px1z1 = waterLevel < mesh->eval( (int)(x1/dX), (int)(z1/dZ) );
|
|
|
|
if(waterPools.waterEdgePointCount==0)
|
|
{
|
|
if(px0z0 == false)
|
|
{
|
|
Verify(px0z0==px0z1 && px0z0==px1z0 && px0z0==px1z1);
|
|
// found water
|
|
}
|
|
}
|
|
*/
|
|
|
|
}
|
|
else
|
|
{
|
|
group_a.SetLength(tempTrianglesPtr.GetLength());
|
|
for (i=0; i<tempTrianglesPtr.GetLength(); ++i)
|
|
{
|
|
group_a[i] = tempTrianglesPtr[i];
|
|
}
|
|
|
|
if(!BinSort(
|
|
subList,
|
|
0,
|
|
maxdepth - depth,
|
|
group_a,
|
|
maxNumOfTrianglesPerMesh,
|
|
&frame,
|
|
&state
|
|
)
|
|
)
|
|
{
|
|
if(silentMode==true)
|
|
{
|
|
fprintf(stderr, "Unstable triangle mesh created!");
|
|
}
|
|
else
|
|
{
|
|
PAUSE(("Unstable triangle mesh created!"));
|
|
}
|
|
}
|
|
}
|
|
|
|
group->Sync();
|
|
group->LockBounds();
|
|
group->SetNeverCullMode();
|
|
subList->LockBounds();
|
|
subList->SetNeverCullMode();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
HFSlimMZ::BuildTile(
|
|
ElementRenderer::ListElement *list,
|
|
ElementRenderer::GroupElement *waterList,
|
|
int index,
|
|
int depth, int maxdepth,
|
|
DynamicArrayOf<unsigned char>& onOffPoints,
|
|
int maxNumOfTrianglesPerMesh,
|
|
Scalar xGridOffset,
|
|
Scalar zGridOffset,
|
|
Scalar xGrid,
|
|
Scalar zGrid,
|
|
int tileX,
|
|
int tileZ,
|
|
const char *texRoot
|
|
)
|
|
{
|
|
char textureName[1024];
|
|
int numOfTriangles = toSortTriangles.GetLength();
|
|
|
|
DynamicArrayOf<TriangleAbstract*> tempTrianglesPtr(numOfTriangles);
|
|
DynamicArrayOf<ToDrawTriangle> tempTriangles(numOfTriangles);
|
|
|
|
int i, j, inCount, newCount = 0, extraTriangles = 0;
|
|
int k, l, m;
|
|
|
|
Scalar x0, z0, x1, z1;
|
|
|
|
x0 = xGridOffset + tileX*xGrid;
|
|
z0 = zGridOffset + tileZ*zGrid;
|
|
x1 = x0 + xGrid;
|
|
z1 = z0 + zGrid;
|
|
|
|
MLRState state;
|
|
|
|
gos_PushCurrentHeap(ElementRenderer::GroupElement::s_Heap);
|
|
ElementRenderer::GroupElement *group = new ElementRenderer::GroupElement;
|
|
Register_Object(group);
|
|
list->AttachIndexedChild(index, group);
|
|
group->NeedNewBounds();
|
|
group->SetVolumeCullMode();
|
|
gos_PopCurrentHeap();
|
|
|
|
gos_PushCurrentHeap(ElementRenderer::ListElement::s_Heap);
|
|
ElementRenderer::ListElement *subList = new ElementRenderer::ListElement;
|
|
Register_Object(subList);
|
|
subList->SetSize(1);
|
|
group->AttachChild(subList);
|
|
subList->NeedNewBounds();
|
|
subList->SetVolumeCullMode();
|
|
gos_PopCurrentHeap();
|
|
|
|
/*
|
|
state.SetBackFaceOn();
|
|
state.SetDitherOff();
|
|
state.SetTextureCorrectionOn();
|
|
state.SetZBufferCompareOn();
|
|
state.SetZBufferWriteOn();
|
|
|
|
state.SetFilterMode(MLRState::BiLinearFilterMode);
|
|
|
|
state.SetFogMode(MLRState::OverrideFogMode);
|
|
state.SetFogData(
|
|
0xff9090f0,
|
|
0.0f,
|
|
700.0f,
|
|
1000.0f
|
|
);
|
|
*/
|
|
state.SetPriority(MLRState::DefaultPriority);
|
|
|
|
#if 0
|
|
sprintf(textureName, "%s_%1d_%02x%02x",
|
|
texRoot,
|
|
depth,
|
|
(1<<depth) - tileX/(1<<(maxdepth-depth)) - 1,
|
|
(1<<depth) - tileZ/(1<<(maxdepth-depth)) - 1
|
|
);
|
|
#else
|
|
sprintf(textureName, "%s_0_0000", texRoot);
|
|
#endif
|
|
|
|
MLRTexture *texture = MLRTexturePool::Instance->Add(textureName);
|
|
texture->SetHint(gosHint_AGPMemory | gosHint_DontShrink);
|
|
state.SetTextureHandle(texture->GetTextureHandle());
|
|
state.SetTextureWrapMode(MLRState::TextureClamp);
|
|
|
|
for(i=0,j=0;i<numOfTriangles;j+=3,++i)
|
|
{
|
|
Verify(i<numOfTriangles);
|
|
Verify(j<3*numOfTriangles);
|
|
if(onOffPoints[i] == 0)
|
|
{
|
|
inCount = 0;
|
|
int clipIt[3] = {0, 0, 0}, orIt = 0, addIt = 0xf;
|
|
|
|
if(toSortTriangles[i]->GetPoint(0).x < x0)
|
|
{
|
|
clipIt[0] |= 1;
|
|
}
|
|
if(toSortTriangles[i]->GetPoint(0).x > x1)
|
|
{
|
|
clipIt[0] |= 4;
|
|
}
|
|
if(toSortTriangles[i]->GetPoint(0).z < z0)
|
|
{
|
|
clipIt[0] |= 8;
|
|
}
|
|
if(toSortTriangles[i]->GetPoint(0).z > z1)
|
|
{
|
|
clipIt[0] |= 2;
|
|
}
|
|
|
|
orIt |= clipIt[0];
|
|
addIt &= clipIt[0];
|
|
|
|
if(toSortTriangles[i]->GetPoint(1).x < x0)
|
|
{
|
|
clipIt[1] |= 1;
|
|
}
|
|
if(toSortTriangles[i]->GetPoint(1).x > x1)
|
|
{
|
|
clipIt[1] |= 4;
|
|
}
|
|
if(toSortTriangles[i]->GetPoint(1).z < z0)
|
|
{
|
|
clipIt[1] |= 8;
|
|
}
|
|
if(toSortTriangles[i]->GetPoint(1).z > z1)
|
|
{
|
|
clipIt[1] |= 2;
|
|
}
|
|
|
|
orIt |= clipIt[1];
|
|
addIt &= clipIt[1];
|
|
|
|
if(toSortTriangles[i]->GetPoint(2).x < x0)
|
|
{
|
|
clipIt[2] |= 1;
|
|
}
|
|
if(toSortTriangles[i]->GetPoint(2).x > x1)
|
|
{
|
|
clipIt[2] |= 4;
|
|
}
|
|
if(toSortTriangles[i]->GetPoint(2).z < z0)
|
|
{
|
|
clipIt[2] |= 8;
|
|
}
|
|
if(toSortTriangles[i]->GetPoint(2).z > z1)
|
|
{
|
|
clipIt[2] |= 2;
|
|
}
|
|
|
|
orIt |= clipIt[2];
|
|
addIt &= clipIt[2];
|
|
|
|
if(orIt == 0)
|
|
{
|
|
onOffPoints[i] = 1;
|
|
|
|
if(toSortTriangles[i]->area > SMALL)
|
|
{
|
|
if(! (toSortTriangles[i]->plane.normal.y > Stuff::SMALL) )
|
|
{
|
|
if(silentMode==true)
|
|
{
|
|
fprintf(stderr, "Found a triangle with a face normal not pointing up, consider revising map ! Program exits !\n");
|
|
exit(-1);
|
|
}
|
|
else
|
|
{
|
|
STOP(("Found a triangle with a face normal not pointing up, consider revising map !"));
|
|
}
|
|
}
|
|
tempTrianglesPtr[newCount++] = toSortTriangles[i];
|
|
}
|
|
}
|
|
else if(addIt==0)
|
|
{
|
|
if(orIt==1 || orIt==2 || orIt==4 || orIt==8)
|
|
{
|
|
Point3D triangle[3], clipPoints[6];
|
|
|
|
triangle[0].x = toSortTriangles[i]->GetPoint(0).x;
|
|
triangle[0].y = toSortTriangles[i]->GetPoint(0).y;
|
|
triangle[0].z = toSortTriangles[i]->GetPoint(0).z;
|
|
|
|
triangle[1].x = toSortTriangles[i]->GetPoint(1).x;
|
|
triangle[1].y = toSortTriangles[i]->GetPoint(1).y;
|
|
triangle[1].z = toSortTriangles[i]->GetPoint(1).z;
|
|
|
|
triangle[2].x = toSortTriangles[i]->GetPoint(2).x;
|
|
triangle[2].y = toSortTriangles[i]->GetPoint(2).y;
|
|
triangle[2].z = toSortTriangles[i]->GetPoint(2).z;
|
|
|
|
l = 0;
|
|
for(k=0;k<3;k++)
|
|
{
|
|
int next = k+1>2?0:k+1;
|
|
if(clipIt[k]==0)
|
|
{
|
|
clipPoints[l++] = triangle[k];
|
|
if(clipIt[next]==0)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(clipIt[next]!=0)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
//
|
|
//-----------------------------------------------------
|
|
// Find the boundary conditions that match our clipping
|
|
// plane
|
|
//-----------------------------------------------------
|
|
//
|
|
int mask = 1;
|
|
for (m=0; m<4; m++)
|
|
{
|
|
if((clipIt[k] | clipIt[next]) & mask)
|
|
{
|
|
switch(m)
|
|
{
|
|
case 0:
|
|
clipPoints[l].AddScaled(
|
|
triangle[k],
|
|
Vector3D(
|
|
triangle[next].x - triangle[k].x,
|
|
triangle[next].y - triangle[k].y,
|
|
triangle[next].z - triangle[k].z
|
|
),
|
|
(x0-triangle[k].x)/(triangle[next].x-triangle[k].x)
|
|
|
|
);
|
|
clipPoints[l++].x = x0;
|
|
break;
|
|
case 1:
|
|
clipPoints[l].AddScaled(
|
|
triangle[k],
|
|
Vector3D(
|
|
triangle[next].x - triangle[k].x,
|
|
triangle[next].y - triangle[k].y,
|
|
triangle[next].z - triangle[k].z
|
|
),
|
|
(z1-triangle[k].z)/(triangle[next].z-triangle[k].z)
|
|
);
|
|
clipPoints[l++].z = z1;
|
|
break;
|
|
case 2:
|
|
clipPoints[l].AddScaled(
|
|
triangle[k],
|
|
Vector3D(
|
|
triangle[next].x - triangle[k].x,
|
|
triangle[next].y - triangle[k].y,
|
|
triangle[next].z - triangle[k].z
|
|
),
|
|
(x1-triangle[k].x)/(triangle[next].x-triangle[k].x)
|
|
);
|
|
clipPoints[l++].x = x1;
|
|
break;
|
|
case 3:
|
|
clipPoints[l].AddScaled(
|
|
triangle[k],
|
|
Vector3D(
|
|
triangle[next].x - triangle[k].x,
|
|
triangle[next].y - triangle[k].y,
|
|
triangle[next].z - triangle[k].z
|
|
),
|
|
(z0-triangle[k].z)/(triangle[next].z-triangle[k].z)
|
|
);
|
|
clipPoints[l++].z = z0;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
mask <<= 1;
|
|
}
|
|
}
|
|
Verify(l>2);
|
|
for(m=1;m<l-1;m++)
|
|
{
|
|
tempTriangles[extraTriangles].SetPoint(0, clipPoints[0].x,
|
|
clipPoints[0].y, clipPoints[0].z);
|
|
tempTriangles[extraTriangles].SetPoint(1, clipPoints[m].x,
|
|
clipPoints[m].y, clipPoints[m].z);
|
|
tempTriangles[extraTriangles].SetPoint(2, clipPoints[m+1].x,
|
|
clipPoints[m+1].y, clipPoints[m+1].z);
|
|
|
|
if(tempTriangles[extraTriangles].GetSurfaceAreaAndCentroid() == true)
|
|
{
|
|
tempTrianglesPtr[newCount++] = &tempTriangles[extraTriangles];
|
|
extraTriangles++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
int key=0, len[2] = {0, 0};
|
|
Point3D clipPoints[2][6];
|
|
int clipMeToo[2][6];
|
|
|
|
clipPoints[key][0].x = toSortTriangles[i]->GetPoint(0).x;
|
|
clipPoints[key][0].y = toSortTriangles[i]->GetPoint(0).y;
|
|
clipPoints[key][0].z = toSortTriangles[i]->GetPoint(0).z;
|
|
|
|
clipPoints[key][1].x = toSortTriangles[i]->GetPoint(1).x;
|
|
clipPoints[key][1].y = toSortTriangles[i]->GetPoint(1).y;
|
|
clipPoints[key][1].z = toSortTriangles[i]->GetPoint(1).z;
|
|
|
|
clipPoints[key][2].x = toSortTriangles[i]->GetPoint(2).x;
|
|
clipPoints[key][2].y = toSortTriangles[i]->GetPoint(2).y;
|
|
clipPoints[key][2].z = toSortTriangles[i]->GetPoint(2).z;
|
|
|
|
clipMeToo[key][0] = clipIt[0];
|
|
clipMeToo[key][1] = clipIt[1];
|
|
clipMeToo[key][2] = clipIt[2];
|
|
|
|
len[key] = 3;
|
|
|
|
int next, mask = 1;
|
|
for(m=0;m<4;++m)
|
|
{
|
|
if(orIt & mask)
|
|
{
|
|
for(k=0;k<len[key];k++)
|
|
{
|
|
next = (k+1) < len[key] ? k+1 : 0;
|
|
|
|
if(!(clipMeToo[key][k] & mask))
|
|
{
|
|
clipPoints[!key][len[!key]++] = clipPoints[key][k];
|
|
if(!(clipMeToo[key][next] & mask))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(clipMeToo[key][next] & mask)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
switch(m)
|
|
{
|
|
case 0:
|
|
clipPoints[!key][len[!key]].AddScaled(
|
|
clipPoints[key][k],
|
|
Vector3D(
|
|
clipPoints[key][next].x - clipPoints[key][k].x,
|
|
clipPoints[key][next].y - clipPoints[key][k].y,
|
|
clipPoints[key][next].z - clipPoints[key][k].z
|
|
),
|
|
(x0-clipPoints[key][k].x)/(clipPoints[key][next].x-clipPoints[key][k].x)
|
|
);
|
|
clipPoints[!key][len[!key]++].x = x0;
|
|
break;
|
|
case 1:
|
|
clipPoints[!key][len[!key]].AddScaled(
|
|
clipPoints[key][k],
|
|
Vector3D(
|
|
clipPoints[key][next].x - clipPoints[key][k].x,
|
|
clipPoints[key][next].y - clipPoints[key][k].y,
|
|
clipPoints[key][next].z - clipPoints[key][k].z
|
|
),
|
|
(z1-clipPoints[key][k].z)/(clipPoints[key][next].z-clipPoints[key][k].z)
|
|
);
|
|
clipPoints[!key][len[!key]++].z = z1;
|
|
break;
|
|
case 2:
|
|
clipPoints[!key][len[!key]].AddScaled(
|
|
clipPoints[key][k],
|
|
Vector3D(
|
|
clipPoints[key][next].x - clipPoints[key][k].x,
|
|
clipPoints[key][next].y - clipPoints[key][k].y,
|
|
clipPoints[key][next].z - clipPoints[key][k].z
|
|
),
|
|
(x1-clipPoints[key][k].x)/(clipPoints[key][next].x-clipPoints[key][k].x)
|
|
);
|
|
clipPoints[!key][len[!key]++].x = x1;
|
|
break;
|
|
case 3:
|
|
clipPoints[!key][len[!key]].AddScaled(
|
|
clipPoints[key][k],
|
|
Vector3D(
|
|
clipPoints[key][next].x - clipPoints[key][k].x,
|
|
clipPoints[key][next].y - clipPoints[key][k].y,
|
|
clipPoints[key][next].z - clipPoints[key][k].z
|
|
),
|
|
(z0-clipPoints[key][k].z)/(clipPoints[key][next].z-clipPoints[key][k].z)
|
|
);
|
|
clipPoints[!key][len[!key]++].z = z0;
|
|
break;
|
|
}
|
|
}
|
|
key = !key;
|
|
for(k=0;k<len[key];k++)
|
|
{
|
|
clipMeToo[key][k] = 0;
|
|
if(clipPoints[key][k].x < x0)
|
|
{
|
|
clipMeToo[key][k] |= 1;
|
|
}
|
|
if(clipPoints[key][k].x > x1)
|
|
{
|
|
clipMeToo[key][k] |= 4;
|
|
}
|
|
if(clipPoints[key][k].z < z0)
|
|
{
|
|
clipMeToo[key][k] |= 8;
|
|
}
|
|
if(clipPoints[key][k].z > z1)
|
|
{
|
|
clipMeToo[key][k] |= 2;
|
|
}
|
|
}
|
|
len[!key] = 0;
|
|
}
|
|
mask <<= 1;
|
|
}
|
|
|
|
for(m=1;m<len[key]-1;m++)
|
|
{
|
|
tempTriangles[extraTriangles].SetPoint(0,
|
|
clipPoints[key][0].x,
|
|
clipPoints[key][0].y,
|
|
clipPoints[key][0].z
|
|
);
|
|
tempTriangles[extraTriangles].SetPoint(1,
|
|
clipPoints[key][m].x,
|
|
clipPoints[key][m].y,
|
|
clipPoints[key][m].z
|
|
);
|
|
tempTriangles[extraTriangles].SetPoint(2,
|
|
clipPoints[key][m+1].x,
|
|
clipPoints[key][m+1].y,
|
|
clipPoints[key][m+1].z
|
|
);
|
|
|
|
if(tempTriangles[extraTriangles].GetSurfaceAreaAndCentroid() == true)
|
|
{
|
|
tempTrianglesPtr[newCount++] = &tempTriangles[extraTriangles];
|
|
extraTriangles++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// SPEWALWAYS(("micgaert", "#1"));
|
|
// tempTriangles.SetLength(extraTriangles);
|
|
|
|
tempTrianglesPtr.SetLength(newCount);
|
|
|
|
#if _ARMOR
|
|
for(i=0,j=0;i<newCount;++i)
|
|
{
|
|
if(onOffPoints[i] == 0)
|
|
{
|
|
Verify(tempTrianglesPtr[i]->GetPoint(0).x >= x0);
|
|
Verify(tempTrianglesPtr[i]->GetPoint(0).x <= x1);
|
|
Verify(tempTrianglesPtr[i]->GetPoint(0).z >= z0);
|
|
Verify(tempTrianglesPtr[i]->GetPoint(0).z <= z1);
|
|
|
|
Verify(tempTrianglesPtr[i]->GetPoint(1).x >= x0);
|
|
Verify(tempTrianglesPtr[i]->GetPoint(1).x <= x1);
|
|
Verify(tempTrianglesPtr[i]->GetPoint(1).z >= z0);
|
|
Verify(tempTrianglesPtr[i]->GetPoint(1).z <= z1);
|
|
|
|
Verify(tempTrianglesPtr[i]->GetPoint(2).x >= x0);
|
|
Verify(tempTrianglesPtr[i]->GetPoint(2).x <= x1);
|
|
Verify(tempTrianglesPtr[i]->GetPoint(2).z >= z0);
|
|
Verify(tempTrianglesPtr[i]->GetPoint(2).z <= z1);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
if(newCount > 0)
|
|
{
|
|
AnalyzeThis(
|
|
tempTrianglesPtr,
|
|
x0,
|
|
z0,
|
|
x1,
|
|
z1
|
|
);
|
|
|
|
int i = 1<<(maxdepth - depth);
|
|
|
|
frameArray frame;
|
|
|
|
frame[0][0] = xGridOffset;
|
|
frame[0][1] = zGridOffset;
|
|
frame[0][2] = xGridOffset + 8*xGrid;
|
|
frame[0][3] = zGridOffset + 8*zGrid;
|
|
|
|
frame[1][0] = xGridOffset + 4*(tileX/4)*xGrid;
|
|
frame[1][1] = zGridOffset + 4*(tileZ/4)*zGrid;
|
|
frame[1][2] = frame[1][0] + 4*xGrid;
|
|
frame[1][3] = frame[1][1] + 4*zGrid;
|
|
|
|
for(i=2;i<8;i++)
|
|
{
|
|
frame[i][0] = xGridOffset + tileX*xGrid;
|
|
frame[i][1] = zGridOffset + tileZ*zGrid;
|
|
frame[i][2] = frame[i][0] + xGrid;
|
|
frame[i][3] = frame[i][1] + zGrid;
|
|
}
|
|
|
|
// SPEWALWAYS(("micgaert", "#2"));
|
|
|
|
if(doWater==true)
|
|
{
|
|
DynamicArrayOf<ToDrawTriangle> underWaterTriangles(2*newCount);
|
|
DynamicArrayOf<ToDrawTriangle> aboveWaterTriangles(2*newCount);
|
|
|
|
WaterPools waterPools(newCount, waterLevel);
|
|
waterPools.SetTileEdges(x0, x1, z0, z1);
|
|
|
|
int org=0, aw=0, uw=0;
|
|
|
|
for(i=0;i<newCount;i++)
|
|
{
|
|
int ac=0, uc=0, ec=0;
|
|
|
|
if(tempTrianglesPtr[i]->GetPoint(0).y < waterLevel)
|
|
{
|
|
uc++;
|
|
}
|
|
else
|
|
{
|
|
if(tempTrianglesPtr[i]->GetPoint(0).y > waterLevel)
|
|
{
|
|
ac++;
|
|
}
|
|
else
|
|
{
|
|
ec++;
|
|
}
|
|
}
|
|
|
|
if(tempTrianglesPtr[i]->GetPoint(1).y < waterLevel)
|
|
{
|
|
uc++;
|
|
}
|
|
else
|
|
{
|
|
if(tempTrianglesPtr[i]->GetPoint(1).y > waterLevel)
|
|
{
|
|
ac++;
|
|
}
|
|
else
|
|
{
|
|
ec++;
|
|
}
|
|
}
|
|
if(tempTrianglesPtr[i]->GetPoint(2).y < waterLevel)
|
|
{
|
|
uc++;
|
|
}
|
|
else
|
|
{
|
|
if(tempTrianglesPtr[i]->GetPoint(2).y > waterLevel)
|
|
{
|
|
ac++;
|
|
}
|
|
else
|
|
{
|
|
ec++;
|
|
}
|
|
}
|
|
|
|
if(uc==0)
|
|
{
|
|
for(int q=0;q<3;q++)
|
|
{
|
|
aboveWaterTriangles[aw].v[q] = tempTrianglesPtr[i]->GetPoint(q);
|
|
}
|
|
if(aboveWaterTriangles[aw].GetSurfaceAreaAndCentroid()==true)
|
|
{
|
|
aw++;
|
|
for(j=0;j<3;j++)
|
|
{
|
|
Verify(aboveWaterTriangles[aw-1].v[j].x<=frame[maxAllDepth][2] &&
|
|
aboveWaterTriangles[aw-1].v[j].x>=frame[maxAllDepth][0]);
|
|
Verify(aboveWaterTriangles[aw-1].v[j].z<=frame[maxAllDepth][3] &&
|
|
aboveWaterTriangles[aw-1].v[j].z>=frame[maxAllDepth][1]);
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if(ac==0)
|
|
{
|
|
for(int q=0;q<3;q++)
|
|
{
|
|
underWaterTriangles[uw].v[q] = tempTrianglesPtr[i]->GetPoint(q);
|
|
}
|
|
if(underWaterTriangles[uw].GetSurfaceAreaAndCentroid()==true)
|
|
{
|
|
uw++;
|
|
for(j=0;j<3;j++)
|
|
{
|
|
Verify(underWaterTriangles[uw-1].v[j].x<=frame[maxAllDepth][2] &&
|
|
underWaterTriangles[uw-1].v[j].x>=frame[maxAllDepth][0]);
|
|
Verify(underWaterTriangles[uw-1].v[j].z<=frame[maxAllDepth][3] &&
|
|
underWaterTriangles[uw-1].v[j].z>=frame[maxAllDepth][1]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Verify(ec<2);
|
|
|
|
if(ec==0)
|
|
{
|
|
Point3D v[4];
|
|
Vector3D vc;
|
|
Scalar l[4];
|
|
|
|
if(ac>uc)
|
|
{
|
|
for(j=0;j<3;j++)
|
|
{
|
|
if(tempTrianglesPtr[i]->GetPoint(j).y < waterLevel)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
Verify(j<3);
|
|
|
|
int next = (j+1)%3;
|
|
int prev = (j+2)%3;
|
|
int now = j;
|
|
|
|
v[0].Lerp(
|
|
tempTrianglesPtr[i]->GetPoint(next),
|
|
tempTrianglesPtr[i]->GetPoint(j),
|
|
(waterLevel-tempTrianglesPtr[i]->GetPoint(next).y)/
|
|
(tempTrianglesPtr[i]->GetPoint(j).y-tempTrianglesPtr[i]->GetPoint(next).y)
|
|
);
|
|
Verify(Close_Enough(waterLevel, v[0].y));
|
|
v[0].y = waterLevel;
|
|
|
|
v[1] = tempTrianglesPtr[i]->GetPoint(next);
|
|
|
|
v[2] = tempTrianglesPtr[i]->GetPoint(prev);
|
|
|
|
v[3].Lerp(
|
|
tempTrianglesPtr[i]->GetPoint(prev),
|
|
tempTrianglesPtr[i]->GetPoint(j),
|
|
(waterLevel-tempTrianglesPtr[i]->GetPoint(prev).y)/
|
|
(tempTrianglesPtr[i]->GetPoint(j).y-tempTrianglesPtr[i]->GetPoint(prev).y)
|
|
);
|
|
Verify(Close_Enough(waterLevel, v[3].y));
|
|
v[3].y = waterLevel;
|
|
|
|
waterPools.AddEdge(v[0], v[3], tempTrianglesPtr[i]->plane.normal);
|
|
|
|
vc.Cross(v[1], v[0], v[3]);
|
|
l[0] = vc.GetLengthSquared();
|
|
|
|
vc.Cross(v[2], v[1], v[0]);
|
|
l[1] = vc.GetLengthSquared();
|
|
|
|
vc.Cross(v[3], v[2], v[1]);
|
|
l[2] = vc.GetLengthSquared();
|
|
|
|
vc.Cross(v[0], v[3], v[2]);
|
|
l[3] = vc.GetLengthSquared();
|
|
|
|
int biggest = 0;
|
|
for(j=1;j<4;j++)
|
|
{
|
|
if(l[biggest]<l[j])
|
|
{
|
|
biggest = j;
|
|
}
|
|
}
|
|
|
|
aboveWaterTriangles[aw].v[0] = v[biggest];
|
|
aboveWaterTriangles[aw].v[1] = v[(biggest+1)%4];
|
|
aboveWaterTriangles[aw].v[2] = v[(biggest+2)%4];
|
|
if(aboveWaterTriangles[aw].GetSurfaceAreaAndCentroid()==true)
|
|
{
|
|
for(j=0;j<3;j++)
|
|
{
|
|
Verify(aboveWaterTriangles[aw].v[j].x<=frame[maxAllDepth][2] &&
|
|
aboveWaterTriangles[aw].v[j].x>=frame[maxAllDepth][0]);
|
|
Verify(aboveWaterTriangles[aw].v[j].z<=frame[maxAllDepth][3] &&
|
|
aboveWaterTriangles[aw].v[j].z>=frame[maxAllDepth][1]);
|
|
}
|
|
aw++;
|
|
}
|
|
|
|
aboveWaterTriangles[aw].v[0] = v[biggest];
|
|
aboveWaterTriangles[aw].v[1] = v[(biggest+2)%4];
|
|
aboveWaterTriangles[aw].v[2] = v[(biggest+3)%4];
|
|
if(aboveWaterTriangles[aw].GetSurfaceAreaAndCentroid()==true)
|
|
{
|
|
for(j=0;j<3;j++)
|
|
{
|
|
Verify(aboveWaterTriangles[aw].v[j].x<=frame[maxAllDepth][2] &&
|
|
aboveWaterTriangles[aw].v[j].x>=frame[maxAllDepth][0]);
|
|
Verify(aboveWaterTriangles[aw].v[j].z<=frame[maxAllDepth][3] &&
|
|
aboveWaterTriangles[aw].v[j].z>=frame[maxAllDepth][1]);
|
|
}
|
|
aw++;
|
|
}
|
|
|
|
underWaterTriangles[uw].v[0] = tempTrianglesPtr[i]->GetPoint(now);
|
|
underWaterTriangles[uw].v[1] = v[0];
|
|
underWaterTriangles[uw].v[2] = v[3];
|
|
if(underWaterTriangles[uw].GetSurfaceAreaAndCentroid()==true)
|
|
{
|
|
for(j=0;j<3;j++)
|
|
{
|
|
Verify(underWaterTriangles[uw].v[j].x<=frame[maxAllDepth][2] &&
|
|
underWaterTriangles[uw].v[j].x>=frame[maxAllDepth][0]);
|
|
Verify(underWaterTriangles[uw].v[j].z<=frame[maxAllDepth][3] &&
|
|
underWaterTriangles[uw].v[j].z>=frame[maxAllDepth][1]);
|
|
}
|
|
uw++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(j=0;j<3;j++)
|
|
{
|
|
if(tempTrianglesPtr[i]->GetPoint(j).y > waterLevel)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
Verify(j<3);
|
|
|
|
int next = (j+1)%3;
|
|
int prev = (j+2)%3;
|
|
int now = j;
|
|
|
|
v[0].Lerp(
|
|
tempTrianglesPtr[i]->GetPoint(next),
|
|
tempTrianglesPtr[i]->GetPoint(j),
|
|
(waterLevel-tempTrianglesPtr[i]->GetPoint(next).y)/
|
|
(tempTrianglesPtr[i]->GetPoint(j).y-tempTrianglesPtr[i]->GetPoint(next).y)
|
|
);
|
|
Verify(Close_Enough(waterLevel, v[0].y));
|
|
v[0].y = waterLevel;
|
|
|
|
v[1] = tempTrianglesPtr[i]->GetPoint(next);
|
|
|
|
v[2] = tempTrianglesPtr[i]->GetPoint(prev);
|
|
|
|
v[3].Lerp(
|
|
tempTrianglesPtr[i]->GetPoint(prev),
|
|
tempTrianglesPtr[i]->GetPoint(j),
|
|
(waterLevel-tempTrianglesPtr[i]->GetPoint(prev).y)/
|
|
(tempTrianglesPtr[i]->GetPoint(j).y-tempTrianglesPtr[i]->GetPoint(prev).y)
|
|
);
|
|
Verify(Close_Enough(waterLevel, v[3].y));
|
|
v[3].y = waterLevel;
|
|
|
|
waterPools.AddEdge(v[0], v[3], tempTrianglesPtr[i]->plane.normal);
|
|
|
|
vc.Cross(v[1], v[0], v[3]);
|
|
l[0] = vc.GetLengthSquared();
|
|
|
|
vc.Cross(v[2], v[1], v[0]);
|
|
l[1] = vc.GetLengthSquared();
|
|
|
|
vc.Cross(v[3], v[2], v[1]);
|
|
l[2] = vc.GetLengthSquared();
|
|
|
|
vc.Cross(v[0], v[3], v[2]);
|
|
l[3] = vc.GetLengthSquared();
|
|
|
|
int biggest = 0;
|
|
for(j=1;j<4;j++)
|
|
{
|
|
if(l[biggest]<l[j])
|
|
{
|
|
biggest = j;
|
|
}
|
|
}
|
|
|
|
underWaterTriangles[uw].v[0] = v[biggest];
|
|
underWaterTriangles[uw].v[1] = v[(biggest+1)%4];
|
|
underWaterTriangles[uw].v[2] = v[(biggest+2)%4];
|
|
if(underWaterTriangles[uw].GetSurfaceAreaAndCentroid()==true)
|
|
{
|
|
for(j=0;j<3;j++)
|
|
{
|
|
Verify(underWaterTriangles[uw].v[j].x<=frame[maxAllDepth][2] &&
|
|
underWaterTriangles[uw].v[j].x>=frame[maxAllDepth][0]);
|
|
Verify(underWaterTriangles[uw].v[j].z<=frame[maxAllDepth][3] &&
|
|
underWaterTriangles[uw].v[j].z>=frame[maxAllDepth][1]);
|
|
}
|
|
uw++;
|
|
}
|
|
|
|
underWaterTriangles[uw].v[0] = v[biggest];
|
|
underWaterTriangles[uw].v[1] = v[(biggest+2)%4];
|
|
underWaterTriangles[uw].v[2] = v[(biggest+3)%4];
|
|
if(underWaterTriangles[uw].GetSurfaceAreaAndCentroid())
|
|
{
|
|
for(j=0;j<3;j++)
|
|
{
|
|
Verify(underWaterTriangles[uw].v[j].x<=frame[maxAllDepth][2] &&
|
|
underWaterTriangles[uw].v[j].x>=frame[maxAllDepth][0]);
|
|
Verify(underWaterTriangles[uw].v[j].z<=frame[maxAllDepth][3] &&
|
|
underWaterTriangles[uw].v[j].z>=frame[maxAllDepth][1]);
|
|
}
|
|
uw++;
|
|
}
|
|
|
|
aboveWaterTriangles[aw].v[0] = tempTrianglesPtr[i]->GetPoint(now);
|
|
aboveWaterTriangles[aw].v[1] = v[0];
|
|
aboveWaterTriangles[aw].v[2] = v[3];
|
|
if(aboveWaterTriangles[aw].GetSurfaceAreaAndCentroid()==true)
|
|
{
|
|
for(j=0;j<3;j++)
|
|
{
|
|
Verify(aboveWaterTriangles[aw].v[j].x<=frame[maxAllDepth][2] &&
|
|
aboveWaterTriangles[aw].v[j].x>=frame[maxAllDepth][0]);
|
|
Verify(aboveWaterTriangles[aw].v[j].z<=frame[maxAllDepth][3] &&
|
|
aboveWaterTriangles[aw].v[j].z>=frame[maxAllDepth][1]);
|
|
}
|
|
aw++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(j=0;j<3;j++)
|
|
{
|
|
if(!(tempTrianglesPtr[i]->GetPoint(j).y < waterLevel) &&
|
|
!(tempTrianglesPtr[i]->GetPoint(j).y > waterLevel))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
Verify(j<3);
|
|
|
|
int next = (j+1)%3;
|
|
int prev = (j+2)%3;
|
|
|
|
if(tempTrianglesPtr[i]->GetPoint(next).y < waterLevel)
|
|
{
|
|
underWaterTriangles[uw].v[0] = tempTrianglesPtr[i]->GetPoint(j);
|
|
underWaterTriangles[uw].v[1] = tempTrianglesPtr[i]->GetPoint(next);
|
|
|
|
underWaterTriangles[uw].v[2].Lerp(
|
|
tempTrianglesPtr[i]->GetPoint(prev),
|
|
tempTrianglesPtr[i]->GetPoint(next),
|
|
(waterLevel-tempTrianglesPtr[i]->GetPoint(prev).y)/
|
|
(tempTrianglesPtr[i]->GetPoint(next).y-tempTrianglesPtr[i]->GetPoint(prev).y)
|
|
);
|
|
Verify(Close_Enough(waterLevel, underWaterTriangles[uw].v[2].y));
|
|
underWaterTriangles[uw].v[2].y = waterLevel;
|
|
|
|
waterPools.AddEdge(
|
|
underWaterTriangles[uw].v[0],
|
|
underWaterTriangles[uw].v[2],
|
|
tempTrianglesPtr[i]->plane.normal
|
|
);
|
|
|
|
if(underWaterTriangles[uw].GetSurfaceAreaAndCentroid()==true)
|
|
{
|
|
for(j=0;j<3;j++)
|
|
{
|
|
Verify(underWaterTriangles[uw].v[j].x<=frame[maxAllDepth][2] &&
|
|
underWaterTriangles[uw].v[j].x>=frame[maxAllDepth][0]);
|
|
Verify(underWaterTriangles[uw].v[j].z<=frame[maxAllDepth][3] &&
|
|
underWaterTriangles[uw].v[j].z>=frame[maxAllDepth][1]);
|
|
}
|
|
uw++;
|
|
}
|
|
|
|
|
|
aboveWaterTriangles[aw].v[0] = tempTrianglesPtr[i]->GetPoint(j);
|
|
aboveWaterTriangles[aw].v[1] = underWaterTriangles[uw-1].v[2];
|
|
aboveWaterTriangles[aw].v[2] = tempTrianglesPtr[i]->GetPoint(prev);
|
|
|
|
if(aboveWaterTriangles[aw].GetSurfaceAreaAndCentroid()==true)
|
|
{
|
|
for(j=0;j<3;j++)
|
|
{
|
|
Verify(aboveWaterTriangles[aw].v[j].x<=frame[maxAllDepth][2] &&
|
|
aboveWaterTriangles[aw].v[j].x>=frame[maxAllDepth][0]);
|
|
Verify(aboveWaterTriangles[aw].v[j].z<=frame[maxAllDepth][3] &&
|
|
aboveWaterTriangles[aw].v[j].z>=frame[maxAllDepth][1]);
|
|
}
|
|
aw++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aboveWaterTriangles[aw].v[0] = tempTrianglesPtr[i]->GetPoint(j);
|
|
aboveWaterTriangles[aw].v[1] = tempTrianglesPtr[i]->GetPoint(next);
|
|
|
|
aboveWaterTriangles[aw].v[2].Lerp(
|
|
tempTrianglesPtr[i]->GetPoint(prev),
|
|
tempTrianglesPtr[i]->GetPoint(next),
|
|
(waterLevel-tempTrianglesPtr[i]->GetPoint(prev).y)/
|
|
(tempTrianglesPtr[i]->GetPoint(next).y-tempTrianglesPtr[i]->GetPoint(prev).y)
|
|
);
|
|
Verify(Close_Enough(waterLevel, aboveWaterTriangles[aw].v[2].y));
|
|
aboveWaterTriangles[aw].v[2].y = waterLevel;
|
|
|
|
waterPools.AddEdge(
|
|
aboveWaterTriangles[aw].v[0],
|
|
aboveWaterTriangles[aw].v[2],
|
|
tempTrianglesPtr[i]->plane.normal
|
|
);
|
|
|
|
if(aboveWaterTriangles[aw].GetSurfaceAreaAndCentroid()==true)
|
|
{
|
|
for(j=0;j<3;j++)
|
|
{
|
|
Verify(aboveWaterTriangles[aw].v[j].x<=frame[maxAllDepth][2] &&
|
|
aboveWaterTriangles[aw].v[j].x>=frame[maxAllDepth][0]);
|
|
Verify(aboveWaterTriangles[aw].v[j].z<=frame[maxAllDepth][3] &&
|
|
aboveWaterTriangles[aw].v[j].z>=frame[maxAllDepth][1]);
|
|
}
|
|
aw++;
|
|
}
|
|
|
|
underWaterTriangles[uw].v[0] = tempTrianglesPtr[i]->GetPoint(j);
|
|
underWaterTriangles[uw].v[1] = aboveWaterTriangles[aw-1].v[2];
|
|
underWaterTriangles[uw].v[2] = tempTrianglesPtr[i]->GetPoint(prev);
|
|
|
|
if(underWaterTriangles[uw].GetSurfaceAreaAndCentroid()==true)
|
|
{
|
|
for(j=0;j<3;j++)
|
|
{
|
|
Verify(underWaterTriangles[uw].v[j].x<=frame[maxAllDepth][2] &&
|
|
underWaterTriangles[uw].v[j].x>=frame[maxAllDepth][0]);
|
|
Verify(underWaterTriangles[uw].v[j].z<=frame[maxAllDepth][3] &&
|
|
underWaterTriangles[uw].v[j].z>=frame[maxAllDepth][1]);
|
|
}
|
|
uw++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// SPEWALWAYS(("micgaert", "#3"));
|
|
|
|
Verify(uw+aw >= newCount);
|
|
|
|
if( (uw==0 && aw==newCount) || (aw==0 && uw==newCount) )
|
|
{
|
|
// SPEWALWAYS(("micgaert", "#3.5"));
|
|
if(uw==newCount)
|
|
{
|
|
gos_PushCurrentHeap(ElementRenderer::ListElement::s_Heap);
|
|
subList->SetSize(2);
|
|
gos_PopCurrentHeap();
|
|
}
|
|
|
|
|
|
if(!BinSort2(
|
|
subList,
|
|
0,
|
|
maxdepth - depth,
|
|
tempTrianglesPtr,
|
|
maxNumOfTrianglesPerMesh,
|
|
&frame,
|
|
&state,
|
|
uw==newCount
|
|
)
|
|
)
|
|
{
|
|
if(silentMode==true)
|
|
{
|
|
fprintf(stderr, "Unstable triangle mesh created!");
|
|
}
|
|
else
|
|
{
|
|
PAUSE(("Unstable triangle mesh created!"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// SPEWALWAYS(("micgaert", "#5"));
|
|
if(uw==newCount)
|
|
{
|
|
gos_PushCurrentHeap(ElementRenderer::ShapeElement::s_Heap);
|
|
|
|
ElementRenderer::ShapeElement* Shape = new
|
|
ElementRenderer::ShapeElement;
|
|
Register_Object(Shape);
|
|
gos_PopCurrentHeap();
|
|
|
|
gos_PushCurrentHeap(MidLevelRenderer::ShapeHeap);
|
|
MLRShape *shape = new MLRShape(1);
|
|
Register_Object(shape);
|
|
gos_PopCurrentHeap();
|
|
|
|
MLRPrimitiveBase *prim = CreateWater( x0, x1, z0, z1, waterLevel);
|
|
Check_Object(prim);
|
|
shape->Add(prim);
|
|
|
|
prim->DetachReference();
|
|
|
|
Shape->SetMLRShape(shape);
|
|
|
|
const Point3D *p = NULL;
|
|
int nr_of_points = 0;
|
|
prim->GetCoordData(&p, &nr_of_points);
|
|
ReadOnlyArrayOf<Point3D> p_array;
|
|
p_array.AssignData(p, nr_of_points);
|
|
Shape->m_localOBB.ComputeBounds(p_array);
|
|
Shape->SetOBBMode();
|
|
|
|
/*
|
|
Shape->m_localOBB.localToParent = LinearMatrix4D::Identity;
|
|
Shape->m_localOBB.localToParent.BuildTranslation(
|
|
Point3D(
|
|
(x1+x0)*0.5f - xCenterOffset - Xoffset*dX,
|
|
waterLevel,
|
|
(z1+z0)*0.5f - zCenterOffset - Zoffset*dZ
|
|
)
|
|
);
|
|
|
|
Shape->m_localOBB.sphereRadius = 0.5f*xGrid*static_cast<Scalar>(sqrt(2.0f));
|
|
Check_Object(Shape);
|
|
*/
|
|
waterList->AttachChild(Shape);
|
|
Shape->SetVolumeCullMode();
|
|
|
|
subList->AttachIndexedChild(1, Shape);
|
|
}
|
|
brokenTriangles += newCount;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// MLRPrimitiveBase *prim = waterPools.LinkEdges();
|
|
|
|
// SPEWALWAYS(("micgaert", "#6"));
|
|
|
|
gos_PushCurrentHeap(ElementRenderer::ListElement::s_Heap);
|
|
subList->SetSize(3);
|
|
gos_PopCurrentHeap();
|
|
|
|
tempTrianglesPtr.SetLength(uw);
|
|
underWaterTriangles.SetLength(uw);
|
|
|
|
for(i=0;i<uw;i++)
|
|
{
|
|
tempTrianglesPtr[i] = &underWaterTriangles[i];
|
|
|
|
}
|
|
|
|
// SPEWALWAYS(("micgaert", "#7"));
|
|
if(!BinSort2(
|
|
subList,
|
|
0,
|
|
maxdepth - depth,
|
|
tempTrianglesPtr,
|
|
maxNumOfTrianglesPerMesh,
|
|
&frame,
|
|
&state,
|
|
true
|
|
)
|
|
)
|
|
{
|
|
if(silentMode==true)
|
|
{
|
|
fprintf(stderr, "Unstable triangle mesh created!");
|
|
}
|
|
else
|
|
{
|
|
PAUSE(("Unstable triangle mesh created!"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
brokenTriangles += uw;
|
|
}
|
|
|
|
tempTrianglesPtr.SetLength(aw);
|
|
aboveWaterTriangles.SetLength(aw);
|
|
|
|
for(i=0;i<aw;i++)
|
|
{
|
|
tempTrianglesPtr[i] = &aboveWaterTriangles[i];
|
|
}
|
|
|
|
// SPEWALWAYS(("micgaert", "#8"));
|
|
if(!BinSort2(
|
|
subList,
|
|
1,
|
|
maxdepth - depth,
|
|
tempTrianglesPtr,
|
|
maxNumOfTrianglesPerMesh,
|
|
&frame,
|
|
&state,
|
|
false
|
|
)
|
|
)
|
|
{
|
|
if(silentMode==true)
|
|
{
|
|
fprintf(stderr, "Unstable triangle mesh created!");
|
|
}
|
|
else
|
|
{
|
|
PAUSE(("Unstable triangle mesh created!"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
brokenTriangles += aw;
|
|
}
|
|
|
|
// SPEWALWAYS(("micgaert", "#8.1"));
|
|
gos_PushCurrentHeap(ElementRenderer::ShapeElement::s_Heap);
|
|
|
|
ElementRenderer::ShapeElement* Shape = new
|
|
ElementRenderer::ShapeElement;
|
|
Register_Object(Shape);
|
|
gos_PopCurrentHeap();
|
|
// SPEWALWAYS(("micgaert", "#8.2"));
|
|
|
|
gos_PushCurrentHeap(MidLevelRenderer::ShapeHeap);
|
|
MLRShape *shape = new MLRShape(1);
|
|
Register_Object(shape);
|
|
gos_PopCurrentHeap();
|
|
// SPEWALWAYS(("micgaert", "#8.3"));
|
|
|
|
MLRPrimitiveBase *prim = CreateWater( x0, x1, z0, z1, waterLevel);;
|
|
Check_Object(prim);
|
|
shape->Add(prim);
|
|
// SPEWALWAYS(("micgaert", "#8.4"));
|
|
|
|
prim->DetachReference();
|
|
|
|
Shape->SetMLRShape(shape);
|
|
|
|
const Point3D *p = NULL;
|
|
int nr_of_points = 0;
|
|
prim->GetCoordData(&p, &nr_of_points);
|
|
ReadOnlyArrayOf<Point3D> p_array;
|
|
p_array.AssignData(p, nr_of_points);
|
|
Shape->m_localOBB.ComputeBounds(p_array);
|
|
Shape->SetOBBMode();
|
|
/*
|
|
Shape->m_localOBB.localToParent = LinearMatrix4D::Identity;
|
|
Shape->m_localOBB.localToParent.BuildTranslation(
|
|
Point3D(
|
|
(x1+x0)*0.5f - xCenterOffset - Xoffset*dX,
|
|
waterLevel,
|
|
(z1+z0)*0.5f - zCenterOffset - Zoffset*dZ
|
|
)
|
|
);
|
|
// SPEWALWAYS(("micgaert", "#8.5"));
|
|
|
|
Shape->m_localOBB.sphereRadius = 0.5f*xGrid*static_cast<Scalar>(sqrt(2.0f));
|
|
Check_Object(Shape);
|
|
*/
|
|
waterList->AttachChild(Shape);
|
|
Shape->SetVolumeCullMode();
|
|
|
|
subList->AttachIndexedChild(2, Shape);
|
|
|
|
// SPEWALWAYS(("micgaert", "#9"));
|
|
}
|
|
|
|
/*
|
|
bool px0z0, px0z1, px1z0, px1z1;
|
|
|
|
px0z0 = waterLevel < mesh->eval( (int)(x0/dX), (int)(z0/dZ) );
|
|
px0z1 = waterLevel < mesh->eval( (int)(x0/dX), (int)(z1/dZ) );
|
|
px1z0 = waterLevel < mesh->eval( (int)(x1/dX), (int)(z0/dZ) );
|
|
px1z1 = waterLevel < mesh->eval( (int)(x1/dX), (int)(z1/dZ) );
|
|
|
|
if(waterPools.waterEdgePointCount==0)
|
|
{
|
|
if(px0z0 == false)
|
|
{
|
|
Verify(px0z0==px0z1 && px0z0==px1z0 && px0z0==px1z1);
|
|
// found water
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
else
|
|
{
|
|
if(!BinSort(
|
|
subList,
|
|
0,
|
|
maxdepth - depth,
|
|
tempTrianglesPtr,
|
|
maxNumOfTrianglesPerMesh,
|
|
&frame,
|
|
&state
|
|
)
|
|
)
|
|
{
|
|
if(silentMode==true)
|
|
{
|
|
fprintf(stderr, "Unstable triangle mesh created!");
|
|
}
|
|
else
|
|
{
|
|
PAUSE(("Unstable triangle mesh created!"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
brokenTriangles += newCount;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(silentMode==true)
|
|
{
|
|
fprintf(stderr, "Found an empty mesh ! Program exits !\n");
|
|
exit(-1);
|
|
}
|
|
else
|
|
{
|
|
STOP(("Found an empty mesh !"));
|
|
}
|
|
}
|
|
// SPEWALWAYS(("micgaert", "#10"));
|
|
|
|
tempTrianglesPtr.SetLength(0);
|
|
group->Sync();
|
|
group->LockBounds();
|
|
group->SetNeverCullMode();
|
|
subList->LockBounds();
|
|
subList->SetNeverCullMode();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
HFSlimMZ::SetMegaTexture(
|
|
int nrOfLevels,
|
|
int bucketSize,
|
|
const char *theName,
|
|
const char *outputpath
|
|
)
|
|
{
|
|
static char megaBaseName[1024];
|
|
|
|
if(detailInfo.name)
|
|
{
|
|
/*
|
|
state1.SetBackFaceOn();
|
|
state1.SetDitherOff();
|
|
state1.SetTextureCorrectionOn();
|
|
state1.SetZBufferCompareOn();
|
|
state1.SetZBufferWriteOff();
|
|
|
|
|
|
state1.SetFilterMode(MLRState::BiLinearFilterMode);
|
|
|
|
state1.SetFogMode(MLRState::DisableFogMode);
|
|
state1.SetFogData(
|
|
0xff000000,
|
|
0.0f,
|
|
90.0f,
|
|
100.0f
|
|
);
|
|
*/
|
|
state1.SetTextureWrapMode(MLRState::TextureWrap);
|
|
state1.SetAlphaMode(detailInfo.alphaMode);
|
|
state1.SetPriority(MLRState::DefaultPriority + 1);
|
|
MLRTexture *texture = MLRTexturePool::Instance->Add(detailInfo.name);
|
|
state1.SetTextureHandle(texture->GetTextureHandle());
|
|
}
|
|
|
|
if(detailInfo.altname)
|
|
{
|
|
state2.SetTextureWrapMode(MLRState::TextureWrap);
|
|
state2.SetAlphaMode(detailInfo.alphaMode);
|
|
state2.SetPriority(MLRState::DefaultPriority + 1);
|
|
MLRTexture *texture = MLRTexturePool::Instance->Add(detailInfo.altname);
|
|
state2.SetTextureHandle(texture->GetTextureHandle());
|
|
}
|
|
|
|
DynamicArrayOf<unsigned char> onOffTriangles;
|
|
|
|
if(!doPrecise)
|
|
{
|
|
onOffTriangles.AssignValue(0, toSortTriangles.GetLength());
|
|
}
|
|
else
|
|
{
|
|
onOffTriangles.AssignValue(0, triangleIndices.GetLength());
|
|
}
|
|
|
|
int i, j, k, l, n, level;
|
|
simpleTerrainGroup.SetLength(xDim*zDim);
|
|
waterGroup.SetLength(xDim*zDim);
|
|
|
|
Stuff::ExtentBox allBox;
|
|
allBox = GetExtents();
|
|
|
|
int len = 1<<nrOfLevels;
|
|
|
|
xGridSize = (256/len)*dX;
|
|
zGridSize = (256/len)*dZ;
|
|
|
|
if(!doPrecise)
|
|
{
|
|
fprintf(stdout, "You don't care about precision !\n");
|
|
|
|
for(l=0;l<zDim;l++)
|
|
{
|
|
for(k=0;k<xDim;k++)
|
|
{
|
|
brokenTriangles = 0;
|
|
|
|
// sprintf(megaBaseName, "Content\\Maps\\%s\\%c%c_water.obj", theName, 'A'+l, 'A'+k );
|
|
// daWaterObj = fopen(megaBaseName, "wt");
|
|
// Verify(daWaterObj!=NULL);
|
|
vertexCountObj = 1;
|
|
|
|
sprintf(megaBaseName, "Maps\\%s\\%c%c\\%s_%c%c", theName, 'A'+l, 'A'+k, theName, 'A'+l, 'A'+k);
|
|
|
|
Scalar xOffset = dX*(k*256+Xoffset);
|
|
Scalar zOffset = dZ*(l*256+Zoffset);
|
|
gos_PushCurrentHeap(ElementRenderer::GridElement::s_Heap);
|
|
simpleTerrainGroup[l*xDim+k] =
|
|
new ElementRenderer::GridElement(
|
|
len, len,
|
|
zOffset - zCenterOffset,
|
|
xOffset - xCenterOffset,
|
|
dZ*256, dX*256
|
|
);
|
|
Register_Object(simpleTerrainGroup[l*xDim+k]);
|
|
|
|
waterGroup[l*xDim+k] = new ElementRenderer::GroupElement();
|
|
Register_Object(waterGroup[l*xDim+k]);
|
|
gos_PopCurrentHeap();
|
|
|
|
for(j=0;j<len;j++)
|
|
{
|
|
for(i=0;i<len;i++)
|
|
{
|
|
level = nrOfLevels;
|
|
|
|
tX = i;
|
|
tY = j;
|
|
|
|
// fprintf(daWaterObj, "\ng G%02d%02d\n", i, j);
|
|
BuildTile(
|
|
simpleTerrainGroup[l*xDim+k],
|
|
waterGroup[l*xDim+k],
|
|
j*len+i,
|
|
level,
|
|
nrOfLevels,
|
|
onOffTriangles,
|
|
bucketSize,
|
|
xOffset,
|
|
zOffset,
|
|
xGridSize,
|
|
zGridSize,
|
|
i,
|
|
j,
|
|
megaBaseName
|
|
);
|
|
// SPEWALWAYS(("micgaert", "%d %d %d %d\n", i, j, k, l));
|
|
}
|
|
}
|
|
|
|
simpleTerrainGroup[l*xDim+k]->LockBounds();
|
|
waterGroup[l*xDim+k]->LockBounds();
|
|
|
|
|
|
fprintf(stdout, "(%d, %d) \"broken\" triangles: %d\n", l, k, brokenTriangles);
|
|
// fclose(daWaterObj);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fprintf(stdout, "You wanted it precise !\n");
|
|
|
|
int numOfTriangles = usedTriangleIndices;
|
|
|
|
DynamicArrayOf<TriangleStruct*> *tempTrianglesPtr;
|
|
|
|
tempTrianglesPtr = new DynamicArrayOf<TriangleStruct*> [zDim*xDim*len*len];
|
|
|
|
int tJunction=0;
|
|
for(i=0,tJunction=0;i<usedUniquePoints;i++)
|
|
{
|
|
if(uniquePoints[i].CheckAngles(0.0f, 0.0f, GetXinM(), GetZinM(), dX, dZ)==false)
|
|
{
|
|
tJunction++;
|
|
SPEWALWAYS((0, "H%4x: %6.2f %6.2f %6.2f - %2d %.2f",
|
|
i,
|
|
uniquePoints[i].p.x, uniquePoints[i].p.y, uniquePoints[i].p.z,
|
|
uniquePoints[i].connectedTo,
|
|
uniquePoints[i].GetAngles()/Pi
|
|
));
|
|
|
|
if(silentMode!=true)
|
|
{
|
|
PAUSE(("Detected hole in terrain mesh!"));
|
|
}
|
|
}
|
|
}
|
|
|
|
for(l=0;l<zDim;l++)
|
|
{
|
|
for(k=0;k<xDim;k++)
|
|
{
|
|
brokenTriangles = 0;
|
|
|
|
Scalar xOffset = dX*(k*256+Xoffset);
|
|
Scalar zOffset = dZ*(l*256+Zoffset);
|
|
|
|
fprintf(stdout, "Working on (%d, %d)", l, k);
|
|
|
|
for(j=0;j<len;j++)
|
|
{
|
|
for(i=0;i<len;i++)
|
|
{
|
|
level = nrOfLevels;
|
|
|
|
tX = i;
|
|
tY = j;
|
|
|
|
tempTrianglesPtr[(l*xDim+k)*len*len + j*len + i].SetLength(numOfTriangles);
|
|
|
|
// fprintf(stdout, "\t(%d, %d)\n", i, j);
|
|
BuildTile(
|
|
tempTrianglesPtr[(l*xDim+k)*len*len + j*len + i],
|
|
j*len+i,
|
|
level,
|
|
nrOfLevels,
|
|
numOfTriangles,
|
|
onOffTriangles,
|
|
bucketSize,
|
|
xOffset,
|
|
zOffset,
|
|
xGridSize,
|
|
zGridSize,
|
|
i,
|
|
j
|
|
);
|
|
}
|
|
}
|
|
|
|
fprintf(stdout, " \"broken\" triangles: %d\n", brokenTriangles);
|
|
}
|
|
}
|
|
|
|
for(i=0,tJunction=0;i<usedUniquePoints;i++)
|
|
{
|
|
if(uniquePoints[i].CheckAngles(Xoffset*dX, Zoffset*dZ, dX*(xDim*256+Xoffset), dZ*(zDim*256+Zoffset), dX, dZ)==false)
|
|
{
|
|
SPEWALWAYS((0, "H%4x: %6.2f %6.2f %6.2f - %2d %.2f",
|
|
i,
|
|
uniquePoints[i].p.x, uniquePoints[i].p.y, uniquePoints[i].p.z,
|
|
uniquePoints[i].connectedTo,
|
|
uniquePoints[i].GetAngles()/Pi
|
|
));
|
|
|
|
// PAUSE(("Detected hole in terrain mesh!"));
|
|
}
|
|
}
|
|
|
|
double one_over_dX = 1.0f/dX;
|
|
double one_over_dZ = 1.0f/dZ;
|
|
bool redo;
|
|
|
|
tJunction = 0;
|
|
for(i=0;i<usedUniquePoints;i++)
|
|
{
|
|
if(uniquePoints[i].connectedTo==0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
redo = false;
|
|
|
|
Point3D point;
|
|
|
|
point = uniquePoints[i].p;
|
|
|
|
if(!Small_Enough(static_cast<Scalar>(fmod(uniquePoints[i].p.x, dX))))
|
|
{
|
|
point.x = static_cast<Scalar>(dX*floor(uniquePoints[i].p.x*one_over_dX + 0.5));
|
|
redo = true;
|
|
}
|
|
if(!Small_Enough(static_cast<Scalar>(fmod(uniquePoints[i].p.z, dZ))))
|
|
{
|
|
point.z = static_cast<Scalar>(dZ*floor(uniquePoints[i].p.z*one_over_dZ + 0.5));
|
|
redo = true;
|
|
}
|
|
|
|
if(redo==true)
|
|
{
|
|
point.y = GetHeight((int)(point.x/dX), (int)(point.z/dZ));
|
|
|
|
int pi = FindPoint(point);
|
|
|
|
uniquePoints[i].p = point;
|
|
|
|
if(pi<0 || i==pi)
|
|
{
|
|
for(j=0;j<uniquePoints[i].connectedTo;j++)
|
|
{
|
|
uniquePoints[uniquePoints[i].myTri[j].tri->v[0]].CalculateAngles();
|
|
uniquePoints[uniquePoints[i].myTri[j].tri->v[1]].CalculateAngles();
|
|
uniquePoints[uniquePoints[i].myTri[j].tri->v[2]].CalculateAngles();
|
|
}
|
|
uniquePoints[i].CalculateAngles();
|
|
}
|
|
else
|
|
{
|
|
int from, to;
|
|
|
|
if(i<pi)
|
|
{
|
|
from = pi;
|
|
to = i;
|
|
}
|
|
else
|
|
{
|
|
from = i;
|
|
to = pi;
|
|
}
|
|
|
|
for(j=0;j<uniquePoints[from].connectedTo;j++)
|
|
{
|
|
for(k=0;k<uniquePoints[to].connectedTo;k++)
|
|
{
|
|
if(uniquePoints[from].myTri[j].tri==uniquePoints[to].myTri[k].tri)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if(k==uniquePoints[to].connectedTo)
|
|
{
|
|
uniquePoints[to].Add(uniquePoints[from].myTri[j].tri, uniquePoints[from].myTri[j].pos);
|
|
}
|
|
}
|
|
|
|
for(j=0;j<uniquePoints[to].connectedTo;j++)
|
|
{
|
|
for(k=0;k<3;k++)
|
|
{
|
|
if(uniquePoints[to].myTri[j].tri->v[k] == from)
|
|
{
|
|
uniquePoints[to].myTri[j].tri->v[k] = to;
|
|
}
|
|
}
|
|
}
|
|
|
|
for(k=0;k<uniquePoints[i].connectedTo;k++)
|
|
{
|
|
uniquePoints[uniquePoints[i].myTri[k].tri->v[0]].CalculateAngles();
|
|
uniquePoints[uniquePoints[i].myTri[k].tri->v[1]].CalculateAngles();
|
|
uniquePoints[uniquePoints[i].myTri[k].tri->v[2]].CalculateAngles();
|
|
}
|
|
|
|
uniquePoints[to].CalculateAngles();
|
|
|
|
uniquePoints[from].connectedTo = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
for(i=0;i<usedTriangleIndices;i++)
|
|
{
|
|
if(
|
|
triangleIndices[i].v[0]==triangleIndices[i].v[1] ||
|
|
triangleIndices[i].v[0]==triangleIndices[i].v[2] ||
|
|
triangleIndices[i].v[1]==triangleIndices[i].v[2]
|
|
)
|
|
{
|
|
RemoveTriangle(i);
|
|
triangleIndices[i].area = -1.0f;
|
|
}
|
|
else
|
|
{
|
|
triangleIndices[i].GetSurfaceAreaAndCentroid();
|
|
}
|
|
}
|
|
|
|
for(i=0,tJunction=0;i<usedUniquePoints;i++)
|
|
{
|
|
if(false == uniquePoints[i].CheckAngles(Xoffset*dX, Zoffset*dZ, dX*(xDim*256+Xoffset), dZ*(zDim*256+Zoffset), dX, dZ))
|
|
{
|
|
tJunction++;
|
|
SPEWALWAYS((0, "H%4x: %6.2f %6.2f %6.2f - %2d %.2f",
|
|
i,
|
|
uniquePoints[i].p.x, uniquePoints[i].p.y, uniquePoints[i].p.z,
|
|
uniquePoints[i].connectedTo,
|
|
uniquePoints[i].GetAngles()/Pi
|
|
));
|
|
// PAUSE(("Detected hole in terrain mesh!"));
|
|
}
|
|
}
|
|
|
|
Verify(tJunction==0);
|
|
|
|
int smallOne = 0, tiltedOne = 0;
|
|
|
|
|
|
for(i=0;i<usedTriangleIndices;i++)
|
|
{
|
|
if(triangleIndices[i].area < 0.0f)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if(triangleIndices[i].area > 0.0f && triangleIndices[i].area <= Stuff::SMALL)
|
|
{
|
|
smallOne++;
|
|
}
|
|
|
|
if(triangleIndices[i].plane.normal.y < Stuff::SMALL)
|
|
{
|
|
int pmin, pmid, pmax;
|
|
bool xCase = false, zCase = false;
|
|
|
|
if( // Triangle forms vertical line
|
|
Close_Enough(triangleIndices[i].GetPoint(0).x, triangleIndices[i].GetPoint(1).x) &&
|
|
Close_Enough(triangleIndices[i].GetPoint(0).x, triangleIndices[i].GetPoint(2).x)
|
|
)
|
|
{
|
|
if(triangleIndices[i].GetPoint(0).z < triangleIndices[i].GetPoint(1).z)
|
|
{
|
|
if(triangleIndices[i].GetPoint(0).z < triangleIndices[i].GetPoint(2).z)
|
|
{
|
|
pmin = triangleIndices[i].v[0];
|
|
if(triangleIndices[i].GetPoint(1).z < triangleIndices[i].GetPoint(2).z)
|
|
{
|
|
pmid = triangleIndices[i].v[1];
|
|
pmax = triangleIndices[i].v[2];
|
|
}
|
|
else
|
|
{
|
|
pmid = triangleIndices[i].v[2];
|
|
pmax = triangleIndices[i].v[1];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pmin = triangleIndices[i].v[2];
|
|
pmid = triangleIndices[i].v[0];
|
|
pmax = triangleIndices[i].v[1];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(triangleIndices[i].GetPoint(1).z < triangleIndices[i].GetPoint(2).z)
|
|
{
|
|
pmin = triangleIndices[i].v[1];
|
|
if(triangleIndices[i].GetPoint(0).z < triangleIndices[i].GetPoint(2).z)
|
|
{
|
|
pmid = triangleIndices[i].v[0];
|
|
pmax = triangleIndices[i].v[2];
|
|
}
|
|
else
|
|
{
|
|
pmid = triangleIndices[i].v[2];
|
|
pmax = triangleIndices[i].v[0];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pmin = triangleIndices[i].v[2];
|
|
pmid = triangleIndices[i].v[1];
|
|
pmax = triangleIndices[i].v[0];
|
|
}
|
|
}
|
|
|
|
xCase = true;
|
|
}
|
|
if( // Triangle forms horizontal line
|
|
Close_Enough(triangleIndices[i].GetPoint(0).z, triangleIndices[i].GetPoint(1).z) &&
|
|
Close_Enough(triangleIndices[i].GetPoint(0).z, triangleIndices[i].GetPoint(2).z)
|
|
)
|
|
{
|
|
if(triangleIndices[i].GetPoint(0).x < triangleIndices[i].GetPoint(1).x)
|
|
{
|
|
if(triangleIndices[i].GetPoint(0).x < triangleIndices[i].GetPoint(2).x)
|
|
{
|
|
pmin = triangleIndices[i].v[0];
|
|
if(triangleIndices[i].GetPoint(1).x < triangleIndices[i].GetPoint(2).x)
|
|
{
|
|
pmid = triangleIndices[i].v[1];
|
|
pmax = triangleIndices[i].v[2];
|
|
}
|
|
else
|
|
{
|
|
pmid = triangleIndices[i].v[2];
|
|
pmax = triangleIndices[i].v[1];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pmin = triangleIndices[i].v[2];
|
|
pmid = triangleIndices[i].v[0];
|
|
pmax = triangleIndices[i].v[1];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(triangleIndices[i].GetPoint(1).x < triangleIndices[i].GetPoint(2).x)
|
|
{
|
|
pmin = triangleIndices[i].v[1];
|
|
if(triangleIndices[i].GetPoint(0).x < triangleIndices[i].GetPoint(2).x)
|
|
{
|
|
pmid = triangleIndices[i].v[0];
|
|
pmax = triangleIndices[i].v[2];
|
|
}
|
|
else
|
|
{
|
|
pmid = triangleIndices[i].v[2];
|
|
pmax = triangleIndices[i].v[0];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pmin = triangleIndices[i].v[2];
|
|
pmid = triangleIndices[i].v[1];
|
|
pmax = triangleIndices[i].v[0];
|
|
}
|
|
}
|
|
|
|
zCase = true;
|
|
}
|
|
|
|
if(zCase==0 && xCase==0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Verify(!(zCase && xCase));
|
|
Verify(uniquePoints[pmin].p.x <= uniquePoints[pmid].p.x && uniquePoints[pmid].p.x <= uniquePoints[pmax].p.x);
|
|
Verify(uniquePoints[pmin].p.z <= uniquePoints[pmid].p.z && uniquePoints[pmid].p.z <= uniquePoints[pmax].p.z);
|
|
|
|
int pfaraway = -1;
|
|
int pminDI = -1, pminVI = -1;
|
|
for(j=0;j<uniquePoints[pmin].connectedTo;j++)
|
|
{
|
|
/*
|
|
if(uniquePoints[pmin].myTri[j].tri->area < Stuff::SMALL)
|
|
{
|
|
continue;
|
|
}
|
|
*/
|
|
if(&triangleIndices[i]==uniquePoints[pmin].myTri[j].tri)
|
|
{
|
|
if(pminVI>=0)
|
|
{
|
|
if(silentMode==true)
|
|
{
|
|
fprintf(stderr, "Error while removing triangles without area ! Program exits !\n");
|
|
exit(-1);
|
|
}
|
|
else
|
|
{
|
|
STOP(("Error while removing triangles without area ?"));
|
|
}
|
|
}
|
|
pminVI = j;
|
|
|
|
continue;
|
|
}
|
|
|
|
for(k=0;k<3;k++)
|
|
{
|
|
if(uniquePoints[pmin].myTri[j].tri->v[k]==pmax)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if(k<3)
|
|
{
|
|
for(k=0;k<3;k++)
|
|
{
|
|
if(uniquePoints[pmin].myTri[j].tri->v[k]!=pmax && uniquePoints[pmin].myTri[j].tri->v[k]!=pmin)
|
|
{
|
|
pfaraway = uniquePoints[pmin].myTri[j].tri->v[k];
|
|
break;
|
|
}
|
|
}
|
|
Verify(pfaraway>=0);
|
|
|
|
if(pminDI<0)
|
|
{
|
|
pminDI = j;
|
|
}
|
|
else
|
|
{
|
|
if(silentMode==true)
|
|
{
|
|
fprintf(stderr, "Error while removing triangles without area ! Program exits !\n");
|
|
exit(-1);
|
|
}
|
|
else
|
|
{
|
|
STOP(("Error while removing triangles without area !"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int pmaxDI = -1, pmaxVI = -1;
|
|
for(j=0;j<uniquePoints[pmax].connectedTo;j++)
|
|
{
|
|
/*
|
|
if(uniquePoints[pmax].myTri[j].tri->area < Stuff::SMALL)
|
|
{
|
|
continue;
|
|
}
|
|
*/
|
|
if(&triangleIndices[i]==uniquePoints[pmax].myTri[j].tri)
|
|
{
|
|
if(pmaxVI>=0)
|
|
{
|
|
if(silentMode==true)
|
|
{
|
|
fprintf(stderr, "Error while removing triangles without area ! Program exits !\n");
|
|
exit(-1);
|
|
}
|
|
else
|
|
{
|
|
STOP(("Error while removing triangles without area ?"));
|
|
}
|
|
}
|
|
pmaxVI = j;
|
|
|
|
continue;
|
|
}
|
|
|
|
for(k=0;k<3;k++)
|
|
{
|
|
if(uniquePoints[pmax].myTri[j].tri->v[k]==pmin)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if(k<3)
|
|
{
|
|
for(k=0;k<3;k++)
|
|
{
|
|
if(uniquePoints[pmax].myTri[j].tri->v[k]!=pmax && uniquePoints[pmax].myTri[j].tri->v[k]!=pmin)
|
|
{
|
|
Verify(pfaraway == uniquePoints[pmax].myTri[j].tri->v[k]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(pmaxDI<0)
|
|
{
|
|
pmaxDI = j;
|
|
}
|
|
else
|
|
{
|
|
if(silentMode==true)
|
|
{
|
|
fprintf(stderr, "Error while removing triangles without area ! Program exits !\n");
|
|
exit(-1);
|
|
}
|
|
else
|
|
{
|
|
STOP(("Error while removing triangles without area !"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(pminDI>=0 && pmaxDI>=0)
|
|
{
|
|
for(k=0;k<3;k++)
|
|
{
|
|
if(uniquePoints[pmin].myTri[pminDI].tri->v[k]==pmax)
|
|
{
|
|
uniquePoints[pmin].myTri[pminDI].tri->v[k] = pmid;
|
|
uniquePoints[pmid].Add(uniquePoints[pmin].myTri[pminDI].tri, k);
|
|
uniquePoints[pmin].myTri[pminDI].tri->GetSurfaceAreaAndCentroid();
|
|
break;
|
|
}
|
|
}
|
|
uniquePoints[pmin].connectedTo--;
|
|
for(j=pminVI;j<uniquePoints[pmin].connectedTo;j++)
|
|
{
|
|
uniquePoints[pmin].myTri[j] = uniquePoints[pmin].myTri[j+1];
|
|
}
|
|
|
|
for(k=0;k<3;k++)
|
|
{
|
|
if(uniquePoints[pmax].myTri[pmaxVI].tri->v[k]==pmin)
|
|
{
|
|
uniquePoints[pmax].myTri[pmaxVI].tri->v[k] = pfaraway;
|
|
uniquePoints[pfaraway].Add(uniquePoints[pmax].myTri[pmaxVI].tri, k);
|
|
uniquePoints[pmax].myTri[pmaxVI].tri->GetSurfaceAreaAndCentroid();
|
|
break;
|
|
}
|
|
}
|
|
uniquePoints[pmax].connectedTo--;
|
|
for(j=pmaxDI;j<uniquePoints[pmax].connectedTo;j++)
|
|
{
|
|
uniquePoints[pmax].myTri[j] = uniquePoints[pmax].myTri[j+1];
|
|
}
|
|
|
|
uniquePoints[pmin].CalculateAngles();
|
|
uniquePoints[pmid].CalculateAngles();
|
|
uniquePoints[pmax].CalculateAngles();
|
|
uniquePoints[pfaraway].CalculateAngles();
|
|
|
|
tiltedOne++;
|
|
}
|
|
else
|
|
{
|
|
if(pminDI<0 && pmaxDI<0)
|
|
{
|
|
triangleIndices[i].area = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
if(silentMode==true)
|
|
{
|
|
fprintf(stderr, "Error while removing triangles without area ! Program exits !\n");
|
|
exit(-1);
|
|
}
|
|
else
|
|
{
|
|
STOP(("Error while removing triangles without area !"));
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
for(i=0;i<usedTriangleIndices;i++)
|
|
{
|
|
if(triangleIndices[i].area == 0.0f)
|
|
{
|
|
RemoveTriangle(&triangleIndices[i]);
|
|
}
|
|
}
|
|
|
|
for(i=0,tJunction=0;i<usedUniquePoints;i++)
|
|
{
|
|
if(
|
|
Small_Enough(static_cast<Scalar>(fmod(uniquePoints[i].p.x, dX))) &&
|
|
Small_Enough(static_cast<Scalar>(fmod(uniquePoints[i].p.z, dZ)))
|
|
)
|
|
{
|
|
uniquePoints[i].p.y = GetHeight(
|
|
Round(uniquePoints[i].p.x/dX),
|
|
Round(uniquePoints[i].p.z/dZ)
|
|
);
|
|
}
|
|
|
|
if(false == uniquePoints[i].CheckAngles(Xoffset*dX, Zoffset*dZ, dX*(xDim*256+Xoffset), dZ*(zDim*256+Zoffset), dX, dZ))
|
|
{
|
|
#ifdef CHANGE_0625
|
|
if(
|
|
Close_Enough(uniquePoints[i].GetAngles(), Pi) &&
|
|
Close_Enough(uniquePoints[i].GetExpectedAngles(Xoffset*dX, Zoffset*dZ, dX*(xDim*256+Xoffset), dZ*(zDim*256+Zoffset)), 2*Pi)
|
|
)
|
|
{
|
|
int greaterX = 0, lesserX = 0, greaterZ = 0, lesserZ = 0, all = 0;
|
|
// check for orientation
|
|
|
|
for(j=0;j<uniquePoints[i].connectedTo;j++)
|
|
{
|
|
for(k=0;k<3;k++)
|
|
{
|
|
all++;
|
|
|
|
if(uniquePoints[i].p.x > uniquePoints[uniquePoints[i].myTri[j].tri->v[k]].p.x)
|
|
{
|
|
lesserX++;
|
|
}
|
|
if(uniquePoints[i].p.x < uniquePoints[uniquePoints[i].myTri[j].tri->v[k]].p.x)
|
|
{
|
|
greaterX++;
|
|
}
|
|
if(uniquePoints[i].p.z > uniquePoints[uniquePoints[i].myTri[j].tri->v[k]].p.z)
|
|
{
|
|
lesserZ++;
|
|
}
|
|
if(uniquePoints[i].p.z < uniquePoints[uniquePoints[i].myTri[j].tri->v[k]].p.z)
|
|
{
|
|
greaterZ++;
|
|
}
|
|
}
|
|
}
|
|
|
|
int gX = 0, lX = 0, gZ = 0, lZ = 0;
|
|
if(greaterX>0 && lesserX==0)
|
|
{
|
|
gX = 1;
|
|
}
|
|
if(greaterX==0 && lesserX>0)
|
|
{
|
|
lX = 1;
|
|
}
|
|
if(greaterZ>0 && lesserZ==0)
|
|
{
|
|
gZ = 1;
|
|
}
|
|
if(greaterZ==0 && lesserZ>0)
|
|
{
|
|
lZ = 1;
|
|
}
|
|
|
|
if(gX + lX + gZ + lZ == 1)
|
|
{
|
|
double dist, distMin = 10000;
|
|
int pmin;
|
|
|
|
if(gX || lX)
|
|
{
|
|
for(j=0;j<uniquePoints[i].connectedTo;j++)
|
|
{
|
|
for(k=0;k<3;k++)
|
|
{
|
|
if( i != uniquePoints[i].myTri[j].tri->v[k] &&
|
|
uniquePoints[i].p.x == uniquePoints[uniquePoints[i].myTri[j].tri->v[k]].p.x)
|
|
{
|
|
dist = fabs(uniquePoints[i].p.z - uniquePoints[uniquePoints[i].myTri[j].tri->v[k]].p.z);
|
|
if(dist < distMin)
|
|
{
|
|
distMin = dist;
|
|
pmin = uniquePoints[i].myTri[j].tri->v[k];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(j=0;j<uniquePoints[i].connectedTo;j++)
|
|
{
|
|
for(k=0;k<3;k++)
|
|
{
|
|
if( i != uniquePoints[i].myTri[j].tri->v[k] &&
|
|
uniquePoints[i].p.z == uniquePoints[uniquePoints[i].myTri[j].tri->v[k]].p.z)
|
|
{
|
|
dist = fabs(uniquePoints[i].p.x - uniquePoints[uniquePoints[i].myTri[j].tri->v[k]].p.x);
|
|
if(dist < distMin)
|
|
{
|
|
distMin = dist;
|
|
pmin = uniquePoints[i].myTri[j].tri->v[k];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for(j=0;j<uniquePoints[i].connectedTo;j++)
|
|
{
|
|
for(k=0;k<3;k++)
|
|
{
|
|
if( i == uniquePoints[i].myTri[j].tri->v[k] )
|
|
{
|
|
uniquePoints[i].myTri[j].tri->v[k] = pmin;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for(l=0;l<uniquePoints[pmin].connectedTo;l++)
|
|
{
|
|
if(uniquePoints[pmin].myTri[l].tri == uniquePoints[i].myTri[j].tri)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(l==uniquePoints[pmin].connectedTo)
|
|
{
|
|
uniquePoints[pmin].Add(uniquePoints[i].myTri[j].tri, k);
|
|
}
|
|
|
|
for(k=0;k<3;k++)
|
|
{
|
|
uniquePoints[uniquePoints[i].myTri[j].tri->v[k]].CalculateAngles();
|
|
}
|
|
uniquePoints[i].myTri[j].tri->GetSurfaceAreaAndCentroid();
|
|
}
|
|
|
|
uniquePoints[i].connectedTo = 0;
|
|
uniquePoints[pmin].CalculateAngles();
|
|
|
|
// try a remedy
|
|
tJunction++;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
tJunction++;
|
|
SPEWALWAYS((0, "H%4x: %6.2f %6.2f %6.2f - %2d %.2f",
|
|
i,
|
|
uniquePoints[i].p.x, uniquePoints[i].p.y, uniquePoints[i].p.z,
|
|
uniquePoints[i].connectedTo,
|
|
uniquePoints[i].GetAngles()/Pi
|
|
));
|
|
if(silentMode!=true)
|
|
{
|
|
PAUSE(("Detected hole in terrain mesh!"));
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
DynamicArrayOf<TriangleStruct*> tileTrianglesPtr;
|
|
|
|
for(l=0;l<zDim;l++)
|
|
{
|
|
for(k=0;k<xDim;k++)
|
|
{
|
|
sprintf(megaBaseName, "Maps\\%s\\%c%c\\%s_%c%c", theName, 'A'+l, 'A'+k, theName, 'A'+l, 'A'+k);
|
|
|
|
Scalar xOffset = dX*(k*256+Xoffset);
|
|
Scalar zOffset = dZ*(l*256+Zoffset);
|
|
|
|
gos_PushCurrentHeap(ElementRenderer::GridElement::s_Heap);
|
|
simpleTerrainGroup[l*xDim+k] =
|
|
new ElementRenderer::GridElement(
|
|
len, len,
|
|
zOffset - zCenterOffset,
|
|
xOffset - xCenterOffset,
|
|
dZ*256, dX*256
|
|
);
|
|
Register_Object(simpleTerrainGroup[l*xDim+k]);
|
|
|
|
waterGroup[l*xDim+k] = new ElementRenderer::GroupElement();
|
|
Register_Object(waterGroup[l*xDim+k]);
|
|
gos_PopCurrentHeap();
|
|
|
|
for(j=0;j<len;j++)
|
|
{
|
|
for(i=0;i<len;i++)
|
|
{
|
|
int m, length = tempTrianglesPtr[(l*xDim+k)*len*len + j*len + i].GetLength();
|
|
int usable = 0;
|
|
|
|
tileTrianglesPtr.SetLength(length);
|
|
for(m=0;m<length;m++)
|
|
{
|
|
if(tempTrianglesPtr[(l*xDim+k)*len*len + j*len + i][m]->area < SMALL)
|
|
{
|
|
RemoveTriangle(tempTrianglesPtr[(l*xDim+k)*len*len + j*len + i][m]);
|
|
|
|
for(n=0,tJunction=0;n<usedUniquePoints;n++)
|
|
{
|
|
if(false == uniquePoints[n].CheckAngles(Xoffset*dX, Zoffset*dZ, dX*(xDim*256+Xoffset), dZ*(zDim*256+Zoffset), dX, dZ))
|
|
{
|
|
tJunction++;
|
|
SPEWALWAYS((0, "H%4x: %6.2f %6.2f %6.2f - %2d %.2f",
|
|
i,
|
|
uniquePoints[n].p.x, uniquePoints[i].p.y, uniquePoints[i].p.z,
|
|
uniquePoints[n].connectedTo,
|
|
uniquePoints[n].GetAngles()/Pi
|
|
));
|
|
if(silentMode!=true)
|
|
{
|
|
PAUSE(("Detected hole in terrain mesh!"));
|
|
}
|
|
}
|
|
}
|
|
|
|
continue;
|
|
}
|
|
else if(tempTrianglesPtr[(l*xDim+k)*len*len + j*len + i][m]->plane.normal.y < Stuff::SMALL)
|
|
{
|
|
RemoveTriangle(tempTrianglesPtr[(l*xDim+k)*len*len + j*len + i][m]);
|
|
|
|
for(n=0,tJunction=0;n<usedUniquePoints;n++)
|
|
{
|
|
if(false == uniquePoints[n].CheckAngles(Xoffset*dX, Zoffset*dZ, dX*(xDim*256+Xoffset), dZ*(zDim*256+Zoffset), dX, dZ))
|
|
{
|
|
tJunction++;
|
|
SPEWALWAYS((0, "H%4x: %6.2f %6.2f %6.2f - %2d %.2f",
|
|
i,
|
|
uniquePoints[n].p.x, uniquePoints[i].p.y, uniquePoints[i].p.z,
|
|
uniquePoints[n].connectedTo,
|
|
uniquePoints[n].GetAngles()/Pi
|
|
));
|
|
if(silentMode!=true)
|
|
{
|
|
PAUSE(("Detected hole in terrain mesh!"));
|
|
}
|
|
}
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
tileTrianglesPtr[usable++] = tempTrianglesPtr[(l*xDim+k)*len*len + j*len + i][m];
|
|
}
|
|
tileTrianglesPtr.SetLength(usable);
|
|
|
|
for(m=0,tJunction=0;m<usedUniquePoints;m++)
|
|
{
|
|
if(false == uniquePoints[m].CheckAngles(Xoffset*dX, Zoffset*dZ, dX*(xDim*256+Xoffset), dZ*(zDim*256+Zoffset), dX, dZ))
|
|
{
|
|
tJunction++;
|
|
SPEWALWAYS((0, "H%4x: %6.2f %6.2f %6.2f - %2d %.2f",
|
|
i,
|
|
uniquePoints[m].p.x, uniquePoints[i].p.y, uniquePoints[i].p.z,
|
|
uniquePoints[m].connectedTo,
|
|
uniquePoints[m].GetAngles()/Pi
|
|
));
|
|
if(silentMode!=true)
|
|
{
|
|
PAUSE(("Detected hole in terrain mesh!"));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
tX = i;
|
|
tY = j;
|
|
|
|
CreateTile(
|
|
simpleTerrainGroup[l*xDim+k],
|
|
waterGroup[l*xDim+k],
|
|
tileTrianglesPtr,
|
|
j*len+i,
|
|
level,
|
|
nrOfLevels,
|
|
bucketSize,
|
|
xOffset,
|
|
zOffset,
|
|
xGridSize,
|
|
zGridSize,
|
|
i,
|
|
j,
|
|
megaBaseName
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
simpleTerrainGroup[l*xDim+k]->LockBounds();
|
|
}
|
|
}
|
|
}
|
|
fprintf(stdout, "Done HFSlimMZ::SetMegaTexture()");
|
|
return true;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
HFSlimMZ::SetCulturals(CulturalLoc* culLoc, int culLocCount)
|
|
{
|
|
int i, j, k, l, n, len = 8;
|
|
|
|
Stuff::ExtentBox allBox;
|
|
allBox = GetExtents();
|
|
|
|
Scalar xGridSize = (allBox.maxX-allBox.minX)/(len*xDim);
|
|
Scalar zGridSize = (allBox.maxZ-allBox.minZ)/(len*zDim);
|
|
|
|
DynamicArrayOf<CulturalLoc> culLocLocal(culLocCount);
|
|
int culLocLocalCount;
|
|
|
|
for(l=0;l<zDim;l++)
|
|
{
|
|
for(k=0;k<xDim;k++)
|
|
{
|
|
ElementRenderer::GridElement *zone = simpleTerrainGroup[l*xDim+k];
|
|
|
|
Scalar xGridOffset = k*dX*256;
|
|
Scalar zGridOffset = l*dZ*256;
|
|
|
|
for(j=0;j<len;j++)
|
|
{
|
|
for(i=0;i<len;i++)
|
|
{
|
|
ElementRenderer::Element *elem = zone->GetIndexedElement(j*len+i);
|
|
|
|
ElementRenderer::GroupElement *group = Cast_Object(ElementRenderer::GroupElement*, elem);
|
|
|
|
Scalar x0, z0, x1, z1;
|
|
|
|
x0 = xGridOffset + i*xGridSize - xCenterOffset;
|
|
z0 = zGridOffset + j*zGridSize - zCenterOffset;
|
|
x1 = x0 + xGridSize;
|
|
z1 = z0 + zGridSize;
|
|
|
|
x0 += 4.5f;
|
|
z0 += 4.5f;
|
|
x1 -= 4.5f;
|
|
z1 -= 4.5f;
|
|
|
|
for(n=0,culLocLocalCount=0;n<culLocCount;n++)
|
|
{
|
|
if(culLoc[n].loc.x > x0 && culLoc[n].loc.x < x1 && culLoc[n].loc.z > z0 && culLoc[n].loc.z < z1)
|
|
{
|
|
Line3D line(
|
|
Point3D(
|
|
culLoc[n].loc.x,
|
|
Offset-100.0f,
|
|
culLoc[n].loc.z
|
|
),
|
|
UnitVector3D(0.0f, 1.0f, 0.0f),
|
|
// 256*dY
|
|
1000
|
|
);
|
|
Normal3D normal;
|
|
ElementRenderer::CollisionQuery cq(&line, &normal);
|
|
#ifdef LAB_ONLY
|
|
bool ret =
|
|
#endif
|
|
group->CastRay(&cq);
|
|
#ifdef LAB_ONLY
|
|
if (!ret)
|
|
{
|
|
char szTemp[256];
|
|
sprintf(szTemp, "Natural couldn't find soil to plant on at x=%f, z=%f",culLoc[n].loc.x, culLoc[n].loc.z);
|
|
// PAUSE((szTemp));
|
|
}
|
|
#endif
|
|
|
|
Point3D end;
|
|
line.FindEnd(&end);
|
|
|
|
culLoc[n].loc.y = end.y;
|
|
|
|
culLocLocal[culLocLocalCount++] = culLoc[n];
|
|
}
|
|
}
|
|
|
|
if(culLocLocalCount>0)
|
|
{
|
|
Stuff::ChainIteratorOf<ElementRenderer::Element*> *children = group->MakeIterator();
|
|
Register_Object(children);
|
|
|
|
ElementRenderer::Element *child = NULL;
|
|
int count = 0;
|
|
child = children->ReadAndNext();
|
|
Unregister_Object(children);
|
|
delete children;
|
|
|
|
Verify(count<2);
|
|
|
|
ElementRenderer::ListElement *list = Cast_Object(ElementRenderer::ListElement*, child);
|
|
|
|
gos_PushCurrentHeap(ElementRenderer::ShapeElement::s_Heap);
|
|
ElementRenderer::ShapeElement* Shape = new ElementRenderer::ShapeElement;
|
|
Register_Object(Shape);
|
|
gos_PopCurrentHeap();
|
|
|
|
gos_PushCurrentHeap(MidLevelRenderer::ShapeHeap);
|
|
MLRCulturShape *shape = new MLRCulturShape();
|
|
Register_Object(shape);
|
|
gos_PopCurrentHeap();
|
|
|
|
MLRCultural *data = new MLRCultural[culLocLocalCount];
|
|
|
|
Mem_Copy(data, culLocLocal.GetData(), culLocLocalCount*sizeof(MLRCultural), culLocLocalCount*sizeof(MLRCultural));
|
|
|
|
shape->AssignCulturalData(data, culLocLocalCount);
|
|
|
|
shape->FadeValue(culturalFadeIn, culturalFadeOut);
|
|
|
|
Shape->SetMLRShape(shape);
|
|
|
|
Shape->m_localOBB.localToParent = LinearMatrix4D::Identity;
|
|
Shape->m_localOBB.localToParent.BuildTranslation(
|
|
Point3D(
|
|
xGridOffset + i*xGridSize + xGridSize*0.5f - xCenterOffset/* - Xoffset*dX*/,
|
|
0.0f,
|
|
zGridOffset + j*zGridSize + zGridSize*0.5f - zCenterOffset/* - Zoffset*dZ*/
|
|
)
|
|
);
|
|
|
|
Shape->m_localOBB.sphereRadius = static_cast<Scalar>(sqrt(xGridSize*xGridSize + zGridSize*zGridSize));
|
|
|
|
shape->SetCenterInWorld(
|
|
xGridOffset + i*xGridSize + xGridSize*0.5f - xCenterOffset/* - Xoffset*dX*/,
|
|
zGridOffset + j*zGridSize + zGridSize*0.5f - zCenterOffset/* - Zoffset*dZ*/,
|
|
Shape->m_localOBB.sphereRadius
|
|
);
|
|
|
|
int lCount = list->GetActiveCount();
|
|
|
|
gos_PushCurrentHeap(ElementRenderer::g_Heap);
|
|
list->ReSize(lCount+1);
|
|
gos_PopCurrentHeap();
|
|
|
|
list->AttachIndexedChild(lCount, Shape);
|
|
|
|
Shape->SetNeverCullMode();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Scalar
|
|
HFSlimMZ::GetHeight(int x, int z)
|
|
{
|
|
if (x<0) x = 0;
|
|
if (x>GetX()-1)
|
|
{
|
|
x = GetX() - 1;
|
|
}
|
|
if (z<0) z = 0;
|
|
if (z>GetZ()-1)
|
|
{
|
|
z = GetZ() - 1;
|
|
}
|
|
return field[z*X + x]*dY + Offset;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void ToDrawTriangle::SetPoint(int idx,float x,float y,float z)
|
|
{
|
|
Verify(idx>=0 && idx<3);
|
|
|
|
v[idx].x=x;
|
|
v[idx].y=y;
|
|
v[idx].z=z;
|
|
}
|
|
|
|
|
|
|