#include #include #include "utils.h" #include "voxel.h" #include "list.h" #include "gl.h" #include "noise.h" void chunk_init(Chunk *chunk, i32 x, i32 y, i32 z) { chunk->blocks = xzalloc(sizeof(Block) * CHUNK_BLOCKS); chunk->pos[0] = x; chunk->pos[1] = y; chunk->pos[2] = z; chunk->state = CHUNK_NEW; chunk->has_mesh = false; } void chunk_free(Chunk *chunk) { if (chunk->state >= CHUNK_MESHED) uniform_free(&chunk->mesh); free(chunk->blocks); } void chunk_generate(Chunk *chunk, seed_t seed) { fnl_state noise; if (chunk->state != CHUNK_NEW) return; chunk->state = CHUNK_GENERATING; noise = fnlCreateState(); noise.seed = seed; noise.noise_type = FNL_NOISE_PERLIN; for (i32 i = 0; i < CHUNK_BLOCKS; i++) { i32 lx = i % CHUNK_SIZE; i32 lz = (i / CHUNK_SIZE) % CHUNK_SIZE; i32 ly = i / (CHUNK_SIZE * CHUNK_SIZE); i32 gx = lx + chunk->pos[0] * CHUNK_SIZE; i32 gy = ly + chunk->pos[1] * CHUNK_SIZE; i32 gz = lz + chunk->pos[2] * CHUNK_SIZE; double data = fnlGetNoise3D(&noise, gx, gy, gz); data -= gy * 0.01; if (data < 0.1) continue; chunk->blocks[i] = A; } chunk->state = CHUNK_GENERATED; } typedef struct { List data; RcChunk *rc_chunks[7]; } MeshState; typedef union { struct { u64 x : 5; u64 y : 5; u64 z : 5; u64 width : 5; u64 height : 5; u64 face : 3; u64 block : 4; u64 : 32; }; u64 raw; } Quad; static void mesh_state_init(MeshState *state, World *world, Chunk *chunk) { i32 cx, cy, cz; cx = chunk->pos[0]; 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); list_init_u64(&state->data); } static void mesh_state_free(MeshState *state) { for (i32 i = 0; i < 7; i++) { RcChunk *rc_chunk = state->rc_chunks[i]; if (rc_chunk != NULL) rcchunk_drop(rc_chunk); } list_free(&state->data); } static Block mesh_state_get_block(MeshState *state, i32 lx, i32 ly, i32 lz) { RcChunk *rc_chunk; i32 index = 0; if (lx < 0) { index = 1; lx += CHUNK_SIZE; } else if (lx >= CHUNK_SIZE) { index = 2; lx -= CHUNK_SIZE; } else if (ly < 0) { index = 3; ly += CHUNK_SIZE; } else if (ly >= CHUNK_SIZE) { index = 4; ly -= CHUNK_SIZE; } else if (lz < 0) { index = 5; lz += CHUNK_SIZE; } else if (lz >= CHUNK_SIZE) { index = 6; lz -= CHUNK_SIZE; } rc_chunk = state->rc_chunks[index]; if (rc_chunk == NULL) return AIR; return chunk_at(&rc_chunk->chunk, lx, ly, lz); } static void add_quad(MeshState *state, const ivec3 xyz, Face face, Block block) { Quad quad = { 0 }; quad.x = xyz[0]; quad.y = xyz[1]; quad.z = xyz[2]; quad.width = 1; quad.height = 1; quad.face = face; quad.block = block; list_push_u64(&state->data, quad.raw); } void chunk_mesh(Chunk *chunk, World *world) { MeshState state; if (chunk->state != CHUNK_GENERATED) return; chunk->state = CHUNK_MESHING; mesh_state_init(&state, world, chunk); for (i32 i = 0; i < CHUNK_BLOCKS; i++) { i32 lx = i % CHUNK_SIZE; i32 lz = (i / CHUNK_SIZE) % CHUNK_SIZE; i32 ly = i / (CHUNK_SIZE * CHUNK_SIZE); ivec3 xyz = { lx, ly, lz }; Block block = chunk->blocks[i]; 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); } if (chunk->has_mesh) uniform_free(&chunk->mesh); Uniform uniform; uniform_init(&uniform, state.data.len * sizeof(Quad)); uniform_store(&uniform, 0, state.data.len * sizeof(Quad), state.data.data); mesh_state_free(&state); chunk->mesh = uniform; chunk->has_mesh = true; chunk->state = CHUNK_MESHED; } Block chunk_at(Chunk *chunk, i32 x, i32 y, i32 z) { if (x < 0 || x >= CHUNK_SIZE) return AIR; if (y < 0 || y >= CHUNK_SIZE) return AIR; if (z < 0 || z >= CHUNK_SIZE) return AIR; i32 i = 0; i += x; i += z * CHUNK_SIZE; i += y * CHUNK_SIZE * CHUNK_SIZE; return chunk->blocks[i]; } AABB chunk_aabb(Chunk *chunk) { AABB aabb = { 0 }; // min aabb.min[0] = chunk->pos[0] * CHUNK_SIZE; aabb.min[1] = chunk->pos[1] * CHUNK_SIZE; aabb.min[2] = chunk->pos[2] * CHUNK_SIZE; // max glm_vec3_adds(aabb.min, CHUNK_SIZE, aabb.max); return aabb; }