From 389e93490039e60e5c07d8f2423bf6f71a536e24 Mon Sep 17 00:00:00 2001 From: catangent Date: Wed, 9 Apr 2025 19:15:08 +0100 Subject: [PATCH] refactor --- src/world/chunk.zig | 240 +++++++++++++++++++++++++------------------- 1 file changed, 139 insertions(+), 101 deletions(-) diff --git a/src/world/chunk.zig b/src/world/chunk.zig index 333f9c1..f6e2d60 100644 --- a/src/world/chunk.zig +++ b/src/world/chunk.zig @@ -5,6 +5,9 @@ const v3 = raylib_helper.v3; const A7r = std.mem.Allocator; const comptimePrint = std.fmt.comptimePrint; +const COORDINATE_FIELD_BYTES = 5; // 5 for 32x32x32 chunk size. +const CHUNK_SIZE = 1 >> COORDINATE_FIELD_BYTES; // 32 + const RawQuad = struct { tile: u32, top_left: raylib.Vector3, @@ -14,6 +17,15 @@ const RawQuad = struct { normal: raylib.Vector3, width: f32, height: f32, + + top_obscuring_pattern: u32, + left_obscuring_pattern: u32, + right_obscuring_pattern: u32, + bottom_obscuring_pattern: u32, + top_left_obscured: bool, + top_right_obscured: bool, + bottom_right_obscured: bool, + bottom_left_obscured: bool, }; const Metadata1 = packed struct { @@ -52,18 +64,22 @@ pub const Chunk = struct { } pub fn getTile(self: Chunk, x: u5, y: u5, z: u5) u32 { + // Fetch the tile at (x, y, z), but with potential side effects. If you imagine tiles to be a 3-dimensional array, this would be tiles[x][y][z]. return self.tiles[@as(u15, x) << 10 | @as(u15, y) << 5 | @as(u15, z)]; } pub fn setTile(self: Chunk, x: u5, y: u5, z: u5, tile: u32) void { + // Set the tile at (x, y, z). If you imagine tiles to be a 3-dimensional array, this would be tiles[x][y][z] = tile. self.tiles[@as(u15, x) << 10 | @as(u15, y) << 5 | @as(u15, z)] = tile; } fn getTileRaw(self: Chunk, x: u5, y: u5, z: u5) u32 { + // Fetch the tile at (x, y, z) without changin anything. If you imagine tiles to be a 3-dimensional array, this would be tiles[x][y][z]. return self.tiles[@as(u15, x) << 10 | @as(u15, y) << 5 | @as(u15, z)]; } inline fn getTileRawShifted(self: Chunk, x: u5, y: u5, z: u5, comptime d: comptime_int) u32 { + // This cyclicaly permutes the x, y, z coordinates at compile time. Useful when iterating over x, y, and z axis. if (d % 3 == 0) { return self.getTileRaw(x, y, z); } else if (d % 3 == 1) { @@ -73,11 +89,91 @@ pub const Chunk = struct { } } + fn pack_raw_quad(y: usize, y2: usize, z: usize, z2: usize, sign: comptime_int, d: comptime_int, surface: u32, xf: f32) RawQuad { + const ymin: f32 = @as(f32, @floatFromInt(y)) - 0.5; + const ymax: f32 = @as(f32, @floatFromInt(y2)) + 0.5; + const zmin: f32 = @as(f32, @floatFromInt(z)) - 0.5; + const zmax: f32 = @as(f32, @floatFromInt(z2)) + 0.5; + const yleft: f32 = if (sign == 1) ymin else ymax; + const yright: f32 = if (sign == 1) ymax else ymin; + const zleft: f32 = if (sign == 1) zmin else zmax; + const zright: f32 = if (sign == 1) zmax else zmin; + var raw_quad: RawQuad = undefined; + switch (d) { + 0 => { + raw_quad = .{ + .tile = surface, + .top_left = v3.new(xf + 0.5 * sign, ymax, zright), + .top_right = v3.new(xf + 0.5 * sign, ymax, zleft), + .bottom_left = v3.new(xf + 0.5 * sign, ymin, zright), + .bottom_right = v3.new(xf + 0.5 * sign, ymin, zleft), + .normal = v3.new(sign, 0, 0), + .width = zmax - zmin, + .height = ymax - ymin, + + .top_obscuring_pattern = 0, + .left_obscuring_pattern = 0, + .right_obscuring_pattern = 0, + .bottom_obscuring_pattern = 0, + .top_left_obscured = false, + .top_right_obscured = false, + .bottom_right_obscured = false, + .bottom_left_obscured = false, + }; + }, + 1 => { + raw_quad = .{ + .tile = surface, + .bottom_left = v3.new(yleft, zmin, xf + 0.5 * sign), + .top_left = v3.new(yleft, zmax, xf + 0.5 * sign), + .bottom_right = v3.new(yright, zmin, xf + 0.5 * sign), + .top_right = v3.new(yright, zmax, xf + 0.5 * sign), + .normal = v3.new(0, 0, sign), + .height = zmax - zmin, + .width = ymax - ymin, + + .top_obscuring_pattern = 0, + .left_obscuring_pattern = 0, + .right_obscuring_pattern = 0, + .bottom_obscuring_pattern = 0, + .top_left_obscured = false, + .top_right_obscured = false, + .bottom_right_obscured = false, + .bottom_left_obscured = false, + }; + }, + 2 => { + raw_quad = .{ + .tile = surface, + .top_left = v3.new(zleft, xf + 0.5 * sign, ymin), + .top_right = v3.new(zright, xf + 0.5 * sign, ymin), + .bottom_left = v3.new(zleft, xf + 0.5 * sign, ymax), + .bottom_right = v3.new(zright, xf + 0.5 * sign, ymax), + .normal = v3.new(0, sign, 0), + .width = zmax - zmin, + .height = ymax - ymin, + + .top_obscuring_pattern = 0xffffffff, + .left_obscuring_pattern = 0xffffffff, + .right_obscuring_pattern = 0xffffffff, + .bottom_obscuring_pattern = 0xffffffff, + .top_left_obscured = false, + .top_right_obscured = false, + .bottom_right_obscured = false, + .bottom_left_obscured = false, + }; + }, + else => unreachable, + } + return raw_quad; + } + pub fn createMesh(chunk: Chunk, tile_rows: u32, tile_columns: u32) !raylib.Mesh { var raw_quads = try std.ArrayList(RawQuad).initCapacity(chunk.a7r, 4096); defer raw_quads.deinit(); - inline for (0..3) |d| { + // Begin scanning the chunk for block surfaces to make raw quads. + inline for (0..3) |d| { // For each of the 3 dimensions, for (0..32) |raw_x| { const x: u5 = @intCast(raw_x); var positive_tile_surfaces: [32][32]u32 = .{.{0} ** 32} ** 32; @@ -105,57 +201,11 @@ pub const Chunk = struct { for (y..y2) |ytmp| if (tile_surfaces[ytmp][z2] != surface) break :zloop; for (y..y2) |ytmp| tile_surfaces[ytmp][z2] = 0; } + // todo: scan tiles around quad surface for ambient occlusion y2 -= 1; z2 -= 1; tile_surfaces[y][z] = 0; - const ymin: f32 = @as(f32, @floatFromInt(y)) - 0.5; - const ymax: f32 = @as(f32, @floatFromInt(y2)) + 0.5; - const zmin: f32 = @as(f32, @floatFromInt(z)) - 0.5; - const zmax: f32 = @as(f32, @floatFromInt(z2)) + 0.5; - const yleft: f32 = if (sign == 1) ymin else ymax; - const yright: f32 = if (sign == 1) ymax else ymin; - const zleft: f32 = if (sign == 1) zmin else zmax; - const zright: f32 = if (sign == 1) zmax else zmin; - var raw_quad: RawQuad = undefined; - switch (d) { - 0 => { - raw_quad = .{ - .tile = surface, - .top_left = v3.new(xf + 0.5 * sign, ymax, zright), - .top_right = v3.new(xf + 0.5 * sign, ymax, zleft), - .bottom_left = v3.new(xf + 0.5 * sign, ymin, zright), - .bottom_right = v3.new(xf + 0.5 * sign, ymin, zleft), - .normal = v3.new(sign, 0, 0), - .width = zmax - zmin, - .height = ymax - ymin, - }; - }, - 1 => { - raw_quad = .{ - .tile = surface, - .bottom_left = v3.new(yleft, zmin, xf + 0.5 * sign), - .top_left = v3.new(yleft, zmax, xf + 0.5 * sign), - .bottom_right = v3.new(yright, zmin, xf + 0.5 * sign), - .top_right = v3.new(yright, zmax, xf + 0.5 * sign), - .normal = v3.new(0, 0, sign), - .height = zmax - zmin, - .width = ymax - ymin, - }; - }, - 2 => { - raw_quad = .{ - .tile = surface, - .top_left = v3.new(zleft, xf + 0.5 * sign, ymin), - .top_right = v3.new(zright, xf + 0.5 * sign, ymin), - .bottom_left = v3.new(zleft, xf + 0.5 * sign, ymax), - .bottom_right = v3.new(zright, xf + 0.5 * sign, ymax), - .normal = v3.new(0, sign, 0), - .width = zmax - zmin, - .height = ymax - ymin, - }; - }, - else => unreachable, - } + const raw_quad = pack_raw_quad(y, y2, z, z2, sign, d, surface, xf); try raw_quads.append(raw_quad); }; } @@ -186,62 +236,49 @@ pub const Chunk = struct { const right_uv = @as(f32, @floatFromInt(tile % tile_columns + 1)) / @as(f32, @floatFromInt(tile_columns)); const top_uv = @as(f32, @floatFromInt(tile / tile_columns)) / @as(f32, @floatFromInt(tile_rows)); const bottom_uv = @as(f32, @floatFromInt(tile / tile_columns + 1)) / @as(f32, @floatFromInt(tile_rows)); + const VERTICES_BLOCK_SIZE = 2 * 3 * 3; + const TEXCOORDS_BLOCK_SIZE = 2 * 2 * 3; - vertices[18 * i + 0] = raw_quad.top_left.x; - vertices[18 * i + 1] = raw_quad.top_left.y; - vertices[18 * i + 2] = raw_quad.top_left.z; - texcoords[12 * i + 0] = left_uv; - texcoords[12 * i + 1] = top_uv; - texcoords2[12 * i + 0] = 0.0; - texcoords2[12 * i + 1] = 0.0; + // Unwrap raw quads vertex coordinates and UV coordinates into OpenGL buffers. + const vertex_corners = .{ raw_quad.top_left, raw_quad.bottom_left, raw_quad.top_right, raw_quad.bottom_right, raw_quad.top_right, raw_quad.bottom_left }; + const texcoords_x = .{ left_uv, left_uv, right_uv, right_uv, right_uv, left_uv }; + const texcoords_y = .{ top_uv, bottom_uv } ** 3; + const texcoords2_x = .{ 0.0, 0.0, raw_quad.width, raw_quad.width, raw_quad.width, 0.0 }; + const texcoords2_y = .{ 0.0, raw_quad.height } ** 3; - vertices[18 * i + 3] = raw_quad.bottom_left.x; - vertices[18 * i + 4] = raw_quad.bottom_left.y; - vertices[18 * i + 5] = raw_quad.bottom_left.z; - texcoords[12 * i + 2] = left_uv; - texcoords[12 * i + 3] = bottom_uv; - texcoords2[12 * i + 2] = 0.0; - texcoords2[12 * i + 3] = raw_quad.height; + inline for (0..6) |corner_id| { + vertices[VERTICES_BLOCK_SIZE * i + corner_id * 3 + 0] = vertex_corners[corner_id].x; + vertices[VERTICES_BLOCK_SIZE * i + corner_id * 3 + 1] = vertex_corners[corner_id].y; + vertices[VERTICES_BLOCK_SIZE * i + corner_id * 3 + 2] = vertex_corners[corner_id].z; + texcoords[TEXCOORDS_BLOCK_SIZE * i + corner_id * 2 + 0] = texcoords_x[corner_id]; + texcoords[TEXCOORDS_BLOCK_SIZE * i + corner_id * 2 + 1] = texcoords_y[corner_id]; + texcoords2[TEXCOORDS_BLOCK_SIZE * i + corner_id * 2 + 0] = texcoords2_x[corner_id]; + texcoords2[TEXCOORDS_BLOCK_SIZE * i + corner_id * 2 + 1] = texcoords2_y[corner_id]; + } - vertices[18 * i + 6] = raw_quad.top_right.x; - vertices[18 * i + 7] = raw_quad.top_right.y; - vertices[18 * i + 8] = raw_quad.top_right.z; - texcoords[12 * i + 4] = right_uv; - texcoords[12 * i + 5] = top_uv; - texcoords2[12 * i + 4] = raw_quad.width; - texcoords2[12 * i + 5] = 0.0; - - vertices[18 * i + 9] = raw_quad.bottom_right.x; - vertices[18 * i + 10] = raw_quad.bottom_right.y; - vertices[18 * i + 11] = raw_quad.bottom_right.z; - texcoords[12 * i + 6] = right_uv; - texcoords[12 * i + 7] = bottom_uv; - texcoords2[12 * i + 6] = raw_quad.width; - texcoords2[12 * i + 7] = raw_quad.height; - - vertices[18 * i + 12] = raw_quad.top_right.x; - vertices[18 * i + 13] = raw_quad.top_right.y; - vertices[18 * i + 14] = raw_quad.top_right.z; - texcoords[12 * i + 8] = right_uv; - texcoords[12 * i + 9] = top_uv; - texcoords2[12 * i + 8] = raw_quad.width; - texcoords2[12 * i + 9] = 0.0; - - vertices[18 * i + 15] = raw_quad.bottom_left.x; - vertices[18 * i + 16] = raw_quad.bottom_left.y; - vertices[18 * i + 17] = raw_quad.bottom_left.z; - texcoords[12 * i + 10] = left_uv; - texcoords[12 * i + 11] = bottom_uv; - texcoords2[12 * i + 10] = 0.0; - texcoords2[12 * i + 11] = raw_quad.height; - - for (0..6) |j| { + // Store metadata into OpenGL buffers. + for (0..3) |j| { const metadata1 = Metadata1{ - .ambient_occlusion_1 = 0xffffffff, - .ambient_occlusion_2 = 0xffffffff, - .ambient_occlusion_corner1 = true, - .ambient_occlusion_corner2 = true, - .ambient_occlusion_corner3 = true, + .ambient_occlusion_1 = raw_quad.left_obscuring_pattern, + .ambient_occlusion_2 = raw_quad.right_obscuring_pattern, + .ambient_occlusion_corner1 = raw_quad.top_left_obscured, + .ambient_occlusion_corner2 = raw_quad.bottom_left_obscured, + .ambient_occlusion_corner3 = raw_quad.top_right_obscured, + .quad_height = @intFromFloat(raw_quad.height), + .quad_width = @intFromFloat(raw_quad.width), + }; + const metadata1_baked: [4]f32 = @bitCast(metadata1); + for (0..4) |k| { + metadata1_packed[24 * i + 4 * j + k] = @bitCast(@as(f32, metadata1_baked[k])); + } + } + for (3..6) |j| { + const metadata1 = Metadata1{ + .ambient_occlusion_1 = raw_quad.right_obscuring_pattern, + .ambient_occlusion_2 = raw_quad.bottom_obscuring_pattern, + .ambient_occlusion_corner1 = raw_quad.bottom_right_obscured, + .ambient_occlusion_corner2 = raw_quad.top_right_obscured, + .ambient_occlusion_corner3 = raw_quad.bottom_left_obscured, .quad_height = @intFromFloat(raw_quad.height), .quad_width = @intFromFloat(raw_quad.width), }; @@ -252,6 +289,7 @@ pub const Chunk = struct { } } + // Create mesh. var mesh = raylib.Mesh{ .triangleCount = triangle_count, .vertexCount = triangle_count * 3,