summaryrefslogtreecommitdiff
path: root/src/chunk.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/chunk.c237
1 files changed, 169 insertions, 68 deletions
diff --git a/src/chunk.c b/src/chunk.c
index 50fe5c3..f142788 100644
--- a/src/chunk.c
+++ b/src/chunk.c
@@ -1,98 +1,183 @@
-#include <stdio.h>
+#include <cglm/vec3.h>
#include <stdlib.h>
-#include <string.h>
+#include "utils.h"
#include "voxel.h"
#include "list.h"
-#include "cube.h"
-#include "mesh.h"
+#include "gl.h"
+#include "noise.h"
-Chunk *chunk_init(int x, int y, int z)
+void chunk_init(Chunk *chunk, i32 x, i32 y, i32 z)
{
- Chunk *chunk = malloc(sizeof(Chunk));
- chunk->x = x;
- chunk->y = y;
- chunk->z = z;
- memset(chunk->blocks, AIR, sizeof(chunk->blocks));
- return chunk;
+ chunk->blocks = xzalloc(sizeof(Block) * CHUNK_BLOCKS);
+ chunk->pos[0] = x;
+ chunk->pos[1] = y;
+ chunk->pos[2] = z;
+ chunk->state = CHUNK_NEW;
+ chunk->has_mesh = false;
}
void chunk_free(Chunk *chunk)
{
- free(chunk);
+ if (chunk->state >= CHUNK_MESHED)
+ uniform_free(&chunk->mesh);
+ free(chunk->blocks);
}
-void chunk_generate(Chunk *chunk)
+void chunk_generate(Chunk *chunk, seed_t seed)
{
- int size = sizeof(chunk->blocks);
- for (int i = 0; i < size; i++) {
- int x = i % CHUNK_SIZE;
- int z = (i / CHUNK_SIZE) % CHUNK_SIZE;
- int y = i / (CHUNK_SIZE * CHUNK_SIZE);
+ fnl_state noise;
- char block = AIR;
- int temp = x + z - y;
- if (temp > 16)
- block = DIRT;
+ if (chunk->state != CHUNK_NEW)
+ return;
- chunk->blocks[i] = block;
+ chunk->state = CHUNK_GENERATING;
+
+ noise = fnlCreateState();
+ noise.seed = seed;
+ noise.noise_type = FNL_NOISE_PERLIN;
+
+ for (i32 i = 0; i < CHUNK_BLOCKS; i++) {
+ i32 lx = i % CHUNK_SIZE;
+ i32 lz = (i / CHUNK_SIZE) % CHUNK_SIZE;
+ i32 ly = i / (CHUNK_SIZE * CHUNK_SIZE);
+
+ i32 gx = lx + chunk->pos[0] * CHUNK_SIZE;
+ i32 gy = ly + chunk->pos[1] * CHUNK_SIZE;
+ i32 gz = lz + chunk->pos[2] * CHUNK_SIZE;
+
+ double data = fnlGetNoise3D(&noise, gx, gy, gz);
+ data -= gy * 0.01;
+ if (data < 0.1)
+ continue;
+
+ chunk->blocks[i] = A;
}
+
+ chunk->state = CHUNK_GENERATED;
}
typedef struct {
- Chunk *chunk;
- List pos;
List data;
- int vertex_count;
+ RcChunk *rc_chunks[7];
} MeshState;
-static void add_vertex(MeshState *state, const vec3 pos, const vec3 xyz, unsigned int data)
+typedef union {
+ struct {
+ u64 x : 5;
+ u64 y : 5;
+ u64 z : 5;
+ u64 width : 5;
+ u64 height : 5;
+ u64 face : 3;
+ u64 block : 4;
+ u64 : 32;
+ };
+ u64 raw;
+} Quad;
+
+static void mesh_state_init(MeshState *state, World *world, Chunk *chunk)
+{
+ i32 cx, cy, cz;
+
+ cx = chunk->pos[0];
+ cy = chunk->pos[1];
+ cz = chunk->pos[2];
+
+ state->rc_chunks[0] = world_get_chunk(world, cx, cy, cz);
+ state->rc_chunks[1] = world_get_chunk(world, cx - 1, cy, cz);
+ state->rc_chunks[2] = world_get_chunk(world, cx + 1, cy, cz);
+ state->rc_chunks[3] = world_get_chunk(world, cx, cy - 1, cz);
+ state->rc_chunks[4] = world_get_chunk(world, cx, cy + 1, cz);
+ state->rc_chunks[5] = world_get_chunk(world, cx, cy, cz - 1);
+ state->rc_chunks[6] = world_get_chunk(world, cx, cy, cz + 1);
+
+ list_init_u64(&state->data);
+}
+
+static void mesh_state_free(MeshState *state)
+{
+ for (i32 i = 0; i < 7; i++) {
+ RcChunk *rc_chunk = state->rc_chunks[i];
+ if (rc_chunk != NULL)
+ rcchunk_drop(rc_chunk);
+ }
+
+ list_free(&state->data);
+}
+
+static Block mesh_state_get_block(MeshState *state, i32 lx, i32 ly, i32 lz)
{
- list_pushf(&state->pos, pos[0] + xyz[0]);
- list_pushf(&state->pos, pos[1] + xyz[1]);
- list_pushf(&state->pos, pos[2] + xyz[2]);
- list_pushu(&state->data, data);
- state->vertex_count++;
+ RcChunk *rc_chunk;
+ i32 index = 0;
+
+ if (lx < 0) {
+ index = 1;
+ lx += CHUNK_SIZE;
+ } else if (lx >= CHUNK_SIZE) {
+ index = 2;
+ lx -= CHUNK_SIZE;
+ } else if (ly < 0) {
+ index = 3;
+ ly += CHUNK_SIZE;
+ } else if (ly >= CHUNK_SIZE) {
+ index = 4;
+ ly -= CHUNK_SIZE;
+ } else if (lz < 0) {
+ index = 5;
+ lz += CHUNK_SIZE;
+ } else if (lz >= CHUNK_SIZE) {
+ index = 6;
+ lz -= CHUNK_SIZE;
+ }
+
+ rc_chunk = state->rc_chunks[index];
+ if (rc_chunk == NULL)
+ return AIR;
+
+ return chunk_at(&rc_chunk->chunk, lx, ly, lz);
}
-static void add_quad(MeshState *state, const vec3 xyz, Face face, Block block)
+static void add_quad(MeshState *state, const ivec3 xyz, Face face, Block block)
{
- unsigned int data = (face << 2) | block;
- const vec3 *verts = CUBE[face];
+ Quad quad = { 0 };
+ quad.x = xyz[0];
+ quad.y = xyz[1];
+ quad.z = xyz[2];
+ quad.width = 1;
+ quad.height = 1;
+ quad.face = face;
+ quad.block = block;
- add_vertex(state, verts[0], xyz, data);
- add_vertex(state, verts[1], xyz, data);
- add_vertex(state, verts[2], xyz, data);
- add_vertex(state, verts[3], xyz, data);
- add_vertex(state, verts[4], xyz, data);
- add_vertex(state, verts[5], xyz, data);
+ list_push_u64(&state->data, quad.raw);
}
-Mesh chunk_mesh(Chunk *chunk)
+void chunk_mesh(Chunk *chunk, World *world)
{
MeshState state;
- state.chunk = chunk;
- state.vertex_count = 0;
- list_initf(&state.pos);
- list_initu(&state.data);
- int size = sizeof(chunk->blocks);
- for (int i = 0; i < size; i++) {
- int x = i % CHUNK_SIZE;
- int z = (i / CHUNK_SIZE) % CHUNK_SIZE;
- int y = i / (CHUNK_SIZE * CHUNK_SIZE);
- vec3 xyz = { x, y, z };
+ if (chunk->state != CHUNK_GENERATED)
+ return;
+
+ chunk->state = CHUNK_MESHING;
+ mesh_state_init(&state, world, chunk);
+
+ for (i32 i = 0; i < CHUNK_BLOCKS; i++) {
+ i32 lx = i % CHUNK_SIZE;
+ i32 lz = (i / CHUNK_SIZE) % CHUNK_SIZE;
+ i32 ly = i / (CHUNK_SIZE * CHUNK_SIZE);
+ ivec3 xyz = { lx, ly, lz };
Block block = chunk->blocks[i];
if (block == AIR)
continue;
- Block px = chunk_at(chunk, x + 1, y, z);
- Block nx = chunk_at(chunk, x - 1, y, z);
- Block py = chunk_at(chunk, x, y + 1, z);
- Block ny = chunk_at(chunk, x, y - 1, z);
- Block pz = chunk_at(chunk, x, y, z + 1);
- Block nz = chunk_at(chunk, x, y, z - 1);
+ Block px = mesh_state_get_block(&state, lx + 1, ly, lz);
+ Block nx = mesh_state_get_block(&state, lx - 1, ly, lz);
+ Block py = mesh_state_get_block(&state, lx, ly + 1, lz);
+ Block ny = mesh_state_get_block(&state, lx, ly - 1, lz);
+ Block pz = mesh_state_get_block(&state, lx, ly, lz + 1);
+ Block nz = mesh_state_get_block(&state, lx, ly, lz - 1);
if (px == AIR)
add_quad(&state, xyz, POS_X, block);
@@ -108,19 +193,20 @@ Mesh chunk_mesh(Chunk *chunk)
add_quad(&state, xyz, NEG_Z, block);
}
- Mesh mesh;
- mesh_init(&mesh, state.vertex_count);
- mesh_storef(&mesh, state.pos.fdata, state.pos.len, 3);
- mesh_storeu(&mesh, state.data.udata, state.data.len, 1);
- mesh_finish();
+ if (chunk->has_mesh)
+ uniform_free(&chunk->mesh);
- list_free(&state.pos);
- list_free(&state.data);
+ Uniform uniform;
+ uniform_init(&uniform, state.data.len * sizeof(Quad));
+ uniform_store(&uniform, 0, state.data.len * sizeof(Quad), state.data.data);
+ mesh_state_free(&state);
- return mesh;
+ chunk->mesh = uniform;
+ chunk->has_mesh = true;
+ chunk->state = CHUNK_MESHED;
}
-Block chunk_at(Chunk *chunk, int x, int y, int z)
+Block chunk_at(Chunk *chunk, i32 x, i32 y, i32 z)
{
if (x < 0 || x >= CHUNK_SIZE)
return AIR;
@@ -129,10 +215,25 @@ Block chunk_at(Chunk *chunk, int x, int y, int z)
if (z < 0 || z >= CHUNK_SIZE)
return AIR;
- int i = 0;
+ i32 i = 0;
i += x;
i += z * CHUNK_SIZE;
i += y * CHUNK_SIZE * CHUNK_SIZE;
return chunk->blocks[i];
}
+
+AABB chunk_aabb(Chunk *chunk)
+{
+ AABB aabb = { 0 };
+
+ // min
+ aabb.min[0] = chunk->pos[0] * CHUNK_SIZE;
+ aabb.min[1] = chunk->pos[1] * CHUNK_SIZE;
+ aabb.min[2] = chunk->pos[2] * CHUNK_SIZE;
+
+ // max
+ glm_vec3_adds(aabb.min, CHUNK_SIZE, aabb.max);
+
+ return aabb;
+}