summaryrefslogtreecommitdiff
path: root/chunks.ha
diff options
context:
space:
mode:
authorLassi Pulkkinen <lassi@pulk.fi>2024-10-31 03:11:21 +0200
committerLassi Pulkkinen <lassi@pulk.fi>2024-10-31 03:51:35 +0200
commitae44478b30d890fe0fb04022f44d474dcdcc3f9d (patch)
tree5f462459ae4b47d22114eed717d1382d08cf4dfe /chunks.ha
Initial commit (import old repo)HEADmain
Diffstat (limited to 'chunks.ha')
-rw-r--r--chunks.ha221
1 files changed, 221 insertions, 0 deletions
diff --git a/chunks.ha b/chunks.ha
new file mode 100644
index 0000000..af78281
--- /dev/null
+++ b/chunks.ha
@@ -0,0 +1,221 @@
+use comparray;
+
+type Chunk = struct {
+ sections: nullable *[*]Section,
+};
+
+type Section = struct {
+ bstates: comparray::Array,
+ dirty: bool,
+ non_air_count: i32,
+
+ // render state
+
+ vertexbuf: uint,
+ vertexcount: i32,
+};
+
+// XXX: the view range behaves a bit weirdly sometimes; further investigation
+// needed.
+def VIEW_MARGIN: i32 = 2;
+
+let CHUNKS: []Chunk = []; // len = VIEW_SIZE * VIEW_SIZE
+let CHUNKS_POS: ChunkPos = ChunkPos { ... }; // -X,-Z corner of the rectangular view area
+let CHUNKS_SIZE = 0i32; // width of the view area
+let CHUNKS_MIN_Y = 0i8; // in chunks
+let CHUNKS_HEIGHT = 0u8; // in chunks
+
+fn chunks_respawn() void = {
+ const dim_type = &DIM_TYPES[DIM_TYPE];
+ CHUNKS_MIN_Y = dim_type.min_y;
+ CHUNKS_HEIGHT = dim_type.height;
+ setview(ChunkPos { ... });
+};
+
+fn setview(center: ChunkPos) void = {
+ const view_pos = ChunkPos {
+ x = center.x - VIEW_DISTANCE - VIEW_MARGIN,
+ z = center.z - VIEW_DISTANCE - VIEW_MARGIN,
+ };
+ const view_size = VIEW_DISTANCE * 2 + VIEW_MARGIN * 2 + 1;
+ let chunks = alloc([Chunk { ... }...],
+ (view_size * view_size): size);
+
+ for (let z = 0i32; z < CHUNKS_SIZE; z += 1)
+ for (let x = 0i32; x < CHUNKS_SIZE; x += 1) {
+ const pos = ChunkPos {
+ x = CHUNKS_POS.x + x,
+ z = CHUNKS_POS.z + z,
+ };
+ const chunk = getchunk(pos) as *Chunk;
+
+ const pos_ = ChunkPos {
+ x = pos.x - view_pos.x,
+ z = pos.z - view_pos.z,
+ };
+ if (pos_.x >= 0 && pos_.x < view_size
+ && pos_.z >= 0 && pos_.z < view_size) {
+ chunks[pos_.x + pos_.z * view_size] = *chunk;
+ } else {
+ chunk_destroy(pos);
+ };
+ };
+ free(CHUNKS);
+
+ CHUNKS = chunks;
+ CHUNKS_POS = view_pos;
+ CHUNKS_SIZE = view_size;
+};
+
+fn setblock(pos: BlockPos, bstate: u16) void = {
+ const spos = block_section(pos);
+ const section = getsection(spos) as *Section;
+
+ const ref = if (section.bstates.palette_size == comparray::DIRECT) {
+ yield bstate;
+ } else :ref {
+ const palette = comparray::get_palette(&section.bstates);
+ for (let i = 0u8; i < len(palette); i += 1) {
+ if (palette[i] == bstate)
+ yield :ref, i: u16;
+ };
+
+ comparray::grow_palette(&section.bstates, 4096,
+ section.bstates.palette_size + 1);
+
+ if (section.bstates.palette_size == comparray::DIRECT) {
+ yield :ref, bstate;
+ } else {
+ const i = section.bstates.palette_size - 1;
+ comparray::get_palette(&section.bstates)[i] = bstate;
+ yield :ref, i: u16;
+ };
+ };
+
+ const i = (pos.x & 0xf): size
+ | (pos.z & 0xf): size << 4
+ | (pos.y & 0xf): size << 8;
+ comparray::set(&section.bstates, i, ref);
+
+ section.dirty = true;
+ if (pos.x & 0xf == 0) section_make_dirty(spos.x - 1, spos.y, spos.z);
+ if (pos.x & 0xf == 15) section_make_dirty(spos.x + 1, spos.y, spos.z);
+ if (pos.y & 0xf == 0) section_make_dirty(spos.x, spos.y - 1, spos.z);
+ if (pos.y & 0xf == 15) section_make_dirty(spos.x, spos.y + 1, spos.z);
+ if (pos.z & 0xf == 0) section_make_dirty(spos.x, spos.y, spos.z - 1);
+ if (pos.z & 0xf == 15) section_make_dirty(spos.x, spos.y, spos.z + 1);
+};
+
+fn getchunk(pos: ChunkPos) nullable *Chunk = {
+ pos.x -= CHUNKS_POS.x;
+ pos.z -= CHUNKS_POS.z;
+
+ if (pos.x < 0 || pos.x >= CHUNKS_SIZE) return null;
+ if (pos.z < 0 || pos.z >= CHUNKS_SIZE) return null;
+
+ return &CHUNKS[pos.x + pos.z * CHUNKS_SIZE];
+};
+
+fn getsection(pos: SectionPos) nullable *Section = {
+ if (pos.y < CHUNKS_MIN_Y || pos.y >= CHUNKS_MIN_Y + CHUNKS_HEIGHT: i8)
+ return null;
+
+ match (getchunk(pos.chunk)) {
+ case let chunk: *Chunk =>
+ match (chunk.sections) {
+ case let sections: *[*]Section =>
+ return &sections[pos.y: size - CHUNKS_MIN_Y: size];
+ case null =>
+ return null;
+ };
+ case null =>
+ return null;
+ };
+};
+
+fn chunk_init(pos: ChunkPos) *Chunk = {
+ chunk_destroy(pos);
+
+ let sections: []Section = alloc([], CHUNKS_HEIGHT);
+
+ for (let i = 0z; i < CHUNKS_HEIGHT; i += 1) {
+ let bstates = comparray::new(1, 4096);
+ comparray::clear(&bstates, 0);
+
+ static append(sections, Section {
+ bstates = bstates,
+ ...
+ });
+ };
+
+ const chunk = getchunk(pos) as *Chunk;
+ *chunk = Chunk {
+ sections = sections: *[*]Section,
+ };
+
+ for (let i = 0u8; i < CHUNKS_HEIGHT; i += 1) {
+ const spos = SectionPos {
+ chunk = pos,
+ y = i: i8 + CHUNKS_MIN_Y,
+ };
+ section_make_dirty(spos.x - 1, spos.y, spos.z);
+ section_make_dirty(spos.x + 1, spos.y, spos.z);
+ section_make_dirty(spos.x, spos.y, spos.z - 1);
+ section_make_dirty(spos.x, spos.y, spos.z + 1);
+ };
+
+ return chunk;
+};
+
+fn section_make_dirty(x: i32, y: i8, z: i32) void = {
+ match (getsection(SectionPos { x = x, y = y, z = z })) {
+ case let section: *Section =>
+ section.dirty = true;
+ case null => void;
+ };
+};
+
+fn chunk_destroy(pos: ChunkPos) void = {
+ const chunk = match (getchunk(pos)) {
+ case let chunk: *Chunk =>
+ yield chunk;
+ case null =>
+ return;
+ };
+
+ const sections = match (chunk.sections) {
+ case let sections: *[*]Section =>
+ yield sections;
+ case null =>
+ return;
+ };
+
+ for (let i = 0u8; i < CHUNKS_HEIGHT; i += 1) {
+ section_destroy(&sections[i]);
+ };
+
+ free(sections);
+ chunk.sections = null;
+};
+
+fn section_destroy(section: *Section) void = {
+ render_chunks_section_destroy(section);
+ comparray::clear(&section.bstates, 0);
+};
+
+fn chunks_despawn() void = {
+ for (let z = 0i32; z < CHUNKS_SIZE; z += 1)
+ for (let x = 0i32; x < CHUNKS_SIZE; x += 1) {
+ const pos = ChunkPos {
+ x = CHUNKS_POS.x + x,
+ z = CHUNKS_POS.z + z,
+ };
+ chunk_destroy(pos);
+ };
+ free(CHUNKS);
+ CHUNKS = [];
+ CHUNKS_POS = ChunkPos { ... };
+ CHUNKS_SIZE = 0;
+ CHUNKS_MIN_Y = 0;
+ CHUNKS_HEIGHT = 0;
+};