summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2025-12-11 22:10:52 -0500
committerFreya Murphy <freya@freyacat.org>2025-12-11 22:10:52 -0500
commite511e9c678eeb76906e75dbc92165e538d13546b (patch)
tree30b6dfde164603fa0a677baebe770f44536dfeff
parenti did a lot (diff)
downloadvoxel-e511e9c678eeb76906e75dbc92165e538d13546b.tar.gz
voxel-e511e9c678eeb76906e75dbc92165e538d13546b.tar.bz2
voxel-e511e9c678eeb76906e75dbc92165e538d13546b.zip
ambient occlusionHEADmain
-rwxr-xr-xassets/fragment.glsl2
-rwxr-xr-xassets/vertex.glsl106
-rw-r--r--src/chunk.c161
-rw-r--r--src/gl.h2
-rw-r--r--src/main.c28
-rw-r--r--src/math.c77
-rw-r--r--src/mesh.c27
-rw-r--r--src/render.c6
-rw-r--r--src/shader.c1
-rw-r--r--src/voxel.h8
-rw-r--r--src/window.c5
-rw-r--r--src/window.h1
-rw-r--r--src/world.c6
13 files changed, 360 insertions, 70 deletions
diff --git a/assets/fragment.glsl b/assets/fragment.glsl
index 5ce136e..bb1eab2 100755
--- a/assets/fragment.glsl
+++ b/assets/fragment.glsl
@@ -1,6 +1,7 @@
#version 330 core
flat in uvec2 pass_data;
+in float pass_ao;
out vec4 color;
@@ -18,5 +19,6 @@ void main(void)
uint block = (pass_data.x >> 28) & 15u;
uint face = (pass_data.x >> 25) & 7u;
float tint = TINT[face];
+ tint *= 1.0 - pow(pass_ao / 3.0, 1.2) * 0.65;
color = vec4(vec3(tint), 1);
}
diff --git a/assets/vertex.glsl b/assets/vertex.glsl
index f4c3fde..78a479c 100755
--- a/assets/vertex.glsl
+++ b/assets/vertex.glsl
@@ -1,6 +1,6 @@
#version 330 core
-layout (location = 0) in vec3 quad;
+layout (location = 0) in vec3 in_quad;
layout (std140) uniform Matrices {
mat4 proj;
@@ -19,6 +19,13 @@ layout (std140) uniform Face {
};
flat out uvec2 pass_data;
+out float pass_ao;
+
+const mat3 ROT90 = mat3(
+ 0.0, 0.0, 1.0,
+ 0.0, 1.0, 0.0,
+ -1.0, 0.0, 0.0
+);
uint get_half(int index)
{
@@ -34,28 +41,98 @@ uvec2 get_data(int index)
return uvec2(lower, upper);
}
+bool get_ao_rotate(uint data)
+{
+ vec4 ao;
+
+ ao.x = (data >> 0) & 3u;
+ ao.y = (data >> 2) & 3u;
+ ao.z = (data >> 4) & 3u;
+ ao.w = (data >> 6) & 3u;
+
+ float a = abs(ao.x - ao.w);
+ float b = abs(ao.y - ao.z);
+
+ return a > b;
+}
+
+float get_ao(uint data, uint face)
+{
+ vec4 ao;
+
+ ao.x = (data >> 0) & 3u;
+ ao.y = (data >> 2) & 3u;
+ ao.z = (data >> 4) & 3u;
+ ao.w = (data >> 6) & 3u;
+
+ switch (face) {
+ case 0u: // PX
+ case 2u: // PY
+ case 4u: // PZ
+ ao = ao.xywz;
+ if (get_ao_rotate(data))
+ ao = ao.wxyz;
+ break;
+ case 1u: // NX
+ case 3u: // NY
+ case 5u: // NZ
+ if (get_ao_rotate(data))
+ ao = ao.ywxz;
+ ao = ao.wzxy;
+ break;
+ }
+
+ return ao[gl_VertexID];
+}
+
+vec3 rotate(vec3 v, uint face)
+{
+ switch(face) {
+ case 0u: // PX
+ case 1u: // NX
+ v = vec3(v.x, v.z, -v.y + 1);
+ break;
+ case 2u: // PY
+ case 3u: // NY
+ v = vec3(-v.z + 1, v.y, v.x);
+ break;
+ case 4u: // PZ
+ case 5u: // NZ
+ v = vec3(v.y, -v.x + 1, v.z);
+ break;
+ }
+
+ return v;
+}
+
vec3 get_quad(uint face, uint width, uint height)
{
- vec3 squad = quad;
- squad.x *= width;
- squad.y *= height;
+ vec3 quad = in_quad;
+ quad.x *= width;
+ quad.y *= height;
switch(face) {
case 0u: // PX
- return squad.yzx + vec3(1, 0, 0);
+ quad = quad.yzx + vec3(1, 0, 0);
+ break;
case 1u: // NX
- return squad.yxz;
+ quad = quad.yxz;
+ break;
case 2u: // PY
- return squad.xyz + vec3(0, 1, 0);
+ quad = quad.xyz + vec3(0, 1, 0);
+ break;
case 3u: // NY
- return squad.zyx;
+ quad = quad.zyx;
+ break;
case 4u: // PZ
- return squad.zxy + vec3(0, 0, 1);
+ quad = quad.zxy + vec3(0, 0, 1);
+ break;
case 5u: // NZ
- return squad.xzy;
+ quad = quad.xzy;
+ break;
}
- // should not happen
- return vec3(0);
+
+ return quad;
}
void main(void)
@@ -71,6 +148,8 @@ void main(void)
// get quad verts
vec3 quad = get_quad(face, width, height);
+ if (get_ao_rotate(data.y))
+ quad = rotate(quad, face);
// get position
vec3 position = vec3(x, y, z);
@@ -79,5 +158,8 @@ void main(void)
// draw
gl_Position = proj * view * vec4(position, 1.0);
+
+ // fragment input
pass_data = data;
+ pass_ao = get_ao(data.y, face);
}
diff --git a/src/chunk.c b/src/chunk.c
index f142788..8610a25 100644
--- a/src/chunk.c
+++ b/src/chunk.c
@@ -59,7 +59,7 @@ void chunk_generate(Chunk *chunk, seed_t seed)
typedef struct {
List data;
- RcChunk *rc_chunks[7];
+ RcChunk *rc_chunks[27];
} MeshState;
typedef union {
@@ -71,7 +71,11 @@ typedef union {
u64 height : 5;
u64 face : 3;
u64 block : 4;
- u64 : 32;
+ u64 ao0 : 2;
+ u64 ao1 : 2;
+ u64 ao2 : 2;
+ u64 ao3 : 2;
+ u64 : 24;
};
u64 raw;
} Quad;
@@ -84,20 +88,20 @@ static void mesh_state_init(MeshState *state, World *world, Chunk *chunk)
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);
+ for (int i = 0; i < 27; i++) {
+ int x_off = ((i / 1) % 3) - 1;
+ int z_off = ((i / 3) % 3) - 1;
+ int y_off = ((i / 9) % 3) - 1;
+
+ state->rc_chunks[i] = world_get_chunk(world, cx + x_off, cy + y_off, cz + z_off);
+ }
list_init_u64(&state->data);
}
static void mesh_state_free(MeshState *state)
{
- for (i32 i = 0; i < 7; i++) {
+ for (i32 i = 0; i < 27; i++) {
RcChunk *rc_chunk = state->rc_chunks[i];
if (rc_chunk != NULL)
rcchunk_drop(rc_chunk);
@@ -106,28 +110,37 @@ static void mesh_state_free(MeshState *state)
list_free(&state->data);
}
-static Block mesh_state_get_block(MeshState *state, i32 lx, i32 ly, i32 lz)
+static Block mesh_state_get_block(MeshState *state, const ivec3 xyz)
{
RcChunk *rc_chunk;
- i32 index = 0;
+ i32 index, lx, ly, lz;
+
+ index = 13;
+ lx = xyz[0];
+ ly = xyz[1];
+ lz = xyz[2];
if (lx < 0) {
- index = 1;
+ index -= 1;
lx += CHUNK_SIZE;
} else if (lx >= CHUNK_SIZE) {
- index = 2;
+ index += 1;
lx -= CHUNK_SIZE;
- } else if (ly < 0) {
- index = 3;
+ }
+
+ if (ly < 0) {
+ index -= 9;
ly += CHUNK_SIZE;
} else if (ly >= CHUNK_SIZE) {
- index = 4;
+ index += 9;
ly -= CHUNK_SIZE;
- } else if (lz < 0) {
- index = 5;
+ }
+
+ if (lz < 0) {
+ index -= 3;
lz += CHUNK_SIZE;
} else if (lz >= CHUNK_SIZE) {
- index = 6;
+ index += 3;
lz -= CHUNK_SIZE;
}
@@ -138,7 +151,8 @@ static Block mesh_state_get_block(MeshState *state, i32 lx, i32 ly, i32 lz)
return chunk_at(&rc_chunk->chunk, lx, ly, lz);
}
-static void add_quad(MeshState *state, const ivec3 xyz, Face face, Block block)
+static void add_quad(MeshState *state, const ivec3 xyz, Face face, Block block,
+ u8 occlusion[4])
{
Quad quad = { 0 };
quad.x = xyz[0];
@@ -148,10 +162,90 @@ static void add_quad(MeshState *state, const ivec3 xyz, Face face, Block block)
quad.height = 1;
quad.face = face;
quad.block = block;
+ quad.ao0 = occlusion[0];
+ quad.ao1 = occlusion[1];
+ quad.ao2 = occlusion[2];
+ quad.ao3 = occlusion[3];
list_push_u64(&state->data, quad.raw);
}
+static void mesh_get_ao(MeshState *state, ivec3 xyz, u32 face, u8 out[4])
+{
+ Face perpendicular[2];
+ ivec3 other, u, v, vecs[8];
+ u8 occluded[8];
+
+ face_to_vec(face, other);
+ glm_ivec3_add(xyz, other, other);
+
+ face_perpendicular(face, perpendicular);
+ face_to_vec(perpendicular[0], u);
+ face_to_vec(perpendicular[1], v);
+
+ // 0: u
+ glm_ivec3_add(other, u, vecs[0]);
+ // 1: -u
+ glm_ivec3_sub(other, u, vecs[1]);
+ // 2: v
+ glm_ivec3_add(other, v, vecs[2]);
+ // 3: -v
+ glm_ivec3_sub(other, v, vecs[3]);
+ // 4: u + v
+ glm_ivec3_add(other, u, vecs[4]);
+ glm_ivec3_add(vecs[4], v, vecs[4]);
+ // 5: u - v
+ glm_ivec3_add(other, u, vecs[5]);
+ glm_ivec3_sub(vecs[5], v, vecs[5]);
+ // 6: -u + v
+ glm_ivec3_sub(other, u, vecs[6]);
+ glm_ivec3_add(vecs[6], v, vecs[6]);
+ // 7: -u - v
+ glm_ivec3_sub(other, u, vecs[7]);
+ glm_ivec3_sub(vecs[7], v, vecs[7]);
+
+ occluded[0] = (mesh_state_get_block(state, vecs[0]) != AIR) * 2;
+ occluded[1] = (mesh_state_get_block(state, vecs[1]) != AIR) * 2;
+ occluded[2] = (mesh_state_get_block(state, vecs[2]) != AIR) * 2;
+ occluded[3] = (mesh_state_get_block(state, vecs[3]) != AIR) * 2;
+ occluded[4] = mesh_state_get_block(state, vecs[4]) != AIR;
+ occluded[5] = mesh_state_get_block(state, vecs[5]) != AIR;
+ occluded[6] = mesh_state_get_block(state, vecs[6]) != AIR;
+ occluded[7] = mesh_state_get_block(state, vecs[7]) != AIR;
+
+ // u + v
+ out[0] = occluded[0] + occluded[2] + occluded[4];
+ // u - v
+ out[1] = occluded[0] + occluded[3] + occluded[5];
+ // -u + v
+ out[2] = occluded[1] + occluded[2] + occluded[6];
+ // -u - v
+ out[3] = occluded[1] + occluded[3] + occluded[7];
+
+ for (u32 i = 0; i < 4; i++)
+ out[i] = (out[i] * 2 + 1) / 3;
+}
+
+static void mesh_face(MeshState *state, ivec3 xyz, Block block, u32 face)
+{
+ u8 occlusion[4];
+ ivec3 other;
+ Block temp;
+
+ face_to_vec(face, other);
+ glm_ivec3_add(xyz, other, other);
+
+ // cull check
+ temp = mesh_state_get_block(state, other);
+ if (temp != AIR)
+ return;
+
+ // ambient occlusion
+ mesh_get_ao(state, xyz, face, occlusion);
+
+ add_quad(state, xyz, face, block, occlusion);
+}
+
void chunk_mesh(Chunk *chunk, World *world)
{
MeshState state;
@@ -172,25 +266,12 @@ void chunk_mesh(Chunk *chunk, World *world)
if (block == AIR)
continue;
- 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);
- if (nx == AIR)
- add_quad(&state, xyz, NEG_X, block);
- if (py == AIR)
- add_quad(&state, xyz, POS_Y, block);
- if (ny == AIR)
- add_quad(&state, xyz, NEG_Y, block);
- if (pz == AIR)
- add_quad(&state, xyz, POS_Z, block);
- if (nz == AIR)
- add_quad(&state, xyz, NEG_Z, block);
+ mesh_face(&state, xyz, block, POS_X);
+ mesh_face(&state, xyz, block, NEG_X);
+ mesh_face(&state, xyz, block, POS_Y);
+ mesh_face(&state, xyz, block, NEG_Y);
+ mesh_face(&state, xyz, block, POS_Z);
+ mesh_face(&state, xyz, block, NEG_Z);
}
if (chunk->has_mesh)
diff --git a/src/gl.h b/src/gl.h
index 58809c9..6ee98b4 100644
--- a/src/gl.h
+++ b/src/gl.h
@@ -13,6 +13,7 @@
typedef struct {
u32 vao;
+ u32 ebo;
u32 vbos[MAX_VBOS];
i32 vbos_count;
i32 vertex_count;
@@ -23,6 +24,7 @@ void mesh_store_float(Mesh *mesh, float *data, u32 count, u32 dimensions);
void mesh_store_i32(Mesh *mesh, i32 *data, u32 count, u32 dimensions);
void mesh_store_u8(Mesh *mesh, u8 *data, u32 count, u32 dimensions);
void mesh_store_u32(Mesh *mesh, u32 *data, u32 count, u32 dimensions);
+void mesh_store_indicies(Mesh *mesh, u16 *data, u32 count);
void mesh_finish(void);
void mesh_bind(Mesh *mesh);
void mesh_unbind(Mesh *mesh);
diff --git a/src/main.c b/src/main.c
index ce01357..0edc5fb 100644
--- a/src/main.c
+++ b/src/main.c
@@ -7,6 +7,8 @@
World world;
Camera camera;
+_Atomic bool loaded;
+
void sleep(double seconds)
{
struct timespec req, rem;
@@ -26,10 +28,12 @@ VOXEL_RESULT render_main(void *)
Renderer renderer;
if (window_init_gl() != VOXEL_OK)
- return VOXEL_ERROR;
+ goto error;
if (renderer_init(&renderer) != VOXEL_OK)
- return VOXEL_ERROR;
+ goto error;
+
+ loaded = true;
while (!window_closed()) {
if (window.resize) {
@@ -46,6 +50,11 @@ VOXEL_RESULT render_main(void *)
renderer_free(&renderer);
return VOXEL_OK;
+
+error:
+ window_close();
+ loaded = true;
+ return VOXEL_ERROR;
}
#define TPS 20
@@ -57,6 +66,9 @@ VOXEL_RESULT logic_main(void *)
last_tick = 0;
next_tick = 0;
+ while (!loaded)
+ ;
+
while (!window_closed()) {
world_update(&world, &camera);
@@ -75,13 +87,14 @@ VOXEL_RESULT input_main(void *)
last_tick = 0;
next_tick = 0;
+ while (!loaded)
+ ;
+
while (!window_closed()) {
window_update();
- if (key_down(GLFW_KEY_ESCAPE)) {
- window.close = true;
- break;
- }
+ if (key_down(GLFW_KEY_ESCAPE))
+ window_close();
camera_update(&camera);
@@ -96,6 +109,7 @@ VOXEL_RESULT input_main(void *)
VOXEL_RESULT main(void)
{
thrd_t render_thread, logic_thread, input_thread;
+ loaded = false;
if (window_init() != VOXEL_OK)
return VOXEL_ERROR;
@@ -112,7 +126,7 @@ VOXEL_RESULT main(void)
thrd_join(render_thread, NULL);
world_free(&world);
- window_close();
+ window_free();
return VOXEL_OK;
}
diff --git a/src/math.c b/src/math.c
new file mode 100644
index 0000000..ecba107
--- /dev/null
+++ b/src/math.c
@@ -0,0 +1,77 @@
+#include "voxel.h"
+
+void face_to_vec(Face face, ivec3 out)
+{
+ glm_ivec3_zero(out);
+
+ switch (face) {
+ case POS_X:
+ out[0] = 1;
+ break;
+ case NEG_X:
+ out[0] = -1;
+ break;
+ case POS_Y:
+ out[1] = 1;
+ break;
+ case NEG_Y:
+ out[1] = -1;
+ break;
+ case POS_Z:
+ out[2] = 1;
+ break;
+ case NEG_Z:
+ out[2] = -1;
+ break;
+ }
+}
+
+Face face_opposite(Face face)
+{
+ switch (face) {
+ case POS_X:
+ return NEG_X;
+ case NEG_X:
+ return POS_X;
+ case POS_Y:
+ return NEG_Y;
+ case NEG_Y:
+ return POS_Y;
+ case POS_Z:
+ return NEG_Z;
+ case NEG_Z:
+ return POS_Z;
+ }
+
+ return 0;
+}
+
+void face_perpendicular(Face face, Face out[2])
+{
+ switch (face) {
+ case POS_X:
+ out[0] = NEG_Z;
+ out[1] = NEG_Y;
+ break;
+ case NEG_X:
+ out[0] = POS_Y;
+ out[1] = POS_Z;
+ break;
+ case POS_Y:
+ out[0] = NEG_X;
+ out[1] = NEG_Z;
+ break;
+ case NEG_Y:
+ out[0] = POS_Z;
+ out[1] = POS_X;
+ break;
+ case POS_Z:
+ out[0] = NEG_Y;
+ out[1] = NEG_X;
+ break;
+ case NEG_Z:
+ out[0] = POS_X;
+ out[1] = POS_Y;
+ break;
+ }
+}
diff --git a/src/mesh.c b/src/mesh.c
index 2ffe61b..2c3d040 100644
--- a/src/mesh.c
+++ b/src/mesh.c
@@ -7,6 +7,7 @@ void mesh_init(Mesh *mesh, u32 vertex_count)
glGenVertexArrays(1, &mesh->vao);
mesh->vbos_count = 0;
mesh->vertex_count = vertex_count;
+ mesh->ebo = 0;
glBindVertexArray(mesh->vao);
}
@@ -16,7 +17,7 @@ static void mesh_store(Mesh *mesh, void *data, u32 len, u32 dimensions, GLenum t
GLint index = mesh->vbos_count;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
- glBufferData(GL_ARRAY_BUFFER, len, data, GL_STATIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, len * dimensions, data, GL_STATIC_DRAW);
glEnableVertexAttribArray(index);
if (type == GL_FLOAT)
glVertexAttribPointer(index, dimensions, type, GL_FALSE, 0, 0);
@@ -45,6 +46,17 @@ void mesh_store_u32(Mesh *mesh, u32 *data, u32 count, u32 dimensions)
mesh_store(mesh, data, count * sizeof(u32), dimensions, GL_UNSIGNED_INT);
}
+void mesh_store_indicies(Mesh *mesh, u16 *data, u32 count)
+{
+ GLuint ebo;
+ u32 len;
+ len = count * sizeof(u16);
+ glGenBuffers(1, &ebo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, len, data, GL_STATIC_DRAW);
+ mesh->ebo = ebo;
+}
+
void mesh_finish(void)
{
glBindVertexArray(0);
@@ -66,18 +78,27 @@ void mesh_unbind(Mesh *mesh)
void mesh_draw(Mesh *mesh)
{
- glDrawArrays(GL_TRIANGLES, 0, mesh->vertex_count);
+ if (mesh->ebo)
+ glDrawElements(GL_TRIANGLES, mesh->vertex_count, GL_UNSIGNED_SHORT, NULL);
+ else
+ glDrawArrays(GL_TRIANGLES, 0, mesh->vertex_count);
}
void mesh_draw_instanced(Mesh *mesh, u32 count)
{
- glDrawArraysInstanced(GL_TRIANGLES, 0, mesh->vertex_count, count);
+ if (mesh->ebo)
+ glDrawElementsInstanced(GL_TRIANGLES, mesh->vertex_count, GL_UNSIGNED_SHORT, NULL,
+ count);
+ else
+ glDrawArraysInstanced(GL_TRIANGLES, 0, mesh->vertex_count, count);
}
void mesh_free(Mesh *mesh)
{
glDeleteBuffers(mesh->vbos_count, mesh->vbos);
glDeleteVertexArrays(1, &mesh->vao);
+ if (mesh->ebo)
+ glDeleteBuffers(1, &mesh->ebo);
}
void uniform_init(Uniform *uniform, u32 len)
diff --git a/src/render.c b/src/render.c
index b70832b..77c0bd8 100644
--- a/src/render.c
+++ b/src/render.c
@@ -10,10 +10,12 @@ VOXEL_RESULT renderer_init(Renderer *renderer)
{
// load quad mesh
float quad_verts[] = {
- 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0,
};
+ u16 quad_indicies[] = { 0, 1, 2, 0, 2, 3 };
mesh_init(&renderer->quad, 6);
- mesh_store_float(&renderer->quad, quad_verts, 6 * 3, 3);
+ mesh_store_float(&renderer->quad, quad_verts, 4, 3);
+ mesh_store_indicies(&renderer->quad, quad_indicies, 6);
mesh_finish();
// load shader
diff --git a/src/shader.c b/src/shader.c
index abb62a2..a0da573 100644
--- a/src/shader.c
+++ b/src/shader.c
@@ -173,7 +173,6 @@ failure:
free(vertex);
if (fragment)
free(fragment);
- free(shader);
return GL_ERROR;
}
diff --git a/src/voxel.h b/src/voxel.h
index 12480b2..bba2c44 100644
--- a/src/voxel.h
+++ b/src/voxel.h
@@ -24,7 +24,7 @@
#define VOXEL_FALSE 1
#define VOXEL_RESULT int
-typedef enum : char {
+typedef enum : u8 {
POS_X = 0,
NEG_X = 1,
POS_Y = 2,
@@ -33,7 +33,11 @@ typedef enum : char {
NEG_Z = 5,
} Face;
-typedef enum : char { AIR = 0, A, B, C, D } Block;
+void face_to_vec(Face face, ivec3 out);
+Face face_opposite(Face face);
+void face_perpendicular(Face face, Face out[2]);
+
+typedef enum : u8 { AIR = 0, A, B, C, D } Block;
#define CHUNK_SIZE 16
#define CHUNK_BLOCKS CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE
diff --git a/src/window.c b/src/window.c
index 559dcc2..d43ba12 100644
--- a/src/window.c
+++ b/src/window.c
@@ -132,6 +132,11 @@ void window_swap(void)
void window_close(void)
{
+ window.close = true;
+}
+
+void window_free(void)
+{
mtx_lock(&window.lock);
glfwDestroyWindow(window.window);
glfwTerminate();
diff --git a/src/window.h b/src/window.h
index 5fc3197..c9de8ac 100644
--- a/src/window.h
+++ b/src/window.h
@@ -43,6 +43,7 @@ bool window_closed(void);
void window_update(void);
void window_swap(void);
void window_close(void);
+void window_free(void);
bool key_down(i32 key);
bool key_pressed(i32 key);
diff --git a/src/world.c b/src/world.c
index a53055d..0be9a85 100644
--- a/src/world.c
+++ b/src/world.c
@@ -110,10 +110,10 @@ void world_free(World *world)
int size = side * side * side;
world_lock(world);
for (int i = 0; i < size; i++) {
- RcChunk **entry = &world->chunks[i];
- if (entry == NULL)
+ RcChunk *rc_chunk = world->chunks[i];
+ if (rc_chunk == NULL)
continue;
- rcchunk_drop(*entry);
+ rcchunk_drop(rc_chunk);
}
free(world->chunks);
mtx_destroy(&world->lock);