const std = @import("std"); const Recti = @import("geometry/Recti.zig"); const Matrix4f = @import("geometry/Matrix4f.zig"); const shaders = @import("shaders.zig"); const Texture = @import("Texture.zig"); const Sprite = @import("Sprite.zig"); const Layer = @import("Layer.zig"); const Color = @import("Color.zig"); const Scene = @import("Scene.zig"); const assets = @import("assets.zig"); const c = @cImport({ @cInclude("glad/glad.h"); @cInclude("GLFW/glfw3.h"); }); const AutoHashMap = std.AutoHashMap; const Error = error { WindowNotInitialized, WindowAlreadyInitialized, NoScene, AlreadyRunning }; var window: ?*c.GLFWwindow = null; var current_scene: ?Scene = null; var next_scene: ?Scene = null; var projection: Matrix4f = undefined; fn glfw_on_error(err: c_int, desc_c: [*c]const u8) callconv(.C) void { const desc: *const u8 = @ptrCast(desc_c); std.log.err("[Engine:glfw_on_error] glfw error {x:0>8}: {s}", .{ err, desc }); } fn glfw_on_resize (_: ?*c.GLFWwindow, width: c_int, height: c_int) callconv(.C) void { std.debug.print("[Engine:glfw_on_resize] {?}: {d} x {d}\n", .{ window, width, height }); c.glViewport(0, 0, width, height); projection = Matrix4f.orthographic(0, @floatFromInt(width), @floatFromInt(height), 0, 0, 100); shaders.set_projection_matrix(&projection); if (current_scene != null) current_scene.?.resize(width, height); } fn get_size() struct { i32, i32 } { var width: c_int = undefined; var height: c_int = undefined; c.glfwGetFramebufferSize(window, @ptrCast(&width), @ptrCast(&height)); return .{ width, height }; } pub fn setup() !void { if (window != null) return Error.WindowAlreadyInitialized; // in case of errors, set callback early! // for some reason this returns an error function as well?? _ = c.glfwSetErrorCallback(glfw_on_error); // initialize glfw capabilities & cleanup if (c.glfwInit() != 1) { std.log.err("Failed to init glfw", .{}); return error.Initialization; } // ensure glfw knows what we're about // c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MAJOR, 3); c.glfwDefaultWindowHints(); c.glfwWindowHint(c.GLFW_SAMPLES, 4); // c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MINOR, 3); // c.glfwWindowHint(c.GLFW_OPENGL_PROFILE, c.GLFW_OPENGL_CORE_PROFILE); // create the window & cleanup window = c.glfwCreateWindow(1920, 1080, "My Title", null, null) orelse { std.log.err("Failed to open window", .{}); return error.Initialization; }; // load opengl into the window c.glfwMakeContextCurrent(window); if (c.gladLoadGL() != 1) { std.log.err("Failed to load GL context", .{}); return error.Initialization; } // configure the context! c.glfwSwapInterval(1); // compile shaders... try shaders.load(); try assets.load(); _ = c.glfwSetWindowSizeCallback(window, glfw_on_resize); const clearBrightness: f32 = 0.09; c.glClearColor(clearBrightness, clearBrightness, clearBrightness, 1.0); // c.glEnable(c.GL_MULTISAMPLE); c.glDisable(c.GL_MULTISAMPLE); c.glEnable(c.GL_BLEND); c.glBlendFunc(c.GL_SRC_ALPHA, c.GL_ONE_MINUS_SRC_ALPHA); c.glEnable(c.GL_DEPTH_TEST); c.glDepthFunc(c.GL_LEQUAL); c.glDepthMask(c.GL_TRUE); const width, const height = get_size(); c.glViewport(0, 0, width, height); projection = Matrix4f.orthographic(0, @floatFromInt(width), @floatFromInt(height), 0, 0, 100); shaders.set_projection_matrix(&projection); } pub fn destroy() void { c.glfwDestroyWindow(window); c.glfwTerminate(); } pub fn set_scene(scene: Scene) void { next_scene = scene; } pub fn run() Error!void { if (window == null) return Error.WindowNotInitialized; if (current_scene != null) return Error.AlreadyRunning; if (next_scene == null) return Error.NoScene; // run the main loop while (c.glfwWindowShouldClose(window) == 0) { // switch scenes if need be if (next_scene != null) { if (current_scene != null) current_scene.?.destroy(); current_scene = next_scene; next_scene = null; // start our scene try current_scene.?.start(); // and send it the appropriate resize. const width, const height = get_size(); current_scene.?.resize(width, height); } // setup for drawing c.glClear(c.GL_COLOR_BUFFER_BIT | c.GL_DEPTH_BUFFER_BIT); current_scene.?.draw(); c.glfwSwapBuffers(window); c.glfwPollEvents(); current_scene.?.update(0.0042); } }