From 35a81340b179ba4bf18ddab36c10d11238495f5a Mon Sep 17 00:00:00 2001 From: catangent Date: Sun, 3 Aug 2025 18:52:11 +0100 Subject: [PATCH] refactor: split large functions into smaller ones --- src/main.zig | 53 ++++++------- src/world/chunk.zig | 189 +++++++++++++++++++++++--------------------- 2 files changed, 121 insertions(+), 121 deletions(-) diff --git a/src/main.zig b/src/main.zig index a8c6a75..ac9384a 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const Allocator = std.mem.Allocator; const raylib_helper = @import("lib_helpers/raylib_helper.zig"); const raylib = raylib_helper.raylib; @@ -9,7 +10,6 @@ const chunks = @import("world/chunk.zig"); const TILE_TEXTURE_RESOLUTION = 16; -const benchmark_chunk_meshing = false; const debug = true; pub fn drawCameraPosition(camera: raylib.Camera3D, x: i32, y: i32) !void { @@ -29,6 +29,26 @@ pub fn moveCamera(camera: *raylib.Camera3D, vec: raylib.Vector3) void { camera.target = v3.add(camera.target, vec); } +pub fn createDefaultChunk(a7r: Allocator) !chunks.Chunk { + var chunk = try chunks.Chunk.init(a7r); + + // const height_generator = znoise.FnlGenerator{ .seed = 413445 }; + const tile_type_generator = znoise.FnlGenerator{ .seed = 4435, .frequency = 0.1 }; + for (0..32) |raw_x| for (0..32) |raw_y| for (0..32) |raw_z| { + const x: u5 = @intCast(raw_x); + const y: u5 = @intCast(raw_y); + const z: u5 = @intCast(raw_z); + const xf: f32 = @floatFromInt(raw_x); + const yf: f32 = @floatFromInt(raw_y); + const zf: f32 = @floatFromInt(raw_z); + const tile_type: u32 = if (tile_type_generator.noise3(xf, yf, zf) > 0) 1 else 2; + // const height: f32 = (height_generator.noise2(xf, zf) + 1) * 16 + @as(f32, if(x > 24) 4.0 else 0.0) + @as(f32, if(z < 8) 4.0 else 0.0); + // if (height >= yf) chunk.setTile(x, y, z, tile_type); + if((xf-16)*(xf-16)+(yf-16)*(yf-16)+(zf-16)*(zf-16) < 16*16) chunk.setTile(x, y, z, tile_type); + }; + return chunk; +} + pub fn main() !void { if (!debug) raylib.SetTraceLogLevel(raylib.LOG_ERROR); @@ -73,38 +93,9 @@ pub fn main() !void { defer raylib.UnloadShader(shader); raylib.SetShaderValue(shader, raylib.GetShaderLocation(shader, "textureTiling"), &.{ @as(f32, @floatFromInt(tile_columns)), @as(f32, @floatFromInt(tile_rows)) }, raylib.SHADER_UNIFORM_VEC2); - var chunk = try chunks.Chunk.init(a7r); + var chunk = try createDefaultChunk(a7r); defer chunk.deinit(); - // const height_generator = znoise.FnlGenerator{ .seed = 413445 }; - const tile_type_generator = znoise.FnlGenerator{ .seed = 4435, .frequency = 0.1 }; - for (0..32) |raw_x| for (0..32) |raw_y| for (0..32) |raw_z| { - const x: u5 = @intCast(raw_x); - const y: u5 = @intCast(raw_y); - const z: u5 = @intCast(raw_z); - const xf: f32 = @floatFromInt(raw_x); - const yf: f32 = @floatFromInt(raw_y); - const zf: f32 = @floatFromInt(raw_z); - const tile_type: u32 = if (tile_type_generator.noise3(xf, yf, zf) > 0) 2 else 2; - // const height: f32 = (height_generator.noise2(xf, zf) + 1) * 16 + @as(f32, if(x > 24) 4.0 else 0.0) + @as(f32, if(z < 8) 4.0 else 0.0); - // if (height >= yf) chunk.setTile(x, y, z, tile_type); - if((xf-16)*(xf-16)+(yf-16)*(yf-16)+(zf-16)*(zf-16) < 16*16) chunk.setTile(x, y, z, tile_type); - }; - - if (benchmark_chunk_meshing) { - var tmp: u64 = 0; - for (0..500) |_| { - const start = try std.time.Instant.now(); - const model = raylib.LoadChunkModelFromMesh(try chunk.createMesh(tile_rows, tile_columns)); - defer raylib.UnloadChunkModel(model); - const end = try std.time.Instant.now(); - tmp += end.since(start); - } - std.debug.print("\nchunk meshing time: {d:.3}ms\n\n", .{ - @as(f64, @floatFromInt(tmp)) / std.time.ns_per_ms / 500, - }); - } - const model = raylib.LoadChunkModelFromMesh(try chunk.createMesh(tile_rows, tile_columns)); defer raylib.UnloadChunkModel(model); model.materials[0].maps[raylib.MATERIAL_MAP_DIFFUSE].texture = texture; diff --git a/src/world/chunk.zig b/src/world/chunk.zig index e57c88b..4345e0c 100644 --- a/src/world/chunk.zig +++ b/src/world/chunk.zig @@ -198,11 +198,100 @@ pub const Chunk = struct { } return raw_quad; } + + fn packMeshFromRawQuads(raw_quads: std.ArrayList(RawQuad), tile_columns: u32, tile_rows: u32) raylib.ChunkMesh { + // Create OpenGL buffers + const triangle_count: i32 = @as(i32, @intCast(raw_quads.items.len)) * 2; - // Create mesh of a chunk. tile_rows and tile_columns are the dimensions of the tiles.png file, in terms of individual tile textures. - pub fn createMesh(chunk: Chunk, tile_rows: u32, tile_columns: u32) !raylib.ChunkMesh { + const arr_size: u32 = @as(u32, @intCast(triangle_count)) * 3 * @sizeOf(f32); + + const vertices: [*]f32 = @ptrCast(@alignCast(raylib.MemAlloc(arr_size * 3))); + const texcoords: [*]f32 = @ptrCast(@alignCast(raylib.MemAlloc(arr_size * 2))); + const tiletexcoords: [*]f32 = @ptrCast(@alignCast(raylib.MemAlloc(arr_size * 2))); + const normals: [*]f32 = @ptrCast(@alignCast(raylib.MemAlloc(arr_size * 3))); + const metadata1_packed: [*]u32 = @ptrCast(@alignCast(raylib.MemAlloc(arr_size * 4))); + const occlusion_sides: [*]u32 = @ptrCast(@alignCast(raylib.MemAlloc(arr_size * 4))); + + for (raw_quads.items, 0..) |raw_quad, i| { + if (raw_quad.tile <= 0) continue; // air tile, no texture + const tile = raw_quad.tile; + + // Set normals for the quads (same as the triangles.) + for (0..6) |j| { + normals[18 * i + 3 * j + 0] = raw_quad.normal.x; + normals[18 * i + 3 * j + 1] = raw_quad.normal.y; + normals[18 * i + 3 * j + 2] = raw_quad.normal.z; + } + + // Find UV coordinates of corresponding tiles. + const left_uv = @as(f32, @floatFromInt(tile % tile_columns)) / @as(f32, @floatFromInt(tile_columns)); + 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)); + + // 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 tiletexcoords_x = if(raw_quad.flip_x) + .{raw_quad.width, raw_quad.width, 0.0, 0.0, 0.0, raw_quad.width} else + .{ 0.0, 0.0, raw_quad.width, raw_quad.width, raw_quad.width, 0.0 }; + const tiletexcoords_y = if(raw_quad.flip_y) .{ raw_quad.height, 0.0 } ** 3 else .{ 0.0, raw_quad.height } ** 3; + + 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]; + tiletexcoords[TEXCOORDS_BLOCK_SIZE * i + corner_id * 2 + 0] = tiletexcoords_x[corner_id]; + tiletexcoords[TEXCOORDS_BLOCK_SIZE * i + corner_id * 2 + 1] = tiletexcoords_y[corner_id]; + } + + // Store metadata into OpenGL buffers. + for (0..6) |j| { + const metadata1 = Metadata1{ + .top_left_obscured = raw_quad.top_left_obscured, + .top_right_obscured = raw_quad.top_right_obscured, + .bottom_left_obscured = raw_quad.bottom_left_obscured, + .bottom_right_obscured = raw_quad.bottom_right_obscured, + .quad_height = @intFromFloat(raw_quad.height), + .quad_width = @intFromFloat(raw_quad.width), + }; + const metadata1_baked: [4]u32 = @bitCast(metadata1); + for (0..4) |k| { + metadata1_packed[24 * i + 4 * j + k] = metadata1_baked[k]; + } + } + + // Store ambient occlusion sides into OpenGL buffers. + for (0..6) |j| { + occlusion_sides[24 * i + 4 * j + 0] = raw_quad.left_obscuring_pattern; + occlusion_sides[24 * i + 4 * j + 1] = raw_quad.right_obscuring_pattern; + occlusion_sides[24 * i + 4 * j + 2] = raw_quad.top_obscuring_pattern; + occlusion_sides[24 * i + 4 * j + 3] = raw_quad.bottom_obscuring_pattern; + } + } + + // Create mesh using the buffers. + return raylib.ChunkMesh{ + .triangleCount = triangle_count, + .vertexCount = triangle_count * 3, + + .vertices = vertices, + .texcoords = texcoords, + .tiletexcoords = tiletexcoords, + .normals = normals, + .metadata1 = metadata1_packed, + .occlusion_sides = occlusion_sides, + + .vaoId = 0, + .vboId = null, + }; + } + + fn scanForRawQuads(chunk: Chunk) !std.ArrayList(RawQuad) { var raw_quads = try std.ArrayList(RawQuad).initCapacity(chunk.a7r, 4096); - defer raw_quads.deinit(); // Begin scanning the chunk for tile surfaces to make raw quads. inline for (0..3) |dimension| { // Iterate over the 3 dimensions, X, Y and Z. @@ -290,95 +379,15 @@ pub const Chunk = struct { } } } + return raw_quads; + } - // Create OpenGL buffers - const triangle_count: i32 = @as(i32, @intCast(raw_quads.items.len)) * 2; + // Create mesh of a chunk. tile_rows and tile_columns are the dimensions of the tiles.png file, in terms of individual tile textures. + pub fn createMesh(chunk: Chunk, tile_rows: u32, tile_columns: u32) !raylib.ChunkMesh { + var raw_quads = try scanForRawQuads(chunk); + defer raw_quads.deinit(); - const arr_size: u32 = @as(u32, @intCast(triangle_count)) * 3 * @sizeOf(f32); - - const vertices: [*]f32 = @ptrCast(@alignCast(raylib.MemAlloc(arr_size * 3))); - const texcoords: [*]f32 = @ptrCast(@alignCast(raylib.MemAlloc(arr_size * 2))); - const tiletexcoords: [*]f32 = @ptrCast(@alignCast(raylib.MemAlloc(arr_size * 2))); - const normals: [*]f32 = @ptrCast(@alignCast(raylib.MemAlloc(arr_size * 3))); - const metadata1_packed: [*]u32 = @ptrCast(@alignCast(raylib.MemAlloc(arr_size * 4))); - const occlusion_sides: [*]u32 = @ptrCast(@alignCast(raylib.MemAlloc(arr_size * 4))); - - for (raw_quads.items, 0..) |raw_quad, i| { - if (raw_quad.tile <= 0) continue; // air tile, no texture - const tile = raw_quad.tile; - - // Set normals for the quads (same as the triangles.) - for (0..6) |j| { - normals[18 * i + 3 * j + 0] = raw_quad.normal.x; - normals[18 * i + 3 * j + 1] = raw_quad.normal.y; - normals[18 * i + 3 * j + 2] = raw_quad.normal.z; - } - - // Find UV coordinates of corresponding tiles. - const left_uv = @as(f32, @floatFromInt(tile % tile_columns)) / @as(f32, @floatFromInt(tile_columns)); - 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)); - - // 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 tiletexcoords_x = if(raw_quad.flip_x) - .{raw_quad.width, raw_quad.width, 0.0, 0.0, 0.0, raw_quad.width} else - .{ 0.0, 0.0, raw_quad.width, raw_quad.width, raw_quad.width, 0.0 }; - const tiletexcoords_y = if(raw_quad.flip_y) .{ raw_quad.height, 0.0 } ** 3 else .{ 0.0, raw_quad.height } ** 3; - - 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]; - tiletexcoords[TEXCOORDS_BLOCK_SIZE * i + corner_id * 2 + 0] = tiletexcoords_x[corner_id]; - tiletexcoords[TEXCOORDS_BLOCK_SIZE * i + corner_id * 2 + 1] = tiletexcoords_y[corner_id]; - } - - // Store metadata into OpenGL buffers. - for (0..6) |j| { - const metadata1 = Metadata1{ - .top_left_obscured = raw_quad.top_left_obscured, - .top_right_obscured = raw_quad.top_right_obscured, - .bottom_left_obscured = raw_quad.bottom_left_obscured, - .bottom_right_obscured = raw_quad.bottom_right_obscured, - .quad_height = @intFromFloat(raw_quad.height), - .quad_width = @intFromFloat(raw_quad.width), - }; - const metadata1_baked: [4]u32 = @bitCast(metadata1); - for (0..4) |k| { - metadata1_packed[24 * i + 4 * j + k] = metadata1_baked[k]; - } - } - - // Store ambient occlusion sides into OpenGL buffers. - for (0..6) |j| { - occlusion_sides[24 * i + 4 * j + 0] = raw_quad.left_obscuring_pattern; - occlusion_sides[24 * i + 4 * j + 1] = raw_quad.right_obscuring_pattern; - occlusion_sides[24 * i + 4 * j + 2] = raw_quad.top_obscuring_pattern; - occlusion_sides[24 * i + 4 * j + 3] = raw_quad.bottom_obscuring_pattern; - } - } - - // Create mesh using the buffers. - var mesh = raylib.ChunkMesh{ - .triangleCount = triangle_count, - .vertexCount = triangle_count * 3, - - .vertices = vertices, - .texcoords = texcoords, - .tiletexcoords = tiletexcoords, - .normals = normals, - .metadata1 = metadata1_packed, - .occlusion_sides = occlusion_sides, - - .vaoId = 0, - .vboId = null, - }; + var mesh = packMeshFromRawQuads(raw_quads, tile_columns, tile_rows); raylib.UploadChunkMesh(@ptrCast(&mesh), false);