From dd41aabf0f8cdf0569ac8f9ff4a5aba0827e9aae Mon Sep 17 00:00:00 2001 From: catangent Date: Sun, 10 Aug 2025 12:02:12 +0100 Subject: [PATCH] feat: basic world state, manual chunkgen for now --- src/main.zig | 64 +++++++++++----------------- src/world/chunk.zig | 14 +++---- src/world/chunk_generators.zig | 23 ++++++++++ src/world/world_state.zig | 77 ++++++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+), 46 deletions(-) create mode 100644 src/world/chunk_generators.zig create mode 100644 src/world/world_state.zig diff --git a/src/main.zig b/src/main.zig index 7f7d5af..3c247b0 100644 --- a/src/main.zig +++ b/src/main.zig @@ -7,6 +7,8 @@ const v3 = raylib_helper.v3; const znoise = @import("znoise"); const chunks = @import("world/chunk.zig"); +const WorldState = @import("world/world_state.zig").WorldState; +const chunk_generators = @import("world/chunk_generators.zig"); const TILE_TEXTURE_RESOLUTION = 16; @@ -29,36 +31,20 @@ 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; - 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); var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - const a7r = gpa.allocator(); + const allocator = gpa.allocator(); defer { const status = gpa.deinit(); if (status == .leak) std.debug.print("MEMORY LEAK DETECTED!!!!!!!!!!!!!!!!!!!!!!\n", .{}) else std.debug.print("no leaks detected.\n", .{}); } + var thread_pool: std.Thread.Pool = undefined; + try thread_pool.init(.{.allocator = allocator}); + defer thread_pool.deinit(); + raylib.SetConfigFlags(raylib.FLAG_WINDOW_RESIZABLE | raylib.FLAG_FULLSCREEN_MODE); const display = raylib.GetCurrentMonitor(); @@ -93,16 +79,13 @@ 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 createDefaultChunk(a7r); - defer chunk.deinit(); - - 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; - model.materials[0].shader = shader; - - model.materials[0].shader.locs[raylib.SHADER_LOC_MAP_DIFFUSE+1] = raylib.GetShaderLocation(shader, "occlusionMap"); - raylib.SetShaderValueTexture(shader, model.materials[0].shader.locs[raylib.SHADER_LOC_MAP_DIFFUSE+1], ambient_occlusion_texture); model.materials[0].maps[raylib.MATERIAL_MAP_DIFFUSE+1].texture = ambient_occlusion_texture; + var world_state: WorldState = WorldState.init(thread_pool, allocator); + defer world_state.deinit(); + + for (0..10) |x| for (0..10) |z| { + _ = try world_state.generateChunk(.{@intCast(x), 0, @intCast(z)}); + _ = try world_state.generateChunkModel(.{@intCast(x), 0, @intCast(z)}, tile_rows, tile_columns, texture, ambient_occlusion_texture, shader); + }; while (!raylib.WindowShouldClose()) { raylib.ClearBackground(raylib.BLACK); @@ -140,18 +123,21 @@ pub fn main() !void { raylib.BeginDrawing(); defer raylib.EndDrawing(); - const model_position = v3.new(0, 0, 0); - { raylib.BeginMode3D(camera); defer raylib.EndMode3D(); - raylib.BeginShaderMode(shader); - defer raylib.EndShaderMode(); - - raylib.SetShaderValueTexture(shader, raylib.GetShaderLocation(shader, "ambientOcclusionTexture"), ambient_occlusion_texture); - raylib.DrawChunkModel(model, model_position, 0.5, raylib.WHITE); + + world_state.chunks_access_mutex.lock(); + var chunks_iterator = world_state.chunks.valueIterator(); + while (chunks_iterator.next()) |entry| { + if (entry.*.model) |model| { + const model_position = v3.new(@floatFromInt(entry.position[0]*16), @floatFromInt(entry.position[1]*16), @floatFromInt(entry.position[2]*16)); + raylib.DrawChunkModel(model, model_position, 0.5, raylib.WHITE); + } + } + world_state.chunks_access_mutex.unlock(); } - + raylib.DrawFPS(10, 10); try drawCameraPosition(camera, 10, 30); } diff --git a/src/world/chunk.zig b/src/world/chunk.zig index 4345e0c..d7bf7a0 100644 --- a/src/world/chunk.zig +++ b/src/world/chunk.zig @@ -2,7 +2,7 @@ const std = @import("std"); const raylib_helper = @import("../lib_helpers/raylib_helper.zig"); const raylib = raylib_helper.raylib; const v3 = raylib_helper.v3; -const A7r = std.mem.Allocator; +const Allocator = std.mem.Allocator; const comptimePrint = std.fmt.comptimePrint; const VERTICES_BLOCK_SIZE = 2 * 3 * 3; @@ -56,19 +56,19 @@ comptime { pub const Chunk = struct { tiles: []u32, - a7r: A7r, + allocator: Allocator, - pub fn init(a7r: A7r) !Chunk { + pub fn init(allocator: Allocator) !Chunk { const self = Chunk{ - .a7r = a7r, - .tiles = try a7r.alloc(u32, 32 * 32 * 32), + .allocator = allocator, + .tiles = try allocator.alloc(u32, 32 * 32 * 32), }; @memset(self.tiles, 0); return self; } pub fn deinit(self: Chunk) void { - self.a7r.free(self.tiles); + self.allocator.free(self.tiles); } // 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]. @@ -291,7 +291,7 @@ pub const Chunk = struct { } fn scanForRawQuads(chunk: Chunk) !std.ArrayList(RawQuad) { - var raw_quads = try std.ArrayList(RawQuad).initCapacity(chunk.a7r, 4096); + var raw_quads = try std.ArrayList(RawQuad).initCapacity(chunk.allocator, 4096); // 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. diff --git a/src/world/chunk_generators.zig b/src/world/chunk_generators.zig new file mode 100644 index 0000000..6d528fc --- /dev/null +++ b/src/world/chunk_generators.zig @@ -0,0 +1,23 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const znoise = @import("znoise"); + +const chunks = @import("chunk.zig"); + +pub fn createChunk(allocator: Allocator, chunk_pos: @Vector(3, i64)) !chunks.Chunk { + var chunk = try chunks.Chunk.init(allocator); + + const height_generator = znoise.FnlGenerator{ .seed = 413445 }; + for (0..32) |raw_x| for (0..32) |raw_y| for (0..32) |raw_z| { + const local_x: u5 = @intCast(raw_x); + const local_y: u5 = @intCast(raw_y); + const local_z: u5 = @intCast(raw_z); + const x: f32 = @floatFromInt(@as(i64, @intCast(raw_x)) + chunk_pos[0]*32); + const y: f32 = @floatFromInt(@as(i64, @intCast(raw_y)) + chunk_pos[1]*32); + const z: f32 = @floatFromInt(@as(i64, @intCast(raw_z)) + chunk_pos[2]*32); + const height: f32 = (height_generator.noise2(x, z) + 1) * 16; + const tile_type: u32 = if(height >= y + 1) 2 else 1; + if (height >= y) chunk.setTile(local_x, local_y, local_z, tile_type); + }; + return chunk; +} diff --git a/src/world/world_state.zig b/src/world/world_state.zig new file mode 100644 index 0000000..3fa1b33 --- /dev/null +++ b/src/world/world_state.zig @@ -0,0 +1,77 @@ +const std = @import("std"); +const Thread = std.Thread; +const Allocator = std.mem.Allocator; +const AutoHashMap = std.AutoHashMap; + +const Chunk = @import("chunk.zig").Chunk; +const chunk_generators = @import("chunk_generators.zig"); + +const raylib_helper = @import("../lib_helpers/raylib_helper.zig"); +const raylib = raylib_helper.raylib; + +pub const WorldStateError = error{ + ChunkNotGeneratedError, +}; + +pub const ChunkEntry = struct { + chunk: ?Chunk = null, + model: ?raylib.ChunkModel = null, + position: @Vector(3, i64), +}; + +pub const WorldState = struct { + pool: Thread.Pool = undefined, + allocator: Allocator = undefined, + + // TODO: we can do better than a hashmap and a mutex + chunks: AutoHashMap(@Vector(3, i64), ChunkEntry) = undefined, + chunks_access_mutex: Thread.Mutex = .{}, + + pub fn init(global_pool: Thread.Pool, allocator: Allocator) WorldState { + var world_state: WorldState = undefined; + world_state.pool = global_pool; + world_state.allocator = allocator; + world_state.chunks = AutoHashMap(@Vector(3, i64), ChunkEntry).init(allocator); + return world_state; + } + + pub fn deinit(self: *WorldState) void { + var chunk_iterator = self.chunks.valueIterator(); + while(chunk_iterator.next()) |entry| { + if(entry.*.chunk) |chunk| { + chunk.deinit(); + } + if(entry.*.model) |model| { + raylib.UnloadChunkModel(model); + } + } + self.chunks.deinit(); + } + + pub fn generateChunk(self: *WorldState, pos: @Vector(3, i64)) !Chunk { + const chunk = try chunk_generators.createChunk(self.allocator, pos); + self.chunks_access_mutex.lock(); + try self.chunks.put(pos, .{.chunk = chunk, .position = pos}); + self.chunks_access_mutex.unlock(); + return chunk; + } + + pub fn generateChunkModel(self: *WorldState, pos: @Vector(3, i64), tile_rows: u32, tile_columns: u32, texture: raylib.Texture, ambient_occlusion_texture: raylib.Texture, shader: raylib.Shader) !raylib.ChunkModel { + self.chunks_access_mutex.lock(); + const chunk_entry = (try self.chunks.getOrPutValue(pos, .{.position = pos})).value_ptr; + self.chunks_access_mutex.unlock(); + + const chunk = chunk_entry.chunk; + if(chunk == null) return WorldStateError.ChunkNotGeneratedError; + + const model = raylib.LoadChunkModelFromMesh(try chunk.?.createMesh(tile_rows, tile_columns)); + model.materials[0].maps[raylib.MATERIAL_MAP_DIFFUSE].texture = texture; + model.materials[0].shader = shader; + + model.materials[0].shader.locs[raylib.SHADER_LOC_MAP_DIFFUSE+1] = raylib.GetShaderLocation(shader, "occlusionMap"); + raylib.SetShaderValueTexture(shader, model.materials[0].shader.locs[raylib.SHADER_LOC_MAP_DIFFUSE+1], ambient_occlusion_texture); model.materials[0].maps[raylib.MATERIAL_MAP_DIFFUSE+1].texture = ambient_occlusion_texture; + + chunk_entry.model = model; + return model; + } +};