diff --git a/src/Log.zig b/src/Log.zig new file mode 100644 index 0000000..3de5e8b --- /dev/null +++ b/src/Log.zig @@ -0,0 +1,11 @@ +const std = @import("std"); + +level: std.log.Level, +message: []const u8, + +pub fn init(level: std.log.Level, message: []const u8) @This() { + return .{ + .level = level, + .message = message, + }; +} diff --git a/src/game.zig b/src/game.zig new file mode 100644 index 0000000..b7da1ea --- /dev/null +++ b/src/game.zig @@ -0,0 +1,110 @@ +const std = @import("std"); + +const zglfw = @import("zglfw"); +const zgui = @import("zgui"); + +const main = @import("main.zig"); + +var show_console: bool = false; +var show_demo_window: bool = false; + +pub fn init() void {} + +pub fn update(dt: f32) void { + _ = dt; + + if (show_console) { + showConsole(); + } + + if (show_demo_window) { + zgui.showDemoWindow(&show_demo_window); + } +} + +pub fn charCallback( + _: *zglfw.Window, + codepoint: u32, +) callconv(.C) void { + _ = codepoint; +} + +pub fn cursorPosCallback( + _: *zglfw.Window, + xpos: f64, + ypos: f64, +) callconv(.C) void { + _ = xpos; + _ = ypos; +} + +pub fn keyCallback( + _: *zglfw.Window, + key: zglfw.Key, + scancode: c_int, + action: zglfw.Action, + mods: zglfw.Mods, +) callconv(.C) void { + _ = scancode; + + const no_mods = @as(c_int, @bitCast(mods)) == 0; + + if (key == .grave_accent and action == .press and no_mods) { + show_console = !show_console; + } + + if (key == .F1 and action == .press and no_mods) { + show_demo_window = true; + } +} + +pub fn mouseButtonCallback( + _: *zglfw.Window, + button: zglfw.MouseButton, + action: zglfw.Action, + mods: zglfw.Mods, +) callconv(.C) void { + _ = button; + _ = action; + _ = mods; +} + +pub fn scrollCallback( + _: *zglfw.Window, + xoffset: f64, + yoffset: f64, +) callconv(.C) void { + _ = xoffset; + _ = yoffset; +} + +pub fn deinit() void {} + +fn showConsole() void { + const display_size = zgui.io.getDisplaySize(); + zgui.setNextWindowPos(.{ + .x = 0, + .y = 0, + }); + zgui.setNextWindowSize(.{ + .w = display_size[0], + .h = main.min_window_height, + .cond = .once, + }); + if (zgui.begin("Console", .{ .flags = .{ + .no_title_bar = true, + .no_resize = true, + .no_move = true, + .no_collapse = true, + } })) { + for (main.logs.items) |log| { + zgui.textUnformattedColored(switch (log.level) { + .err => .{ 1, 0, 0, 1 }, + .warn => .{ 1, 1, 0, 1 }, + .info => .{ 1, 1, 1, 1 }, + .debug => .{ 0.5, 0.5, 0.5, 1 }, + }, log.message); + } + } + zgui.end(); +} diff --git a/src/main.zig b/src/main.zig index d0c771d..92438cc 100644 --- a/src/main.zig +++ b/src/main.zig @@ -6,12 +6,27 @@ const zgpu = @import("zgpu"); const zgui = @import("zgui"); const ztracy = @import("ztracy"); +const game = @import("game.zig"); +const Log = @import("Log.zig"); + +pub const min_framerate = 30.0; +pub const min_frametime = 1.0 / min_framerate; +pub const min_window_height = 360; +pub const min_window_width = 640; +pub const temp_allocator_capacity = 16 * 1024 * 1024; +pub const window_title = "voxel-game"; + pub var allocator: std.mem.Allocator = undefined; pub var audio_engine: *zaudio.Engine = undefined; pub var gctx: *zgpu.GraphicsContext = undefined; +pub var logs: std.ArrayListUnmanaged(Log) = undefined; pub var temp_allocator: std.mem.Allocator = undefined; pub var window: *zglfw.Window = undefined; +pub const std_options: std.Options = .{ + .logFn = logFn, +}; + pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); @@ -19,12 +34,19 @@ pub fn main() !void { var ta = ztracy.TracyAllocator.init(gpa.allocator()); var fba = std.heap.FixedBufferAllocator.init(&struct { - pub var buffer: [16 * 1024 * 1024]u8 = undefined; + pub var buffer: [temp_allocator_capacity]u8 = undefined; }.buffer); allocator = ta.allocator(); temp_allocator = fba.threadSafeAllocator(); + defer { + for (logs.items) |log| { + allocator.free(log.message); + } + logs.deinit(allocator); + } + // --- zaudio -------------------------------------------------------------- const zone_init_zaudio = ztracy.ZoneN(@src(), "Init zaudio"); @@ -44,11 +66,25 @@ pub fn main() !void { try zglfw.init(); defer zglfw.terminate(); + const monitor = zglfw.getPrimaryMonitor() orelse return error.PrimaryMonitorNotFound; + const video_mode = try monitor.getVideoMode(); + zglfw.windowHint(.client_api, .no_api); - window = try zglfw.Window.create(1280, 720, "voxel-game", null); - window.setSizeLimits(640, 360, -1, -1); + window = try zglfw.Window.create(video_mode.width, video_mode.height, window_title, monitor); + window.setSizeLimits( + min_window_width, + min_window_height, + -1, + -1, + ); defer window.destroy(); + std.debug.assert(zglfw.setCharCallback(window, game.charCallback) == null); + std.debug.assert(zglfw.setCursorPosCallback(window, game.cursorPosCallback) == null); + std.debug.assert(zglfw.setKeyCallback(window, game.keyCallback) == null); + std.debug.assert(zglfw.setMouseButtonCallback(window, game.mouseButtonCallback) == null); + std.debug.assert(zglfw.setScrollCallback(window, game.scrollCallback) == null); + zone_init_zglfw.End(); // --- zgpu ---------------------------------------------------------------- @@ -81,7 +117,7 @@ pub fn main() !void { window, gctx.device, @intFromEnum(zgpu.GraphicsContext.swapchain_format), - @intFromEnum(zgpu.wgpu.TextureFormat.depth32_float), + @intFromEnum(zgpu.wgpu.TextureFormat.undef), ); defer zgui.backend.deinit(); @@ -89,21 +125,38 @@ pub fn main() !void { zone_init_zgui.End(); + // --- game ---------------------------------------------------------------- + + const zone_init_game = ztracy.ZoneN(@src(), "Init game"); + + game.init(); + defer game.deinit(); + + zone_init_game.End(); + // --- main loop ----------------------------------------------------------- const zone_main_loop = ztracy.ZoneN(@src(), "Main loop"); + var t2 = zglfw.getTime(); + while (!window.shouldClose()) { ztracy.FrameMark(); fba.reset(); + const t1 = zglfw.getTime(); + const dt: f32 = @floatCast(@max(t2 - t1, min_frametime)); + t2 = t1; + zglfw.pollEvents(); zgui.backend.newFrame( gctx.swapchain_descriptor.width, gctx.swapchain_descriptor.height, ); + game.update(dt); + const swapchain_texture_view = gctx.swapchain.getCurrentTextureView(); defer swapchain_texture_view.release(); @@ -134,3 +187,16 @@ pub fn main() !void { zone_main_loop.End(); } + +fn logFn( + comptime level: std.log.Level, + comptime _: @Type(.enum_literal), + comptime fmt: []const u8, + args: anytype, +) void { + const message = std.fmt.allocPrint(allocator, fmt, args) catch return; + logs.append(allocator, Log.init(level, message)) catch { + allocator.free(message); + return; + }; +}