|
|
|
const std = @import("std");
|
|
|
|
const GeneralPurposeAllocator = std.heap.GeneralPurposeAllocator(.{});
|
|
|
|
|
|
|
|
const core = @import("mach").core;
|
|
|
|
const Renderer = @import("./renderer.zig");
|
|
|
|
|
|
|
|
pub const App = @This();
|
|
|
|
|
|
|
|
gpa: GeneralPurposeAllocator,
|
|
|
|
allocator: std.mem.Allocator,
|
|
|
|
random: std.rand.Random,
|
|
|
|
|
|
|
|
renderer: *Renderer,
|
|
|
|
|
|
|
|
app_timer: core.Timer,
|
|
|
|
title_timer: core.Timer,
|
|
|
|
|
|
|
|
pub fn init(app: *App) !void {
|
|
|
|
try core.init(.{
|
|
|
|
// Request high performance = prefer dedicated GPU when available.
|
|
|
|
.power_preference = .high_performance,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Set up a "general purpose allocator" that will handle allocations for
|
|
|
|
// the lifetime of the application, for which a more specific allocation
|
|
|
|
// strategy is not necessary.
|
|
|
|
//
|
|
|
|
// Here, `gpa` is an instance of this allocator, which handles the
|
|
|
|
// allocation logic, while `allocator` is the interface through which
|
|
|
|
// functions such as `alloc` and `free` are called.
|
|
|
|
app.gpa = GeneralPurposeAllocator{};
|
|
|
|
app.allocator = app.gpa.allocator();
|
|
|
|
|
|
|
|
// Create a pseudo-random number generator, but initialize it with
|
|
|
|
// a constant seed so we always get the same result when launching.
|
|
|
|
var prng = std.rand.DefaultPrng.init(0);
|
|
|
|
app.random = prng.random();
|
|
|
|
|
|
|
|
app.renderer = try Renderer.init(app);
|
|
|
|
|
|
|
|
app.app_timer = try core.Timer.start();
|
|
|
|
app.title_timer = try core.Timer.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn deinit(app: *App) void {
|
|
|
|
// Using `defer` here, so we can specify them
|
|
|
|
// in the order they were created in `init`.
|
|
|
|
defer core.deinit();
|
|
|
|
defer _ = app.gpa.deinit(); // TODO: Check for memory leaks?
|
|
|
|
defer app.renderer.deinit();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn update(app: *App) !bool {
|
|
|
|
// Read events from the OS such as input.
|
|
|
|
var iter = core.pollEvents();
|
|
|
|
while (iter.next()) |event| {
|
|
|
|
switch (event) {
|
|
|
|
// Allow the renderer to act on the window being resized.
|
|
|
|
// This is required so we can resize necessary buffers.
|
|
|
|
.framebuffer_resize => |_| app.renderer.resize(),
|
|
|
|
|
|
|
|
// Close the window when requested, such as when
|
|
|
|
// pressing the X button in the window title bar.
|
|
|
|
.close => return true,
|
|
|
|
|
|
|
|
else => {},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
app.renderer.update();
|
|
|
|
|
|
|
|
// Update the window title to show FPS and input frequency.
|
|
|
|
if (app.title_timer.read() >= 1.0) {
|
|
|
|
app.title_timer.reset();
|
|
|
|
try core.printTitle("Triangle [ {d}fps ] [ Input {d}hz ]", .{ core.frameRate(), core.inputRate() });
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|