360 lines
8.7 KiB
C
360 lines
8.7 KiB
C
#include <stdlib.h>
|
|
#include <math.h>
|
|
|
|
#include "engine_chunk.h"
|
|
#include "engine_renderer.h"
|
|
|
|
void
|
|
InitializeChunk(Chunk* Chk, int size, vec3f_t Transform)
|
|
{
|
|
Chk->Transform.x = Transform.x;
|
|
Chk->Transform.y = Transform.y;
|
|
Chk->Transform.z = Transform.z;
|
|
|
|
Chk->ChunkDimension = size;
|
|
|
|
Chk->Grid = (Cube***)malloc(size * sizeof(Cube**));
|
|
Chk->ActiveCubes = 0;
|
|
|
|
Cube** YData = (Cube**)malloc(size * size * sizeof(Cube*));
|
|
Cube* ZData = (Cube*)malloc(size * size * size * sizeof(Cube));
|
|
|
|
int CubeID = rand() % 3;
|
|
|
|
for (int x = 0; x < size; x++)
|
|
{
|
|
Chk->Grid[x] = YData + (x * size);
|
|
|
|
for (int y = 0; y < size; y++)
|
|
{
|
|
Chk->Grid[x][y] = ZData + (x*size*size) + (y*size);
|
|
|
|
for (int z = 0; z < size; z++)
|
|
{
|
|
//SetActive(&Chk->Grid[x][y][z], (rand() <= 1500));
|
|
SetActive(&Chk->Grid[x][y][z], 1);
|
|
SetType(&Chk->Grid[x][y][z], CubeID);
|
|
|
|
if (GetActive(&Chk->Grid[x][y][z]))
|
|
{
|
|
Chk->ActiveCubes++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
FreeChunk(Chunk* Chk)
|
|
{
|
|
free(**Chk->Grid);
|
|
free(*Chk->Grid);
|
|
free(Chk->Grid);
|
|
}
|
|
|
|
void
|
|
GreedyMesh(Chunk* Chk, CubeType* CubeTypes,
|
|
float* RenderBuffer, int* VertexCount)
|
|
{
|
|
*VertexCount = 0;
|
|
Chk->MeshVertexCount = 0;
|
|
|
|
int CubeFace;
|
|
|
|
int FrontFace, BackFace,
|
|
Front, Back;
|
|
|
|
int u, v;
|
|
|
|
int index[] = {0, 0, 0};
|
|
int disp[] = {0, 0, 0};
|
|
|
|
int MaskSize = (Chk->ChunkDimension * Chk->ChunkDimension);
|
|
int* Mask = malloc(sizeof(int)*MaskSize);
|
|
|
|
int MaskIndex = 0;
|
|
|
|
int QWidth, QHeight;
|
|
|
|
for (FrontFace = 1, BackFace = 0; !(FrontFace && BackFace); )
|
|
{
|
|
for (int dim = 0; dim < 3; dim++)
|
|
{
|
|
|
|
// Determine CubeFace
|
|
if (BackFace)
|
|
{
|
|
switch (dim)
|
|
{
|
|
case 0:
|
|
CubeFace = LEFT;
|
|
break;
|
|
case 1:
|
|
CubeFace = BOTTOM;
|
|
break;
|
|
case 2:
|
|
CubeFace = BACK;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else if (FrontFace)
|
|
{
|
|
switch (dim)
|
|
{
|
|
case 0:
|
|
CubeFace = RIGHT;
|
|
break;
|
|
case 1:
|
|
CubeFace = TOP;
|
|
break;
|
|
case 2:
|
|
CubeFace = FORWARD;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
u = (dim+1) % 3;
|
|
v = (dim+2) % 3;
|
|
|
|
index[0] = 0;
|
|
index[1] = 0;
|
|
index[2] = 0;
|
|
|
|
disp[0] = 0;
|
|
disp[1] = 0;
|
|
disp[2] = 0;
|
|
disp[dim] = 1;
|
|
|
|
for (index[dim] = -1; index[dim] < Chk->ChunkDimension; )
|
|
{
|
|
// Reset the mask
|
|
MaskIndex = 0;
|
|
|
|
// Create a mask for each two dimensional plane
|
|
for (index[u] = 0; index[u] < Chk->ChunkDimension; index[u]++)
|
|
{
|
|
for (index[v] = 0; index[v] < Chk->ChunkDimension; index[v]++)
|
|
{
|
|
Front = (index[dim] >= 0) ?
|
|
GetActive(&Chk->Grid[index[0]][index[1]][index[2]]) : 0;
|
|
|
|
Back = (index[dim] < Chk->ChunkDimension - 1) ?
|
|
GetActive(&Chk->Grid[index[0]+disp[0]]
|
|
[index[1]+disp[1]]
|
|
[index[2]+disp[2]]) : 0;
|
|
|
|
int FrontType = -1;
|
|
int BackType = -1;
|
|
|
|
if (Front && index[dim] >= 0)
|
|
{
|
|
FrontType = GetType(&Chk->Grid[index[0]][index[1]][index[2]]);
|
|
}
|
|
if (Back && index[dim] < Chk->ChunkDimension - 1)
|
|
{
|
|
BackType = GetType(&Chk->Grid[index[0]+disp[0]][index[1]+disp[1]][index[2]+disp[2]]);
|
|
}
|
|
|
|
Mask[MaskIndex++] = (Front != 0 && Back != 0 && FrontType == BackType) ? -1 :
|
|
BackFace ? BackType : FrontType;
|
|
|
|
}
|
|
}
|
|
|
|
index[dim]++;
|
|
|
|
// Generate mesh
|
|
MaskIndex = 0;
|
|
|
|
for (int i = 0; i < Chk->ChunkDimension; i++)
|
|
{
|
|
for (int j = 0; j < Chk->ChunkDimension; )
|
|
{
|
|
if (Mask[MaskIndex] != -1)
|
|
{
|
|
|
|
// Width of Quad
|
|
for (QWidth = 1;
|
|
(Mask[MaskIndex + QWidth] != -1 && Mask[MaskIndex + QWidth] == Mask[MaskIndex] && j + QWidth < Chk->ChunkDimension);
|
|
++QWidth) {}
|
|
|
|
// Height of Quad
|
|
int Done = 0;
|
|
|
|
for (QHeight = 1; i + QHeight < Chk->ChunkDimension; QHeight++)
|
|
{
|
|
for (int k = 0; k < QWidth; k++)
|
|
{
|
|
if (Mask[MaskIndex + k + QHeight*Chk->ChunkDimension] == -1 || Mask[MaskIndex + k + QHeight*Chk->ChunkDimension] != Mask[MaskIndex])
|
|
{
|
|
Done = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Done)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
index[u] = i;
|
|
index[v] = j;
|
|
|
|
int index_Du[] = {0, 0, 0};
|
|
int index_Dv[] = {0, 0, 0};
|
|
|
|
index_Du[u] = QHeight;
|
|
index_Dv[v] = QWidth;
|
|
|
|
AddQuad(Chk, CubeFace,
|
|
Vec3f(index[0], index[1], index[2]),
|
|
Vec3f(index[0] + index_Dv[0],
|
|
index[1] + index_Dv[1],
|
|
index[2] + index_Dv[2]),
|
|
Vec3f(index[0] + index_Du[0] + index_Dv[0],
|
|
index[1] + index_Du[1] + index_Dv[1],
|
|
index[2] + index_Du[2] + index_Dv[2]),
|
|
Vec3f(index[0] + index_Du[0],
|
|
index[1] + index_Du[1],
|
|
index[2] + index_Du[2]),
|
|
Mask[MaskIndex], CubeTypes,
|
|
RenderBuffer, VertexCount);
|
|
|
|
// Munch away at the part of the mask that we just consumed
|
|
for (int t = 0; t < QHeight; t++)
|
|
{
|
|
for (int s = 0; s < QWidth; s++)
|
|
{
|
|
Mask[MaskIndex + s + t*Chk->ChunkDimension] = -1;
|
|
}
|
|
}
|
|
|
|
MaskIndex += QWidth;
|
|
j += QWidth;
|
|
}
|
|
else
|
|
{
|
|
MaskIndex++;
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FrontFace)
|
|
{
|
|
BackFace = 1;
|
|
FrontFace = 0;
|
|
}
|
|
else if (BackFace)
|
|
{
|
|
FrontFace = 1;
|
|
}
|
|
}
|
|
|
|
free(Mask);
|
|
}
|
|
|
|
void
|
|
ChunkHeightFill(int x, int z, int height, Chunk* Chk)
|
|
{
|
|
for (int y = 0; y < height; y++)
|
|
{
|
|
if (!GetActive(&Chk->Grid[x][y][z]))
|
|
{
|
|
(Chk->ActiveCubes)++;
|
|
SetActive(&Chk->Grid[x][y][z], 1);
|
|
}
|
|
}
|
|
for (int y = height; y < Chk->ChunkDimension; y++)
|
|
{
|
|
if (GetActive(&Chk->Grid[x][y][z]))
|
|
{
|
|
(Chk->ActiveCubes)--;
|
|
SetActive(&Chk->Grid[x][y][z], 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
AddQuad(Chunk* Chk, int Side,
|
|
vec3f_t P1, vec3f_t P2,
|
|
vec3f_t P3, vec3f_t P4,
|
|
int CubeID, CubeType* Types,
|
|
float* RenderBuffer, int* VertexCount)
|
|
{
|
|
|
|
vec3f_t Normal;
|
|
|
|
switch(Side)
|
|
{
|
|
case LEFT:
|
|
Normal = Vec3f(-1.0f, 0.0f, 0.0f);
|
|
break;
|
|
case RIGHT:
|
|
Normal = Vec3f(1.0f, 0.0f, 0.0f);
|
|
break;
|
|
case BACK:
|
|
Normal = Vec3f(0.0f, 0.0f, -1.0f);
|
|
break;
|
|
case FORWARD:
|
|
Normal = Vec3f(0.0f, 0.0f, 1.0f);
|
|
break;
|
|
case TOP:
|
|
Normal = Vec3f(0.0f, 1.0f, 0.0f);
|
|
break;
|
|
case BOTTOM:
|
|
Normal = Vec3f(0.0f, -1.0f, 0.0f);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
GenerateQuadFace(RenderBuffer+(RENDER_FLOATS_PER_CUBE_VERTEX*
|
|
*VertexCount),
|
|
P1, P2, P3, P4,
|
|
Normal,
|
|
Types[CubeID].Color);
|
|
|
|
*VertexCount += 6;
|
|
Chk->MeshVertexCount += 6;
|
|
|
|
}
|
|
|
|
Cube*
|
|
GetCubeFromPosition(Chunk* Chk, vec3f_t Position)
|
|
{
|
|
|
|
vec3f_t Max = Vec3f(Chk->Transform.x + Chk->ChunkDimension,
|
|
Chk->Transform.y + Chk->ChunkDimension,
|
|
Chk->Transform.z + Chk->ChunkDimension);
|
|
|
|
if (Position.x < Chk->Transform.x || Position.x >= Max.x) return(0);
|
|
if (Position.y < Chk->Transform.y || Position.y >= Max.y) return(0);
|
|
if (Position.z < Chk->Transform.z || Position.z >= Max.z) return(0);
|
|
|
|
return (&Chk->Grid[(int)floor(Position.x)][(int)floor(Position.y)][(int)floor(Position.z)]);
|
|
}
|
|
|
|
|
|
// TODO: Get the height of the chunk at a certain X, Z position
|
|
int
|
|
GetChunkHeight(Chunk* Chk, int X, int Z)
|
|
{
|
|
int Height;
|
|
for (Height = 0; Height < Chk->ChunkDimension; Height++)
|
|
{
|
|
if (!GetActive(&Chk->Grid[X][Height][Z]))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return (Height);
|
|
}
|