Files
firestorm/Gameleap/code/mw4/Tools/TCTb/HFslimMZ0p3.cpp
T
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

1677 lines
38 KiB
C++

#include <MLR\MLRHeaders.hpp>
#if !defined(HFSLIMMZ0P3_HPP)
#include "HFSlimMZ0p3.hpp"
#include "terra\terra.hpp"
#endif
const Scalar One_Over_Three = 1.0f/3.0f;
extern FILE *analyzeFile;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ToDrawTriangle::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 = Point3D::Identity;
//
//-----------------------------------------------
// Generate all the information on the first pass
//-----------------------------------------------
//
position_a = v[0];
position_b = v[1];
position_c = v[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;
}
}
plane.normal.x = 0.0f;
plane.normal.y = 0.0f;
plane.normal.z = 1.0f;
plane.offset = 0.0f;
if(area > SMALL)
{
plane.BuildPlane(
v[0],
v[2],
v[1]
);
center *= (One_Over_Three/area);
}
else
{
center *= One_Over_Three;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
HFSlimMZ0p3::HFSlimMZ0p3()
{
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;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
HFSlimMZ0p3::~HFSlimMZ0p3()
{
for(int i=0;i<simpleTerrainGroup.GetLength();i++)
{
Unregister_Object(simpleTerrainGroup[i]);
delete simpleTerrainGroup[i];
simpleTerrainGroup[i] = NULL;
}
simpleTerrainGroup.SetLength(0);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Stuff::ExtentBox
HFSlimMZ0p3::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
HFSlimMZ0p3::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
HFSlimMZ0p3::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);
}
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++;
}
#define TERRAIN2_TEST
Point3D center;
Scalar maxRadius;
bool
HFSlimMZ0p3::CreateMesh(
MLR_Terrain2 *erf_mesh,
DynamicArrayOf<ToDrawTriangle*>& tdtrilist,
ExtentBox *uvFrame
)
{
int polygon_count = tdtrilist.GetLength();
if(polygon_count==0 || polygon_count*3 >= Limits::Max_Number_Vertices_Per_Mesh)
{
return NULL;
}
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]->v[0].x,
maxx=tdtrilist[0]->v[0].x,
miny=tdtrilist[0]->v[0].y,
maxy=tdtrilist[0]->v[0].y,
minz=tdtrilist[0]->v[0].z,
maxz=tdtrilist[0]->v[0].z;
Point3D
center0 = Point3D::Identity,
center1 = Point3D::Identity,
center2 = Point3D::Identity,
center3 = Point3D::Identity;
for(i=0;i<polygon_count;++i)
{
center3 += tdtrilist[i]->center;
if(tdtrilist[i]->v[0].x < minx)
{
minX[0] = i;
minX[1] = 0;
minx = tdtrilist[i]->v[0].x;
} else if(tdtrilist[i]->v[0].x > maxx)
{
maxX[0] = i;
maxX[1] = 0;
maxx = tdtrilist[i]->v[0].x;
}
if(tdtrilist[i]->v[0].y < miny)
{
minY[0] = i;
minY[1] = 0;
miny = tdtrilist[i]->v[0].y;
} else if(tdtrilist[i]->v[0].y > maxy)
{
maxY[0] = i;
maxY[1] = 0;
maxy = tdtrilist[i]->v[0].y;
}
if(tdtrilist[i]->v[0].z < minz)
{
minZ[0] = i;
minZ[1] = 0;
minz = tdtrilist[i]->v[0].z;
} else if(tdtrilist[i]->v[0].z > maxz)
{
maxZ[0] = i;
maxZ[1] = 0;
maxz = tdtrilist[i]->v[0].z;
}
x = (int)(tdtrilist[i]->v[0].x/dX);
z = (int)(tdtrilist[i]->v[0].z/dZ);
vert_id[x + X*z]++;
if(vert_id[x + X*z]==1)
{
center0 += tdtrilist[i]->v[0];
point_count++;
}
if(tdtrilist[i]->v[2].x < minx)
{
minX[0] = i;
minX[1] = 2;
minx = tdtrilist[i]->v[2].x;
} else if(tdtrilist[i]->v[2].x > maxx)
{
maxX[0] = i;
maxX[1] = 2;
maxx = tdtrilist[i]->v[2].x;
}
if(tdtrilist[i]->v[2].y < miny)
{
minY[0] = i;
minY[1] = 2;
miny = tdtrilist[i]->v[2].y;
} else if(tdtrilist[i]->v[2].y > maxy)
{
maxY[0] = i;
maxY[1] = 2;
maxy = tdtrilist[i]->v[2].y;
}
if(tdtrilist[i]->v[2].z < minz)
{
minZ[0] = i;
minZ[1] = 2;
minz = tdtrilist[i]->v[2].z;
} else if(tdtrilist[i]->v[2].z > maxz)
{
maxZ[0] = i;
maxZ[1] = 2;
maxz = tdtrilist[i]->v[2].z;
}
x = (int)(tdtrilist[i]->v[2].x/dX);
z = (int)(tdtrilist[i]->v[2].z/dZ);
vert_id[x + X*z]++;
if(vert_id[x + X*z]==1)
{
center0 += tdtrilist[i]->v[1];
point_count++;
}
if(tdtrilist[i]->v[1].x < minx)
{
minX[0] = i;
minX[1] = 0;
minx = tdtrilist[i]->v[1].x;
} else if(tdtrilist[i]->v[1].x > maxx)
{
maxX[0] = i;
maxX[1] = 1;
maxx = tdtrilist[i]->v[1].x;
}
if(tdtrilist[i]->v[1].y < miny)
{
minY[0] = i;
minY[1] = 1;
miny = tdtrilist[i]->v[1].y;
} else if(tdtrilist[i]->v[1].y > maxy)
{
maxY[0] = i;
maxY[1] = 1;
maxy = tdtrilist[i]->v[1].y;
}
if(tdtrilist[i]->v[1].z < minz)
{
minZ[0] = i;
minZ[1] = 1;
minz = tdtrilist[i]->v[1].z;
} else if(tdtrilist[i]->v[1].z > maxz)
{
maxZ[0] = i;
maxZ[1] = 1;
maxz = tdtrilist[i]->v[1].z;
}
x = (int)(tdtrilist[i]->v[1].x/dX);
z = (int)(tdtrilist[i]->v[1].z/dZ);
vert_id[x + X*z]++;
if(vert_id[x + X*z]==1)
{
center0 += tdtrilist[i]->v[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]]->v[maxX[1]], tdtrilist[minX[0]]->v[minX[1]]);
d[0] = v3.GetLengthSquared();
v3.Subtract(tdtrilist[maxY[0]]->v[maxY[1]], tdtrilist[minY[0]]->v[minY[1]]);
d[1] = v3.GetLengthSquared();
v3.Subtract(tdtrilist[maxZ[0]]->v[maxZ[1]], tdtrilist[minZ[0]]->v[minZ[1]]);
d[2] = v3.GetLengthSquared();
if(d[0] > d[1])
{
if(d[0]>d[2])
{
center1 = tdtrilist[maxX[0]]->v[maxX[1]];
center1 += tdtrilist[minX[0]]->v[minX[1]];
center1 *= 0.5f;
}
else
{
center1 = tdtrilist[maxZ[0]]->v[maxZ[1]];
center1 += tdtrilist[minZ[0]]->v[minZ[1]];
center1 *= 0.5f;
}
}
else
{
if(d[1]>d[2])
{
center1 = tdtrilist[maxY[0]]->v[maxY[1]];
center1 += tdtrilist[minY[0]]->v[minY[1]];
center1 *= 0.5f;
}
else
{
center1 = tdtrilist[maxZ[0]]->v[maxZ[1]];
center1 += tdtrilist[minZ[0]]->v[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)<=uvFrame->maxX && GetX(x)>=uvFrame->minX);
Verify(GetZ(z)<=uvFrame->maxZ && GetZ(z)>=uvFrame->minZ);
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;
}
maxRadius0 = static_cast<Scalar>(sqrt(maxRadius0));
maxRadius1 = static_cast<Scalar>(sqrt(maxRadius1));
maxRadius2 = static_cast<Scalar>(sqrt(maxRadius2));
maxRadius3 = static_cast<Scalar>(sqrt(maxRadius3));
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];
int k, l;
for(i=0,l=0;i<polygon_count;i++)
{
k = 0;
x = (int)(tdtrilist[i]->v[0].x/dX);
z = (int)(tdtrilist[i]->v[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]->v[2].x/dX);
z = (int)(tdtrilist[i]->v[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]->v[1].x/dX);
z = (int)(tdtrilist[i]->v[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;
}
}
gos_PushCurrentHeap(MidLevelRenderer::Heap);
erf_mesh->SetSubprimitiveLengths(NULL, l/3);
#ifdef _ARMOR
for(i=0;i<nrOfPoints;i++)
{
for(j=0;j<8;j++)
{
Verify(coords[i].x>=erf_mesh->GetFrame(j, 0) && coords[i].x<=erf_mesh->GetFrame(j, 2) );
Verify(coords[i].z>=erf_mesh->GetFrame(j, 1) && coords[i].z<=erf_mesh->GetFrame(j, 3) );
}
}
#endif
erf_mesh->SetCoordData(coords, nrOfPoints);
#ifdef TERRAIN2_TEST
erf_mesh->SetFrame(0, xOffset, zOffset, xOffset+8*xGridSize, zOffset+8*zGridSize);
erf_mesh->SetCurrentDepth(0);
#else
erf_mesh->SetTexCoordData(texCoords, nrOfPoints);
#endif
erf_mesh->SetIndexData(index, l);
gos_PopCurrentHeap();
erf_mesh->FindFacePlanes();
delete [] coords;
delete [] texCoords;
delete [] index;
return true;
}
int
primCounter, maxPrims;
void
HFSlimMZ0p3::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);
tdtrilist.SetLength((X-1)*(Z-1));
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;
triangleCounter = 0;
int count=1;
while(mesh.pointCount()<point_limit && mesh.maxError() > error_threshold)
{
mesh.greedyInsert();
}
fprintf(stdout, "The mesh was greedy.\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;
tdtrilist[i].GetSurfaceAreaAndCentroid();
}
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) )
{
STOP(("Danger Danger !"));
}
/*
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);
}
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");
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
HFSlimMZ0p3::BuildTile(
MLR_Terrain2 *erf_mesh,
DynamicArrayOf<unsigned char>& onOffPoints,
int maxNumOfTrianglesPerMesh,
Scalar x0,
Scalar z0,
Scalar x1,
Scalar z1
)
{
int numOfTriangles = toSortTriangles.GetLength();
DynamicArrayOf<ToDrawTriangle*> tempTrianglesPtr(numOfTriangles);
DynamicArrayOf<ToDrawTriangle> tempTriangles(numOfTriangles);
int i, j, inCount, newCount = 0, extraTriangles = 0;
int k, l, m;
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]->GetV0().x < x0)
{
clipIt[0] |= 1;
}
if(toSortTriangles[i]->GetV0().x > x1)
{
clipIt[0] |= 4;
}
if(toSortTriangles[i]->GetV0().z < z0)
{
clipIt[0] |= 8;
}
if(toSortTriangles[i]->GetV0().z > z1)
{
clipIt[0] |= 2;
}
orIt |= clipIt[0];
addIt &= clipIt[0];
if(toSortTriangles[i]->GetV1().x < x0)
{
clipIt[1] |= 1;
}
if(toSortTriangles[i]->GetV1().x > x1)
{
clipIt[1] |= 4;
}
if(toSortTriangles[i]->GetV1().z < z0)
{
clipIt[1] |= 8;
}
if(toSortTriangles[i]->GetV1().z > z1)
{
clipIt[1] |= 2;
}
orIt |= clipIt[1];
addIt &= clipIt[1];
if(toSortTriangles[i]->GetV2().x < x0)
{
clipIt[2] |= 1;
}
if(toSortTriangles[i]->GetV2().x > x1)
{
clipIt[2] |= 4;
}
if(toSortTriangles[i]->GetV2().z < z0)
{
clipIt[2] |= 8;
}
if(toSortTriangles[i]->GetV2().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) )
{
STOP(("Danger Danger !"));
}
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]->GetV0().x;
triangle[0].y = toSortTriangles[i]->GetV0().y;
triangle[0].z = toSortTriangles[i]->GetV0().z;
triangle[1].x = toSortTriangles[i]->GetV1().x;
triangle[1].y = toSortTriangles[i]->GetV1().y;
triangle[1].z = toSortTriangles[i]->GetV1().z;
triangle[2].x = toSortTriangles[i]->GetV2().x;
triangle[2].y = toSortTriangles[i]->GetV2().y;
triangle[2].z = toSortTriangles[i]->GetV2().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);
tempTriangles[extraTriangles].GetSurfaceAreaAndCentroid();
if(tempTriangles[extraTriangles].area > SMALL)
{
if(! (tempTriangles[extraTriangles].plane.normal.y > Stuff::SMALL) )
{
STOP(("Danger Danger !"));
}
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]->GetV0().x;
clipPoints[key][0].y = toSortTriangles[i]->GetV0().y;
clipPoints[key][0].z = toSortTriangles[i]->GetV0().z;
clipPoints[key][1].x = toSortTriangles[i]->GetV1().x;
clipPoints[key][1].y = toSortTriangles[i]->GetV1().y;
clipPoints[key][1].z = toSortTriangles[i]->GetV1().z;
clipPoints[key][2].x = toSortTriangles[i]->GetV2().x;
clipPoints[key][2].y = toSortTriangles[i]->GetV2().y;
clipPoints[key][2].z = toSortTriangles[i]->GetV2().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
);
tempTriangles[extraTriangles].GetSurfaceAreaAndCentroid();
if(tempTriangles[extraTriangles].area > SMALL)
{
if(! (tempTriangles[extraTriangles].plane.normal.y > Stuff::SMALL) )
{
STOP(("Danger Danger !"));
}
tempTrianglesPtr[newCount++] = &tempTriangles[extraTriangles];
extraTriangles++;
}
}
}
}
}
}
// tempTriangles.SetLength(extraTriangles);
tempTrianglesPtr.SetLength(newCount);
#if _ARMOR
for(i=0,j=0;i<newCount;++i)
{
if(onOffPoints[i] == 0)
{
Verify(tempTrianglesPtr[i]->GetV0().x >= x0);
Verify(tempTrianglesPtr[i]->GetV0().x <= x1);
Verify(tempTrianglesPtr[i]->GetV0().z >= z0);
Verify(tempTrianglesPtr[i]->GetV0().z <= z1);
Verify(tempTrianglesPtr[i]->GetV1().x >= x0);
Verify(tempTrianglesPtr[i]->GetV1().x <= x1);
Verify(tempTrianglesPtr[i]->GetV1().z >= z0);
Verify(tempTrianglesPtr[i]->GetV1().z <= z1);
Verify(tempTrianglesPtr[i]->GetV2().x >= x0);
Verify(tempTrianglesPtr[i]->GetV2().x <= x1);
Verify(tempTrianglesPtr[i]->GetV2().z >= z0);
Verify(tempTrianglesPtr[i]->GetV2().z <= z1);
}
}
#endif
MLR_Terrain2 *ret_mesh = NULL;
if(newCount > 0)
{
AnalyzeThis(
tempTrianglesPtr,
x0,
z0,
x1,
z1
);
Stuff::ExtentBox box;
box.minX = x0;
box.maxX = x1;
box.minY = Offset;
box.maxY = Offset+256.0f;
box.minZ = z0;
box.maxZ = z1;
if(!CreateMesh(erf_mesh, tempTrianglesPtr, &box))
{
PAUSE(("Unstable triangle mesh created!"));
}
else
{
brokenTriangles += newCount;
}
}
else
{
STOP(("Danger Danger !"));
}
tempTrianglesPtr.SetLength(0);
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
HFSlimMZ0p3::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::AlphaPriority);
MLRTexture *texture = MLRTexturePool::Instance->Add(detailInfo.name);
state1.SetTextureHandle(texture->GetTextureHandle());
}
DynamicArrayOf<unsigned char> onOffTriangles;
onOffTriangles.AssignValue(0, toSortTriangles.GetLength());
int i, j, k, l, m, n;
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);
for(l=0;l<zDim;l++)
{
for(k=0;k<xDim;k++)
{
brokenTriangles = 0;
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++)
{
tX = i;
tY = j;
gos_PushCurrentHeap(ElementRenderer::Heap);
ElementRenderer::GroupElement *group = new GroupElement;
Register_Object(group);
simpleTerrainGroup[l*xDim+k]->AttachIndexedChild(j, i, group);
group->NeedNewBounds();
group->SetVolumeCullMode();
ElementRenderer::ListElement *subList = new ListElement;
Register_Object(subList);
subList->SetSize(4);
group->AttachChild(subList);
subList->NeedNewBounds();
subList->SetVolumeCullMode();
gos_PopCurrentHeap();
for(n=0;n<2;n++)
{
for(m=0;m<2;m++)
{
MLRState state;
/*
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
);
*/
char textureName[1024];
state.SetPriority(MLRState::DefaultPriority);
#if 0
sprintf(textureName, "%s_%1d_%02x%02x",
megaBaseName,
depth,
(1<<depth) - tileX/(1<<(maxdepth-depth)) - 1,
(1<<depth) - tileZ/(1<<(maxdepth-depth)) - 1
);
#else
sprintf(textureName, "%s_0_0000", megaBaseName);
#endif
MLRTexture *texture = MLRTexturePool::Instance->Add(textureName);
texture->SetHint(gosHint_AGPMemory | gosHint_DontShrink);
state.SetTextureHandle(texture->GetTextureHandle());
state.SetTextureWrapMode(MLRState::TextureClamp);
gos_PushCurrentHeap(MidLevelRenderer::Heap);
MLR_Terrain2 *erf_mesh = new MLR_Terrain2;
gos_PopCurrentHeap();
erf_mesh->SetReferenceState(state);
erf_mesh->SetReferenceState(state1, 1);
erf_mesh->SetLevelTexture(0, texture->GetTextureHandle());
Scalar x0, z0, x1, z1;
if(i<len/2)
{
x0 = xOffset;
x1 = xOffset + (len/2)*xGridSize;
}
else
{
x0 = xOffset + (len/2)*xGridSize;
x1 = xOffset + len*xGridSize;
}
if(j<len/2)
{
z0 = zOffset;
z1 = zOffset + (len/2)*zGridSize;
}
else
{
z0 = zOffset + (len/2)*zGridSize;
z1 = zOffset + len*zGridSize;
}
erf_mesh->SetFrame(1, x0, z0, x1, z1);
x0 = xOffset + i*xGridSize;
z0 = zOffset + j*zGridSize;
x1 = x0 + xGridSize;
z1 = z0 + zGridSize;
erf_mesh->SetFrame(0, xOffset, zOffset, xOffset+len*xGridSize, zOffset+len*zGridSize);
erf_mesh->SetFrame(2, x0, z0, x1, z1);
erf_mesh->SetFrame(3, x0, z0, x1, z1);
erf_mesh->SetFrame(4, x0, z0, x1, z1);
erf_mesh->SetFrame(5, x0, z0, x1, z1);
erf_mesh->SetFrame(6, x0, z0, x1, z1);
erf_mesh->SetFrame(7, x0, z0, x1, z1);
erf_mesh->SetDepthData(maxAllDepth, maxAllDepth);
erf_mesh->SetTileData(tX, tY);
erf_mesh->SetBorderPixel(borderPixelFun);
Register_Object(erf_mesh);
erf_mesh->SetDetailData(
detailInfo.xOff,
detailInfo.zOff,
detailInfo.xFac,
detailInfo.zFac,
detailInfo.dStart,
detailInfo.dEnd
);
x0 = xOffset + i*xGridSize + m*xGridSize/2.0f;
z0 = zOffset + j*zGridSize + n*xGridSize/2.0f;
x1 = x0 + xGridSize/2.0f;
z1 = z0 + zGridSize/2.0f;
BuildTile(erf_mesh, onOffTriangles, bucketSize, x0, z0, x1, z1);
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;
subList->AttachIndexedChild(2*n+m, Shape);
Shape->SetVolumeCullMode();
}
}
group->Sync();
group->LockBounds();
group->SetNeverCullMode();
subList->LockBounds();
subList->SetNeverCullMode();
}
}
simpleTerrainGroup[l*xDim+k]->LockBounds();
fprintf(stdout, "\"broken\" triangles: %d\n", brokenTriangles);
}
}
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
HFSlimMZ0p3::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;
}