*
This commit is contained in:
@@ -0,0 +1,924 @@
|
||||
#ifndef Terrain_h__
|
||||
#define Terrain_h__
|
||||
#include "Globals.h"
|
||||
#include "math/LifeMath.h"
|
||||
#include "camera/Camera.h"
|
||||
#include "ResourceManager.h"
|
||||
#include <vector>
|
||||
|
||||
namespace LifeGraphics
|
||||
{
|
||||
enum TerrainDimention
|
||||
{
|
||||
TD_X128 = 128,
|
||||
TD_X256 = 256,
|
||||
TD_X512 = 512,
|
||||
TD_X1024 = 1024,
|
||||
TD_X2048 = 2048,
|
||||
TD_X4096 = 4096,
|
||||
TD_X8192 = 8192
|
||||
};
|
||||
|
||||
struct TerraVertex
|
||||
{
|
||||
int index;
|
||||
char nX;
|
||||
char nZ;
|
||||
USHORT height;
|
||||
|
||||
TerraVertex()
|
||||
{
|
||||
index = 0;
|
||||
nX = nZ = 0;
|
||||
height = 0;
|
||||
}
|
||||
|
||||
TerraVertex(int _index, char _nx, char _nz, USHORT _height)
|
||||
{
|
||||
index = _index;
|
||||
nX = _nx;
|
||||
nZ = _nz;
|
||||
height = _height;
|
||||
}
|
||||
};
|
||||
struct TerraChunk
|
||||
{
|
||||
int LOD;
|
||||
int Offset;
|
||||
LifeCore::BoundingBox3D BoundingBox;
|
||||
IIndexBuffer* IB;
|
||||
int Column, Row;
|
||||
bool Visible;
|
||||
int NumVerts;
|
||||
};
|
||||
|
||||
struct LOD
|
||||
{
|
||||
IIndexBuffer* Top;
|
||||
IIndexBuffer* Bottom;
|
||||
IIndexBuffer* Left;
|
||||
IIndexBuffer* Right;
|
||||
|
||||
IIndexBuffer* TopLeft;
|
||||
IIndexBuffer* TopRight;
|
||||
IIndexBuffer* BottomLeft;
|
||||
IIndexBuffer* BottomRight;
|
||||
|
||||
IIndexBuffer* full;
|
||||
IIndexBuffer* allSides;
|
||||
};
|
||||
|
||||
#define MAX_VISIBLE_DISTANCE 1025 //must be n ^ 2 + 1
|
||||
|
||||
struct TERRA_DATA
|
||||
{
|
||||
float size;
|
||||
LifeMath::float3 sunDir;
|
||||
};
|
||||
class Terrain
|
||||
{
|
||||
public:
|
||||
std::vector<LOD> lods;
|
||||
IVertexBuffer* vb;
|
||||
int vertexCount;
|
||||
IInputLayout* layout;
|
||||
TerraChunk* chunks;
|
||||
IShader* terraVs;
|
||||
IShader* terraPs;
|
||||
|
||||
IConstantBuffer* terraCb;
|
||||
|
||||
IShader* terraVs_g;
|
||||
IShader* terraPs_g;
|
||||
|
||||
texture_ptr diffuse;
|
||||
IRasterizerState* solidState;
|
||||
IRasterizerState* wireState;
|
||||
void* data;
|
||||
IBitmapInfo* info;
|
||||
USHORT* heightMap;
|
||||
|
||||
int TerrainWidth;
|
||||
|
||||
std::vector<TerraChunk*> visibleChunks;
|
||||
|
||||
static INLINE int fround(float val)
|
||||
{
|
||||
return static_cast<int>(floor(val + 0.5f));
|
||||
}
|
||||
|
||||
static INLINE float clampFloat(float val, float min, float max)
|
||||
{
|
||||
if(val < min)return min;
|
||||
if(val > max)return max;
|
||||
return val;
|
||||
}
|
||||
|
||||
static INLINE UINT blendrgb(UINT d, UINT s, UINT a)
|
||||
{
|
||||
const UINT dstrb = d & 0xFF00FF;
|
||||
const UINT dstg = d & 0xFF00;
|
||||
|
||||
const UINT srcrb = s & 0xFF00FF;
|
||||
const UINT srcg = s & 0xFF00;
|
||||
|
||||
UINT drb = srcrb - dstrb;
|
||||
UINT dg = srcg - dstg;
|
||||
|
||||
drb *= a;
|
||||
dg *= a;
|
||||
drb >>= 8;
|
||||
dg >>= 8;
|
||||
|
||||
UINT rb = (drb + dstrb) & 0xFF00FF;
|
||||
UINT g = (dg + dstg) & 0xFF00;
|
||||
|
||||
return rb | g;
|
||||
}
|
||||
|
||||
static INLINE UINT sampleTex(void* tex, IBitmapInfo* info, float tX, float tY)
|
||||
{
|
||||
tX = clampFloat(tX, 0.0f, 1.0f);
|
||||
tY = clampFloat(tY, 0.0f, 1.0f);
|
||||
|
||||
float texelW = 1.0f / (float)(info->Width);
|
||||
float texelH = 1.0f / (float)(info->Height);
|
||||
|
||||
// tX *= (1.0f - texelW * 2.0f);
|
||||
// tY *= (1.0f - texelH * 2.0f);
|
||||
|
||||
int x = fround((tX * (float)(info->Width)));
|
||||
int y = fround((tY * (float)(info->Height)));
|
||||
UCHAR* ptr = reinterpret_cast<UCHAR*>(tex);
|
||||
|
||||
float pX = tX * info->Width;
|
||||
float pY = tY * info->Height;
|
||||
|
||||
UINT frX = static_cast<UINT>((pX - floorf(pX))* 255.0f);
|
||||
UINT frY = static_cast<UINT>((pY - floorf(pY))* 255.0f);
|
||||
|
||||
UINT* ptr2 = reinterpret_cast<UINT*>(tex);
|
||||
|
||||
UINT color;
|
||||
if(info->Bpp < 4)
|
||||
{
|
||||
UINT tl = 0xff000000;
|
||||
UINT tr = 0xff000000;
|
||||
UINT rl = 0xff000000;
|
||||
UINT rr = 0xff000000;
|
||||
|
||||
memcpy(&tl, ptr+ (y*info->Width + x)* info->Bpp, 3);
|
||||
memcpy(&tr, ptr+ (y*info->Width + x + 1)* info->Bpp, 3);
|
||||
memcpy(&rl, ptr+ ((y + 1)*info->Width + x)* info->Bpp, 3);
|
||||
memcpy(&rr, ptr+ ((y + 1)*info->Width + x + 1)* info->Bpp, 3);
|
||||
|
||||
color = blendrgb ( blendrgb ( tl, tr, frX), blendrgb ( rl, rr, frX), frY);
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
#define MAX_HEIGHT 128
|
||||
#define AS_FLOAT(ololo) ololo##.0f
|
||||
|
||||
Terrain(TerrainDimention dim, int chunkSize = 64, int maxVisibleRange = 100)
|
||||
{
|
||||
terraCb = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(TERRA_DATA));
|
||||
diffuse = ResourceManager::me()->GetTexture(String(_text("root/Data/Textures/Terrain/shortGrass.png")));
|
||||
|
||||
ResourceManager::me()->ReadBitmap(String(_text("root/Data/Textures/hm.bmp")), &data, &info);
|
||||
|
||||
terraVs = ResourceManager::me()->CompileUserShaderVS(String(_text("Terrain.vsh")));
|
||||
terraPs = ResourceManager::me()->CompileUserShaderPS(String(_text("Terrain.psh")));
|
||||
|
||||
terraVs_g = ResourceManager::me()->CompileUserShaderVS(String(_text("Terrain_g.vsh")));
|
||||
terraPs_g = ResourceManager::me()->CompileUserShaderPS(String(_text("Terrain_g.psh")));
|
||||
|
||||
visibleCunkOffset = maxVisibleRange / chunkSize;
|
||||
TerrainWidth = (int)dim;
|
||||
ChunkWidth = chunkSize;
|
||||
|
||||
//Generate LOD IndexBuffers
|
||||
//------------------------------------LOD_1-------------------
|
||||
LOD1Full = GenerateLOD(chunkSize, 1, false, false, false, false);
|
||||
LOD1TrimAllSides = GenerateLOD(chunkSize, 1, true, true, true, true);
|
||||
LOD1TrimNorthEast = GenerateLOD(chunkSize, 1, true, false, false, true);
|
||||
LOD1TrimNorthWest = GenerateLOD(chunkSize, 1, true, false, true, false);
|
||||
LOD1TrimSouthEast = GenerateLOD(chunkSize, 1, false, true, false, true);
|
||||
LOD1TrimSouthWest = GenerateLOD(chunkSize, 1, false, true, true, false);
|
||||
//------------------------------------LOD_2-------------------
|
||||
LOD2Full = GenerateLOD(chunkSize, 2, false, false, false, false);
|
||||
LOD2TrimAllSides = GenerateLOD(chunkSize, 2, true, true, true, true);
|
||||
LOD2TrimNorth = GenerateLOD(chunkSize, 2, true, false, false, false);
|
||||
LOD2TrimSouth = GenerateLOD(chunkSize, 2, false, true, false, false);
|
||||
LOD2TrimWest = GenerateLOD(chunkSize, 2, false, false, true, false);
|
||||
LOD2TrimEast = GenerateLOD(chunkSize, 2, false, false, false, true);
|
||||
LOD2TrimNorthEast = GenerateLOD(chunkSize, 2, true, false, false, true);
|
||||
LOD2TrimNorthWest = GenerateLOD(chunkSize, 2, true, false, true, false);
|
||||
LOD2TrimSouthEast = GenerateLOD(chunkSize, 2, false, true, false, true);
|
||||
LOD2TrimSouthWest = GenerateLOD(chunkSize, 2, false, true, true, false);
|
||||
|
||||
//------------------------------------LOD_3-------------------
|
||||
LOD3Full = GenerateLOD(chunkSize, 3, false, false, false, false);
|
||||
LOD3TrimAllSides = GenerateLOD(chunkSize, 3, true, true, true, true);
|
||||
LOD3TrimNorth = GenerateLOD(chunkSize, 3, true, false, false, false);
|
||||
LOD3TrimSouth = GenerateLOD(chunkSize, 3, false, true, false, false);
|
||||
LOD3TrimWest = GenerateLOD(chunkSize, 3, false, false, true, false);
|
||||
LOD3TrimEast = GenerateLOD(chunkSize, 3, false, false, false, true);
|
||||
LOD3TrimNorthEast = GenerateLOD(chunkSize, 3, true, false, false, true);
|
||||
LOD3TrimNorthWest = GenerateLOD(chunkSize, 3, true, false, true, false);
|
||||
LOD3TrimSouthEast = GenerateLOD(chunkSize, 3, false, true, false, true);
|
||||
LOD3TrimSouthWest = GenerateLOD(chunkSize, 3, false, true, true, false);
|
||||
//------------------------------------LOD_4-------------------
|
||||
LOD4Full = GenerateLOD(chunkSize, 4, false, false, false, false);
|
||||
|
||||
LOD lod1;
|
||||
lod1.allSides = LOD1TrimAllSides;
|
||||
|
||||
LOD lod2;
|
||||
lod2.Top = LOD2TrimNorth;
|
||||
lod2.Bottom = LOD2TrimSouth;
|
||||
lod2.Left = LOD2TrimWest;
|
||||
lod2.Right = LOD2TrimEast;
|
||||
lod2.TopLeft = LOD2TrimNorthWest;
|
||||
lod2.TopRight = LOD2TrimNorthEast;
|
||||
lod2.BottomLeft = LOD2TrimSouthWest;
|
||||
lod2.BottomRight = LOD2TrimSouthEast;
|
||||
lod2.full = LOD2Full;
|
||||
lod2.allSides = LOD2TrimAllSides;
|
||||
|
||||
LOD lod3;
|
||||
lod3.Top = LOD3TrimNorth;
|
||||
lod3.Bottom = LOD3TrimSouth;
|
||||
lod3.Left = LOD3TrimWest;
|
||||
lod3.Right = LOD3TrimEast;
|
||||
lod3.TopLeft = LOD3TrimNorthWest;
|
||||
lod3.TopRight = LOD3TrimNorthEast;
|
||||
lod3.BottomLeft = LOD3TrimSouthWest;
|
||||
lod3.BottomRight = LOD3TrimSouthEast;
|
||||
lod3.full = LOD3Full;
|
||||
lod3.allSides = LOD3TrimAllSides;
|
||||
|
||||
LOD lod4;
|
||||
lod4.full = LOD4Full;
|
||||
|
||||
lods.push_back(lod1);
|
||||
lods.push_back(lod2);
|
||||
lods.push_back(lod3);
|
||||
lods.push_back(lod4);
|
||||
|
||||
solidState = CG::me()->GetRenderer()->CreateRasterizerState(FILL_SOLID);
|
||||
wireState = CG::me()->GetRenderer()->CreateRasterizerState(FILL_WIREFRAME);
|
||||
|
||||
vertexCount = (TerrainWidth + 1) * (TerrainWidth + 1);
|
||||
vb = CG::me()->GetRenderer()->CreateVertexBufferDynamic(vertexCount * sizeof(TerraVertex), sizeof(TerraVertex));
|
||||
|
||||
float multiplier = (float)(0xffff/MAX_HEIGHT);
|
||||
|
||||
heightMap = new USHORT[(TerrainWidth + 1) * (TerrainWidth + 1)];
|
||||
|
||||
//load height map
|
||||
for(int y = 0; y <= TerrainWidth; y++)
|
||||
{
|
||||
for(int x = 0; x <= TerrainWidth; x++)
|
||||
{
|
||||
UINT col = sampleTex(data, info, (float)x / (TerrainWidth + 2), 1.0f - ((float)y / (TerrainWidth + 2)));
|
||||
|
||||
USHORT h = (USHORT)(col & 0xff) * (0xffff / 0xff);
|
||||
int index = y * (TerrainWidth + 1) + x;
|
||||
heightMap[index] = h;
|
||||
}
|
||||
}
|
||||
|
||||
//smooth terrain heights
|
||||
int numSmoothSteps = 1;
|
||||
|
||||
for(int i = 0; i < numSmoothSteps; i++)
|
||||
{
|
||||
//smooth by X
|
||||
for(int y = 0; y <= TerrainWidth; y++)
|
||||
{
|
||||
for(int x = 1; x < TerrainWidth; x++)
|
||||
{
|
||||
int idL = y * (TerrainWidth + 1) + (x - 1);
|
||||
int idC = y * (TerrainWidth + 1) + (x);
|
||||
int idR = y * (TerrainWidth + 1) + (x + 1);
|
||||
float h1 = (float)heightMap[idL];
|
||||
float h2 = (float)heightMap[idC];
|
||||
float h3 = (float)heightMap[idR];
|
||||
|
||||
USHORT avg = (USHORT)((h1 + h2 + h3) / 3.0f);
|
||||
|
||||
heightMap[idL] = avg;
|
||||
heightMap[idC] = avg;
|
||||
heightMap[idR] = avg;
|
||||
}
|
||||
}
|
||||
|
||||
//smooth by Y
|
||||
for(int y = 1; y < TerrainWidth; y++)
|
||||
{
|
||||
for(int x = 0; x <= TerrainWidth; x++)
|
||||
{
|
||||
int idT = (y - 1) * (TerrainWidth + 1) + x;
|
||||
int idC = y * (TerrainWidth + 1) + x;
|
||||
int idB = (y + 1) * (TerrainWidth + 1) + x;
|
||||
float h1 = (float)heightMap[idT];
|
||||
float h2 = (float)heightMap[idC];
|
||||
float h3 = (float)heightMap[idB];
|
||||
|
||||
USHORT avg = (USHORT)((h1 + h2 + h3) / 3.0f);
|
||||
|
||||
heightMap[idT] = avg;
|
||||
heightMap[idC] = avg;
|
||||
heightMap[idB] = avg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//build terrain geometry
|
||||
TerraVertex* vertexData = new TerraVertex[vertexCount];
|
||||
for(int y = 0; y <= TerrainWidth; y++)
|
||||
{
|
||||
for(int x = 0; x <= TerrainWidth; x++)
|
||||
{
|
||||
int index = y * (TerrainWidth + 1) + x;
|
||||
vertexData[index] = TerraVertex(index, 0,0, heightMap[index]);
|
||||
}
|
||||
}
|
||||
|
||||
delete info;
|
||||
delete[] data;
|
||||
|
||||
//compute normals
|
||||
LifeMath::float3 p1, p2, p3, d1, d2, n;
|
||||
TerraVertex v1, v2, v3;
|
||||
|
||||
for(int y = 0; y < TerrainWidth; y++)
|
||||
{
|
||||
for(int x = 0; x < TerrainWidth; x++)
|
||||
{
|
||||
//first triangle
|
||||
int i1 = y * (TerrainWidth + 1) + x;
|
||||
int i2 = y * (TerrainWidth + 1) + x + 1;
|
||||
int i3 = (y + 1) * (TerrainWidth + 1) + x;
|
||||
|
||||
v1 = vertexData[i1];
|
||||
v2 = vertexData[i2];
|
||||
v3 = vertexData[i3];
|
||||
|
||||
p1 = LifeMath::float3((float)(x), (float)v1.height / multiplier,-(float)(y));
|
||||
p2 = LifeMath::float3((float)(x + 1), v2.height / multiplier, -(float)(y));
|
||||
p3 = LifeMath::float3((float)(x), (float)v3.height / multiplier, -(float)(y + 1));
|
||||
|
||||
d1 = p2 - p1;
|
||||
d2 = p3 - p1;
|
||||
|
||||
n = LifeMath::Vec3Cross(d1,d2);
|
||||
LifeMath::Vec3Normalize(&n);
|
||||
|
||||
printf("ACHTUNG! Maybe wrong value computed for normal! What about NEAGTIVE numbers?\n");
|
||||
char nnx = (char)(n.X * 127.0f);
|
||||
char nnz = (char)(n.Z * 127.0f);
|
||||
|
||||
vertexData[i1].nX = nnx;
|
||||
vertexData[i1].nZ = nnz;
|
||||
|
||||
vertexData[i2].nX = nnx;
|
||||
vertexData[i2].nZ = nnz;
|
||||
|
||||
vertexData[i3].nX = nnx;
|
||||
vertexData[i3].nZ = nnz;
|
||||
|
||||
//second triangle
|
||||
i1 = (y + 1) * (TerrainWidth + 1) + x;
|
||||
i2 = y * (TerrainWidth + 1) + x + 1;
|
||||
i3 = (y + 1) * (TerrainWidth + 1) + x + 1;
|
||||
|
||||
v1 = vertexData[i1];
|
||||
v2 = vertexData[i2];
|
||||
v3 = vertexData[i3];
|
||||
|
||||
p1 = LifeMath::float3((float)(x), v1.height / multiplier, -(float)(y + 1));
|
||||
p2 = LifeMath::float3((float)(x + 1), v2.height / multiplier, -(float)(y));
|
||||
p3 = LifeMath::float3((float)(x + 1), v3.height / multiplier, -(float)(y + 1));
|
||||
|
||||
d1 = p2 - p1;
|
||||
d2 = p3 - p1;
|
||||
|
||||
n = LifeMath::Vec3Cross(d1,d2);
|
||||
LifeMath::Vec3Normalize(&n);
|
||||
|
||||
nnx = (char)(n.X * 127.0f);
|
||||
nnz = (char)(n.Z * 127.0f);
|
||||
|
||||
vertexData[i1].nX = nnx;
|
||||
vertexData[i1].nZ = nnz;
|
||||
|
||||
vertexData[i2].nX = nnx;
|
||||
vertexData[i2].nZ = nnz;
|
||||
|
||||
vertexData[i3].nX = nnx;
|
||||
vertexData[i3].nZ = nnz;
|
||||
}
|
||||
}
|
||||
|
||||
LifeCore::IDataStream* stm = vb->Map(0,LF_Discard);
|
||||
stm->Write(vertexData, vertexCount * sizeof(TerraVertex));
|
||||
vb->Unmap();
|
||||
|
||||
int chunkStride = (TerrainWidth / chunkSize);
|
||||
|
||||
//create and process chunk info
|
||||
chunks = new TerraChunk[chunkStride * chunkStride];
|
||||
for(int x = 0; x < chunkStride; x++)
|
||||
{
|
||||
for(int y = 0; y < chunkStride; y++)
|
||||
{
|
||||
int index = y * chunkStride + x;
|
||||
chunks[index].Offset = y * (TerrainWidth + 1) * chunkSize + x * chunkSize;
|
||||
chunks[index].Column = x;
|
||||
chunks[index].Row = y;
|
||||
chunks[index].LOD = 1;
|
||||
chunks[index].IB = LOD1Full;
|
||||
|
||||
//now compute chunk bounding box
|
||||
int minX = x * ChunkWidth;
|
||||
int maxX = minX + ChunkWidth;
|
||||
|
||||
int minY = y * ChunkWidth;
|
||||
int maxY = minY + ChunkWidth;
|
||||
|
||||
UINT minH;
|
||||
UINT maxH;
|
||||
|
||||
minH = maxH = vertexData[minY * (TerrainWidth + 1) + minX].height;
|
||||
|
||||
for (int i = minX; i<=maxX; i++)
|
||||
{
|
||||
for (int j = minY; j<=maxY; j++)
|
||||
{
|
||||
UINT h = vertexData[j * (TerrainWidth + 1) + i].height;
|
||||
if(minH > h)
|
||||
minH = h;
|
||||
if(maxH < h)
|
||||
maxH = h;
|
||||
}
|
||||
}
|
||||
|
||||
chunks[index].BoundingBox.resize(LifeMath::float3((float)(x * ChunkWidth), (float)minH / multiplier, -(float)(maxY)),
|
||||
LifeMath::float3((float)(maxX), (float)maxH / multiplier, -(float)(minY)));
|
||||
|
||||
/*printf("Chunk= X:%i Y:%i\nMin= X:%f Z:%f\nMax= X:%f Z:%f\n\n", x,y,chunks[index].BoundingBox.minimum().X,
|
||||
chunks[index].BoundingBox.minimum().Z, chunks[index].BoundingBox.maximum().X,
|
||||
chunks[index].BoundingBox.maximum().Z );*/
|
||||
}
|
||||
}
|
||||
|
||||
delete[] vertexData;
|
||||
|
||||
IInputElement elements[] =
|
||||
{
|
||||
IInputElement("POSITION", 0, 0, FORMAT_R32_UINT, 0, 0, 0),
|
||||
IInputElement("TEXCOORD", 0, 4, FORMAT_R8G8_SINT, 0, 0, 0),
|
||||
IInputElement("TEXCOORD", 1, 6, FORMAT_R16_UINT, 0, 0, 0),
|
||||
};
|
||||
|
||||
layout = CG::me()->GetRenderer()->CreateInputLayout(elements, 3, terraVs);
|
||||
}
|
||||
~Terrain()
|
||||
{
|
||||
delete[] chunks;
|
||||
SAFE_DELETE(vb);
|
||||
SAFE_DELETE(layout);
|
||||
SAFE_DELETE(terraVs);
|
||||
SAFE_DELETE(terraPs_g);
|
||||
diffuse->Release();
|
||||
|
||||
SAFE_DELETE(solidState);
|
||||
SAFE_DELETE(wireState);
|
||||
SAFE_DELETE_ARRAY(heightMap);
|
||||
|
||||
SAFE_DELETE(LOD1Full);
|
||||
SAFE_DELETE(LOD1TrimAllSides);
|
||||
SAFE_DELETE(LOD1TrimNorthEast);
|
||||
SAFE_DELETE(LOD1TrimNorthWest);
|
||||
SAFE_DELETE(LOD1TrimSouthEast);
|
||||
SAFE_DELETE(LOD1TrimSouthWest);
|
||||
|
||||
SAFE_DELETE(LOD2Full);
|
||||
SAFE_DELETE(LOD2TrimAllSides);
|
||||
SAFE_DELETE(LOD2TrimNorth);
|
||||
SAFE_DELETE(LOD2TrimSouth);
|
||||
SAFE_DELETE(LOD2TrimEast);
|
||||
SAFE_DELETE(LOD2TrimWest);
|
||||
SAFE_DELETE(LOD2TrimNorthEast);
|
||||
SAFE_DELETE(LOD2TrimNorthWest);
|
||||
SAFE_DELETE(LOD2TrimSouthEast);
|
||||
SAFE_DELETE(LOD2TrimSouthWest);
|
||||
|
||||
SAFE_DELETE(LOD3Full);
|
||||
SAFE_DELETE(LOD3TrimAllSides);
|
||||
SAFE_DELETE(LOD3TrimNorth);
|
||||
SAFE_DELETE(LOD3TrimSouth);
|
||||
SAFE_DELETE(LOD3TrimEast);
|
||||
SAFE_DELETE(LOD3TrimWest);
|
||||
SAFE_DELETE(LOD3TrimNorthEast);
|
||||
SAFE_DELETE(LOD3TrimNorthWest);
|
||||
SAFE_DELETE(LOD3TrimSouthEast);
|
||||
SAFE_DELETE(LOD3TrimSouthWest);
|
||||
|
||||
SAFE_DELETE(LOD4Full);
|
||||
}
|
||||
void Update(Camera* cam, const LifeMath::float3& sunDir)
|
||||
{
|
||||
TERRA_DATA newData;
|
||||
newData.size = (float)TerrainWidth;
|
||||
newData.sunDir = sunDir;
|
||||
terraCb->Update(&newData, sizeof(TERRA_DATA));
|
||||
|
||||
visibleChunks.clear();
|
||||
|
||||
LifeMath::float3 pos = cam->getPosition();
|
||||
int pX = static_cast<int>(floorf(pos.X));
|
||||
int pZ = static_cast<int>(floorf(pos.Z));
|
||||
|
||||
int col = pX / ChunkWidth;
|
||||
int row = -pZ / ChunkWidth;
|
||||
|
||||
//int vis = 0;
|
||||
|
||||
//update all terrain chunks to minimal LOD (FIX IT: should not update ALL terrain)
|
||||
int chunkStride = TerrainWidth / ChunkWidth;
|
||||
for(int x = 0; x < chunkStride; x++)
|
||||
{
|
||||
for(int y = 0; y < chunkStride; y++)
|
||||
{
|
||||
if(cam->getFrustum()->BoxInFrustum(chunks[y * chunkStride + x].BoundingBox))
|
||||
{
|
||||
visibleChunks.push_back(&chunks[y * chunkStride + x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//check if cam is in terrain area
|
||||
if(col >= 0 && row >= 0 && col < (TerrainWidth / ChunkWidth) && row < (TerrainWidth / ChunkWidth))
|
||||
{
|
||||
int numChunks = visibleChunks.size();
|
||||
for(int i = 0; i < numChunks; i++)
|
||||
{
|
||||
TerraChunk* c = visibleChunks[i];
|
||||
int diffCol = col - c->Column;
|
||||
int diffRow = row - c->Row;
|
||||
|
||||
int lodNum = abs(diffCol) > abs(diffRow) ? abs(diffCol) : abs(diffRow);
|
||||
|
||||
if(lodNum < 3)
|
||||
{
|
||||
switch(lodNum)
|
||||
{
|
||||
case 0:
|
||||
c->LOD = 1;
|
||||
c->IB = LOD1TrimAllSides;
|
||||
break;
|
||||
default:
|
||||
LOD* curLod = &lods[lodNum];
|
||||
c->LOD = lodNum + 1;
|
||||
if(abs(diffRow) > abs(diffCol))
|
||||
{
|
||||
if(diffRow > 0)
|
||||
c->IB = curLod->Left;
|
||||
else
|
||||
c->IB = curLod->Right;
|
||||
}
|
||||
else if(abs(diffRow) < abs(diffCol))
|
||||
{
|
||||
if(diffCol > 0)
|
||||
c->IB = curLod->Top;
|
||||
else
|
||||
c->IB = curLod->Bottom;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(diffCol < 0 && diffRow < 0)
|
||||
c->IB = curLod->BottomRight;
|
||||
else if(diffCol > 0 && diffRow < 0)
|
||||
c->IB = curLod->TopRight;
|
||||
else if(diffCol < 0 && diffRow > 0)
|
||||
c->IB = curLod->BottomLeft;
|
||||
else
|
||||
c->IB = curLod->TopLeft;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
c->LOD = 4;
|
||||
c->IB = LOD4Full;
|
||||
}
|
||||
}
|
||||
}
|
||||
// printf("Visible chunks: %i\n", visibleChunks.size());
|
||||
}
|
||||
void Render(PassType pass)
|
||||
{
|
||||
IRenderer* renderer = CG::me()->GetRenderer();
|
||||
|
||||
renderer->SetPSConstantBuffer(terraCb, 2);
|
||||
//renderer->SetRasterizerState(wireState);
|
||||
renderer->SetPrimitiveTopology(PT_TRIANGLE_LIST);
|
||||
renderer->SetVertexBuffer(vb);
|
||||
if(pass == PT_COMPOSE_G_BUF)
|
||||
{
|
||||
renderer->SetPixelShader(terraPs_g);
|
||||
renderer->SetVertexShader(terraVs_g);
|
||||
}
|
||||
else if(pass == PT_RENDER_SHADOW_MAP)
|
||||
{
|
||||
renderer->SetVertexShader(terraVs);
|
||||
}
|
||||
else
|
||||
{
|
||||
renderer->SetPixelShader(terraPs);
|
||||
renderer->SetVertexShader(terraVs);
|
||||
}
|
||||
|
||||
renderer->SetInputLayout(layout);
|
||||
renderer->SetPSTexture(diffuse.ptr(), 0);
|
||||
|
||||
int chunkStride = TerrainWidth / ChunkWidth;
|
||||
|
||||
int renderCount = visibleChunks.size();
|
||||
|
||||
for (int j = 0; j < renderCount; j++)
|
||||
{
|
||||
TerraChunk* c = visibleChunks[j];
|
||||
//CG.GraphicsDevice.VertexFormat = g_terra.TerrainGeometryBuffer.Description.FVF;
|
||||
//if (c->Visible)
|
||||
//{
|
||||
switch (c->LOD)
|
||||
{
|
||||
case 1:
|
||||
renderer->SetIndexBuffer(c->IB);
|
||||
//renderer->DrawIndexed(chunks[index].Offset, (ChunkWidth / 1) * (ChunkWidth / 1) * 2);
|
||||
renderer->DrawIndexed(0, (ChunkWidth / 1) * (ChunkWidth / 1) * 2, c->Offset);
|
||||
break;
|
||||
case 2:
|
||||
renderer->SetIndexBuffer(c->IB);
|
||||
renderer->DrawIndexed(0, (ChunkWidth / 2) * (ChunkWidth / 2) * 2, c->Offset);
|
||||
break;
|
||||
case 3:
|
||||
renderer->SetIndexBuffer(c->IB);
|
||||
renderer->DrawIndexed(0, (ChunkWidth / 4) * (ChunkWidth / 4) * 2, c->Offset);
|
||||
break;
|
||||
case 4:
|
||||
renderer->SetIndexBuffer(c->IB);
|
||||
renderer->DrawIndexed(0, (ChunkWidth / 8) * (ChunkWidth / 8) * 2, c->Offset);
|
||||
break;
|
||||
}
|
||||
//}
|
||||
}
|
||||
//renderer->SetRasterizerState(solidState);
|
||||
}
|
||||
float GetHeight(float x, float z) const
|
||||
{
|
||||
//return 0.0f;
|
||||
/*
|
||||
UINT col = sampleTex(data, info, (float)x / (TerrainWidth + 2), 1.0f - ((float)y / (TerrainWidth + 2)));
|
||||
float r = (float)(col & 0xff) / 255.0f * AS_FLOAT(MAX_HEIGHT);
|
||||
float g = (float)((col & 0xff00) >> 8) / 255.0f * AS_FLOAT(MAX_HEIGHT);
|
||||
float b = (float)((col & 0xff0000) >> 16) / 255.0f * AS_FLOAT(MAX_HEIGHT);
|
||||
|
||||
float h = (r + g + b) / 3.0f * multiplier;*/
|
||||
|
||||
float multiplier = (float)(0xffff/MAX_HEIGHT);
|
||||
|
||||
z = -z;
|
||||
|
||||
if(x < 0 || x > TerrainWidth || z < 0 || z > TerrainWidth) return 0;
|
||||
|
||||
int iX = (int)x;
|
||||
int iZ = (int)z;
|
||||
|
||||
float fX = x - (float)iX;
|
||||
float fZ = z - (float)iZ;
|
||||
|
||||
float y1 = ((float)heightMap[(iZ + 0) * (TerrainWidth + 1) + (iX + 0)]) / multiplier;
|
||||
float y2 = ((float)heightMap[(iZ + 0) * (TerrainWidth + 1) + (iX + 1)]) / multiplier;
|
||||
float y3 = ((float)heightMap[(iZ + 1) * (TerrainWidth + 1) + (iX + 1)]) / multiplier;
|
||||
float y4 = ((float)heightMap[(iZ + 1) * (TerrainWidth + 1) + (iX + 0)]) / multiplier;
|
||||
|
||||
if((1.0f - fZ) >= (fX))
|
||||
return y1 + (y2 - y1) * fX + (y4 - y1) * fZ; //top triangle
|
||||
else
|
||||
return y3 + (y4 - y3) * (1.0f - fX) + (y2 - y3) * (1.0f - fZ); //bottom triangle
|
||||
}
|
||||
private:
|
||||
|
||||
IIndexBuffer* LOD1Full;
|
||||
IIndexBuffer* LOD1TrimAllSides;
|
||||
IIndexBuffer* LOD1TrimNorthEast;
|
||||
IIndexBuffer* LOD1TrimNorthWest;
|
||||
IIndexBuffer* LOD1TrimSouthEast;
|
||||
IIndexBuffer* LOD1TrimSouthWest;
|
||||
|
||||
IIndexBuffer* LOD2Full;
|
||||
IIndexBuffer* LOD2TrimAllSides;
|
||||
IIndexBuffer* LOD2TrimNorth;
|
||||
IIndexBuffer* LOD2TrimSouth;
|
||||
IIndexBuffer* LOD2TrimEast;
|
||||
IIndexBuffer* LOD2TrimWest;
|
||||
IIndexBuffer* LOD2TrimNorthEast;
|
||||
IIndexBuffer* LOD2TrimNorthWest;
|
||||
IIndexBuffer* LOD2TrimSouthEast;
|
||||
IIndexBuffer* LOD2TrimSouthWest;
|
||||
|
||||
IIndexBuffer* LOD3Full;
|
||||
IIndexBuffer* LOD3TrimAllSides;
|
||||
IIndexBuffer* LOD3TrimNorth;
|
||||
IIndexBuffer* LOD3TrimSouth;
|
||||
IIndexBuffer* LOD3TrimEast;
|
||||
IIndexBuffer* LOD3TrimWest;
|
||||
IIndexBuffer* LOD3TrimNorthEast;
|
||||
IIndexBuffer* LOD3TrimNorthWest;
|
||||
IIndexBuffer* LOD3TrimSouthEast;
|
||||
IIndexBuffer* LOD3TrimSouthWest;
|
||||
|
||||
IIndexBuffer* LOD4Full;
|
||||
|
||||
int ChunkWidth;
|
||||
int visibleCunkOffset;
|
||||
|
||||
IIndexBuffer* GenerateLOD(uint32 chunkLength, uint32 lodNumber, bool trimTop, bool trimBottom, bool trimLeft, bool trimRight)
|
||||
{
|
||||
uint32 mNum = 1, Counter = 0;
|
||||
switch (lodNumber)
|
||||
{
|
||||
case 1:
|
||||
mNum = 1;
|
||||
break;
|
||||
case 2:
|
||||
mNum = 2;
|
||||
break;
|
||||
case 3:
|
||||
mNum = 4;
|
||||
break;
|
||||
case 4:
|
||||
mNum = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned int* Indices = new unsigned int[(chunkLength / mNum) * (chunkLength / mNum) * 6];
|
||||
for (uint32 i = 0; i < chunkLength / mNum; i++)
|
||||
{
|
||||
for (uint32 j = 0; j < chunkLength / mNum; j++)
|
||||
{
|
||||
Indices[Counter] = (i + 1) * (TerrainWidth + 1) * mNum + j * mNum;
|
||||
Counter += 1;
|
||||
Indices[Counter] = i * (TerrainWidth + 1) * mNum + j * mNum;
|
||||
Counter += 1;
|
||||
|
||||
Indices[Counter] = i * (TerrainWidth + 1) * mNum + (j + 1) * mNum;
|
||||
Counter += 1;
|
||||
|
||||
Indices[Counter] = (i + 1) * (TerrainWidth + 1) * mNum + j * mNum;
|
||||
Counter += 1;
|
||||
Indices[Counter] = i * (TerrainWidth + 1) * mNum + (j + 1) * mNum;
|
||||
Counter += 1;
|
||||
|
||||
Indices[Counter] = (i + 1) * (TerrainWidth + 1) * mNum + (j + 1) * mNum;
|
||||
Counter += 1;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------LOD trimmers----------------------------
|
||||
|
||||
//trim top corner
|
||||
if (trimTop)
|
||||
{
|
||||
for (unsigned int i = 0; i < (chunkLength / mNum); i++)
|
||||
{
|
||||
if ((int)((float)((i + 1) / 2.0f)) == (float)((i + 1) / 2.0f))
|
||||
{
|
||||
//÷¸òíàÿ
|
||||
Indices[i * chunkLength / mNum * 6 + 0] = 0;
|
||||
Indices[i * chunkLength / mNum * 6 + 1] = 0;
|
||||
Indices[i * chunkLength / mNum * 6 + 2] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Indices[i * chunkLength / mNum * 6 + 3] = Indices[(i + 1) * chunkLength / mNum * 6 + 3];
|
||||
if (trimLeft == true)
|
||||
{
|
||||
if (i != 0)
|
||||
Indices[i * chunkLength / mNum * 6 + 4] -= (mNum);
|
||||
else
|
||||
Indices[i * chunkLength / mNum * 6 + 0] -= (mNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
Indices[i * chunkLength / mNum * 6 + 4] -= (mNum);
|
||||
}
|
||||
Indices[i * chunkLength / mNum * 6 + 0] += (mNum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//trim bottom corner
|
||||
if (trimBottom)
|
||||
{
|
||||
for (unsigned int i = 0; i < (chunkLength / mNum); i++)
|
||||
{
|
||||
if ((int)((float)((i + 1) / 2.0f)) == (float)((i + 1) / 2.0f))
|
||||
{
|
||||
//÷¸òíàÿ
|
||||
Indices[(i + 1) * (chunkLength / mNum) * 6 - 6 + 0] = 0;
|
||||
Indices[(i + 1) * (chunkLength / mNum) * 6 - 6 + 1] = 0;
|
||||
Indices[(i + 1) * (chunkLength / mNum) * 6 - 6 + 2] = 0;
|
||||
Indices[(i + 1) * (chunkLength / mNum) * 6 - 6 + 4] -= mNum;
|
||||
}
|
||||
else
|
||||
{
|
||||
Indices[(i + 1) * (chunkLength / mNum) * 6 - 6 + 5] = Indices[(i + 2) * (chunkLength / mNum) * 6 - 6 + 5];
|
||||
}
|
||||
}
|
||||
}
|
||||
int offset = (chunkLength / mNum) * ((chunkLength / mNum) - 1) * 6;
|
||||
if (trimRight)
|
||||
{
|
||||
//Trim right corner
|
||||
|
||||
for (unsigned int i = 1; i < (chunkLength / mNum) + 1; i++)
|
||||
{
|
||||
if ((int)((float)i / 2.0f) == (float)i / 2.0f)
|
||||
{
|
||||
//÷¸òíàÿ
|
||||
Indices[offset + (i - 1) * 6 + 0] += (mNum);
|
||||
Indices[offset + (i - 1) * 6 + 3] = 0;
|
||||
Indices[offset + (i - 1) * 6 + 4] = 0;
|
||||
Indices[offset + (i - 1) * 6 + 5] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Indices[offset + (i - 1) * 6 + 5] += (mNum);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (trimLeft)
|
||||
{
|
||||
//Trim left corner
|
||||
offset = (chunkLength / mNum) * 6;
|
||||
for (unsigned int i = 1; i < (chunkLength / mNum) + 1; i++)
|
||||
{
|
||||
if ((int)((float)i / 2.0f) == (float)i / 2.0f)
|
||||
{
|
||||
Indices[(i - 1) * 6 + 0] = 0;
|
||||
Indices[(i - 1) * 6 + 1] = 0;
|
||||
Indices[(i - 1) * 6 + 2] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Indices[(i - 1) * 6 + 0] += (mNum);
|
||||
Indices[(i - 1) * 6 + 2] += (mNum);
|
||||
Indices[(i - 1) * 6 + 4] -= (mNum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IIndexBuffer* _ib = CG::me()->GetRenderer()->CreateIndexBuffer((chunkLength / mNum) * (chunkLength / mNum) * 6 * sizeof(unsigned int),Indices, FALSE);
|
||||
return _ib;
|
||||
}
|
||||
|
||||
static void GenerateMaxLOD(int chunkLength, int* indices)
|
||||
{
|
||||
// int[] indices = new int[chunkLength * chunkLength * 6];
|
||||
int counter = 0;
|
||||
for (int i = 0; i < chunkLength; i++)
|
||||
{
|
||||
for (int j = 0; j < chunkLength; j++)
|
||||
{
|
||||
//First cell's triangle
|
||||
indices[counter] = i * (chunkLength + 1) + (j + 1);
|
||||
counter += 1;
|
||||
indices[counter] = (i + 1) * (chunkLength + 1) + j;
|
||||
counter += 1;
|
||||
indices[counter] = i * (chunkLength + 1) + j;
|
||||
counter += 1;
|
||||
|
||||
//Second cell's triangle
|
||||
indices[counter] = (i + 1) * (chunkLength + 1) + (j + 1);
|
||||
counter += 1;
|
||||
indices[counter] = (i + 1) * (chunkLength + 1) + j;
|
||||
counter += 1;
|
||||
indices[counter] = i * (chunkLength + 1) + (j + 1);
|
||||
counter += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif // Terrain_h__
|
||||
Reference in New Issue
Block a user