ona/source/ona/ona.zig
kayomn b012e1e5f6
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
Re-implement native function binding / calling
2023-08-12 14:11:19 +01:00

148 lines
3.5 KiB
Zig

const app = @import("./app.zig");
const coral = @import("coral");
const ext = @import("./ext.zig");
pub const file = @import("./file.zig");
const heap = @import("./heap.zig");
const kym = @import("./kym.zig");
fn kym_handle_errors(info: kym.ErrorInfo) void {
app.log_fail(info.message);
var remaining_frames = info.frames.len;
if (remaining_frames != 0) {
app.log_fail("stack trace:");
while (remaining_frames != 0) {
remaining_frames -= 1;
app.log_fail(info.frames[remaining_frames].name);
}
}
}
fn kym_log_info(env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeRef {
const argument = try env.expect(try env.arg(0));
defer env.discard(argument);
app.log_info(try env.unbox_string(argument));
return null;
}
fn kym_log_warn(env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeRef {
const argument = try env.expect(try env.arg(0));
defer env.discard(argument);
app.log_warn(try env.unbox_string(argument));
return null;
}
fn kym_log_fail(env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeRef {
const argument = try env.expect(try env.arg(0));
defer env.discard(argument);
app.log_fail(try env.unbox_string(argument));
return null;
}
fn last_sdl_error() [:0]const u8 {
return coral.io.slice_sentineled(@as(u8, 0), @as([*:0]const u8, @ptrCast(ext.SDL_GetError())));
}
pub fn run_app(file_access: file.Access) void {
defer heap.trace_leaks();
if (ext.SDL_Init(ext.SDL_INIT_EVERYTHING) != 0) {
return app.log_fail(last_sdl_error());
}
defer ext.SDL_Quit();
var script_env = kym.RuntimeEnv.make(heap.allocator, kym.ErrorHandler.from(kym_handle_errors)) catch {
return app.log_fail("failed to initialize script runtime");
};
defer script_env.free();
kym.bind_syscaller(&script_env, "log_info", kym.Caller.from(kym_log_info)) catch {
return app.log_fail("failed to bind `log_info` syscall");
};
kym.bind_syscaller(&script_env, "log_warn", kym.Caller.from(kym_log_warn)) catch {
return app.log_fail("failed to bind `log_warn` syscall");
};
kym.bind_syscaller(&script_env, "log_fail", kym.Caller.from(kym_log_fail)) catch {
return app.log_fail("failed to bind `log_fail` syscall");
};
var manifest = app.Manifest{};
manifest.load(&script_env, file_access) catch return;
const window = create: {
const pos = ext.SDL_WINDOWPOS_CENTERED;
const flags = 0;
break: create ext.SDL_CreateWindow(&manifest.title, pos, pos, manifest.width, manifest.height, flags) orelse {
return app.log_fail(last_sdl_error());
};
};
defer ext.SDL_DestroyWindow(window);
const renderer = create: {
const default_driver_index = -1;
const flags = ext.SDL_RENDERER_ACCELERATED;
break: create ext.SDL_CreateRenderer(window, default_driver_index, flags) orelse {
return app.log_fail(last_sdl_error());
};
};
defer ext.SDL_DestroyRenderer(renderer);
{
var previous_ticks = ext.SDL_GetTicks64();
while (true) {
{
var event = @as(ext.SDL_Event, undefined);
while (ext.SDL_PollEvent(&event) != 0) {
switch (event.type) {
ext.SDL_QUIT => return,
else => {},
}
}
}
{
// Based on https://fabiensanglard.net/timer_and_framerate/index.php.
const current_ticks = ext.SDL_GetTicks64();
const milliseconds_per_second = 1000.0;
const tick_frequency = @as(u64, @intFromFloat(milliseconds_per_second / manifest.tick_rate));
while (previous_ticks < current_ticks) {
previous_ticks += tick_frequency;
}
}
_ = ext.SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
_ = ext.SDL_RenderClear(renderer);
_ = ext.SDL_RenderPresent(renderer);
}
}
}