Add support for launch args and "dump_shader_translations" arg #59

Merged
kayomn merged 1 commits from launch_args into main 2024-07-22 22:29:47 +02:00
7 changed files with 141 additions and 109 deletions

View File

@ -30,12 +30,10 @@ const Player = struct {
move_y: ona.act.Axis = .{.keys = .{.w, .s}},
};
pub fn main() !void {
try ona.start_app(setup, .{
.tick_rate = 60,
.execution = .{.thread_share = 0.1},
});
}
pub const main = ona.start(setup, .{
.tick_rate = 60,
.execution = .{.thread_share = 0.1},
});
fn load(config: ona.Write(ona.gfx.Config), actors: ona.Write(Actors), assets: ona.Write(ona.gfx.Assets)) !void {
config.res.width, config.res.height = .{1280, 720};

View File

@ -1,25 +0,0 @@
const coral = @import("coral");
const flow = @import("flow");
events: *const Events,
target_frame_time: f64,
elapsed_time: f64,
is_running: bool,
pub const Events = struct {
load: flow.World.Event,
pre_update: flow.World.Event,
update: flow.World.Event,
post_update: flow.World.Event,
render: flow.World.Event,
finish: flow.World.Event,
exit: flow.World.Event,
};
const Self = @This();
pub fn quit(self: *Self) void {
self.is_running = false;
}

View File

@ -1,17 +1,13 @@
const App = @import("./App.zig");
const coral = @import("coral");
const flow = @import("flow");
const gfx = @import("./gfx.zig");
const msg = @import("./msg.zig");
const ona = @import("./ona.zig");
const std = @import("std");
pub const Axis = struct {
keys: ?[2]gfx.Input.Key = null,
keys: ?[2]ona.gfx.Input.Key = null,
};
pub const Mapping = struct {
@ -37,7 +33,7 @@ pub const Mapping = struct {
}
};
pub fn setup(world: *flow.World, events: App.Events) std.mem.Allocator.Error!void {
pub fn setup(world: *flow.World, events: ona.App.Events) std.mem.Allocator.Error!void {
try world.set_state(Mapping{});
try world.on_event(events.pre_update, flow.system_fn(update), .{
@ -45,7 +41,7 @@ pub fn setup(world: *flow.World, events: App.Events) std.mem.Allocator.Error!voi
});
}
pub fn update(inputs: msg.Receive(gfx.Input), mapping: flow.Write(Mapping)) void {
pub fn update(inputs: ona.msg.Receive(ona.gfx.Input), mapping: flow.Write(Mapping)) void {
mapping.res.keys_pressed = Mapping.ScancodeSet.initEmpty();
for (inputs.messages()) |message| {

View File

@ -1,5 +1,3 @@
const App = @import("./App.zig");
pub const colors = @import("./gfx/colors.zig");
const coral = @import("coral");
@ -8,7 +6,7 @@ const ext = @import("./ext.zig");
const flow = @import("flow");
const msg = @import("./msg.zig");
const ona = @import("./ona.zig");
const rendering = @import("./gfx/rendering.zig");
@ -437,7 +435,7 @@ fn load_bmp_texture(arena: *std.heap.ArenaAllocator, storage: coral.files.Storag
};
}
pub fn poll(app: flow.Write(App), inputs: msg.Send(Input)) !void {
pub fn poll(app: flow.Write(ona.App), inputs: ona.msg.Send(Input)) !void {
var event = @as(ext.SDL_Event, undefined);
while (ext.SDL_PollEvent(&event) != 0) {
@ -450,7 +448,7 @@ pub fn poll(app: flow.Write(App), inputs: msg.Send(Input)) !void {
}
}
pub fn setup(world: *flow.World, events: App.Events) (error {Unsupported} || std.Thread.SpawnError || std.mem.Allocator.Error)!void {
pub fn setup(world: *flow.World, events: ona.App.Events) (error {Unsupported} || std.Thread.SpawnError || std.mem.Allocator.Error)!void {
if (ext.SDL_Init(ext.SDL_INIT_VIDEO) != 0) {
return error.Unsupported;
}

View File

@ -4,6 +4,8 @@ const ext = @cImport({
@cInclude("spirv-cross/spirv_cross_c.h");
});
const ona = @import("../ona.zig");
const std = @import("std");
pub const Error = std.mem.Allocator.Error || error {
@ -283,7 +285,9 @@ pub fn analyze(arena: *std.heap.ArenaAllocator, options: Options) Error!Program
try stage.reflect_images_samplers(arena, compiler, resources);
try stage.reflect_uniform_blocks(arena, compiler, resources);
std.log.info("{s}", .{stage.source});
if (ona.launch_arg(.dump_shader_translations) != null) {
std.log.info("Vertex translated:\n{s}", .{stage.source});
}
break: vertex_stage stage;
},
@ -307,7 +311,9 @@ pub fn analyze(arena: *std.heap.ArenaAllocator, options: Options) Error!Program
try stage.reflect_images_samplers(arena, compiler, resources);
try stage.reflect_uniform_blocks(arena, compiler, resources);
std.log.info("{s}", .{stage.source});
if (ona.launch_arg(.dump_shader_translations) != null) {
std.log.info("Fragment translated:\n{s}", .{stage.source});
}
break: fragment_stage stage;
},

View File

@ -1,9 +1,9 @@
const App = @import("./App.zig");
const coral = @import("coral");
const flow = @import("flow");
const ona = @import("./ona.zig");
const std = @import("std");
fn Channel(comptime Message: type) type {
@ -106,7 +106,7 @@ pub fn Send(comptime Message: type) type {
.channel = (try context.register_writable_state_access(TypedChannel)) orelse set: {
try context.world.set_state(TypedChannel.init(coral.heap.allocator));
const app = context.world.get_state(App).?;
const app = context.world.get_state(ona.App).?;
try context.world.on_event(app.events.post_update, flow.system_fn(TypedChannel.swap), .{
.label = "swap channel of " ++ @typeName(Message),

View File

@ -1,5 +1,3 @@
pub const App = @import("./App.zig");
pub const act = @import("./act.zig");
const coral = @import("coral");
@ -14,6 +12,35 @@ pub const msg = @import("./msg.zig");
const std = @import("std");
pub const App = struct {
events: *const Events,
target_frame_time: f64,
elapsed_time: f64,
is_running: bool,
pub const Events = struct {
load: flow.World.Event,
pre_update: flow.World.Event,
update: flow.World.Event,
post_update: flow.World.Event,
render: flow.World.Event,
finish: flow.World.Event,
exit: flow.World.Event,
};
pub fn quit(self: *App) void {
self.is_running = false;
}
};
pub const Flag = enum {
dump_shader_translations,
var launch_args = [_]?[]const u8{null} ** std.enums.values(Flag).len;
const values = std.enums.values(Flag);
};
pub const Options = struct {
tick_rate: u64,
execution: Execution,
@ -38,79 +65,111 @@ pub const default_middlewares = &.{
act.setup,
};
pub fn start_app(setup: Setup, options: Options) anyerror!void {
defer {
coral.heap.trace_leaks();
ext.SDL_Quit();
}
pub fn launch_arg(flag: Flag) ?[]const u8 {
return Flag.launch_args[@intFromEnum(flag)];
}
var world = try switch (options.execution) {
.single_threaded => flow.World.init(0),
pub fn start(comptime setup: Setup, options: Options) fn () anyerror!void {
const Start = struct {
fn main() anyerror!void {
defer {
coral.heap.trace_leaks();
ext.SDL_Quit();
}
.thread_share => |thread_share| init: {
const cpu_count = @as(u32, @intCast(std.math.clamp(std.Thread.getCpuCount() catch |cpu_count_error| {
@panic(switch (cpu_count_error) {
error.PermissionDenied => "permission denied retrieving CPU count",
error.SystemResources => "system resources are preventing retrieval of the CPU count",
error.Unexpected => "unexpected failure retrieving CPU count",
});
}, 0, std.math.maxInt(u32))));
parse_args: for (std.os.argv[1 ..]) |arg| {
const arg_span = std.mem.span(arg);
const arg_split_index = std.mem.indexOfScalar(u8, arg_span, '=') orelse arg_span.len;
const arg_name = arg_span[0 .. arg_split_index];
break: init flow.World.init(coral.scalars.fractional(cpu_count, thread_share) orelse 0);
},
};
for (Flag.values) |value| {
const name = @tagName(value);
defer world.deinit();
if (!std.mem.eql(u8, arg_name, name)) {
continue;
}
const events = App.Events{
.load = try world.create_event("load"),
.pre_update = try world.create_event("pre-update"),
.update = try world.create_event("update"),
.post_update = try world.create_event("post-update"),
.render = try world.create_event("render"),
.finish = try world.create_event("finish"),
.exit = try world.create_event("exit"),
};
Flag.launch_args[@intFromEnum(value)] =
if (arg_split_index == arg_span.len)
name
else
arg_span[arg_split_index ..];
const app = try world.set_get_state(App{
.events = &events,
.target_frame_time = 1.0 / @as(f64, @floatFromInt(options.tick_rate)),
.elapsed_time = 0,
.is_running = true,
});
continue: parse_args;
}
}
for (options.middlewares) |setup_middleware| {
try setup_middleware(&world, events);
}
var world = try switch (options.execution) {
.single_threaded => flow.World.init(0),
try setup(&world, events);
try world.run_event(events.load);
.thread_share => |thread_share| init: {
const cpu_count = @as(u32, @intCast(std.math.clamp(std.Thread.getCpuCount() catch |cpu_count_error| {
@panic(switch (cpu_count_error) {
error.PermissionDenied => "permission denied retrieving CPU count",
error.SystemResources => "system resources are preventing retrieval of the CPU count",
error.Unexpected => "unexpected failure retrieving CPU count",
});
}, 0, std.math.maxInt(u32))));
const ticks_initial = std.time.milliTimestamp();
var ticks_previous = ticks_initial;
var accumulated_time = @as(f64, 0);
break: init flow.World.init(coral.scalars.fractional(cpu_count, thread_share) orelse 0);
},
};
while (app.is_running) {
const ticks_current = std.time.milliTimestamp();
const milliseconds_per_second = 1000.0;
const delta_time = @as(f64, @floatFromInt(ticks_current - ticks_previous)) / milliseconds_per_second;
defer world.deinit();
app.elapsed_time = @as(f64, @floatFromInt(ticks_current - ticks_initial)) / milliseconds_per_second;
ticks_previous = ticks_current;
accumulated_time += delta_time;
const events = App.Events{
.load = try world.create_event("load"),
.pre_update = try world.create_event("pre-update"),
.update = try world.create_event("update"),
.post_update = try world.create_event("post-update"),
.render = try world.create_event("render"),
.finish = try world.create_event("finish"),
.exit = try world.create_event("exit"),
};
try world.run_event(events.pre_update);
const app = try world.set_get_state(App{
.events = &events,
.target_frame_time = 1.0 / @as(f64, @floatFromInt(options.tick_rate)),
.elapsed_time = 0,
.is_running = true,
});
while (accumulated_time >= app.target_frame_time) : (accumulated_time -= app.target_frame_time) {
try world.run_event(events.update);
for (options.middlewares) |setup_middleware| {
try setup_middleware(&world, events);
}
try setup(&world, events);
try world.run_event(events.load);
const ticks_initial = std.time.milliTimestamp();
var ticks_previous = ticks_initial;
var accumulated_time = @as(f64, 0);
while (app.is_running) {
const ticks_current = std.time.milliTimestamp();
const milliseconds_per_second = 1000.0;
const delta_time = @as(f64, @floatFromInt(ticks_current - ticks_previous)) / milliseconds_per_second;
app.elapsed_time = @as(f64, @floatFromInt(ticks_current - ticks_initial)) / milliseconds_per_second;
ticks_previous = ticks_current;
accumulated_time += delta_time;
try world.run_event(events.pre_update);
while (accumulated_time >= app.target_frame_time) : (accumulated_time -= app.target_frame_time) {
try world.run_event(events.update);
}
try world.run_event(events.post_update);
try world.run_event(events.render);
try world.run_event(events.finish);
}
try world.run_event(events.exit);
}
};
try world.run_event(events.post_update);
try world.run_event(events.render);
try world.run_event(events.finish);
}
try world.run_event(events.exit);
return Start.main;
}
pub const system_fn = flow.system_fn;