diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/chunk.c | 161 | ||||
| -rw-r--r-- | src/gl.h | 2 | ||||
| -rw-r--r-- | src/main.c | 28 | ||||
| -rw-r--r-- | src/math.c | 77 | ||||
| -rw-r--r-- | src/mesh.c | 27 | ||||
| -rw-r--r-- | src/render.c | 6 | ||||
| -rw-r--r-- | src/shader.c | 1 | ||||
| -rw-r--r-- | src/voxel.h | 8 | ||||
| -rw-r--r-- | src/window.c | 5 | ||||
| -rw-r--r-- | src/window.h | 1 | ||||
| -rw-r--r-- | src/world.c | 6 |
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) @@ -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); @@ -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; + } +} @@ -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); |