summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author0undefined <oscar@nelin.dk>2026-03-03 01:17:23 +0000
committer0undefined <oscar@nelin.dk>2026-03-03 01:17:23 +0000
commite57736f1b3bf1cc2f46276bdba3b62b7b6365ff7 (patch)
treee99a64a960e58c7f04dc3ffd7dda6972f06a47db
parenteef15506347455593d0daf1159eaa1b2c5097802 (diff)
Cull blocks
-rw-r--r--include/worldgen.h81
-rw-r--r--state_mainstate/include/states/mainstate.h2
-rw-r--r--state_mainstate/src/mainstate.c15
-rw-r--r--state_mainstate/src/worldgen.c221
4 files changed, 297 insertions, 22 deletions
diff --git a/include/worldgen.h b/include/worldgen.h
index 9095906..e1c0025 100644
--- a/include/worldgen.h
+++ b/include/worldgen.h
@@ -16,24 +16,83 @@ extern "C" {
// World size is defined in terms of number of chunks. Chunks are not stacked
// vertically
-#define WORLD_WIDTH 4
-#define WORLD_LENGTH 4
+#define WORLD_WIDTH 16
+#define WORLD_LENGTH 16
#define WORLD_SIZE (WORLD_LENGTH * WORLD_WIDTH)
-// first 4 bits for material type, 16 types in total
+// first 5 bits for material type
#define BLOCK_none 0
-#define BLOCK_grass 1
-#define BLOCK_rock 2
+#define BLOCK_dirt 1
+#define BLOCK_grass 2
+#define BLOCK_rock 3
+#define BLOCK_ore 4
+// ... Room for 32 in total
// next 4 bits for shape type
-#define SHAPE_none (0 << 4)
-#define SHAPE_slope_north (1 << 4)
-#define SHAPE_slope_east (2 << 4)
-#define SHAPE_slope_south (3 << 4)
-#define SHAPE_slope_west (4 << 4)
+//#define SHAPE_none (0 << 4)
+//#define SHAPE_slope_north (1 << 4)
+//#define SHAPE_slope_east (2 << 4)
+//#define SHAPE_slope_south (3 << 4)
+//#define SHAPE_slope_west (4 << 4)
+// ... Room for 16 in total
-void gen_terrain(u8 *world);
+
+// 24 bits for storing neighbouring blocks
+// Used for kernel operations
+
+#define FILLED_TOP_NW (1 << 5)
+#define FILLED_TOP_N (1 << 6)
+#define FILLED_TOP_NE (1 << 7)
+#define FILLED_TOP_W (1 << 8)
+#define FILLED_TOP_C (1 << 8)
+#define FILLED_TOP_E (1 << 9)
+#define FILLED_TOP_SW (1 << 10)
+#define FILLED_TOP_S (1 << 11)
+#define FILLED_TOP_SE (1 << 12)
+
+#define FILLED_NW (1 << 13)
+#define FILLED_N (1 << 14)
+#define FILLED_NE (1 << 15)
+#define FILLED_W (1 << 16)
+#define FILLED_C (1 << 16)
+#define FILLED_E (1 << 17)
+#define FILLED_SW (1 << 18)
+#define FILLED_S (1 << 19)
+#define FILLED_SE (1 << 20)
+
+#define FILLED_BOT_NW (1 << 21)
+#define FILLED_BOT_N (1 << 22)
+#define FILLED_BOT_NE (1 << 23)
+#define FILLED_BOT_W (1 << 24)
+#define FILLED_BOT_C (1 << 24)
+#define FILLED_BOT_E (1 << 25)
+#define FILLED_BOT_SW (1 << 26)
+#define FILLED_BOT_S (1 << 27)
+#define FILLED_BOT_SE (1 << 28)
+
+// 0b11111 aka. 31 or 2**5
+#define FILLED_MASK_TOP (u32)(\
+ FILLED_TOP_NW | FILLED_TOP_N | FILLED_TOP_NE | \
+ FILLED_TOP_W | FILLED_TOP_C | FILLED_TOP_E | \
+ FILLED_TOP_SW | FILLED_TOP_S | FILLED_TOP_SE \
+)
+#define FILLED_MASK (u32)(\
+ FILLED_NW | FILLED_N | FILLED_NE | \
+ FILLED_W | FILLED_C | FILLED_E | \
+ FILLED_SW | FILLED_S | FILLED_SE \
+)
+#define FILLED_MASK_BOT (u32)(\
+ FILLED_BOT_NW | FILLED_BOT_N | FILLED_BOT_NE | \
+ FILLED_BOT_W | FILLED_BOT_C | FILLED_BOT_E | \
+ FILLED_BOT_SW | FILLED_BOT_S | FILLED_BOT_SE \
+)
+
+#define FILLED_MASK_ALL (u32)(~((1 << 5) - 1))
+
+#define SURROUNDED(x) ((x & FILLED_MASK_ALL) == FILLED_MASK_ALL)
+
+void gen_terrain(u32 *world);
#ifdef __cplusplus
diff --git a/state_mainstate/include/states/mainstate.h b/state_mainstate/include/states/mainstate.h
index 5f04a84..486e468 100644
--- a/state_mainstate/include/states/mainstate.h
+++ b/state_mainstate/include/states/mainstate.h
@@ -16,7 +16,7 @@ typedef struct mainstate_state {
Shader shaders[10];
RenderBatch terrain;
RenderObject objects[10];
- u8 world[WORLD_SIZE * CHUNK_SIZE];
+ u32 world[WORLD_SIZE * CHUNK_SIZE];
i_ctx input_ctx;
binding_t input_bindings[10];
vec3 cam_dir;
diff --git a/state_mainstate/src/mainstate.c b/state_mainstate/src/mainstate.c
index fc3a2a8..172f3a7 100644
--- a/state_mainstate/src/mainstate.c
+++ b/state_mainstate/src/mainstate.c
@@ -261,7 +261,7 @@ void mainstate_init(Window *restrict w, mainstate_state *state, void* arg) {
/// Setup the camera
// Set the position (it is zero initialized)
- glm_vec3_copy((vec3){CHUNK_WIDTH / 2.f, CHUNK_HEIGHT / 4.f + 4.f, CHUNK_LENGTH / 2.f}, state->c.pos);
+ glm_vec3_copy((vec3){CHUNK_WIDTH * WORLD_WIDTH / 2.f, CHUNK_HEIGHT / 4.f + 4.f, CHUNK_LENGTH * WORLD_LENGTH / 2.f}, state->c.pos);
// Copy to the desired position
glm_vec3_copy(state->c.pos, state->cam_pos);
@@ -330,6 +330,8 @@ void mainstate_init(Window *restrict w, mainstate_state *state, void* arg) {
}
gen_terrain(state->world);
+ usize total = 0;
+ usize culled = 0;
for (isize i = 0; i < WORLD_SIZE * CHUNK_SIZE; i++) {
if (state->world[i] == BLOCK_none) continue;
@@ -349,7 +351,14 @@ void mainstate_init(Window *restrict w, mainstate_state *state, void* arg) {
Transform t = {
.position = {(float)x, (float)y, (float)z},
};
- switch (state->world[i]) {
+ if (state->world[i] & ((1 << 5) - 1)) {
+ total++;
+ }
+ if (SURROUNDED(state->world[i])) {
+ culled++;
+ continue;
+ }
+ switch (state->world[i] & ((1 << 5) - 1)) {
case BLOCK_grass:
if (-1 == renderbatch_add(&(state->terrain), &(state->objects[0]), &t)) {
ERROR("Failed to add model 0 to render batch!");
@@ -366,6 +375,8 @@ void mainstate_init(Window *restrict w, mainstate_state *state, void* arg) {
}
}
+ INFO("Culled %u / %u (%.2f)", culled, total, (float)culled / (float)total);
+
// Create the render object from the buffer
renderbatch_refresh(&(state->terrain));
state->terrain.renderobj = RenderObject_new(
diff --git a/state_mainstate/src/worldgen.c b/state_mainstate/src/worldgen.c
index 6e5b9c1..51ed21a 100644
--- a/state_mainstate/src/worldgen.c
+++ b/state_mainstate/src/worldgen.c
@@ -44,28 +44,39 @@ static usize global_idx(ivec3 pos) {
}
// Chunks are laid out in worldspace as [c1, ..., cN]
-static void gen_chunk(u8 *chunk, usize z, usize x) {
+static void gen_chunk(u32 *chunk, usize z, usize x) {
// Flat chunks
for (usize yy = 0; yy < CHUNK_HEIGHT / 4; yy++) {
for (usize zz = 0; zz < CHUNK_LENGTH; zz++) {
for (usize xx = 0; xx < CHUNK_WIDTH; xx++) {
- chunk[yy * CHUNK_LENGTH * CHUNK_WIDTH
- + zz * CHUNK_WIDTH
- + xx] = BLOCK_grass;
+ ivec3 pos = {xx,yy,zz};
+ chunk[global_idx(pos)] = BLOCK_grass;
+ //chunk[yy * CHUNK_LENGTH * CHUNK_WIDTH
+ // + zz * CHUNK_WIDTH
+ // + xx] = BLOCK_grass;
}
}
}
+ for (usize zz = 0; zz < CHUNK_LENGTH; zz++) {
+ for (usize xx = 0; xx < CHUNK_WIDTH; xx++) {
+ if (zz % 2 != 0) continue;
+ if (xx % 2 != 0) continue;
+ chunk[(CHUNK_HEIGHT / 4 + 0) * CHUNK_LENGTH * CHUNK_WIDTH
+ + zz * CHUNK_WIDTH
+ + xx] = BLOCK_rock;
+ }
+ }
}
-void gen_terrain(u8 *world) {
+void gen_terrain(u32 *world) {
if (world == NULL) {
world = calloc(WORLD_SIZE * CHUNK_SIZE, sizeof(u8));
}
- for (usize z = 0; z < WORLD_WIDTH; z++) {
- for (usize x = 0; x < WORLD_LENGTH; x++) {
+ for (usize z = 0; z < WORLD_LENGTH; z++) {
+ for (usize x = 0; x < WORLD_WIDTH; x++) {
gen_chunk(&world[
- z * WORLD_LENGTH * CHUNK_SIZE
+ z * WORLD_WIDTH * CHUNK_SIZE
+ x * CHUNK_SIZE
], z, x);
}
@@ -97,4 +108,198 @@ void gen_terrain(u8 *world) {
world[global_idx(pos)] = BLOCK_none;
pos[1]++;
world[global_idx(pos)] = BLOCK_none;
+
+
+ // Mask everything
+ for (usize z = 0; z < WORLD_LENGTH; z++) {
+ for (usize x = 0; x < WORLD_WIDTH; x++) {
+
+ u32 * restrict chunk = &world[
+ z * WORLD_WIDTH * CHUNK_SIZE
+ + x * CHUNK_SIZE
+ ];
+
+ for (isize yy = 0; yy < CHUNK_HEIGHT; yy++) {
+ for (isize zz = 0; zz < CHUNK_LENGTH; zz++) {
+ for (isize xx = 0; xx < CHUNK_WIDTH; xx++) {
+
+ u32 mask = 0;
+
+ // TODO: Fix OOB access
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ for (int k = 0; k < 3; k++) {
+ if (i == 0 && yy - 1 < 0) continue;
+ if (j == 0 && zz - 1 < 0) continue;
+ if (k == 0 && xx - 1 < 0) continue;
+ if (i == 2 && yy + 1 >= CHUNK_HEIGHT) continue;
+ if (j == 2 && zz + 1 >= CHUNK_LENGTH) continue;
+ if (k == 2 && xx + 1 >= CHUNK_WIDTH) continue;
+
+ if (
+ chunk[(i + yy - 1) * CHUNK_LENGTH * CHUNK_WIDTH
+ + (j + zz - 1) * CHUNK_WIDTH
+ + (k + xx - 1)] & ((1 << 5) - 1)
+ ) {
+ mask |= 1 << ((i * 9) + j * 3 + k);
+ }
+ }
+ }
+ }
+
+ if (yy == 0) {
+ mask |= FILLED_MASK_BOT;
+ }
+ chunk[yy * CHUNK_LENGTH * CHUNK_WIDTH
+ + zz * CHUNK_WIDTH
+ + xx] |= mask << 5;
+ }
+ }
+ }
+
+ }
+ }
+
+ // Mask chunk borders
+ for (usize z = 0; z < WORLD_LENGTH; z++) {
+ for (usize x = 0; x < WORLD_WIDTH; x++) {
+ u32 * restrict chunk = &world[
+ z * WORLD_WIDTH * CHUNK_SIZE
+ + x * CHUNK_SIZE
+ ];
+
+ // LEFT (-X)
+ if (x > 0) {
+ u32 * restrict lchunk = &world[
+ z * WORLD_WIDTH * CHUNK_SIZE
+ + (x - 1) * CHUNK_SIZE
+ ];
+ // local YZ
+ for (isize ly = 0; ly < CHUNK_HEIGHT; ly++) {
+ for (isize lz = 0; lz < CHUNK_LENGTH; lz++) {
+ u32 mask = 0;
+
+ // neighbouring xy
+ for (isize i = 0; i < 3; i++) {
+ for (isize j = 0; j < 3; j++) {
+ if (i == 0 && ly - 1 < 0) continue;
+ if (j == 0 && lz - 1 < 0) continue;
+ if (i == 2 && ly + 1 >= CHUNK_HEIGHT) continue;
+ if (j == 2 && lz + 1 >= CHUNK_LENGTH) continue;
+
+ ivec3 pos = {CHUNK_WIDTH - 1, i + ly - 1, j + lz - 1};
+ if (lchunk[global_idx(pos)] & (((1 << 5) - 1))) {
+ mask |= 1 << (i * 9 + j * 3);
+ }
+ }
+ }
+ ivec3 pos = {0, ly, lz};
+ chunk[ly * CHUNK_LENGTH * CHUNK_WIDTH
+ + lz * CHUNK_WIDTH
+ + 0] |= mask << 5;
+ }
+ }
+ }
+ // RIGHT (+X)
+ if (x < WORLD_WIDTH - 1) {
+ u32 * restrict rchunk = &world[
+ z * WORLD_WIDTH * CHUNK_SIZE
+ + (x + 1) * CHUNK_SIZE
+ ];
+
+ // local YZ
+ for (isize ly = 0; ly < CHUNK_HEIGHT; ly++) {
+ for (isize lz = 0; lz < CHUNK_LENGTH; lz++) {
+ u32 mask = 0;
+
+ // neighbouring xy
+ for (isize i = 0; i < 3; i++) {
+ for (isize j = 0; j < 3; j++) {
+ if (i == 0 && ly - 1 < 0) continue;
+ if (j == 0 && lz - 1 < 0) continue;
+ if (i == 2 && ly + 1 >= CHUNK_HEIGHT) continue;
+ if (j == 2 && lz + 1 >= CHUNK_LENGTH) continue;
+
+ ivec3 pos = {0, i + ly - 1, j + lz - 1};
+ if (rchunk[global_idx(pos)] & (((1 << 5) - 1))) {
+ mask |= 1 << (i * 9 + j * 3 + 2);
+ }
+ }
+ }
+ ivec3 pos = {CHUNK_WIDTH - 1, ly, lz};
+ chunk[ly * CHUNK_LENGTH * CHUNK_WIDTH
+ + lz * CHUNK_WIDTH
+ + (CHUNK_WIDTH - 1)] |= mask << 5;
+ }
+ }
+ }
+ // BACK (-Z)
+ if (z > 0) {
+ u32 * restrict bchunk = &world[
+ (z - 1) * WORLD_WIDTH * CHUNK_SIZE
+ + x * CHUNK_SIZE
+ ];
+ // local YZ
+ for (isize ly = 0; ly < CHUNK_HEIGHT; ly++) {
+ for (isize lx = 0; lx < CHUNK_LENGTH; lx++) {
+ u32 mask = 0;
+
+ // neighbouring xy
+ for (isize i = 0; i < 3; i++) {
+ for (isize j = 0; j < 3; j++) {
+ if (i == 0 && ly - 1 < 0) continue;
+ if (j == 0 && lx - 1 < 0) continue;
+ if (i == 2 && ly + 1 >= CHUNK_HEIGHT) continue;
+ if (j == 2 && lx + 1 >= CHUNK_WIDTH) continue;
+
+ ivec3 pos = {j + lx - 1, i + ly - 1, CHUNK_LENGTH - 1};
+ if (bchunk[global_idx(pos)] & (((1 << 5) - 1))) {
+ mask |= 1 << (i * 9 + j);
+ }
+ }
+ }
+ ivec3 pos = {lx, ly, 0};
+ chunk[ly * CHUNK_LENGTH * CHUNK_WIDTH
+ + 0
+ + lx] |= mask << 5;
+ }
+ }
+ }
+ // FRONT (+Z)
+ if (z < WORLD_LENGTH - 1) {
+ u32 * restrict rchunk = &world[
+ (z + 1) * WORLD_WIDTH * CHUNK_SIZE
+ + x * CHUNK_SIZE
+ ];
+
+ // local YZ
+ for (isize ly = 0; ly < CHUNK_HEIGHT; ly++) {
+ for (isize lx = 0; lx < CHUNK_WIDTH; lx++) {
+ u32 mask = 0;
+
+ // neighbouring xy
+ for (isize i = 0; i < 3; i++) {
+ for (isize j = 0; j < 3; j++) {
+ if (i == 0 && ly - 1 < 0) continue;
+ if (j == 0 && lx - 1 < 0) continue;
+ if (i == 2 && ly + 1 >= CHUNK_HEIGHT) continue;
+ if (j == 2 && lx + 1 >= CHUNK_WIDTH) continue;
+
+ ivec3 pos = {j + lx - 1, i + ly - 1, 0};
+ if (rchunk[global_idx(pos)] & (((1 << 5) - 1))) {
+ mask |= 1 << (i * 9 + j + 6);
+ }
+ }
+ }
+ ivec3 pos = {lx, ly, CHUNK_LENGTH - 1};
+ chunk[ly * CHUNK_LENGTH * CHUNK_WIDTH
+ + (CHUNK_LENGTH - 1) * CHUNK_WIDTH
+ + lx] |= mask << 5;
+ }
+ }
+ }
+
+
+ }
+ }
}