Attempt at making a bloxel game in Zig using Mach and Flecs
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

113 lines
3.9 KiB

const std = @import("std");
const GeneralPurposeAllocator = std.heap.GeneralPurposeAllocator(.{});
const core = @import("mach").core;
const Renderer = @import("./renderer.zig");
const flecszigble = @import("flecs-zig-ble");
const Context = flecszigble.Context(void);
const World = Context.World;
const Iter = Context.Iter;
const flecs = flecszigble.flecs;
const OnLoad = flecs.pipeline.OnLoad;
const OnUpdate = flecs.pipeline.OnUpdate;
const OnStore = flecs.pipeline.OnStore;
pub const App = @This();
gpa: GeneralPurposeAllocator,
allocator: std.mem.Allocator,
random: std.Random,
world: *World,
renderer: *Renderer,
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.Random.DefaultPrng.init(0);
app.random = prng.random();
// Initialize flecs-zig-ble and create a new Flecs world.
//
// Flecs is a library for using Entity Component System (ECS) design
// intuitively and efficiently. Entities can be created and have various
// components – and relationships to other entities – added to them.
//
// This data is stored in an in-memory database, which can be queried
// and modified. For example by using systems, you are able to get
// entities that match a set of components, and modify their values.
flecszigble.init(app.allocator);
const world = try World.init();
app.world = world;
// Create a singleton component for accessing the `App` from ECS.
_ = try world.singleton("App", *App, app);
// TODO: The way we register systems using flecs-zig-ble is still very WIP.
_ = try world.system("PollEvents", pollEvents, OnLoad, "App");
const s = try world.system("UpdateWindowTitle", updateWindowTitle, OnStore, "");
// Set the update interval of the `UpdateWindowTitle` system to 1 second.
_ = flecszigble.c.ecs_set_interval(world.raw, s.raw, 1.0);
app.renderer = try Renderer.init(app);
}
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();
defer app.world.deinit();
defer app.renderer.deinit();
}
/// Update function called by Mach Core, which we'll just use to update Flecs.
/// This will then process all the systems we've registered in our pipeline.
pub fn update(app: *App) !bool {
return !app.world.progress(0.0);
}
/// Read events from the OS such as input.
pub fn pollEvents(it: Iter) void {
const app = it.field(*App, 1)[0];
var pollIter = core.pollEvents();
while (pollIter.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 => it.world.quit(),
else => {},
}
}
}
/// Update the window title to show FPS and input frequency.
pub fn updateWindowTitle(_: Iter) void {
core.printTitle(
"Triangle [ {d}fps ] [ Input {d}hz ]",
.{ core.frameRate(), core.inputRate() },
) catch @panic("Title too long!");
}