const std = @import("std"); const glfw = @import("zglfw"); const stbi = @import("zstbi"); const vk = @import("vulkan"); const c = @import("const.zig"); const atoms = @import("engine/atoms.zig"); const Engine = @import("engine/Engine.zig"); const Swapchain = @import("engine/Swapchain.zig"); const Game = @import("Game.zig"); pub fn main() !void { var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init; defer _ = gpa.deinit(); const allocator = gpa.allocator(); atoms.init(allocator); defer atoms.deinit(); stbi.init(allocator); defer stbi.deinit(); glfw.init() catch |err| { std.log.err("Could not initialize GLFW", .{}); return err; }; defer glfw.terminate(); if (!glfw.isVulkanSupported()) { std.log.err("Vulkan is not supported by this system", .{}); return error.NoVulkan; } glfw.windowHint(.client_api, .no_api); var window = glfw.Window.create(c.default_window_width, c.default_window_height, c.window_title, null) catch |err| { std.log.err("Could not create window", .{}); return err; }; defer window.destroy(); window.setSizeLimits(c.min_window_width, c.min_window_height, -1, -1); window.setInputMode(.cursor, .disabled) catch {}; if (glfw.rawMouseMotionSupported()) { window.setInputMode(.raw_mouse_motion, true) catch {}; } _ = window.setKeyCallback(keyCallback); _ = window.setCursorPosCallback(cursorPosCallback); _ = window.setMouseButtonCallback(mouseButtonCallback); var engine = try Engine.init(allocator, window); defer engine.deinit(); var swapchain = try Swapchain.init(&engine); defer swapchain.deinit(&engine); var game = try Game.init(allocator, &engine, &swapchain); var callback_context: CallbackContext = blk: { const cursor_last_xpos, const cursor_last_ypos = window.getCursorPos(); break :blk .{ .game = &game, .cursor_last_xpos = cursor_last_xpos, .cursor_last_ypos = cursor_last_ypos, .focused = (window.getInputMode(.cursor) catch .normal) == .disabled, }; }; window.setUserPointer(&callback_context); defer { window.setUserPointer(null); game.deinit(); } var t1 = glfw.getTime(); while (!window.shouldClose()) { glfw.pollEvents(); const t2 = glfw.getTime(); const dt: f32 = @floatCast(t2 - t1); t1 = t2; game.update(dt); } std.log.debug("Exitted the game loop", .{}); for (swapchain.swapchain_images) |x| engine.waitForFence(x.fence) catch {}; engine.device.deviceWaitIdle() catch {}; } const CallbackContext = struct { game: *Game, focused: bool, cursor_last_xpos: f64, cursor_last_ypos: f64, }; fn keyCallback(window: *glfw.Window, key_code: glfw.Key, _: c_int, action: glfw.Action, mods: glfw.Mods) callconv(.c) void { const maybe_ctx = window.getUserPointer(CallbackContext); if (key_code == .escape and action == .press and (window.getInputMode(.cursor) catch .normal) == .disabled) { window.setInputMode(.cursor, .normal) catch {}; if (maybe_ctx) |ctx| { const cursor_last_xpos, const cursor_last_ypos = window.getCursorPos(); ctx.cursor_last_xpos = cursor_last_xpos; ctx.cursor_last_ypos = cursor_last_ypos; ctx.focused = false; } return; } if (maybe_ctx) |ctx| { if (ctx.focused) { switch (action) { .press => ctx.game.onKeyDown(key_code, mods), .release => ctx.game.onKeyUp(key_code, mods), .repeat => {}, } } } } fn cursorPosCallback(window: *glfw.Window, cursor_xpos: f64, cursor_ypos: f64) callconv(.c) void { const maybe_ctx = window.getUserPointer(CallbackContext); if (maybe_ctx) |ctx| { if (ctx.focused) { const dx: f32 = @floatCast(cursor_xpos - ctx.cursor_last_xpos); const dy: f32 = @floatCast(cursor_ypos - ctx.cursor_last_ypos); ctx.game.onMouseMove(dx, dy); ctx.cursor_last_xpos = cursor_xpos; ctx.cursor_last_ypos = cursor_ypos; } } } fn mouseButtonCallback(window: *glfw.Window, button: glfw.MouseButton, action: glfw.Action, mods: glfw.Mods) callconv(.c) void { const maybe_ctx = window.getUserPointer(CallbackContext); if (button == .left and action == .press and (window.getInputMode(.cursor) catch .normal) == .normal) { window.setInputMode(.cursor, .disabled) catch {}; if (maybe_ctx) |ctx| { const cursor_last_xpos, const cursor_last_ypos = window.getCursorPos(); ctx.cursor_last_xpos = cursor_last_xpos; ctx.cursor_last_ypos = cursor_last_ypos; ctx.focused = true; } } if (maybe_ctx) |ctx| { if (ctx.focused) { switch (action) { .press => ctx.game.onMouseDown(button, mods), .release => ctx.game.onMouseUp(button, mods), .repeat => {}, } } } }