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

2166 lines
47 KiB
C++

#include "stdafx.h"
#include "resource.h"
#include "ProgDlg.h"
#include "FinalBitmapWnd.h"
#include <MLR\MLRHeaders.hpp>
#if !defined(MLR_TERRAIN_HEIGHTFIELD_HPP)
#include "MLRHeightField.hpp"
#include "terra\terra.hpp"
#endif
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
const Scalar One_Over_Three = 1.0f/3.0f;
#define USE_TRI_MESH 1
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
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;
}
}
if(area > SMALL)
{
center *= (One_Over_Three/area);
}
else
{
center *= One_Over_Three;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLRHeightField::MLRHeightField()
{
X = (int)0.0f;
Z = (int)0.0f;
dX = 2.0f;
dY = 0.15f;
dZ = 2.0f;
visHeight = 0;
nrOfIZs = 0;
#ifdef _DEBUG
#undef new
#endif
terrainGroup = new GroupElement();
Register_Object(terrainGroup);
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
fullTerrainGroup = NULL;
simpleTerrainGroup = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLRHeightField::~MLRHeightField()
{
if(fullTerrainGroup!=NULL)
{
Unregister_Object(fullTerrainGroup);
delete fullTerrainGroup;
fullTerrainGroup = NULL;
}
if(simpleTerrainGroup!=NULL)
{
Unregister_Object(simpleTerrainGroup);
delete simpleTerrainGroup;
simpleTerrainGroup = NULL;
}
Unregister_Object(terrainGroup);
delete terrainGroup;
terrainGroup = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Stuff::ExtentBox
MLRHeightField::GetExtents()
{
Stuff::ExtentBox ebox;
ebox.minX = 0.0f;
ebox.minY = GetOffset();
ebox.minZ = 0.0f;
ebox.maxX = dX*(X-1);
ebox.maxZ = dZ*(Z-1);
int i;
ebox.maxY= field[0]*dY+GetOffset() > 16.0f ? field[0]*dY+GetOffset() : 16.0f;
for (i=1;i<X*Z;i++)
{
ebox.maxY = ebox.maxY > (field[i]*dY+GetOffset()) ? ebox.maxY:(field[i]*dY+GetOffset());
}
return ebox;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MLRHeightField::MakeTerrainFromField()
{
terrainGroup->SetNeverCullMode();
terrainGroup->SetName("Terrain");
#ifdef _DEBUG
#undef new
#endif
fullTerrainGroup = new GroupElement();
Register_Object(fullTerrainGroup);
fullTerrainGroup->SetName("FullTerrain");
DisplayFull(true);
int side = 1 + (int)sqrt( (6*(X-1)*(Z-1)) / Limits::Max_Number_Vertices_Per_Mesh);
meshX = X / side;
meshZ = Z / side;
UnitVector3D sun;
sun = Vector3D(-1.0f, -1.0f, 0.0f);
int i, j, mx, mz, k, l, count, test;
test = side-1;
terrain.SetLength(test*test);
i = 0, j = 0, count = 0;
MLR_I_DT_PMesh *mesh;
if(field.GetLength() > 0)
{
Scalar maxFH = field[0];
for(i=1;i<X*Z;i++)
{
maxFH = field[i] > maxFH ? field[i] : maxFH;
}
Offset = -maxFH*dY;
}
CProgressDlg pdlg;
pdlg.Create();
pdlg.ShowWindow(SW_SHOW);
pdlg.SetWindowText("Create regular terrain");
pdlg.SetErrorText(0.0f);
for(i=0;i<test;i++)
{
mz = (i+1)*meshZ < Z ? meshZ : Z - i*meshZ;
mz++;
for(j=0;j<test;j++,count++)
{
#ifdef _DEBUG
#undef new
#endif
mesh = new MLR_I_DT_PMesh();
Register_Object(mesh);
terrain[count] = new MLRShape(1);
Register_Object(terrain[count]);
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
mx = (j+1)*meshX < X ? meshX : X - j*meshX;
mx++;
Point3D *points = new Point3D [mx*mz];
Vector2DScalar *texCoords = new Vector2DScalar [2*mx*mz];
Scalar h, minH = 0.0f, maxH = 0.0f;
for(k=0;k<mz;k++)
{
for(l=0;l<mx;l++)
{
h = GetHeight(j*meshX+l, i*meshZ+k);
if(k+l == 0)
{
minH = maxH = h;
}
else
{
minH = minH < h ? minH : h;
maxH = maxH > h ? maxH : h;
}
points[mx*k+l] =
Point3D(
(j*meshX+l) * dX,
h,
(i*meshZ+k) * dZ
);
texCoords[mx*k+l] =
Vector2DScalar(
// (Scalar)(j*side+l)/(Scalar)X,
// (Scalar)(i*side+k)/(Scalar)Z
// (Scalar)(l+j*mx)/(16.0f*(mx-1)),
// (Scalar)(k+i*mz)/(16.0f*(mz-1))
// (Scalar)(l+j*mx)/(16.0f*(mx-0)),
// (Scalar)(k+i*mz)/(16.0f*(mz-0))
(Scalar)(j*meshX+l)/(X-1),
(Scalar)(i*meshZ+k)/(Z-1)
);
texCoords[mx*k+l+mx*mz] =
Vector2DScalar(
(Scalar)(l)/(Scalar)(mx-1),
(Scalar)(k)/(Scalar)(mz-1)
);
}
}
mesh->SetCoordData(points, mx*mz);
mesh->SetTexCoordData(texCoords, 2*mx*mz);
delete [] points;
delete [] texCoords;
WORD *indices = new WORD [(mx-1)*(mz-1)*6];
for(k=0;k<mz-1;k++)
{
for(l=0;l<mx-1;l++)
{
indices[6*(k*(mx-1) + l)] = k*mx + l;
indices[6*(k*(mx-1) + l)+1] = (k+1)*mx + l;
indices[6*(k*(mx-1) + l)+2] = k*mx + l + 1;
indices[6*(k*(mx-1) + l)+3] = (k+1)*mx + l;
indices[6*(k*(mx-1) + l)+4] = (k+1)*mx + l + 1;
indices[6*(k*(mx-1) + l)+5] = k*mx + l + 1;
}
}
mesh->SetIndexData(indices, (mx-1)*(mz-1)*6);
delete indices;
unsigned char *lengths = new unsigned char [(mx-1)*(mz-1)*2];
for(k=0;k<(mx-1)*(mz-1)*2;k++)
{
lengths[k] = 3;
}
mesh->SetSubprimitiveLengths(lengths, (mx-1)*(mz-1)*2);
mesh->FindFacePlanes();
delete lengths;
mesh->SetReferenceState(state0);
mesh->SetReferenceState(state1, 1);
terrain[count]->Add(mesh);
mesh->DetachReference();
#ifdef _DEBUG
#undef new
#endif
ShapeElement* Shape = new ShapeElement;
Register_Object(Shape);
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
Shape->SetMLRShape(terrain[count]);
fullTerrainGroup->AttachChild(Shape);
Shape->localOBB.localToParent.BuildTranslation(Point3D(
(((Scalar)j + 0.5f)*meshX) * dX,
(maxH-minH)/2.0f + minH,
(((Scalar)i + 0.5f)*meshZ) * dZ
));
Shape->localOBB.sphereRadius = sqrt(3.0f)/2.0f *
meshX * dX > meshZ * dZ ?
(meshX * dX > (maxH-minH) ? meshX * dX : (maxH-minH)) :
(meshZ * dZ > (maxH-minH) ? meshZ * dZ : (maxH-minH)) ;
Shape->SetVolumeCullMode();
pdlg.SetPos(count*100/(test*test));
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MLRHeightField::Blur2D ()
{
// 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<3;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;
}
int triangleCounter = 0;
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++;
}
bool
MLRHeightField::CreateMesh(
ListElement *parent,
int listIndex,
DynamicArrayOf<ToDrawTriangle*>& tdtrilist,
ExtentBox *uvFrame,
MLRState *state
)
{
int polygon_count = tdtrilist.GetLength();
if(polygon_count==0 || polygon_count*3 >= Limits::Max_Number_Vertices_Per_Mesh)
{
return false;
}
#ifdef _DEBUG
#undef new
#endif
#if USE_TRI_MESH
MLR_I_DeT_TMesh *erf_mesh = new MLR_I_DeT_TMesh;
#else
// MLR_I_C_PMesh *erf_mesh = new MLR_I_C_PMesh;
MLR_I_DeT_PMesh *erf_mesh = new MLR_I_DeT_PMesh;
#endif
Register_Object(erf_mesh);
erf_mesh->SetDetailData(detailInfo.xOff, detailInfo.zOff, detailInfo.xFac, detailInfo.zFac);
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
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.y += Offset;
center3 *= 1.0f/polygon_count;
center3.y += Offset;
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.y += Offset;
center2.x = (maxx+minx)*0.5f;
center2.y = (maxy+miny)*0.5f;
center2.z = (maxz+minz)*0.5f;
center2.y += Offset;
Point3D *coords = new Point3D [point_count];
Register_Pointer(coords);
Vector2DScalar *texCoords = new Vector2DScalar[point_count];
Register_Pointer(texCoords);
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;
coords[nrOfPoints].x = dX*x;
coords[nrOfPoints].y = GetHeight(x, z);
coords[nrOfPoints].z = dZ*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;
texCoords[nrOfPoints][0] = (coords[nrOfPoints].x - uvFrame->minX)/(uvFrame->maxX-uvFrame->minX);
texCoords[nrOfPoints][1] = (coords[nrOfPoints].z - uvFrame->minZ)/(uvFrame->maxZ-uvFrame->minZ);
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));
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;
}
}
}
COLORREF col;
col=(Random::GetLessThan(255))|
(Random::GetLessThan(255)<<8)|
(Random::GetLessThan(255)<<16);
Wnd2D->DrawGrid(
tdtrilist.GetData(),
polygon_count,
col,
center.x,
center.z,
maxRadius
);
#if USE_TRI_MESH
#else
unsigned char *lengths = new unsigned char [polygon_count];
Register_Pointer(lengths);
#endif
unsigned short *index = new unsigned short [polygon_count*3];
Register_Pointer(index);
int k, l;
for(i=0,l=0;i<polygon_count;i++)
{
k = 0;
#if USE_TRI_MESH
#else
lengths[i] = 3;
#endif
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;
}
}
#if USE_TRI_MESH
erf_mesh->SetSubprimitiveLengths(NULL, l/3);
#else
erf_mesh->SetSubprimitiveLengths(lengths, l/3);
Unregister_Pointer(lengths);
delete lengths;
#endif
erf_mesh->SetCoordData(coords, nrOfPoints);
erf_mesh->SetTexCoordData(texCoords, nrOfPoints);
erf_mesh->SetIndexData(index, l);
erf_mesh->FindFacePlanes();
Unregister_Pointer(coords);
delete coords;
Unregister_Pointer(texCoords);
delete texCoords;
Unregister_Pointer(index);
delete index;
if(state)
{
erf_mesh->SetReferenceState(*state);
}
else
{
erf_mesh->SetReferenceState(state0);
}
erf_mesh->SetReferenceState(state1, 1);
#ifdef _DEBUG
#undef new
#endif
ShapeElement* Shape = new ShapeElement;
Register_Object(Shape);
MLRShape *shape = new MLRShape(1);
Register_Object(shape);
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
shape->Add(erf_mesh);
erf_mesh->DetachReference();
Shape->SetMLRShape(shape);
Shape->localOBB.localToParent.BuildTranslation(center);
Shape->localOBB.sphereRadius = maxRadius;
// Shape->SetVolumeCullMode();
Shape->SetRootMode();
parent->AttachIndexedChild(listIndex, Shape);
Shape->SetVolumeCullMode();
return true;
}
int
primCounter, maxPrims;
bool
MLRHeightField::BinSort(
ListElement *parent,
int index,
DynamicArrayOf<ToDrawTriangle*>& tdtrilist,
int binSize,
CProgressDlg *pdlg,
ExtentBox *uvFrame,
MLRState *state
)
{
int polygon_count = tdtrilist.GetLength();
if (polygon_count==0)
{
return false;
}
unsigned i;
#ifdef _ARMOR
unsigned j;
for (i=0; i<polygon_count; ++i)
{
for(j=0;j<3;j++)
{
Verify(tdtrilist[i]->v[j].x >= 0.0f && tdtrilist[i]->v[j].x <= GetXinM());
Verify(tdtrilist[i]->v[j].y >= Offset && tdtrilist[i]->v[j].y <= -Offset);
Verify(tdtrilist[i]->v[j].z >= 0.0f && tdtrilist[i]->v[j].z <= GetZinM());
}
}
#endif
//
//---------------------------------------------------------
// If the polygon mesh is already small enough, just return
//---------------------------------------------------------
//
if (polygon_count <= binSize)
{
if(pdlg)
pdlg->SetPos(++primCounter*100/maxPrims);
return CreateMesh(parent, index, tdtrilist, uvFrame, 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))
{
if(pdlg)
pdlg->SetPos(++primCounter*100/maxPrims);
return CreateMesh(parent, index, tdtrilist, uvFrame, state);
}
//
//-------------------------------------------------------------------------
// The mesh is too big, so we have to cut it up. Make a group proxy to
// hold the new mesh collection
//-------------------------------------------------------------------------
//
#ifdef _DEBUG
#undef new
#endif
Check_Object(parent);
ListElement *group = new ListElement;
Register_Object(group);
group->SetSize(2);
parent->AttachIndexedChild(index, group);
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
//
//----------------------------------
// 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<ToDrawTriangle*>
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.DistanceTo(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
//-------------------------------------------------------------------
//
if (BinSort(
group,
0,
group_a,
binSize,
pdlg,
uvFrame,
state))
{
}
if (BinSort(
group,
1,
group_b,
binSize,
pdlg,
uvFrame,
state))
{
}
//
//-----------------------------------------
// Now set the bounding sphere of the group
//-----------------------------------------
//
Check_Object(group);
#if 0
DynamicArrayOf<int> vert_id(X*Z);
memset(vert_id.GetData(), 0, vert_id.GetSize());
Point3D center = Point3D::Identity;
int x, z, point_count;
for(i=0;i<polygon_count;++i)
{
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)
{
center += tdtrilist[i]->v[0];
point_count++;
}
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)
{
center += tdtrilist[i]->v[1];
point_count++;
}
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)
{
center += tdtrilist[i]->v[2];
point_count++;
}
}
center *= 1.0f/point_count;
center.y += Offset;
int nrOfPoints = 0;
Point3D p;
Vector3D v3;
Scalar radiusSquared, maxRadius = 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);
p.x = dX*x;
p.y = GetHeight(x, z);
p.z = dZ*z;
v3.Subtract(p, center);
radiusSquared = v3.GetLengthSquared();
maxRadius = radiusSquared>maxRadius ? radiusSquared:maxRadius;
nrOfPoints++;
}
else
vert_id[z*X+x] = -1;
}
maxRadius = static_cast<Scalar>(sqrt(maxRadius));
group->localOBB.localToParent.BuildTranslation(center);
group->localOBB.sphereRadius = maxRadius;
#endif
group->NeedNewBounds();
group->SetVolumeCullMode();
return false;
}
void
MLRHeightField::OptimizeHField(int mode, int depth, int binSize)
{
if(X*Z == 0)
{
return;
}
#ifdef _DEBUG
#undef new
#endif
simpleTerrainGroup = new ListElement;
Register_Object(simpleTerrainGroup);
simpleTerrainGroup->SetSize(1);
simpleTerrainGroup->SetName("OptimizedTerrain");
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
DirectMap<real> map(X,Z);
DynamicArrayOf<ToDrawTriangle> tdtrilist((X-1)*(Z-1));
int i, j;
for(j=0;j<Z;j++)
for(i=0;i<X;i++)
{
map.ref(i,j) = field[j*X + i];
}
MASK = new ImportMask;
MASK->width=X;
MASK->height=Z;
GreedySubdivision mesh(&map);
point_limit=1024;
CProgressDlg pdlg;
pdlg.Create();
pdlg.ShowWindow(SW_SHOW);
if(depth==0)
point_limit = GetFullPolyCount()/4;
else
point_limit = depth;
while(mesh.pointCount()<point_limit && mesh.maxError() > error_threshold)
{
triangleCounter = 0;
mesh.greedyInsert();
if(!(mesh.pointCount()%100))
pdlg.SetPos(mesh.pointCount()*100/point_limit);
pdlg.SetErrorText(static_cast<float>(mesh.maxError()));
}
mesh.overFaces(GetFacesCB, tdtrilist.GetData());
for(i=0;i<triangleCounter;i++)
{
tdtrilist[i].v[0].y = static_cast<float>(dY*mesh.eval(
(int)(tdtrilist[i].v[0].x),
(int)(tdtrilist[i].v[0].z)
));
tdtrilist[i].v[1].y = static_cast<float>(dY*mesh.eval(
(int)(tdtrilist[i].v[1].x),
(int)(tdtrilist[i].v[1].z)
));
tdtrilist[i].v[2].y = 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();
}
Wnd2D->DrawGrid(tdtrilist.GetData(), triangleCounter);
Sleep(100);
OptPolyCount = triangleCounter;
{
Point3D *points;
RGBAColor *colors;
int x, z, point_count, color_count;
Scalar diff;
MLRPrimitiveBase *primitive;
for(i=0;i<terrain.GetLength();++i)
{
Check_Object(terrain[i]);
for(j=0;j<terrain[i]->GetNum();j++)
{
primitive = terrain[i]->Find(j);
Check_Object(primitive);
if(primitive->IsDerivedFrom(MidLevelRenderer::MLR_I_C_PMesh::DefaultData))
{
Cast_Object(MLR_I_C_PMesh*, primitive)->GetColorData(&colors, &color_count);
} else if(primitive->IsDerivedFrom(MidLevelRenderer::MLR_I_C_DT_PMesh::DefaultData))
{
Cast_Object(MLR_I_C_DT_PMesh*, primitive)->GetColorData(&colors, &color_count);
} else if(primitive->IsDerivedFrom(MidLevelRenderer::MLR_I_C_DeT_PMesh::DefaultData))
{
Cast_Object(MLR_I_C_DeT_PMesh*, primitive)->GetColorData(&colors, &color_count);
} else
{
continue;
}
primitive->GetCoordData(&points, &point_count);
Verify(point_count==color_count);
for(j=0;j<point_count;++j)
{
x = static_cast<int>(points[j].x/dX);
z = static_cast<int>(points[j].z/dZ);
diff = static_cast<Scalar>(mesh.eval(x, z) - field[z*X + x]);
if(diff > 0.0f)
{
colors[j].red = 1.0f;
colors[j].green = 1.0f - diff/32.0f;
colors[j].blue = 1.0f - diff/32.0f;
colors[j].alpha = 1.0f;
}
else
{
colors[j].red = 1.0f + diff/32.0f;
colors[j].green = 1.0f + diff/32.0f;
colors[j].blue = 1.0f;
colors[j].alpha = 1.0f;
}
}
}
}
}
if(triangleCounter == 0 || mesh.pointCount() == 0)
{
return;
}
DynamicArrayOf<ToDrawTriangle*> toSortTriangles(triangleCounter);
for(i=0,j=0;i<triangleCounter;++i)
{
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);
primCounter = 0;
maxPrims = (int)(1.5f*triangleCounter/binSize) + 1;
pdlg.SetWindowText("Create optimized terrain");
Stuff::ExtentBox allBox;
allBox = GetExtents();
BinSort(
simpleTerrainGroup,
0,
toSortTriangles,
binSize,
&pdlg,
&allBox
);
simpleTerrainGroup->NeedNewBounds();
nrOfIZs = 1;
Sleep(1000);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SuckVerticesFromElement(
ElementRenderer::Element *group,
Point3D *points,
int& numOfPoints,
LinearMatrix4D& matrix
)
{
Check_Object(group);
LinearMatrix4D localMatrix;
localMatrix.Multiply(matrix, group->GetLocalToParent());
if(group->IsDerivedFrom(ElementRenderer::GroupElement::DefaultData))
{
Stuff::ChainIteratorOf<ElementRenderer::Element *> *children;
ElementRenderer::Element *curelt;
children = Cast_Pointer(ElementRenderer::GroupElement*, group)->MakeIterator();
int j;
while ((curelt = children->ReadAndNext()) != NULL)
{
if(curelt->IsDerivedFrom(ElementRenderer::ShapeElement::DefaultData) )
{
MidLevelRenderer::MLRShape *Shape = Cast_Object(ElementRenderer::ShapeElement *,curelt)->GetMLRShape();
for(j=0;j<Shape->GetNum();j++)
{
MLRPrimitiveBase *primitive = Shape->Find(j);
Check_Object(primitive);
Point3D *coords;
int nrOfPoints;
if(primitive->IsDerivedFrom(MLRIndexedPrimitiveBase::DefaultData))
{
unsigned short *indices;
int nrOfIndices;
primitive->GetCoordData(&coords, &nrOfPoints);
(Cast_Pointer(MLRIndexedPrimitiveBase*, primitive))->GetIndexData(&indices, &nrOfIndices);
for(int i=0;i<nrOfIndices;++i)
{
(points+numOfPoints++)->Multiply(coords[indices[i]], localMatrix);
}
}
else
{
primitive->GetCoordData(&coords, &nrOfPoints);
for(int i=0;i<nrOfPoints;++i)
{
(points+numOfPoints++)->Multiply(coords[i], localMatrix);
}
}
}
}
else if(curelt->IsDerivedFrom(ElementRenderer::GroupElement::DefaultData) )
{
SuckVerticesFromElement(
Cast_Object(ElementRenderer::GroupElement *, curelt),
points,
numOfPoints,
localMatrix
);
}
}
}
else if(group->IsDerivedFrom(ElementRenderer::ListElement::DefaultData))
{
ElementRenderer::Element *curelt;
int i, j, end = Cast_Pointer(ElementRenderer::ListElement*, group)->GetActiveCount();
for(i=0;i<end;i++)
{
curelt = Cast_Pointer(ElementRenderer::ListElement*, group)->GetIndexedElement(i);
if(curelt->IsDerivedFrom(ElementRenderer::ShapeElement::DefaultData) )
{
MidLevelRenderer::MLRShape *Shape = Cast_Object(ElementRenderer::ShapeElement *,curelt)->GetMLRShape();
for(j=0;j<Shape->GetNum();j++)
{
MLRPrimitiveBase *primitive = Shape->Find(j);
Check_Object(primitive);
Point3D *coords;
int nrOfPoints;
if(primitive->IsDerivedFrom(MLRIndexedPrimitiveBase::DefaultData))
{
unsigned short *indices;
int nrOfIndices;
primitive->GetCoordData(&coords, &nrOfPoints);
(Cast_Pointer(MLRIndexedPrimitiveBase*, primitive))->GetIndexData(&indices, &nrOfIndices);
for(int i=0;i<nrOfIndices;++i)
{
(points+numOfPoints++)->Multiply(coords[indices[i]], localMatrix);
}
}
else
{
primitive->GetCoordData(&coords, &nrOfPoints);
for(int i=0;i<nrOfPoints;++i)
{
(points+numOfPoints++)->Multiply(coords[i], localMatrix);
}
}
}
}
else if(curelt->IsDerivedFrom(ElementRenderer::GroupElement::DefaultData) )
{
SuckVerticesFromElement(
Cast_Object(ElementRenderer::GroupElement *, curelt),
points,
numOfPoints,
localMatrix
);
}
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MLRHeightField::DescentToUnderMountain(
int depth,
ElementRenderer::ListElement *group,
Point3D *points,
unsigned char *onOffPoints,
int numOfTriangles,
int maxNumOfTrianglesPerMesh,
Scalar x0,
Scalar z0,
Scalar x1,
Scalar z1,
int tileX,
int tileZ,
const char *texRoot
)
{
if((depth & 0xff) ==0)
{
char textureName[1024];
DynamicArrayOf<Point3D> tempPoints(3*numOfTriangles);
DynamicArrayOf<Point3D> collapsedPoints(3*maxNumOfTrianglesPerMesh);
DynamicArrayOf<unsigned short> tempIndices(3*maxNumOfTrianglesPerMesh);
DynamicArrayOf<Vector2DScalar> tempTexCoords(3*maxNumOfTrianglesPerMesh);
DynamicArrayOf<unsigned char> tempLength(3*maxNumOfTrianglesPerMesh);
int i, j, k, l, m, inCount, newCount = 0;
sprintf(textureName, "%s_%1d_%02x%02x", texRoot, (depth>>8)-depth&0xff, tileZ, tileX);
MLRState state;
state.SetBackFaceOn();
state.SetDitherOff();
state.SetTextureCorrectionOn();
state.SetZBufferCompareOn();
state.SetZBufferWriteOn();
state.SetFilterMode(MLRState::BiLinearFilterMode);
state.SetFogMode(MLRState::DisableFogMode);
state.SetFogData(
0,
0.0f,
1.0f,
100.0f
);
MLRTexture *texture = MLRTexturePool::Instance->Add(textureName);
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;
for(k=0;k<3;k++)
{
if(points[j+k].x < x0)
{
clipIt[k] |= 1;
}
if(points[j+k].x > x1)
{
clipIt[k] |= 4;
}
if(points[j+k].z < z0)
{
clipIt[k] |= 8;
}
if(points[j+k].z > z1)
{
clipIt[k] |= 2;
}
orIt |= clipIt[k];
addIt &= clipIt[k];
}
if(orIt == 0)
{
onOffPoints[i] = 1;
tempPoints[newCount++] = points[j];
tempPoints[newCount++] = points[j+1];
tempPoints[newCount++] = points[j+2];
}
else if(addIt==0)
{
Point3D clipPoints[5];
if(orIt==1 || orIt==2 || orIt==4 || orIt==8)
{
l = 0;
for(k=0;k<3;k++)
{
int next = k+1>2?0:k+1;
if(clipIt[k]==0)
{
clipPoints[l++] = points[j+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(
points[j+k],
Vector3D(
points[j+next].x - points[j+k].x,
points[j+next].y - points[j+k].y,
points[j+next].z - points[j+k].z
),
(x0-points[j+k].x)/(points[j+next].x-points[j+k].x)
);
break;
case 1:
clipPoints[l++].AddScaled(
points[j+k],
Vector3D(
points[j+next].x - points[j+k].x,
points[j+next].y - points[j+k].y,
points[j+next].z - points[j+k].z
),
(z1-points[j+k].z)/(points[j+next].z-points[j+k].z)
);
break;
case 2:
clipPoints[l++].AddScaled(
points[j+k],
Vector3D(
points[j+next].x - points[j+k].x,
points[j+next].y - points[j+k].y,
points[j+next].z - points[j+k].z
),
(x1-points[j+k].x)/(points[j+next].x-points[j+k].x)
);
break;
case 3:
clipPoints[l++].AddScaled(
points[j+k],
Vector3D(
points[j+next].x - points[j+k].x,
points[j+next].y - points[j+k].y,
points[j+next].z - points[j+k].z
),
(z0-points[j+k].z)/(points[j+next].z-points[j+k].z)
);
break;
}
break;
}
mask <<= 1;
}
}
Verify(l>2);
for(m=1;m<l-1;m++)
{
tempPoints[newCount++] = clipPoints[0];
tempPoints[newCount++] = clipPoints[m];
tempPoints[newCount++] = clipPoints[m+1];
}
}
else
{
}
}
}
}
if(newCount > 0)
{
group->SetSize(1);
#ifdef _DEBUG
#undef new
#endif
DynamicArrayOf<ToDrawTriangle> tdtrilist(newCount/3);
DynamicArrayOf<ToDrawTriangle*> ptrTdtrilist(newCount/3);
for(i=0,j=0;i<newCount/3;j+=3,i++)
{
tdtrilist[i].v[0].x = tempPoints[j].x;
tdtrilist[i].v[0].y = tempPoints[j].y;
tdtrilist[i].v[0].z = tempPoints[j].z;
tdtrilist[i].v[1].x = tempPoints[j+2].x;
tdtrilist[i].v[1].y = tempPoints[j+2].y;
tdtrilist[i].v[1].z = tempPoints[j+2].z;
tdtrilist[i].v[2].x = tempPoints[j+1].x;
tdtrilist[i].v[2].y = tempPoints[j+1].y;
tdtrilist[i].v[2].z = tempPoints[j+1].z;
tdtrilist[i].GetSurfaceAreaAndCentroid();
ptrTdtrilist[i] = &tdtrilist[i];
}
Stuff::ExtentBox box;
box.minX = x0;
box.maxX = x1;
box.minY = 0.0f;
box.maxY = 0.0f;
box.minZ = z0;
box.maxZ = z1;
BinSort(
group,
0,
ptrTdtrilist,
maxNumOfTrianglesPerMesh,
NULL,
&box,
&state
);
tdtrilist.SetLength(0);
ptrTdtrilist.SetLength(0);
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
}
else
{
}
tempPoints.SetLength(0);
collapsedPoints.SetLength(0);
tempIndices.SetLength(0);
tempTexCoords.SetLength(0);
tempLength.SetLength(0);
}
else
{
ElementRenderer::ListElement *group00, *group01, *group10, *group11;
group->SetSize(4);
#ifdef _DEBUG
#undef new
#endif
group00 = new ElementRenderer::ListElement;
Register_Object(group00);
group->AttachIndexedChild(0, group00);
group00->NeedNewBounds();
group00->SetVolumeCullMode();
group01 = new ElementRenderer::ListElement;
Register_Object(group01);
group->AttachIndexedChild(1, group01);
group01->NeedNewBounds();
group01->SetVolumeCullMode();
group10 = new ElementRenderer::ListElement;
Register_Object(group10);
group->AttachIndexedChild(2, group10);
group10->NeedNewBounds();
group10->SetVolumeCullMode();
group11 = new ElementRenderer::ListElement;
Register_Object(group11);
group->AttachIndexedChild(3, group11);
group11->NeedNewBounds();
group11->SetVolumeCullMode();
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
DescentToUnderMountain(
depth-1, group00, points, onOffPoints, numOfTriangles, maxNumOfTrianglesPerMesh,
x0, z0, x0 + (x1-x0)/2.0f, z0 + (z1-z0)/2.0f, 2*tileX, 2*tileZ, texRoot
);
DescentToUnderMountain(
depth-1, group01, points, onOffPoints, numOfTriangles, maxNumOfTrianglesPerMesh,
x0 + (x1-x0)/2.0f, z0, x1, z0 + (z1-z0)/2.0f, 2*tileX+1, 2*tileZ, texRoot
);
DescentToUnderMountain(
depth-1, group10, points, onOffPoints, numOfTriangles, maxNumOfTrianglesPerMesh,
x0, z0 + (z1-z0)/2.0f, x0 + (x1-x0)/2.0f, z1, 2*tileX, 2*tileZ+1, texRoot
);
DescentToUnderMountain(
depth-1, group11, points, onOffPoints, numOfTriangles, maxNumOfTrianglesPerMesh,
x0 + (x1-x0)/2.0f, z0 + (z1-z0)/2.0f, x1, z1, 2*tileX+1, 2*tileZ+1, texRoot
);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
MLRHeightField::SetMegaTexture(
int nrOfLevels,
const char *mega_base_name
)
{
if(simpleTerrainGroup==NULL)
{
return false;
}
if(detailInfo.name)
{
state1.SetBackFaceOn();
state1.SetDitherOff();
state1.SetTextureCorrectionOn();
state1.SetZBufferCompareOn();
state1.SetZBufferWriteOff();
state1.SetAlphaMode(detailInfo.alphaMode);
state1.SetPriority(MLRState::DefaultPriority + 1);
state1.SetFilterMode(MLRState::BiLinearFilterMode);
state1.SetFogMode(MLRState::DisableFogMode);
state1.SetFogData(
0,
0.0f,
1.0f,
100.0f
);
MLRTexture *texture = MLRTexturePool::Instance->Add(detailInfo.name);
state1.SetTextureHandle(texture->GetTextureHandle());
}
// analyzing the data
// textures on the lowest level
int totll = static_cast<int>(pow(2, nrOfLevels-1));
// lets care about the regular grid
bool simpleWasAttached = (NULL != (terrainGroup->FindElement(simpleTerrainGroup->GetName())));
if(simpleWasAttached == true)
terrainGroup->DetachChild(simpleTerrainGroup);
DynamicArrayOf<Point3D> allTheTriangles(3*OptPolyCount);
LinearMatrix4D matrix;
matrix = LinearMatrix4D::Identity;
int nrOfTriangles, nrOfPoints = 0;
SuckVerticesFromElement(
simpleTerrainGroup,
allTheTriangles.GetData(),
nrOfPoints,
matrix
);
Verify(0==nrOfPoints%3);
allTheTriangles.SetLength(nrOfPoints);
nrOfTriangles = nrOfPoints/3;
DynamicArrayOf<unsigned char> onOffTriangles;
onOffTriangles.AssignValue(0, nrOfTriangles);
Unregister_Object(simpleTerrainGroup);
delete simpleTerrainGroup;
simpleTerrainGroup = NULL;
#ifdef _DEBUG
#undef new
#endif
simpleTerrainGroup = new ListElement;
Register_Object(simpleTerrainGroup);
simpleTerrainGroup->SetName("OptimizedTerrain");
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
Stuff::ExtentBox allBox;
allBox = GetExtents();
DescentToUnderMountain
(
(nrOfLevels<<8) + nrOfLevels,
simpleTerrainGroup,
allTheTriangles.GetData(),
onOffTriangles.GetData(),
nrOfTriangles,
256,
allBox.minX,
allBox.minZ,
allBox.maxX,
allBox.maxZ,
0,
0,
mega_base_name
);
simpleTerrainGroup->NeedNewBounds();
MLRTexturePool::Instance->LoadImages();
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
MLRHeightField::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;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
MLRHeightField::GetHeight(Scalar _x, Scalar _z)
{
int x, z, x1, z1, key = 0;
Scalar dy00, dy10, dy20, dy30, dy01, dy11, dy21, dy31;
Scalar gp0, gp1, gp2, gp3;
Scalar ret;
x = (int) floor (_x / dX);
if (x<0) x = 0;
if (x>GetX()-1)
{
x = GetX() - 1;
}
z = (int) floor (_z / dZ);
if (z<0) z = 0;
if (z>GetZ()-1)
{
z = GetZ() - 1;
}
if (_x - x*dX > 0.5*dX)
{
x1 = x + 1;
key |= 2;
} else {
x1 = x;
key |= 1;
}
if (_z - z*dZ > 0.5*dZ)
{
z1 = z + 1;
key |= 8;
} else {
z1 = z;
key |= 4;
}
ret = GetHeight (x1, z1);
gp0 = GetHeight (x, z);
gp1 = GetHeight (x, z+1);
gp2 = GetHeight (x+1, z+1);
gp3 = GetHeight (x+1, z);
dy00 = ( gp1 - gp0 ) * (_z - z*dZ) / dZ;
dy01 = ( gp0 - gp1 ) * ((z+1)*dZ - _z) / dZ;
dy10 = ( gp2 - gp1 ) * (_x - x*dX) / dX;
dy11 = ( gp1 - gp2 ) * ((x+1)*dX - _x) / dX;
dy20 = ( gp3 - gp2 ) * ((z+1)*dZ - _z) / dZ;
dy21 = ( gp2 - gp3 ) * (_z - z*dZ) / dZ;
dy30 = ( gp0 - gp3 ) * ((x+1)*dX - _x) / dX;
dy31 = ( gp3 - gp0 ) * (_x - x*dX) / dX;
switch (key)
{
case 5:
ret += (dy00 + dy31);
break;
case 9:
ret += (dy01 + dy10);
break;
case 6:
ret += (dy21 + dy30);
break;
case 10:
ret += (dy20 + dy11);
break;
}
// ret += visHeight*dY;
return ret;
}
bool
MLRHeightField::SaveHeightFieldInformations(MString& file_name)
{
HeightFieldFileHeader hffh;
hffh.signature = 'HTMP';
hffh.version = 1;
hffh.minX = 0.0f;
hffh.maxX = GetXinM();
hffh.minZ = 0.0f;
hffh.maxZ = GetZinM();
hffh.vertexCountX = X;
hffh.vertexCountZ = Z;
hffh.totalSizeOfFile = sizeof(HeightFieldFileHeader) +
X*Z*(sizeof(float) + sizeof(char));
FILE *hd;
hd = fopen(file_name, "wb");
if(!hd)
{
return false;
}
fwrite(&hffh, sizeof(HeightFieldFileHeader), 1, hd);
int i, j;
Scalar height;
for(i=0;i<Z;i++)
{
for(j=0;j<X;j++)
{
height = GetHeight(j, i);
fwrite(&height, sizeof(float), 1, hd);
}
}
unsigned char m = 0;
for(i=0;i<Z;i++)
{
for(j=0;j<X;j++)
{
fwrite(&m, 1, 1, hd);
}
}
fclose(hd);
return true;
}
void MLRHeightField::DisplayFull(bool bl)
{
ElementRenderer::Element *element;
if(bl==true)
{
element=terrainGroup->FindElement(fullTerrainGroup->GetName());
if(element==NULL)
terrainGroup->AttachChild(fullTerrainGroup);
}
else
{
element=terrainGroup->FindElement(fullTerrainGroup->GetName());
if(element!=NULL)
terrainGroup->DetachChild(fullTerrainGroup);
}
}
void MLRHeightField::DisplayOpt(bool bl)
{
ElementRenderer::Element *element;
if(bl==true)
{
element=terrainGroup->FindElement(simpleTerrainGroup->GetName());
if(element==NULL)
terrainGroup->AttachChild(simpleTerrainGroup);
}
else
{
element=terrainGroup->FindElement(simpleTerrainGroup->GetName());
if(element!=NULL)
terrainGroup->DetachChild(simpleTerrainGroup);
}
}
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;
}