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.
2166 lines
47 KiB
C++
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;
|
|
}
|
|
|
|
|