summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
11 files changed, 264 insertions, 58 deletions
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);