cubious/src/engine_chunk.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);
}