diff options
Diffstat (limited to 'src/chunk.c')
| -rw-r--r-- | src/chunk.c | 161 |
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) |