Files
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

2571 lines
57 KiB
C++

#include <MLR\MLRHeaders.hpp>
#if !defined(HFSLIMMZL_HPP)
#include "HFslimMZL.hpp"
#include "terra\terra.hpp"
#endif
const Scalar One_Over_Three = 1.0f/3.0f;
bool doWater = false;
Scalar waterLevel;
bool doBSP = false;
extern FILE *analyzeFile;
DynamicArrayOf<PointStruct> uniquePoints;
int usedUniquePoints;
PointStruct *TriangleStruct::points = NULL;
DynamicArrayOf<TriangleStruct> triangleIndices;
int usedTriangleIndices;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
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)
{
for(int i=0;i<usedUniquePoints;i++)
{
if(Close_Enough(uniquePoints[i].p, point))
{
return i;
}
}
if(i==usedUniquePoints)
{
uniquePoints[i].p = point;
usedUniquePoints++;
}
return i;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
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)
);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
PointStruct::CheckAngles(Scalar xMax, Scalar zMax)
{
Check_Object(this);
if(connectedTo==0)
{
return true;
}
float angle = 0.0f;
for(int j=0;j<connectedTo;j++)
{
angle += myTri[j].angle;
}
if( (p.x == 0.0f || p.x==xMax) &&
(p.z == 0.0f || p.z==zMax) )
{
if(!Close_Enough(angle, Pi*0.5f, 0.005f))
{
return false;
}
}
else
if( (p.x == 0.0f || p.x==xMax) ||
(p.z == 0.0f || p.z==zMax) )
{
if(!Close_Enough(angle, Pi, 0.005f))
{
return false;
}
}
else
{
if(!Close_Enough(angle, 2.0f*Pi, 0.005f))
{
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);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TriangleStruct::GetSurfaceAreaAndCentroid()
{
Verify(points!=NULL);
//
//---------------------
// 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 = Point3D::Identity;
plane.normal.x = 0.0f;
plane.normal.y = 0.0f;
plane.normal.z = 1.0f;
plane.offset = 0.0f;
if(v[0]==v[1] || v[0]==v[2] || v[1]==v[2])
{
return;
}
//
//-----------------------------------------------
// Generate all the information on the first pass
//-----------------------------------------------
//
position_a = GetPoint(0);
position_b = GetPoint(1);
position_c = GetPoint(2);
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)
{
plane.BuildPlane(
GetPoint(0),
GetPoint(1),
GetPoint(2)
);
center *= (One_Over_Three/area);
}
else
{
center *= One_Over_Three;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/*
bool
ToDrawTriangle::IntersectTriangle(ToDrawTriangle *tri)
{
Scalar x, dx, dz, dx1, dz1;
int i, i1, j, j1;
for(i=0;i<3;i++)
{
i1 = i<2 ? i+1 : 0;
dx1 = v[i1].x - v[i].x;
dz1 = v[i1].z - v[i].z;
for(j=0;j<3;j++)
{
j1 = j<2 ? j+1 : 0;
dx = tri->v[j1].x - tri->v[j].x;
dz = tri->v[j1].z - tri->v[j].z;
if(dx<=SMALL && dx1<=SMALL)
{
continue;
}
if(dz<=SMALL && dz1<=SMALL)
{
continue;
}
if( Close_Enough(dz*dx1, dz1*dx) )
{
continue;
}
x = (dx*dx1*v[i].z - tri->v[j].z*dx*dx1 - dz1*dx*v[i].x + dz*dx1*tri->v[j].x) / (dz*dx1 - dz1*dx);
if(v[i].x < v[i1].x)
{
if(tri->v[j].x < tri->v[j1].x)
{
if(x>v[i].x && x<v[i1].x && x>tri->v[j].x && x<tri->v[j1].x)
{
return true;
}
}
else
{
if(x>v[i].x && x<v[i1].x && x>tri->v[j1].x && x<tri->v[j].x)
{
return true;
}
}
}
else
{
if(tri->v[j].x < tri->v[j1].x)
{
if(x>v[i1].x && x<v[i].x && x>tri->v[j].x && x<tri->v[j1].x)
{
return true;
}
}
else
{
if(x>v[i1].x && x<v[i].x && x>tri->v[j1].x && x<tri->v[j].x)
{
return true;
}
}
}
}
}
return false;
}
*/
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
HFSlimMZL::HFSlimMZL()
{
X = (int)0.0f;
Z = (int)0.0f;
dX = 2.0f;
dY = 0.15f;
dZ = 2.0f;
xOffset = 0.0f;
zOffset = 0.0f;
Offset = 0.0f;
visHeight = 0;
simpleTerrainGroup.SetLength(0);
borderPixelFun = 0.0f;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
HFSlimMZL::~HFSlimMZL()
{
for(int i=0;i<simpleTerrainGroup.GetLength();i++)
{
Unregister_Object(simpleTerrainGroup[i]);
delete simpleTerrainGroup[i];
simpleTerrainGroup[i] = NULL;
}
simpleTerrainGroup.SetLength(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Stuff::ExtentBox
HFSlimMZL::GetExtents()
{
Stuff::ExtentBox ebox;
ebox.minX = GetX(0);
ebox.minZ = GetZ(0);
ebox.maxX = GetX(X-1);
ebox.maxZ = GetZ(Z-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
HFSlimMZL::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
HFSlimMZL::FillFromImage(Image &image, int smooth)
{
X = image.GetWidth()+1;
Z = image.GetHeight()+1;
Verify(((X-1)%256 == 0) && ((Z-1)%256 == 0));
xDim = image.GetWidth()/256;
zDim = image.GetHeight()/256;
Verify(image.GetBpp()==8);
field.SetLength(X*Z);
unsigned char *ptr;
ptr=(unsigned char *)image.Lock();
int i, j;
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];
image.UnLock();
Blur2D(smooth);
}
Scalar xGridSize, zGridSize;
int tX, tY;
#ifdef TCTD2
extern void TCTDrawLine(int x1,int y1,int x2,int y2,COLORREF ref=0xffffff);
extern void TCTClearLines();
#endif
void GetFacesCB(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.point2()[0];
point.y = 0.0f;
point.z = (float)tri.point2()[1];
triangleIndices[usedTriangleIndices].v[2] = FindAddPoint(point);
point.x = (float)tri.point3()[0];
point.y = 0.0f;
point.z = (float)tri.point3()[1];
triangleIndices[usedTriangleIndices].v[1] = FindAddPoint(point);
usedTriangleIndices++;
#ifdef TCTD2
// TCTDrawLine((int)tri.point1()[0], (int)tri.point1()[1], (int)tri.point2()[0], (int)tri.point2()[1], 0xf7777f);
// TCTDrawLine((int)tri.point2()[0], (int)tri.point2()[1], (int)tri.point3()[0], (int)tri.point3()[1], 0xf7777f);
// TCTDrawLine((int)tri.point3()[0], (int)tri.point3()[1], (int)tri.point1()[0], (int)tri.point1()[1], 0xf7777f);
#endif
}
#ifdef TCTD2
void GetEdgesCB(Edge *edge, void *ptr)
{
Vec2 from = edge->Org();
Vec2 to = edge->Dest();
int x1 = (int)from[0] & ~31;
int z1 = (int)from[1] & ~31;
int x2 = (int)to[0] & ~31;
int z2 = (int)to[1] & ~31;
int color = 0xffffff;
if(x1!=x2)
{
if(abs(x1-x2) > 32)
{
color &= 0xff00ff;
}
else
{
if(x1<x2)
{
if((int)to[0] & 31)
{
color &= 0xff00ff;
}
}
else
{
if((int)from[0] & 31)
{
color &= 0xff00ff;
}
}
}
}
if(z1!=z2)
{
if(abs(z1-z2) > 32)
{
color &= 0xffff00;
}
else
{
if(z1<z2)
{
if((int)to[1] & 31)
{
color &= 0xffff00;
}
}
else
{
if((int)from[1] & 31)
{
color &= 0xffff00;
}
}
}
}
// TCTDrawLine((int)from[0], (int)from[1], (int)to[0], (int)to[1], color);
}
#endif
#define TERRAIN2_TEST
bool
HFSlimMZL::CreateMesh(
ListElement *parent,
int listIndex,
int diffLevel,
DynamicArrayOf<TriangleStruct*>& tdtrilist,
frameArray *frame,
MLRState *state
)
{
int polygon_count = tdtrilist.GetLength();
if(polygon_count==0 || polygon_count*3 >= Limits::Max_Number_Vertices_Per_Mesh)
{
return false;
}
#ifndef TERRAIN2_TEST
MLR_I_DeT_TMesh *erf_mesh = new MLR_I_DeT_TMesh;
#else
gos_PushCurrentHeap(MidLevelRenderer::Heap);
MLR_Terrain2 *erf_mesh = new MLR_Terrain2;
gos_PopCurrentHeap();
erf_mesh->SetDepthData(maxAllDepth-diffLevel, maxAllDepth);
erf_mesh->SetTileData(tX, tY);
erf_mesh->SetBorderPixel(borderPixelFun);
// erf_mesh->SetOffset(xOffset, zOffset);
// erf_mesh->SetGrid(xGridSize, zGridSize);
for(int ii=0;ii<8;ii++)
{
erf_mesh->SetFrame(ii, (*frame)[ii][0], (*frame)[ii][1], (*frame)[ii][2], (*frame)[ii][3]);
}
#endif
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, k, l, 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;
int *uPoints = new int [3*polygon_count];
point_count = 0;
for(i=0;i<polygon_count;++i)
{
center3 += tdtrilist[i]->center;
for(k=0;k<3;k++)
{
for(l=0;l<point_count;l++)
{
if(uPoints[l]==tdtrilist[i]->v[k])
{
break;
}
}
if(l==point_count)
{
uPoints[point_count++] = tdtrilist[i]->v[k];
center0 += tdtrilist[i]->GetPoint(k);
}
if(tdtrilist[i]->GetPoint(k).x < minx)
{
minX[0] = i;
minX[1] = k;
minx = tdtrilist[i]->GetPoint(k).x;
} else if(tdtrilist[i]->GetPoint(k).x > maxx)
{
maxX[0] = i;
maxX[1] = k;
maxx = tdtrilist[i]->GetPoint(k).x;
}
if(tdtrilist[i]->GetPoint(k).y < miny)
{
minY[0] = i;
minY[1] = k;
miny = tdtrilist[i]->GetPoint(k).y;
} else if(tdtrilist[i]->GetPoint(k).y > maxy)
{
maxY[0] = i;
maxY[1] = k;
maxy = tdtrilist[i]->GetPoint(k).y;
}
if(tdtrilist[i]->GetPoint(k).z < minz)
{
minZ[0] = i;
minZ[1] = k;
minz = tdtrilist[i]->GetPoint(k).z;
} else if(tdtrilist[i]->GetPoint(k).z > maxz)
{
maxZ[0] = i;
maxZ[1] = k;
maxz = tdtrilist[i]->GetPoint(k).z;
}
}
}
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);
Scalar radiusSquared,
maxRadius0 = 0.0f,
maxRadius1 = 0.0f,
maxRadius2 = 0.0f,
maxRadius3 = 0.0f;
for(i=0;i<point_count;i++)
{
coords[i] = uniquePoints[uPoints[i]].p;
Verify(coords[i].x<=(*frame)[maxAllDepth][2] && coords[i].x>=(*frame)[maxAllDepth][0]);
Verify(coords[i].z<=(*frame)[maxAllDepth][3] && coords[i].z>=(*frame)[maxAllDepth][1]);
v3.Subtract(coords[i], center0);
radiusSquared = v3.GetLengthSquared();
maxRadius0 = radiusSquared>maxRadius0 ? radiusSquared:maxRadius0;
v3.Subtract(coords[i], center1);
radiusSquared = v3.GetLengthSquared();
maxRadius1 = radiusSquared>maxRadius1 ? radiusSquared:maxRadius1;
v3.Subtract(coords[i], center2);
radiusSquared = v3.GetLengthSquared();
maxRadius2 = radiusSquared>maxRadius2 ? radiusSquared:maxRadius2;
v3.Subtract(coords[i], center3);
radiusSquared = v3.GetLengthSquared();
maxRadius3 = radiusSquared>maxRadius3 ? radiusSquared:maxRadius3;
#ifndef TERRAIN2_TEST
texCoords[i][0] =
borderPixelFun + (1.0f-2*borderPixelFun)*(((*frame)[maxAllDepth][2] - coords[i].x)/((*frame)[maxAllDepth][2]-uvFrame->minX));
texCoords[i][1] =
borderPixelFun + (1.0f-2*borderPixelFun)*(((*frame)[maxAllDepth][3] - coords[i].z)/((*frame)[maxAllDepth][3]-uvFrame->minZ));
#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;
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;
}
}
}
unsigned short *index = new unsigned short [polygon_count*3];
for(i=0,l=0;i<polygon_count;i++)
{
for(k=0;k<3;k++)
{
for(j=0;j<point_count;j++)
{
if(uPoints[j]==tdtrilist[i]->v[k])
{
break;
}
}
Verify(j<point_count);
index[l++] = j;
}
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;
}
}
gos_PushCurrentHeap(MidLevelRenderer::Heap);
erf_mesh->SetSubprimitiveLengths(NULL, l/3);
erf_mesh->SetCoordData(coords, point_count);
#ifdef TERRAIN2_TEST
erf_mesh->SetCurrentDepth(maxAllDepth-diffLevel);
#else
erf_mesh->SetTexCoordData(texCoords, point_count);
#endif
erf_mesh->SetIndexData(index, l);
gos_PopCurrentHeap();
delete [] uPoints;
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::Heap);
ShapeElement* Shape = new ShapeElement;
Register_Object(Shape);
gos_PopCurrentHeap();
gos_PushCurrentHeap(MidLevelRenderer::Heap);
MLRShape *shape = new MLRShape(1);
Register_Object(shape);
gos_PopCurrentHeap();
shape->Add(erf_mesh);
erf_mesh->DetachReference();
Shape->SetMLRShape(shape);
Shape->m_localOBB.localToParent = LinearMatrix4D::Identity;
Shape->m_localOBB.localToParent.BuildTranslation(center);
Shape->m_localOBB.sphereRadius = maxRadius;
parent->AttachIndexedChild(listIndex, Shape);
Shape->SetVolumeCullMode();
return true;
}
int
primCounter, maxPrims;
bool
HFSlimMZL::BinSort(
ListElement *parent,
int index,
int levDiff,
DynamicArrayOf<TriangleStruct*>& 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::Heap);
ListElement *group = new 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<TriangleStruct*>
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))
{
worked |= 1;
}
if (BinSort(
group,
1,
levDiff,
group_b,
binSize,
frame,
state))
{
worked |= 2;
}
if(worked != 3)
{
if(worked == 0)
return false;
ListElement *smallgroup = new ListElement;
Register_Object(smallgroup);
group->SetSize(1);
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);
}
else
{
Check_Object(group);
parent->AttachIndexedChild(index, group);
}
//
//-----------------------------------------
// Now set the bounding sphere of the group
//-----------------------------------------
//
group->NeedNewBounds();
group->SetVolumeCullMode();
return true;
}
void
HFSlimMZL::OptimizeHField(int depth, int binSize)
{
if(X*Z == 0)
{
return;
}
fprintf(stdout, "Going to optimize the terrain: MaxNr.Of Points: %d BinSize: %d\n", depth, binSize);
DirectMap<real> map(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;
GreedySubdivision mesh(&map);
point_limit=1024;
point_limit = depth;
int count=1;
while(mesh.pointCount()<point_limit && mesh.maxError() > error_threshold)
{
mesh.greedyInsert();
}
fprintf(stdout, "The mesh was greedy.\n");
mesh.overEdges(GetEdgesCB, NULL);
usedUniquePoints = 0;
usedTriangleIndices = 0;
uniquePoints.SetLength(2*mesh.pointCount());
TriangleStruct::points = uniquePoints.GetData();
triangleIndices.SetLength(8*mesh.pointCount());
mesh.overFaces(GetFacesCB, 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) )
{
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<ToDrawTriangle*> &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]->GetV0().x >= x0n && tempTrianglesPtr[k]->GetV0().x <= x1n &&
tempTrianglesPtr[k]->GetV0().z >= z0n && tempTrianglesPtr[k]->GetV0().z < z1n
)
{
l++;
}
if( tempTrianglesPtr[k]->GetV1().x >= x0n && tempTrianglesPtr[k]->GetV1().x <= x1n &&
tempTrianglesPtr[k]->GetV1().z >= z0n && tempTrianglesPtr[k]->GetV1().z <= z1n
)
{
l++;
}
if( tempTrianglesPtr[k]->GetV2().x >= x0n && tempTrianglesPtr[k]->GetV2().x <= x1n &&
tempTrianglesPtr[k]->GetV2().z >= z0n && tempTrianglesPtr[k]->GetV2().z <= z1n
)
{
l++;
}
if(l==3)
{
in++;
}
else if(l>0)
{
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
HFSlimMZL::CreateTile(
ElementRenderer::ListElement *list,
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::Heap);
ElementRenderer::GroupElement *group = new GroupElement;
Register_Object(group);
list->AttachIndexedChild(index, group);
group->NeedNewBounds();
group->SetVolumeCullMode();
ElementRenderer::ListElement *subList = new 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 = 1<<(maxdepth - depth);
Scalar frame[8][4];
frame[0][0] = xOffset;
frame[0][1] = zOffset;
frame[0][2] = xOffset + 8*xGrid;
frame[0][3] = zOffset + 8*zGrid;
frame[1][0] = xOffset + 4*(tileX/4)*xGrid;
frame[1][1] = zOffset + 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] = xOffset + tileX*xGrid;
frame[i][1] = zOffset + tileZ*zGrid;
frame[i][2] = frame[i][0] + xGrid;
frame[i][3] = frame[i][1] + zGrid;
}
/*
x0 = xGridOffset + (tileX/i)*(i*xGrid);
z0 = zGridOffset + (tileZ/i)*(i*zGrid);
x1 = x0 + i*xGrid;
z1 = z0 + i*zGrid;
Stuff::ExtentBox box;
box.minX = x0;
box.maxX = x1;
box.minY = Offset;
box.maxY = Offset+256.0f;
box.minZ = z0;
box.maxZ = z1;
*/
if(!BinSort(
subList,
0,
maxdepth - depth,
tempTrianglesPtr,
maxNumOfTrianglesPerMesh,
&frame,
&state
)
)
{
PAUSE(("Unstable triangle mesh created!"));
}
group->Sync();
group->LockBounds();
group->SetNeverCullMode();
subList->LockBounds();
subList->SetNeverCullMode();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
HFSlimMZL::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[6];
int index[6];
float angles[6];
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][6];
int index[6];
float angles[6];
int clipMeToo[2][6];
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)
);
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=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;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
HFSlimMZL::SetMegaTexture(
int nrOfLevels,
int bucketSize,
const char *theName
)
{
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());
}
DynamicArrayOf<unsigned char> onOffTriangles;
onOffTriangles.AssignValue(0, triangleIndices.GetLength());
int i, j, k, l, level;
simpleTerrainGroup.SetLength(xDim*zDim);
Stuff::ExtentBox allBox;
allBox = GetExtents();
int len = 1<<nrOfLevels;
xGridSize = (allBox.maxX-allBox.minX)/(len*xDim);
zGridSize = (allBox.maxZ-allBox.minZ)/(len*zDim);
int numOfTriangles = usedTriangleIndices;
DynamicArrayOf<TriangleStruct*> *tempTrianglesPtr;
tempTrianglesPtr = new DynamicArrayOf<TriangleStruct*> [zDim*xDim*len*len];
for(l=0;l<zDim;l++)
{
for(k=0;k<xDim;k++)
{
brokenTriangles = 0;
xOffset = k*dX*256;
zOffset = l*dZ*256;
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);
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);
}
}
int tJunction = 0;
for(i=0;i<usedUniquePoints;i++)
{
if(uniquePoints[i].CheckAngles(GetXinM(), GetZinM())==false)
{
tJunction++;
}
}
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;
}
}
}
tJunction = 0;
for(i=0;i<usedUniquePoints;i++)
{
if(false == uniquePoints[i].CheckAngles(GetXinM(), GetZinM()))
{
tJunction++;
}
}
Verify(tJunction==0);
for(i=0;i<usedTriangleIndices;i++)
{
triangleIndices[i].GetSurfaceAreaAndCentroid();
}
int smallOne = 0, tiltedOne = 0;
for(i=0;i<usedTriangleIndices;i++)
{
if(triangleIndices[i].area > Stuff::SMALL && triangleIndices[i].plane.normal.y < Stuff::SMALL)
{
int pmin, pmid, pmax;
bool xCase = false, zCase = false;
if(
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(
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;
}
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)
{
STOP(("What, the hell, happend ?"));
}
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
{
STOP(("Now we are in real trouble !"));
}
}
}
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)
{
STOP(("What, the hell, happend ?"));
}
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
{
STOP(("Now we are in real trouble !"));
}
}
}
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
{
STOP(("Very odd indeed !"));
}
}
}
}
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);
xOffset = k*dX*256;
zOffset = l*dZ*256;
gos_PushCurrentHeap(ElementRenderer::Heap);
simpleTerrainGroup[l*xDim+k] = new GridElement(len, len, zOffset, xOffset, dZ*256, dX*256);
Register_Object(simpleTerrainGroup[l*xDim+k]);
simpleTerrainGroup[l*xDim+k]->SetName("OptimizedTerrain");
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)
{
continue;
}
else if(tempTrianglesPtr[(l*xDim+k)*len*len + j*len + i][m]->plane.normal.y < Stuff::SMALL)
{
continue;
}
tileTrianglesPtr[usable++] = tempTrianglesPtr[(l*xDim+k)*len*len + j*len + i][m];
}
tileTrianglesPtr.SetLength(usable);
tX = i;
tY = j;
CreateTile(
simpleTerrainGroup[l*xDim+k],
tileTrianglesPtr,
j*len+i,
level,
nrOfLevels,
bucketSize,
xOffset,
zOffset,
xGridSize,
zGridSize,
i,
j,
megaBaseName
);
}
}
simpleTerrainGroup[l*xDim+k]->LockBounds();
}
}
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
HFSlimMZL::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;
}