diff --git a/examples/core/custom-entrypoint/App.zig b/examples/core/custom-entrypoint/App.zig index 49ceb950..83e3aacc 100644 --- a/examples/core/custom-entrypoint/App.zig +++ b/examples/core/custom-entrypoint/App.zig @@ -71,8 +71,7 @@ fn init(app: *Mod, core: *mach.Core.Mod) !void { } fn tick(core: *mach.Core.Mod, app: *Mod) !void { - var iter = core.state().pollEvents(); - while (iter.next()) |event| { + while (core.state().nextEvent()) |event| { switch (event) { .close => core.schedule(.exit), // Tell mach.Core to exit the app else => {}, diff --git a/examples/core/triangle/App.zig b/examples/core/triangle/App.zig index 49ceb950..83e3aacc 100644 --- a/examples/core/triangle/App.zig +++ b/examples/core/triangle/App.zig @@ -71,8 +71,7 @@ fn init(app: *Mod, core: *mach.Core.Mod) !void { } fn tick(core: *mach.Core.Mod, app: *Mod) !void { - var iter = core.state().pollEvents(); - while (iter.next()) |event| { + while (core.state().nextEvent()) |event| { switch (event) { .close => core.schedule(.exit), // Tell mach.Core to exit the app else => {}, diff --git a/examples/custom-renderer/App.zig b/examples/custom-renderer/App.zig index 89d47bb8..da73ab39 100644 --- a/examples/custom-renderer/App.zig +++ b/examples/custom-renderer/App.zig @@ -96,10 +96,9 @@ fn tick( renderer: *Renderer.Mod, app: *Mod, ) !void { - var iter = core.state().pollEvents(); var direction = app.state().direction; var spawning = app.state().spawning; - while (iter.next()) |event| { + while (core.state().nextEvent()) |event| { switch (event) { .key_press => |ev| { switch (ev.key) { diff --git a/examples/glyphs/App.zig b/examples/glyphs/App.zig index b6ffbaa5..33cc45df 100644 --- a/examples/glyphs/App.zig +++ b/examples/glyphs/App.zig @@ -110,12 +110,9 @@ fn tick( glyphs: *Glyphs.Mod, app: *Mod, ) !void { - // TODO(important): event polling should occur in mach.Core module and get fired as ECS events. - // TODO(Core) - var iter = core.state().pollEvents(); var direction = app.state().direction; var spawning = app.state().spawning; - while (iter.next()) |event| { + while (core.state().nextEvent()) |event| { switch (event) { .key_press => |ev| { switch (ev.key) { diff --git a/examples/hardware-check/App.zig b/examples/hardware-check/App.zig index c950aef6..03b3f7ed 100644 --- a/examples/hardware-check/App.zig +++ b/examples/hardware-check/App.zig @@ -185,9 +185,8 @@ fn tick( ) !void { // TODO(important): event polling should occur in mach.Core module and get fired as ECS events. // TODO(Core) - var iter = core.state().pollEvents(); var gotta_go_fast = app.state().gotta_go_fast; - while (iter.next()) |event| { + while (core.state().nextEvent()) |event| { switch (event) { .key_press => |ev| { switch (ev.key) { diff --git a/examples/piano/App.zig b/examples/piano/App.zig index e30676a8..17744b7d 100644 --- a/examples/piano/App.zig +++ b/examples/piano/App.zig @@ -104,9 +104,7 @@ fn tick( audio: *mach.Audio.Mod, app: *Mod, ) !void { - // TODO(Core) - var iter = core.state().pollEvents(); - while (iter.next()) |event| { + while (core.state().nextEvent()) |event| { switch (event) { .key_press => |ev| { switch (ev.key) { diff --git a/examples/play-opus/App.zig b/examples/play-opus/App.zig index be7dd644..17522fa6 100644 --- a/examples/play-opus/App.zig +++ b/examples/play-opus/App.zig @@ -118,9 +118,7 @@ fn tick( audio: *mach.Audio.Mod, app: *Mod, ) !void { - // TODO(Core) - var iter = core.state().pollEvents(); - while (iter.next()) |event| { + while (core.state().nextEvent()) |event| { switch (event) { .key_press => |ev| switch (ev.key) { .down => { diff --git a/examples/sprite/App.zig b/examples/sprite/App.zig index fc72671d..106d93fa 100644 --- a/examples/sprite/App.zig +++ b/examples/sprite/App.zig @@ -114,12 +114,9 @@ fn tick( sprite_pipeline: *gfx.SpritePipeline.Mod, app: *Mod, ) !void { - // TODO(important): event polling should occur in mach.Core module and get fired as ECS events. - // TODO(Core) - var iter = core.state().pollEvents(); var direction = app.state().direction; var spawning = app.state().spawning; - while (iter.next()) |event| { + while (core.state().nextEvent()) |event| { switch (event) { .key_press => |ev| { switch (ev.key) { diff --git a/examples/text/App.zig b/examples/text/App.zig index cbe9e5f8..2e04b6e6 100644 --- a/examples/text/App.zig +++ b/examples/text/App.zig @@ -125,12 +125,9 @@ fn tick( text_pipeline: *gfx.TextPipeline.Mod, app: *Mod, ) !void { - // TODO(important): event polling should occur in mach.Core module and get fired as ECS events. - // TODO(Core) - var iter = core.state().pollEvents(); var direction = app.state().direction; var spawning = app.state().spawning; - while (iter.next()) |event| { + while (core.state().nextEvent()) |event| { switch (event) { .key_press => |ev| { switch (ev.key) { diff --git a/src/Core.zig b/src/Core.zig index 89d5db2b..21c5e2a3 100644 --- a/src/Core.zig +++ b/src/Core.zig @@ -23,15 +23,7 @@ pub const supports_non_blocking = switch (build_options.core_platform) { .null => true, }; -pub const EventQueue = std.fifo.LinearFifo(Event, .Dynamic); - -pub const EventIterator = struct { - queue: *EventQueue, - - pub fn next(self: *EventIterator) ?Event { - return self.queue.readItem(); - } -}; +const EventQueue = std.fifo.LinearFifo(Event, .Dynamic); /// Set this to true if you intend to drive the main loop yourself. /// @@ -126,8 +118,10 @@ pub const components = .{ }, }; -// Callback systems +/// Callback system invoked per tick (e.g. per-frame) on_tick: ?mach.AnySystem = null, + +/// Callback system invoked when application is exiting on_exit: ?mach.AnySystem = null, allocator: std.mem.Allocator, @@ -156,6 +150,9 @@ surface: *gpu.Surface, swap_chain: *gpu.SwapChain, descriptor: gpu.SwapChain.Descriptor, +// Internal state +events: EventQueue, + // TODO: this needs to be removed. pub const InitOptions = struct { allocator: std.mem.Allocator, @@ -200,9 +197,13 @@ fn init(core: *Mod, entities: *mach.Entities.Mod) !void { title[options.title.len] = 0; } + var events = EventQueue.init(allocator); + try events.ensureTotalCapacity(8192); + core.init(.{ .allocator = allocator, .main_window = main_window, + .events = events, // TODO: remove undefined initialization (disgusting!) .platform = undefined, @@ -220,7 +221,8 @@ fn init(core: *Mod, entities: *mach.Entities.Mod) !void { .descriptor = undefined, }); const state = core.state(); - try Platform.init(&state.platform, options); + + try Platform.init(&state.platform, core, options); state.instance = gpu.createInstance(null) orelse { log.err("failed to create GPU instance", .{}); @@ -386,6 +388,7 @@ pub fn deinit(entities: *mach.Entities.Mod, core: *Mod) !void { state.surface.release(); state.adapter.release(); state.instance.release(); + state.events.deinit(); } pub const InputState = struct { @@ -602,8 +605,10 @@ pub const KeyMods = packed struct(u8) { _padding: u2 = 0, }; -pub inline fn pollEvents(core: *@This()) EventIterator { - return .{ .platform = core.platform.pollEvents() }; +/// Returns the next event until there are no more available. You should check for events during +/// every on_tick() +pub inline fn nextEvent(core: *@This()) ?Event { + return core.events.readItem(); } /// Sets the window title. The string must be owned by Core, and will not be copied or freed. It is @@ -1063,7 +1068,6 @@ comptime { assertHasDecl(Platform, "init"); assertHasDecl(Platform, "deinit"); - assertHasDecl(Platform, "pollEvents"); assertHasDecl(Platform, "setTitle"); @@ -1104,10 +1108,8 @@ fn assertHasField(comptime T: anytype, comptime field_name: []const u8) void { } test { - @import("std").testing.refAllDecls(Platform); - + _ = Platform; @import("std").testing.refAllDeclsRecursive(InitOptions); - @import("std").testing.refAllDeclsRecursive(EventIterator); @import("std").testing.refAllDeclsRecursive(VSyncMode); @import("std").testing.refAllDeclsRecursive(Size); @import("std").testing.refAllDeclsRecursive(Position); diff --git a/src/core/Darwin.zig b/src/core/Darwin.zig index fe612e2e..70894597 100644 --- a/src/core/Darwin.zig +++ b/src/core/Darwin.zig @@ -23,11 +23,7 @@ pub const Darwin = @This(); allocator: std.mem.Allocator, core: *Core, - -events: Core.EventQueue, input_state: Core.InputState, -// modifiers: KeyMods, - title: [:0]const u8, display_mode: DisplayMode, vsync_mode: VSyncMode, @@ -72,7 +68,12 @@ pub fn run(comptime on_each_update_fn: anytype, args_tuple: std.meta.ArgsTuple(@ } // Called on the main thread -pub fn init(darwin: *Darwin, options: InitOptions) !void { +pub fn init( + darwin: *Darwin, + core: *Core.Mod, + options: InitOptions, +) !void { + _ = core; var surface_descriptor = gpu.Surface.Descriptor{}; // TODO: support UIKit. @@ -106,13 +107,9 @@ pub fn init(darwin: *Darwin, options: InitOptions) !void { window.?.makeKeyAndOrderFront(null); } - var events = EventQueue.init(options.allocator); - try events.ensureTotalCapacity(2048); - darwin.* = .{ .allocator = options.allocator, .core = @fieldParentPtr("platform", darwin), - .events = events, .input_state = .{}, .title = options.title, .display_mode = options.display_mode, @@ -138,11 +135,6 @@ pub fn update(_: *Darwin) !void { return; } -// May be called from any thread. -pub inline fn pollEvents(n: *Darwin) Core.EventIterator { - return .{ .queue = &n.events }; -} - // May be called from any thread. pub fn setTitle(_: *Darwin, _: [:0]const u8) void { return; diff --git a/src/core/Null.zig b/src/core/Null.zig index a738ddba..0f67dd4f 100644 --- a/src/core/Null.zig +++ b/src/core/Null.zig @@ -25,11 +25,8 @@ pub const Null = @This(); allocator: std.mem.Allocator, core: *Core, - -events: Core.EventQueue, input_state: Core.InputState, modifiers: KeyMods, - title: [:0]u8, display_mode: DisplayMode, vsync_mode: VSyncMode, @@ -42,7 +39,14 @@ size: Size, surface_descriptor: gpu.Surface.Descriptor, // Called on the main thread -pub fn init(_: *Null, _: InitOptions) !void { +pub fn init( + nul: *Null, + core: *Core.Mod, + options: InitOptions, +) !void { + _ = nul; + _ = options; + _ = core; return; } @@ -55,11 +59,6 @@ pub fn update(_: *Null) !void { return; } -// May be called from any thread. -pub inline fn pollEvents(n: *Null) Core.EventIterator { - return .{ .queue = &n.events }; -} - // May be called from any thread. pub fn setTitle(_: *Null, _: [:0]const u8) void { return; diff --git a/src/core/Windows.zig b/src/core/Windows.zig index d877656a..5857ffc7 100644 --- a/src/core/Windows.zig +++ b/src/core/Windows.zig @@ -44,7 +44,7 @@ surrogate: u16 = 0, dinput: *w.IDirectInput8W, saved_window_rect: w.RECT, surface_descriptor_from_hwnd: gpu.Surface.DescriptorFromWindowsHWND, -events: EventQueue, +state: *Core, input_state: Core.InputState, oom: std.Thread.ResetEvent = .{}, @@ -53,11 +53,12 @@ oom: std.Thread.ResetEvent = .{}, // ------------------------------ pub fn init( self: *Win32, + core: *Core.Mod, options: InitOptions, ) !void { + self.state = core.state(); self.allocator = options.allocator; self.core = @fieldParentPtr("platform", self); - self.events = EventQueue.init(self.allocator); self.size = options.size; self.input_state = .{}; self.saved_window_rect = .{ .top = 0, .left = 0, .right = 0, .bottom = 0 }; @@ -138,7 +139,6 @@ pub fn init( } pub fn deinit(self: *Win32) void { - self.events.deinit(); _ = self.dinput.IUnknown_Release(); } @@ -151,10 +151,6 @@ pub fn update(self: *Win32) !void { } } -pub fn pollEvents(self: *Win32) EventIterator { - return .{ .queue = &self.events }; -} - pub fn setTitle(self: *Win32, title: [:0]const u8) void { const wtitle = std.unicode.utf8ToUtf16LeAllocZ(self.allocator, title) catch { self.oom.set(); @@ -316,7 +312,7 @@ pub fn outOfMemory(self: *Win32) bool { } fn pushEvent(self: *Win32, event: Event) void { - self.events.writeItem(event) catch self.oom.set(); + self.state.events.writeItem(event) catch self.oom.set(); } fn getKeyboardModifiers() mach.Core.KeyMods {