summaryrefslogtreecommitdiff
path: root/src/chunk.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/chunk.c')
-rw-r--r--src/chunk.c161
1 files changed, 121 insertions, 40 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)