mach: Implement key input handling as event loop
This commit changes the former callback based design to handle key input (GLFW-like) to an event loop based design (SDL-like). This uses a TailQueue to store the events from inside of standard glfw callbacks. This Queue is then popped while polling, thereby emulating event loop. Removes from Engine the function: ``setKeyCallback`` and adds the function: ``pollEvent`` which may return an event or null. This change was done for two reasons: 1) Removing dependence of Engine on App. This was a circular dependency and a genuine bad design. 2) Solve the recent regression due to the same which was (i) preventing using types declared in Engine.zig and (ii) preventing usage of multiple source files in an application. Currently only key press and release events are implemented as these are the ones currently used in examples.
This commit is contained in:
parent
92028a11ef
commit
7486b0ebea
3 changed files with 56 additions and 21 deletions
|
|
@ -2,7 +2,6 @@ const std = @import("std");
|
|||
const Allocator = std.mem.Allocator;
|
||||
const glfw = @import("glfw");
|
||||
const gpu = @import("gpu");
|
||||
const App = @import("app");
|
||||
const structs = @import("structs.zig");
|
||||
const enums = @import("enums.zig");
|
||||
const Timer = @import("Timer.zig");
|
||||
|
|
@ -43,8 +42,8 @@ pub const Core = struct {
|
|||
return core.internal.setSizeLimits(min, max);
|
||||
}
|
||||
|
||||
pub fn setKeyCallback(core: *Core, comptime cb: fn (app: *App, engine: *Engine, key: enums.Key, action: enums.Action) void) void {
|
||||
core.internal.setKeyCallback(cb);
|
||||
pub fn pollEvent(core: *Core) ?structs.Event {
|
||||
return core.internal.pollEvent();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -11,12 +11,17 @@ const c = @import("c.zig").c;
|
|||
pub const CoreGlfw = struct {
|
||||
window: glfw.Window,
|
||||
backend_type: gpu.Adapter.BackendType,
|
||||
allocator: std.mem.Allocator,
|
||||
events: EventQueue = .{},
|
||||
user_ptr: UserPtr = undefined,
|
||||
|
||||
const EventQueue = std.TailQueue(structs.Event);
|
||||
const EventNode = EventQueue.Node;
|
||||
|
||||
const UserPtr = struct {
|
||||
app: *App,
|
||||
engine: *Engine,
|
||||
core: *CoreGlfw,
|
||||
};
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator, engine: *Engine) !CoreGlfw {
|
||||
const options = engine.options;
|
||||
const backend_type = try util.detectBackendType(allocator);
|
||||
|
|
@ -39,16 +44,44 @@ pub const CoreGlfw = struct {
|
|||
return CoreGlfw{
|
||||
.window = window,
|
||||
.backend_type = backend_type,
|
||||
.allocator = engine.allocator,
|
||||
};
|
||||
}
|
||||
|
||||
fn initCallback(self: *CoreGlfw, app: *App, engine: *Engine) void {
|
||||
self.user_ptr = UserPtr{
|
||||
.app = app,
|
||||
.engine = engine,
|
||||
};
|
||||
fn pushEvent(self: *CoreGlfw, event: structs.Event) void {
|
||||
const node = self.allocator.create(EventNode) catch unreachable;
|
||||
node.* = .{ .data = event };
|
||||
self.events.append(node);
|
||||
}
|
||||
|
||||
fn initCallback(self: *CoreGlfw) void {
|
||||
self.user_ptr = UserPtr{ .core = self };
|
||||
|
||||
self.window.setUserPointer(&self.user_ptr);
|
||||
|
||||
const callback = struct {
|
||||
fn callback(window: glfw.Window, key: glfw.Key, scancode: i32, action: glfw.Action, mods: glfw.Mods) void {
|
||||
const core = (window.getUserPointer(UserPtr) orelse unreachable).core;
|
||||
|
||||
switch (action) {
|
||||
.press => core.pushEvent(.{
|
||||
.key_press = .{
|
||||
.key = toMachKey(key),
|
||||
},
|
||||
}),
|
||||
.release => core.pushEvent(.{
|
||||
.key_release = .{
|
||||
.key = toMachKey(key),
|
||||
},
|
||||
}),
|
||||
else => {},
|
||||
}
|
||||
|
||||
_ = scancode;
|
||||
_ = mods;
|
||||
}
|
||||
}.callback;
|
||||
self.window.setKeyCallback(callback);
|
||||
}
|
||||
|
||||
pub fn setShouldClose(self: *CoreGlfw, value: bool) void {
|
||||
|
|
@ -67,16 +100,9 @@ pub const CoreGlfw = struct {
|
|||
);
|
||||
}
|
||||
|
||||
pub fn setKeyCallback(self: *CoreGlfw, comptime cb: fn (app: *App, engine: *Engine, key: enums.Key, action: enums.Action) void) void {
|
||||
const callback = struct {
|
||||
fn callback(window: glfw.Window, key: glfw.Key, scancode: i32, action: glfw.Action, mods: glfw.Mods) void {
|
||||
const usrptr = window.getUserPointer(UserPtr) orelse unreachable;
|
||||
cb(usrptr.app, usrptr.engine, CoreGlfw.toMachKey(key), CoreGlfw.toMachAction(action));
|
||||
_ = scancode;
|
||||
_ = mods;
|
||||
}
|
||||
}.callback;
|
||||
self.window.setKeyCallback(callback);
|
||||
pub fn pollEvent(self: *CoreGlfw) ?structs.Event {
|
||||
if (self.events.popFirst()) |n| return n.data;
|
||||
return null;
|
||||
}
|
||||
|
||||
fn toMachAction(action: glfw.Action) enums.Action {
|
||||
|
|
@ -381,7 +407,7 @@ pub fn main() !void {
|
|||
defer app.deinit(&engine);
|
||||
|
||||
// Glfw specific: initialize the user pointer used in callbacks
|
||||
engine.core.internal.initCallback(&app, &engine);
|
||||
engine.core.internal.initCallback();
|
||||
|
||||
const window = engine.core.internal.window;
|
||||
while (!window.shouldClose()) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
const gpu = @import("gpu");
|
||||
const enums = @import("enums.zig");
|
||||
|
||||
pub const Size = struct {
|
||||
width: u32,
|
||||
|
|
@ -51,3 +52,12 @@ pub const Options = struct {
|
|||
/// Whether the application has a preference for low power or high performance GPU.
|
||||
power_preference: gpu.PowerPreference = .none,
|
||||
};
|
||||
|
||||
pub const Event = union(enum) {
|
||||
key_press: struct {
|
||||
key: enums.Key,
|
||||
},
|
||||
key_release: struct {
|
||||
key: enums.Key,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue