Improve App entry-point declaration (closes #61)
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
f49906c714
commit
0f2950a630
14
build.zig
14
build.zig
|
@ -208,9 +208,9 @@ pub fn build(b: *std.Build) !void {
|
||||||
});
|
});
|
||||||
|
|
||||||
const ona_module = try project.add_module(b, "ona", .{});
|
const ona_module = try project.add_module(b, "ona", .{});
|
||||||
const input_module = try project.add_module(b, "input", .{});
|
const hid_module = try project.add_module(b, "hid", .{});
|
||||||
|
|
||||||
const coral_module = try project.add_module(b, "coral", .{
|
const gfx_module = try project.add_module(b, "gfx", .{
|
||||||
.imports = &.{
|
.imports = &.{
|
||||||
.{
|
.{
|
||||||
.name = "sokol",
|
.name = "sokol",
|
||||||
|
@ -224,14 +224,14 @@ pub fn build(b: *std.Build) !void {
|
||||||
|
|
||||||
.{
|
.{
|
||||||
.name = "input",
|
.name = "input",
|
||||||
.module = input_module,
|
.module = hid_module,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
coral_module.addIncludePath(b.path("ext/"));
|
gfx_module.addIncludePath(b.path("ext/"));
|
||||||
|
|
||||||
coral_module.linkLibrary(spirv_cross: {
|
gfx_module.linkLibrary(spirv_cross: {
|
||||||
const dir = "ext/spirv-cross/";
|
const dir = "ext/spirv-cross/";
|
||||||
|
|
||||||
const sources = [_][]const u8{
|
const sources = [_][]const u8{
|
||||||
|
@ -274,12 +274,12 @@ pub fn build(b: *std.Build) !void {
|
||||||
break: spirv_cross lib;
|
break: spirv_cross lib;
|
||||||
});
|
});
|
||||||
|
|
||||||
coral_module.linkSystemLibrary("SDL2", .{
|
gfx_module.linkSystemLibrary("SDL2", .{
|
||||||
.needed = true,
|
.needed = true,
|
||||||
.preferred_link_mode = .dynamic,
|
.preferred_link_mode = .dynamic,
|
||||||
});
|
});
|
||||||
|
|
||||||
coral_module.link_libc = true;
|
gfx_module.link_libc = true;
|
||||||
|
|
||||||
try project.find_tests(b);
|
try project.find_tests(b);
|
||||||
try project.find_demos(b);
|
try project.find_demos(b);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const coral = @import("coral");
|
const gfx = @import("gfx");
|
||||||
|
|
||||||
const ona = @import("ona");
|
const ona = @import("ona");
|
||||||
|
|
||||||
|
@ -12,17 +12,11 @@ const CRT = extern struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
const Effects = struct {
|
const Effects = struct {
|
||||||
render_texture: coral.Texture = .default,
|
render_texture: gfx.Texture = .default,
|
||||||
crt_effect: coral.Effect = .default,
|
crt_effect: gfx.Effect = .default,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const main = ona.start(setup, .{
|
fn load(display: ona.Write(gfx.Display), actors: ona.Write(Effects), assets: ona.Write(gfx.Assets)) !void {
|
||||||
.tick_rate = 60,
|
|
||||||
.execution = .{.thread_share = 0.1},
|
|
||||||
.middleware = &.{coral.setup},
|
|
||||||
});
|
|
||||||
|
|
||||||
fn load(display: ona.Write(coral.Display), actors: ona.Write(Effects), assets: ona.Write(coral.Assets)) !void {
|
|
||||||
display.state.width, display.state.height = .{1280, 720};
|
display.state.width, display.state.height = .{1280, 720};
|
||||||
|
|
||||||
actors.state.render_texture = try assets.state.load_texture(.{
|
actors.state.render_texture = try assets.state.load_texture(.{
|
||||||
|
@ -39,10 +33,16 @@ fn load(display: ona.Write(coral.Display), actors: ona.Write(Effects), assets: o
|
||||||
actors.state.crt_effect = try assets.state.load_effect_file(ona.files.bundle, "./crt.frag.spv");
|
actors.state.crt_effect = try assets.state.load_effect_file(ona.files.bundle, "./crt.frag.spv");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(commands: coral.Commands, effects: ona.Write(Effects), app: ona.Read(ona.App), display: ona.Write(coral.Display)) !void {
|
pub const main = ona.App.setup.
|
||||||
|
with_module(gfx).
|
||||||
|
with_state(Effects{}).
|
||||||
|
with_system(.load, ona.system_fn(load), .{.label = "load effects"}).
|
||||||
|
with_system(.render, ona.system_fn(render), .{.label = "render effects"}).build();
|
||||||
|
|
||||||
|
fn render(commands: gfx.Commands, effects: ona.Write(Effects), app: ona.Read(ona.App), display: ona.Write(gfx.Display)) !void {
|
||||||
try commands.set_target(.{
|
try commands.set_target(.{
|
||||||
.texture = effects.state.render_texture,
|
.texture = effects.state.render_texture,
|
||||||
.clear_color = coral.colors.black,
|
.clear_color = gfx.colors.black,
|
||||||
.clear_depth = 0,
|
.clear_depth = 0,
|
||||||
.clear_stencil = 0,
|
.clear_stencil = 0,
|
||||||
});
|
});
|
||||||
|
@ -50,7 +50,7 @@ fn render(commands: coral.Commands, effects: ona.Write(Effects), app: ona.Read(o
|
||||||
const display_width: f32 = @floatFromInt(display.state.width);
|
const display_width: f32 = @floatFromInt(display.state.width);
|
||||||
const display_height: f32 = @floatFromInt(display.state.height);
|
const display_height: f32 = @floatFromInt(display.state.height);
|
||||||
|
|
||||||
const display_transform = coral.Transform2D{
|
const display_transform = gfx.Transform2D{
|
||||||
.origin = .{display_width / 2, display_height / 2},
|
.origin = .{display_width / 2, display_height / 2},
|
||||||
.xbasis = .{display_width, 0},
|
.xbasis = .{display_width, 0},
|
||||||
.ybasis = .{0, display_height},
|
.ybasis = .{0, display_height},
|
||||||
|
@ -84,9 +84,3 @@ fn render(commands: coral.Commands, effects: ona.Write(Effects), app: ona.Read(o
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup(world: *ona.World, events: ona.App.Events) !void {
|
|
||||||
try world.set_state(Effects{});
|
|
||||||
|
|
||||||
try world.on_event(events.load, ona.system_fn(load), .{.label = "load"});
|
|
||||||
try world.on_event(events.render, ona.system_fn(render), .{.label = "render actors"});
|
|
||||||
}
|
|
||||||
|
|
|
@ -44,11 +44,11 @@ As the project evolves, dependencies on libraries external to the project codeba
|
||||||
|
|
||||||
After the repository has finished cloning, you will then want to also clone all Git submodule dependencies via the `git submodule update --init --recursive` command. If you are using a Git front-end, this may be a menu option or is handled *automagically*, it varies depending on the front-end.
|
After the repository has finished cloning, you will then want to also clone all Git submodule dependencies via the `git submodule update --init --recursive` command. If you are using a Git front-end, this may be a menu option or is handled *automagically*, it varies depending on the front-end.
|
||||||
|
|
||||||
Once all third-party tools and dependencies are satisfied, navigate to the root project folder and run `zig build demos` to build the demo executables. The resulting binaries will be placed in `/demos` will a name respective to the source file it was built from.
|
Once all third-party tools and dependencies are satisfied, navigate to the root project folder and run `zig build demos` to build the demo executables. The resulting binaries will be placed in `/demos` with a name respective to the source file it was built from.
|
||||||
|
|
||||||
To experiment without creating your own Zig project, you can create a new uniquely named source file in this directory and the `zig build demos` step will (re)build it along with everything else.
|
To experiment without creating your own Zig project, you can create a new uniquely named source file in this directory and the `zig build demos` step will (re)build it along with everything else.
|
||||||
|
|
||||||
The unit testing suite for the engine modules (`src/ona`, `src/coral`, etc.) may be built and ran via `zig build tests`.
|
The unit testing suite for the engine modules (`src/ona`, `src/gfx`, etc.) may be built and ran via `zig build tests`.
|
||||||
|
|
||||||
Tests are ran by our continuous integration host so should these shouldn't fail locally without user intervention. If they do, feel free to report an issue via my email linked in my Sauce Control bio or through any other means of public communication I have.
|
Tests are ran by our continuous integration host so should these shouldn't fail locally without user intervention. If they do, feel free to report an issue via my email linked in my Sauce Control bio or through any other means of public communication I have.
|
||||||
|
|
||||||
|
@ -103,6 +103,6 @@ const app = b.addExecutable(.{
|
||||||
});
|
});
|
||||||
|
|
||||||
app.root_module.addImport("ona", ona_dependency.module("ona"));
|
app.root_module.addImport("ona", ona_dependency.module("ona"));
|
||||||
app.root_module.addImport("coral", ona_dependency.module("coral"));
|
app.root_module.addImport("gfx", ona_dependency.module("gfx"));
|
||||||
app.root_module.addImport("input", ona_dependency.module("input"));
|
app.root_module.addImport("hid", ona_dependency.module("hid"));
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
const coral = @import("./coral.zig");
|
|
||||||
|
|
||||||
pub const black = greyscale(0);
|
|
||||||
|
|
||||||
pub const white = greyscale(1);
|
|
||||||
|
|
||||||
pub fn greyscale(v: f32) coral.Color {
|
|
||||||
return .{v, v, v, 1};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rgb(r: f32, g: f32, b: f32) coral.Color {
|
|
||||||
return .{r, g, b, 1};
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
const coral = @import("./coral.zig");
|
const gfx = @import("./gfx.zig");
|
||||||
|
|
||||||
const ona = @import("ona");
|
const ona = @import("ona");
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ pub const Effect = struct {
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(desc: coral.Effect.Desc) spirv.Error!Effect {
|
pub fn init(desc: gfx.Effect.Desc) spirv.Error!Effect {
|
||||||
var spirv_arena = std.heap.ArenaAllocator.init(ona.heap.allocator);
|
var spirv_arena = std.heap.ArenaAllocator.init(ona.heap.allocator);
|
||||||
|
|
||||||
defer {
|
defer {
|
||||||
|
@ -282,7 +282,7 @@ pub const Texture = struct {
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(desc: coral.Texture.Desc) std.mem.Allocator.Error!Texture {
|
pub fn init(desc: gfx.Texture.Desc) std.mem.Allocator.Error!Texture {
|
||||||
const pixel_format = switch (desc.format) {
|
const pixel_format = switch (desc.format) {
|
||||||
.rgba8 => sokol.gfx.PixelFormat.RGBA8,
|
.rgba8 => sokol.gfx.PixelFormat.RGBA8,
|
||||||
.bgra8 => sokol.gfx.PixelFormat.BGRA8,
|
.bgra8 => sokol.gfx.PixelFormat.BGRA8,
|
||||||
|
@ -386,7 +386,7 @@ pub const Texture = struct {
|
||||||
|
|
||||||
const TexturePool = ona.Pool(Texture);
|
const TexturePool = ona.Pool(Texture);
|
||||||
|
|
||||||
pub fn create_effect(self: *Self, desc: coral.Effect.Desc) !coral.Effect {
|
pub fn create_effect(self: *Self, desc: gfx.Effect.Desc) !gfx.Effect {
|
||||||
var effect = try Effect.init(desc);
|
var effect = try Effect.init(desc);
|
||||||
|
|
||||||
errdefer effect.deinit();
|
errdefer effect.deinit();
|
||||||
|
@ -394,7 +394,7 @@ pub fn create_effect(self: *Self, desc: coral.Effect.Desc) !coral.Effect {
|
||||||
return @enumFromInt(try self.effects.insert(effect));
|
return @enumFromInt(try self.effects.insert(effect));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_texture(self: *Self, desc: coral.Texture.Desc) !coral.Texture {
|
pub fn create_texture(self: *Self, desc: gfx.Texture.Desc) !gfx.Texture {
|
||||||
var texture = try Texture.init(desc);
|
var texture = try Texture.init(desc);
|
||||||
|
|
||||||
errdefer texture.deinit();
|
errdefer texture.deinit();
|
||||||
|
@ -422,7 +422,7 @@ pub fn deinit(self: *Self) void {
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy_effect(self: *Self, handle: coral.Effect) bool {
|
pub fn destroy_effect(self: *Self, handle: gfx.Effect) bool {
|
||||||
switch (handle) {
|
switch (handle) {
|
||||||
.default => {},
|
.default => {},
|
||||||
|
|
||||||
|
@ -438,7 +438,7 @@ pub fn destroy_effect(self: *Self, handle: coral.Effect) bool {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy_texture(self: *Self, handle: coral.Texture) bool {
|
pub fn destroy_texture(self: *Self, handle: gfx.Texture) bool {
|
||||||
switch (handle) {
|
switch (handle) {
|
||||||
.default => {},
|
.default => {},
|
||||||
|
|
||||||
|
@ -454,11 +454,11 @@ pub fn destroy_texture(self: *Self, handle: coral.Texture) bool {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_effect(self: *Self, handle: coral.Effect) ?*Effect {
|
pub fn get_effect(self: *Self, handle: gfx.Effect) ?*Effect {
|
||||||
return self.effects.get(@intFromEnum(handle));
|
return self.effects.get(@intFromEnum(handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_texture(self: *Self, handle: coral.Texture) ?*Texture {
|
pub fn get_texture(self: *Self, handle: gfx.Texture) ?*Texture {
|
||||||
return self.textures.get(@intFromEnum(handle));
|
return self.textures.get(@intFromEnum(handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,11 +478,11 @@ pub fn init() !Self {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
assert.is_handle(coral.Effect.default, try pools.create_effect(.{
|
assert.is_handle(gfx.Effect.default, try pools.create_effect(.{
|
||||||
.fragment_spirv_ops = &spirv.to_ops(@embedFile("./shaders/2d_default.frag.spv")),
|
.fragment_spirv_ops = &spirv.to_ops(@embedFile("./shaders/2d_default.frag.spv")),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
assert.is_handle(coral.Texture.default, try pools.create_texture(.{
|
assert.is_handle(gfx.Texture.default, try pools.create_texture(.{
|
||||||
.format = .rgba8,
|
.format = .rgba8,
|
||||||
|
|
||||||
.access = .{
|
.access = .{
|
||||||
|
@ -503,7 +503,7 @@ pub fn init() !Self {
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
assert.is_handle(coral.Texture.backbuffer, try pools.create_texture(.{
|
assert.is_handle(gfx.Texture.backbuffer, try pools.create_texture(.{
|
||||||
.format = .rgba8,
|
.format = .rgba8,
|
||||||
|
|
||||||
.access = .{
|
.access = .{
|
|
@ -0,0 +1,13 @@
|
||||||
|
const gfx = @import("./gfx.zig");
|
||||||
|
|
||||||
|
pub const black = greyscale(0);
|
||||||
|
|
||||||
|
pub const white = greyscale(1);
|
||||||
|
|
||||||
|
pub fn greyscale(v: f32) gfx.Color {
|
||||||
|
return .{v, v, v, 1};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rgb(r: f32, g: f32, b: f32) gfx.Color {
|
||||||
|
return .{r, g, b, 1};
|
||||||
|
}
|
|
@ -477,9 +477,9 @@ pub fn setup(world: *ona.World, events: ona.App.Events) (error {Unsupported} ||
|
||||||
}
|
}
|
||||||
|
|
||||||
try world.set_state(Display{});
|
try world.set_state(Display{});
|
||||||
try world.on_event(events.pre_update, ona.system_fn(poll), .{.label = "poll coral"});
|
try world.on_event(events.pre_update, ona.system_fn(poll), .{.label = "poll gfx"});
|
||||||
try world.on_event(events.exit, ona.system_fn(stop), .{.label = "stop coral"});
|
try world.on_event(events.exit, ona.system_fn(stop), .{.label = "stop gfx"});
|
||||||
try world.on_event(events.finish, ona.system_fn(synchronize), .{.label = "synchronize coral"});
|
try world.on_event(events.finish, ona.system_fn(synchronize), .{.label = "synchronize gfx"});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stop(assets: ona.Write(Assets)) void {
|
pub fn stop(assets: ona.Write(Assets)) void {
|
|
@ -1,6 +1,6 @@
|
||||||
const Resources = @import("./Resources.zig");
|
const Resources = @import("./Resources.zig");
|
||||||
|
|
||||||
const coral = @import("./coral.zig");
|
const gfx = @import("./gfx.zig");
|
||||||
|
|
||||||
const ext = @cImport({
|
const ext = @cImport({
|
||||||
@cInclude("SDL2/SDL.h");
|
@cInclude("SDL2/SDL.h");
|
||||||
|
@ -20,12 +20,12 @@ const Frame = struct {
|
||||||
quad_vertex_buffer: sokol.gfx.Buffer,
|
quad_vertex_buffer: sokol.gfx.Buffer,
|
||||||
drawn_count: usize = 0,
|
drawn_count: usize = 0,
|
||||||
flushed_count: usize = 0,
|
flushed_count: usize = 0,
|
||||||
current_source_texture: coral.Texture = .default,
|
current_source_texture: gfx.Texture = .default,
|
||||||
current_target_texture: coral.Texture = .backbuffer,
|
current_target_texture: gfx.Texture = .backbuffer,
|
||||||
current_effect: coral.Effect = .default,
|
current_effect: gfx.Effect = .default,
|
||||||
|
|
||||||
const DrawTexture = extern struct {
|
const DrawTexture = extern struct {
|
||||||
transform: coral.Transform2D,
|
transform: gfx.Transform2D,
|
||||||
tint: @Vector(4, u8) = @splat(std.math.maxInt(u8)),
|
tint: @Vector(4, u8) = @splat(std.math.maxInt(u8)),
|
||||||
depth: f32 = 0,
|
depth: f32 = 0,
|
||||||
texture_offset: @Vector(2, f32) = @splat(0),
|
texture_offset: @Vector(2, f32) = @splat(0),
|
||||||
|
@ -73,7 +73,7 @@ const Frame = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_texture(self: *Frame, resources: *Resources, command: coral.Commands.DrawTextureCommand) !void {
|
pub fn draw_texture(self: *Frame, resources: *Resources, command: gfx.Commands.DrawTextureCommand) !void {
|
||||||
if (command.texture != self.current_source_texture) {
|
if (command.texture != self.current_source_texture) {
|
||||||
self.flush(resources);
|
self.flush(resources);
|
||||||
}
|
}
|
||||||
|
@ -173,7 +173,7 @@ const Frame = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_effect(self: *Frame, resources: *Resources, command: coral.Commands.SetEffectCommand) void {
|
pub fn set_effect(self: *Frame, resources: *Resources, command: gfx.Commands.SetEffectCommand) void {
|
||||||
if (command.effect != self.current_effect) {
|
if (command.effect != self.current_effect) {
|
||||||
self.flush(resources);
|
self.flush(resources);
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,7 @@ const Frame = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_target(self: *Frame, resources: *Resources, command: coral.Commands.SetTargetCommand) void {
|
pub fn set_target(self: *Frame, resources: *Resources, command: gfx.Commands.SetTargetCommand) void {
|
||||||
sokol.gfx.endPass();
|
sokol.gfx.endPass();
|
||||||
|
|
||||||
var pass = sokol.gfx.Pass{
|
var pass = sokol.gfx.Pass{
|
||||||
|
@ -237,7 +237,7 @@ const vertex_indices = .{
|
||||||
.instance = 1,
|
.instance = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn orthographic_projection(near: f32, far: f32, viewport: coral.Rect) Matrix(4, f32) {
|
fn orthographic_projection(near: f32, far: f32, viewport: gfx.Rect) Matrix(4, f32) {
|
||||||
const width = viewport.right - viewport.left;
|
const width = viewport.right - viewport.left;
|
||||||
const height = viewport.bottom - viewport.top;
|
const height = viewport.bottom - viewport.top;
|
||||||
|
|
||||||
|
@ -249,7 +249,7 @@ fn orthographic_projection(near: f32, far: f32, viewport: coral.Rect) Matrix(4,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_work(pending_work: *coral.Assets.WorkQueue, window: *ext.SDL_Window) !void {
|
pub fn process_work(pending_work: *gfx.Assets.WorkQueue, window: *ext.SDL_Window) !void {
|
||||||
const context = configure_and_create: {
|
const context = configure_and_create: {
|
||||||
var result = @as(c_int, 0);
|
var result = @as(c_int, 0);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const coral = @import("./coral.zig");
|
const gfx = @import("./gfx.zig");
|
||||||
|
|
||||||
const ext = @cImport({
|
const ext = @cImport({
|
||||||
@cInclude("spirv-cross/spirv_cross_c.h");
|
@cInclude("spirv-cross/spirv_cross_c.h");
|
|
@ -128,11 +128,17 @@ const Schedule = struct {
|
||||||
graph: Graph,
|
graph: Graph,
|
||||||
arena: std.heap.ArenaAllocator,
|
arena: std.heap.ArenaAllocator,
|
||||||
system_id_nodes: ona.map.Hashed(usize, NodeBundle, ona.map.usize_traits),
|
system_id_nodes: ona.map.Hashed(usize, NodeBundle, ona.map.usize_traits),
|
||||||
|
inserted_systems: ona.stack.Sequential(InsertedSystem) = .{},
|
||||||
read_write_resource_id_nodes: ResourceNodeBundle,
|
read_write_resource_id_nodes: ResourceNodeBundle,
|
||||||
read_only_resource_id_nodes: ResourceNodeBundle,
|
read_only_resource_id_nodes: ResourceNodeBundle,
|
||||||
parallel_work_bundles: ParallelNodeBundles,
|
parallel_work_bundles: ParallelNodeBundles,
|
||||||
blocking_work: NodeBundle,
|
blocking_work: NodeBundle,
|
||||||
|
|
||||||
|
const InsertedSystem = struct {
|
||||||
|
info: *const ona.SystemInfo,
|
||||||
|
order: ona.SystemOrder,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn deinit(self: *Schedule, world: *Self) void {
|
pub fn deinit(self: *Schedule, world: *Self) void {
|
||||||
{
|
{
|
||||||
var nodes = self.system_id_nodes.entries();
|
var nodes = self.system_id_nodes.entries();
|
||||||
|
@ -184,12 +190,91 @@ const Schedule = struct {
|
||||||
self.system_id_nodes.deinit();
|
self.system_id_nodes.deinit();
|
||||||
self.read_write_resource_id_nodes.deinit();
|
self.read_write_resource_id_nodes.deinit();
|
||||||
self.read_only_resource_id_nodes.deinit();
|
self.read_only_resource_id_nodes.deinit();
|
||||||
|
self.inserted_systems.deinit();
|
||||||
self.arena.deinit();
|
self.arena.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(self: *Schedule, world: *Self) anyerror!void {
|
pub fn run(self: *Schedule, world: *Self) anyerror!void {
|
||||||
if (self.is_invalidated()) {
|
if (self.is_invalidated()) {
|
||||||
const work = struct {
|
const work = struct {
|
||||||
|
fn bind_systems(schedule: *Schedule, world_: *Self) !void {
|
||||||
|
for (schedule.inserted_systems.values) |system| {
|
||||||
|
const nodes = lazily_create: {
|
||||||
|
const system_id = @intFromPtr(system.info);
|
||||||
|
|
||||||
|
break: lazily_create schedule.system_id_nodes.get(system_id) orelse insert: {
|
||||||
|
std.debug.assert(try schedule.system_id_nodes.emplace(system_id, .{
|
||||||
|
.allocator = schedule.system_id_nodes.allocator,
|
||||||
|
}));
|
||||||
|
|
||||||
|
break: insert schedule.system_id_nodes.get(system_id).?;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const dependencies = init: {
|
||||||
|
const total_run_orders = system.order.run_after.len + system.order.run_before.len;
|
||||||
|
const dependencies = try ona.heap.allocator.alloc(Dependency, total_run_orders);
|
||||||
|
var dependencies_written = @as(usize, 0);
|
||||||
|
|
||||||
|
for (system.order.run_after) |after_system| {
|
||||||
|
dependencies[dependencies_written] = .{
|
||||||
|
.id = @intFromPtr(after_system),
|
||||||
|
.kind = .after,
|
||||||
|
};
|
||||||
|
|
||||||
|
dependencies_written += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (system.order.run_before) |before_system| {
|
||||||
|
dependencies[dependencies_written] = .{
|
||||||
|
.id = @intFromPtr(before_system),
|
||||||
|
.kind = .before,
|
||||||
|
};
|
||||||
|
|
||||||
|
dependencies_written += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
break: init dependencies;
|
||||||
|
};
|
||||||
|
|
||||||
|
errdefer ona.heap.allocator.free(dependencies);
|
||||||
|
|
||||||
|
const label = try ona.heap.allocator.dupeZ(u8, if (system.order.label.len == 0) "anonymous system" else system.order.label);
|
||||||
|
|
||||||
|
errdefer ona.heap.allocator.free(label);
|
||||||
|
|
||||||
|
const node = try schedule.graph.append(.{
|
||||||
|
.info = system.info,
|
||||||
|
.label = label,
|
||||||
|
.dependencies = dependencies,
|
||||||
|
.resource_accesses = .{.allocator = ona.heap.allocator},
|
||||||
|
});
|
||||||
|
|
||||||
|
const system_node = schedule.graph.get_ptr(node).?;
|
||||||
|
const system_parameter_states = system_node.parameter_states[0 .. system.info.parameter_count];
|
||||||
|
|
||||||
|
errdefer {
|
||||||
|
for (system.info.used_parameters(), system_parameter_states) |parameter, state| {
|
||||||
|
parameter.unbind(schedule.arena.allocator(), state, .{
|
||||||
|
.world = world_,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std.debug.assert(schedule.graph.remove_node(node) != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (system_parameter_states, system.info.used_parameters()) |*state, parameter| {
|
||||||
|
state.* = try parameter.bind(schedule.arena.allocator(), .{
|
||||||
|
.world = world_,
|
||||||
|
.node = node,
|
||||||
|
.systems = schedule,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try nodes.push_grow(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn regenerate_graph(schedule: *Schedule) !void {
|
fn regenerate_graph(schedule: *Schedule) !void {
|
||||||
schedule.graph.clear_edges();
|
schedule.graph.clear_edges();
|
||||||
|
|
||||||
|
@ -311,6 +396,7 @@ const Schedule = struct {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
try work.bind_systems(self, world);
|
||||||
try work.regenerate_graph(self);
|
try work.regenerate_graph(self);
|
||||||
try work.sort(self);
|
try work.sort(self);
|
||||||
}
|
}
|
||||||
|
@ -375,7 +461,12 @@ const Schedule = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn invalidate_work(self: *Schedule) void {
|
pub fn insert(self: *Schedule, info: *const ona.SystemInfo, order: ona.SystemOrder) std.mem.Allocator.Error!void {
|
||||||
|
try self.inserted_systems.push_grow(.{
|
||||||
|
.info = info,
|
||||||
|
.order = order,
|
||||||
|
});
|
||||||
|
|
||||||
self.blocking_work.clear();
|
self.blocking_work.clear();
|
||||||
|
|
||||||
for (self.parallel_work_bundles.values) |*bundle| {
|
for (self.parallel_work_bundles.values) |*bundle| {
|
||||||
|
@ -388,83 +479,6 @@ const Schedule = struct {
|
||||||
pub fn is_invalidated(self: Schedule) bool {
|
pub fn is_invalidated(self: Schedule) bool {
|
||||||
return self.parallel_work_bundles.is_empty() and self.blocking_work.is_empty();
|
return self.parallel_work_bundles.is_empty() and self.blocking_work.is_empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn then(self: *Schedule, world: *Self, info: *const ona.SystemInfo, order: ona.SystemOrder) std.mem.Allocator.Error!void {
|
|
||||||
const nodes = lazily_create: {
|
|
||||||
const system_id = @intFromPtr(info);
|
|
||||||
|
|
||||||
break: lazily_create self.system_id_nodes.get(system_id) orelse insert: {
|
|
||||||
std.debug.assert(try self.system_id_nodes.emplace(system_id, .{
|
|
||||||
.allocator = self.system_id_nodes.allocator,
|
|
||||||
}));
|
|
||||||
|
|
||||||
break: insert self.system_id_nodes.get(system_id).?;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const dependencies = init: {
|
|
||||||
const total_run_orders = order.run_after.len + order.run_before.len;
|
|
||||||
const dependencies = try ona.heap.allocator.alloc(Dependency, total_run_orders);
|
|
||||||
var dependencies_written = @as(usize, 0);
|
|
||||||
|
|
||||||
for (order.run_after) |after_system| {
|
|
||||||
dependencies[dependencies_written] = .{
|
|
||||||
.id = @intFromPtr(after_system),
|
|
||||||
.kind = .after,
|
|
||||||
};
|
|
||||||
|
|
||||||
dependencies_written += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (order.run_before) |before_system| {
|
|
||||||
dependencies[dependencies_written] = .{
|
|
||||||
.id = @intFromPtr(before_system),
|
|
||||||
.kind = .before,
|
|
||||||
};
|
|
||||||
|
|
||||||
dependencies_written += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
break: init dependencies;
|
|
||||||
};
|
|
||||||
|
|
||||||
errdefer ona.heap.allocator.free(dependencies);
|
|
||||||
|
|
||||||
const label = try ona.heap.allocator.dupeZ(u8, if (order.label.len == 0) "anonymous system" else order.label);
|
|
||||||
|
|
||||||
errdefer ona.heap.allocator.free(label);
|
|
||||||
|
|
||||||
const node = try self.graph.append(.{
|
|
||||||
.info = info,
|
|
||||||
.label = label,
|
|
||||||
.dependencies = dependencies,
|
|
||||||
.resource_accesses = .{.allocator = ona.heap.allocator},
|
|
||||||
});
|
|
||||||
|
|
||||||
const system = self.graph.get_ptr(node).?;
|
|
||||||
|
|
||||||
errdefer {
|
|
||||||
for (info.used_parameters(), system.parameter_states[0 .. info.parameter_count]) |parameter, state| {
|
|
||||||
parameter.unbind(self.arena.allocator(), state, .{
|
|
||||||
.world = world,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
std.debug.assert(self.graph.remove_node(node) != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (system.parameter_states[0 .. info.parameter_count], info.used_parameters()) |*state, parameter| {
|
|
||||||
state.* = try parameter.bind(self.arena.allocator(), .{
|
|
||||||
.world = world,
|
|
||||||
.node = node,
|
|
||||||
.systems = self,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
try nodes.push_grow(node);
|
|
||||||
|
|
||||||
self.invalidate_work();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
@ -598,7 +612,7 @@ pub fn init(thread_count: u32) std.Thread.SpawnError!Self {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_event(self: *Self, event: Event, action: *const ona.SystemInfo, order: ona.SystemOrder) std.mem.Allocator.Error!void {
|
pub fn on_event(self: *Self, event: Event, action: *const ona.SystemInfo, order: ona.SystemOrder) std.mem.Allocator.Error!void {
|
||||||
try self.event_systems.values[@intFromEnum(event)].then(self, action, order);
|
try self.event_systems.values[@intFromEnum(event)].insert(action, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_event(self: *Self, event: Event) anyerror!void {
|
pub fn run_event(self: *Self, event: Event) anyerror!void {
|
||||||
|
|
282
src/ona/ona.zig
282
src/ona/ona.zig
|
@ -44,6 +44,169 @@ pub const App = struct {
|
||||||
exit: World.Event,
|
exit: World.Event,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Setup = struct {
|
||||||
|
pub const Event = enum {
|
||||||
|
load,
|
||||||
|
pre_update,
|
||||||
|
update,
|
||||||
|
post_update,
|
||||||
|
render,
|
||||||
|
finish,
|
||||||
|
exit,
|
||||||
|
};
|
||||||
|
|
||||||
|
step: fn (*World, Events) anyerror!void = noop,
|
||||||
|
|
||||||
|
fn noop(_: *World, _: Events) !void {}
|
||||||
|
|
||||||
|
pub fn build(self: Setup) fn () anyerror!void {
|
||||||
|
const Start = struct {
|
||||||
|
fn main() anyerror!void {
|
||||||
|
defer {
|
||||||
|
heap.trace_leaks();
|
||||||
|
}
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
||||||
|
for (LaunchFlag.values) |value| {
|
||||||
|
const name = @tagName(value);
|
||||||
|
|
||||||
|
if (!std.mem.eql(u8, arg_name, name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchFlag.args[@intFromEnum(value)] =
|
||||||
|
if (arg_split_index == arg_span.len)
|
||||||
|
name
|
||||||
|
else
|
||||||
|
arg_span[arg_split_index ..];
|
||||||
|
|
||||||
|
continue: parse_args;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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))));
|
||||||
|
|
||||||
|
var world = try World.init(scalars.fractional(cpu_count, @as(f32, 0.75)) orelse 0);
|
||||||
|
|
||||||
|
defer world.deinit();
|
||||||
|
|
||||||
|
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"),
|
||||||
|
};
|
||||||
|
|
||||||
|
const app = try world.set_get_state(App{
|
||||||
|
.events = &events,
|
||||||
|
.target_frame_time = 1.0 / 60.0,
|
||||||
|
.elapsed_time = 0,
|
||||||
|
.is_running = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
try self.step(&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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Start.main;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_module(self: Setup, comptime Module: type) Setup {
|
||||||
|
if (!@hasDecl(Module, "setup")) {
|
||||||
|
@compileError("`Module` argument must have a setup fn declaration");
|
||||||
|
}
|
||||||
|
|
||||||
|
const WithState = struct {
|
||||||
|
fn step(world: *World, events: App.Events) !void {
|
||||||
|
try Module.setup(world, events);
|
||||||
|
try self.step(world, events);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.step = WithState.step,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_state(self: Setup, comptime state: anytype) Setup {
|
||||||
|
const WithState = struct {
|
||||||
|
fn step(world: *World, events: App.Events) !void {
|
||||||
|
try world.set_state(state);
|
||||||
|
try self.step(world, events);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.step = WithState.step,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_system(self: Setup, comptime event: Event, comptime info: *const SystemInfo, comptime order: SystemOrder) Setup {
|
||||||
|
const WithState = struct {
|
||||||
|
fn step(world: *World, events: App.Events) !void {
|
||||||
|
const app_event = switch (event) {
|
||||||
|
.load => events.load,
|
||||||
|
.pre_update => events.pre_update,
|
||||||
|
.update => events.update,
|
||||||
|
.post_update => events.post_update,
|
||||||
|
.render => events.render,
|
||||||
|
.finish => events.finish,
|
||||||
|
.exit => events.exit,
|
||||||
|
};
|
||||||
|
|
||||||
|
try world.on_event(app_event, info, order);
|
||||||
|
try self.step(world, events);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.step = WithState.step,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const setup = Setup{};
|
||||||
|
|
||||||
pub fn quit(self: *App) void {
|
pub fn quit(self: *App) void {
|
||||||
self.is_running = false;
|
self.is_running = false;
|
||||||
}
|
}
|
||||||
|
@ -161,7 +324,7 @@ pub fn Exclusive(comptime values: []const type) type {
|
||||||
.Optional => has_state,
|
.Optional => has_state,
|
||||||
|
|
||||||
else => has_state orelse {
|
else => has_state orelse {
|
||||||
@panic(std.fmt.comptimePrint("attempt to use exclusive {s} that has not yet been set", .{
|
@panic(std.fmt.comptimePrint("attempt to use exclusive {s} that has not been set yet", .{
|
||||||
@typeName(Value),
|
@typeName(Value),
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
@ -190,17 +353,6 @@ pub const LaunchFlag = enum {
|
||||||
const values = std.enums.values(LaunchFlag);
|
const values = std.enums.values(LaunchFlag);
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Options = struct {
|
|
||||||
tick_rate: u64,
|
|
||||||
execution: Execution,
|
|
||||||
middleware: []const *const Setup,
|
|
||||||
|
|
||||||
pub const Execution = union (enum) {
|
|
||||||
single_threaded,
|
|
||||||
thread_share: f32,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn Params(comptime Value: type) type {
|
pub fn Params(comptime Value: type) type {
|
||||||
if (!@hasDecl(Value, "Param")) {
|
if (!@hasDecl(Value, "Param")) {
|
||||||
@compileError("System parameters must have a Params type declaration");
|
@compileError("System parameters must have a Params type declaration");
|
||||||
|
@ -430,8 +582,6 @@ pub fn Send(comptime Message: type) type {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const Setup = fn (*World, App.Events) anyerror!void;
|
|
||||||
|
|
||||||
pub const ShareInfo = struct {
|
pub const ShareInfo = struct {
|
||||||
thread_restriction: ThreadRestriction,
|
thread_restriction: ThreadRestriction,
|
||||||
read_only: bool,
|
read_only: bool,
|
||||||
|
@ -497,7 +647,7 @@ pub fn Shared(comptime Value: type, comptime info: ShareInfo) type {
|
||||||
.Optional => state,
|
.Optional => state,
|
||||||
|
|
||||||
else => state orelse {
|
else => state orelse {
|
||||||
@panic(std.fmt.comptimePrint("attempt to use {s}{s} {s} that has not yet been set", .{
|
@panic(std.fmt.comptimePrint("attempt to use {s}{s} {s} that has not been set yet", .{
|
||||||
thread_restriction_name,
|
thread_restriction_name,
|
||||||
if (info.read_only) "read-only" else "read-write",
|
if (info.read_only) "read-only" else "read-write",
|
||||||
@typeName(Value),
|
@typeName(Value),
|
||||||
|
@ -688,108 +838,6 @@ fn parameter_type(comptime Value: type) *const SystemInfo.Parameter {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(comptime setup: Setup, comptime options: Options) fn () anyerror!void {
|
|
||||||
const Start = struct {
|
|
||||||
fn main() anyerror!void {
|
|
||||||
defer {
|
|
||||||
heap.trace_leaks();
|
|
||||||
}
|
|
||||||
|
|
||||||
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];
|
|
||||||
|
|
||||||
for (LaunchFlag.values) |value| {
|
|
||||||
const name = @tagName(value);
|
|
||||||
|
|
||||||
if (!std.mem.eql(u8, arg_name, name)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
LaunchFlag.args[@intFromEnum(value)] =
|
|
||||||
if (arg_split_index == arg_span.len)
|
|
||||||
name
|
|
||||||
else
|
|
||||||
arg_span[arg_split_index ..];
|
|
||||||
|
|
||||||
continue: parse_args;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var world = try switch (options.execution) {
|
|
||||||
.single_threaded => World.init(0),
|
|
||||||
|
|
||||||
.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))));
|
|
||||||
|
|
||||||
break: init World.init(scalars.fractional(cpu_count, thread_share) orelse 0);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
defer world.deinit();
|
|
||||||
|
|
||||||
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"),
|
|
||||||
};
|
|
||||||
|
|
||||||
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,
|
|
||||||
});
|
|
||||||
|
|
||||||
inline for (options.middleware) |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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return Start.main;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn system_fn(comptime call: anytype) *const SystemInfo {
|
pub fn system_fn(comptime call: anytype) *const SystemInfo {
|
||||||
const Call = @TypeOf(call);
|
const Call = @TypeOf(call);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue