From 9f0f565b0b2d6574aae0236a68933f5ab3d536c7 Mon Sep 17 00:00:00 2001 From: kayomn Date: Thu, 25 Jul 2024 01:11:58 +0100 Subject: [PATCH] Add mouse input, axis mappings, and an input demo (closes #63) --- .vscode/launch.json | 2 +- build.zig | 12 +++- demos/effects.zig | 6 +- demos/inputs.zig | 129 ++++++++++++++++++++++++++++++++++++++++++ src/gfx/gfx.zig | 77 +++++++++++++++++++++++-- src/gfx/rendering.zig | 2 +- src/hid/hid.zig | 113 +++++++++++++++++++++++++++--------- src/ona/World.zig | 22 +++---- src/ona/dag.zig | 20 ++++--- src/ona/ona.zig | 18 +++++- src/ona/slices.zig | 18 +----- src/ona/stack.zig | 24 ++++---- 12 files changed, 355 insertions(+), 88 deletions(-) create mode 100644 demos/inputs.zig diff --git a/.vscode/launch.json b/.vscode/launch.json index 62345d6..bddb4ae 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "name": "Runner", "type": "gdb", "request": "launch", - "target": "${workspaceRoot}/demos/effects.out", + "target": "${workspaceRoot}/demos/inputs.out", "cwd": "${workspaceRoot}/demos/", "valuesFormatting": "prettyPrinters", "preLaunchTask": "Build All" diff --git a/build.zig b/build.zig index 1a2a0ee..f1229ca 100644 --- a/build.zig +++ b/build.zig @@ -208,7 +208,15 @@ pub fn build(b: *std.Build) !void { }); const ona_module = try project.add_module(b, "ona", .{}); - const hid_module = try project.add_module(b, "hid", .{}); + + const hid_module = try project.add_module(b, "hid", .{ + .imports = &.{ + .{ + .name = "ona", + .module = ona_module, + }, + }, + }); const gfx_module = try project.add_module(b, "gfx", .{ .imports = &.{ @@ -223,7 +231,7 @@ pub fn build(b: *std.Build) !void { }, .{ - .name = "input", + .name = "hid", .module = hid_module, }, }, diff --git a/demos/effects.zig b/demos/effects.zig index 5fc70d0..5e75f2b 100644 --- a/demos/effects.zig +++ b/demos/effects.zig @@ -16,10 +16,10 @@ const Effects = struct { crt_effect: gfx.Effect = .default, }; -fn load(display: ona.Write(gfx.Display), actors: ona.Write(Effects), assets: ona.Write(gfx.Assets)) !void { +fn load(display: ona.Write(gfx.Display), effects: ona.Write(Effects), assets: ona.Write(gfx.Assets)) !void { display.state.width, display.state.height = .{1280, 720}; - actors.state.render_texture = try assets.state.load_texture(.{ + effects.state.render_texture = try assets.state.load_texture(.{ .format = .rgba8, .access = .{ @@ -30,7 +30,7 @@ fn load(display: ona.Write(gfx.Display), actors: ona.Write(Effects), assets: ona }, }); - actors.state.crt_effect = try assets.state.load_effect_file(ona.files.bundle, "./crt.frag.spv"); + effects.state.crt_effect = try assets.state.load_effect_file(ona.files.bundle, "./crt.frag.spv"); } pub const main = ona.App.setup. diff --git a/demos/inputs.zig b/demos/inputs.zig new file mode 100644 index 0000000..fd3f478 --- /dev/null +++ b/demos/inputs.zig @@ -0,0 +1,129 @@ +const gfx = @import("gfx"); + +const hid = @import("hid"); + +const ona = @import("ona"); + +const std = @import("std"); + +const Spawned = struct { + transform: gfx.Transform2D, + lifetime_seconds: f32, +}; + +const Visuals = struct { + spawned_keyboards: ona.stack.Parallel(Spawned) = .{}, + spawned_mouses: ona.stack.Parallel(Spawned) = .{}, + keyboard_icon: gfx.Texture = .default, + mouse_icon: gfx.Texture = .default, + random: std.Random.Xoroshiro128, + mouse_position: @Vector(2, f32) = @splat(0), +}; + +fn cleanup(visuals: ona.Write(Visuals)) !void { + visuals.state.spawned_keyboards.deinit(); + visuals.state.spawned_mouses.deinit(); +} + +fn load(visuals: ona.Write(Visuals)) !void { + const initial_spawn_capacity = 1024; + + try visuals.state.spawned_keyboards.grow(initial_spawn_capacity); + try visuals.state.spawned_mouses.grow(initial_spawn_capacity); +} + +pub const main = ona.App.setup. + with_module(gfx). + with_module(hid). + with_state(Visuals{.random = std.Random.Xoroshiro128.init(47342563891212)}). + with_system(.load, ona.system_fn(load), .{.label = "load visuals"}). + with_system(.update, ona.system_fn(update), .{.label = "spawn visuals"}). + with_system(.render, ona.system_fn(render), .{.label = "render visuals"}). + with_system(.exit, ona.system_fn(cleanup), .{.label = "clean up visuals"}).build(); + +fn update(visuals: ona.Write(Visuals), app: ona.Read(ona.App), events: ona.Receive(hid.Event), display: ona.Read(gfx.Display)) !void { + update_spawned(&visuals.state.spawned_keyboards, @floatCast(app.state.delta_time)); + update_spawned(&visuals.state.spawned_mouses, @floatCast(app.state.delta_time)); + + const random = visuals.state.random.random(); + const width: f32 = @floatFromInt(display.state.width); + const height: f32 = @floatFromInt(display.state.height); + const icon_scale = .{64, 64}; + + for (events.messages()) |event| { + switch (event) { + .key_down => { + try visuals.state.spawned_keyboards.push_grow(.{ + .lifetime_seconds = 2.5 + (5 * random.float(f32)), + + .transform = gfx.Transform2D.from_simplified(.{ + .translation = .{width * random.float(f32), height}, + .rotation = std.math.pi * random.float(f32), + .scale = icon_scale, + }), + }); + }, + + .mouse_down => { + try visuals.state.spawned_mouses.push_grow(.{ + .lifetime_seconds = 2.5 + (5 * random.float(f32)), + + .transform = gfx.Transform2D.from_simplified(.{ + .translation = visuals.state.mouse_position, + .rotation = std.math.pi * random.float(f32), + .scale = icon_scale, + }), + }); + }, + + .mouse_motion => |motion| { + visuals.state.mouse_position = motion.absolute_position; + }, + + else => {} + } + } +} + +fn update_spawned(spawned: *ona.stack.Parallel(Spawned), delta_time: f32) void { + const float_speed = 50; + + for (spawned.values.slice(.transform)) |*transform| { + transform.* = transform.translated(.{0, float_speed * -delta_time}); + } + + { + var range = spawned.len(); + var index: usize = 0; + + while (index < range) : (index += 1) { + const lifetime_seconds = spawned.values.get(.lifetime_seconds, index).?; + + lifetime_seconds.* -= delta_time; + + if (lifetime_seconds.* <= 0) { + range -= 1; + + std.mem.swap(f32, lifetime_seconds, spawned.values.get(.lifetime_seconds, range).?); + } + } + + std.debug.assert(spawned.pop_many(spawned.len() - range)); + } +} + +fn render(visuals: ona.Write(Visuals), commands: gfx.Commands) !void { + for (visuals.state.spawned_keyboards.values.slice(.transform)) |transform| { + try commands.draw_texture(.{ + .texture = visuals.state.keyboard_icon, + .transform = transform, + }); + } + + for (visuals.state.spawned_mouses.values.slice(.transform)) |transform| { + try commands.draw_texture(.{ + .texture = visuals.state.keyboard_icon, + .transform = transform, + }); + } +} diff --git a/src/gfx/gfx.zig b/src/gfx/gfx.zig index 5612145..48b8736 100644 --- a/src/gfx/gfx.zig +++ b/src/gfx/gfx.zig @@ -1,6 +1,6 @@ pub const colors = @import("./colors.zig"); -const input = @import("input"); +const hid = @import("hid"); const ona = @import("ona"); @@ -349,7 +349,32 @@ pub const Transform2D = extern struct { ybasis: Vector = .{0, 1}, origin: Vector = @splat(0), - const Vector = @Vector(2, f32); + pub const Simplified = struct { + translation: Vector = @splat(0), + rotation: f32 = 0, + scale: Vector = @splat(1), + skew: f32 = 0, + }; + + pub const Vector = @Vector(2, f32); + + pub fn from_simplified(simplified: Simplified) Transform2D { + const rotation_skew = simplified.rotation + simplified.skew; + + return .{ + .xbasis = simplified.scale * Vector{std.math.cos(simplified.rotation), std.math.sin(simplified.rotation)}, + .ybasis = simplified.scale * Vector{-std.math.sin(rotation_skew), std.math.cos(rotation_skew)}, + .origin = simplified.translation, + }; + } + + pub fn translated(self: Transform2D, translation: Vector) Transform2D { + var transform = self; + + transform.origin += translation; + + return transform; + } }; fn load_bmp_texture(arena: *std.heap.ArenaAllocator, storage: ona.files.Storage, path: []const u8) !Texture.Desc { @@ -426,14 +451,54 @@ fn load_bmp_texture(arena: *std.heap.ArenaAllocator, storage: ona.files.Storage, }; } -pub fn poll(app: ona.Write(ona.App), events: ona.Send(input.Event)) !void { +pub fn poll(app: ona.Write(ona.App), events: ona.Send(hid.Event)) !void { var event = @as(ext.SDL_Event, undefined); while (ext.SDL_PollEvent(&event) != 0) { switch (event.type) { - ext.SDL_QUIT => app.state.quit(), - ext.SDL_KEYUP => try events.push(.{.key_up = @enumFromInt(event.key.keysym.scancode)}), - ext.SDL_KEYDOWN => try events.push(.{.key_down = @enumFromInt(event.key.keysym.scancode)}), + ext.SDL_QUIT => { + app.state.quit(); + }, + + ext.SDL_KEYUP => { + try events.push(.{.key_up = @enumFromInt(event.key.keysym.scancode)}); + }, + + ext.SDL_KEYDOWN => { + try events.push(.{.key_down = @enumFromInt(event.key.keysym.scancode)}); + }, + + ext.SDL_MOUSEBUTTONUP => { + try events.push(.{ + .mouse_up = switch (event.button.button) { + ext.SDL_BUTTON_LEFT => .left, + ext.SDL_BUTTON_RIGHT => .right, + ext.SDL_BUTTON_MIDDLE => .middle, + else => unreachable, + }, + }); + }, + + ext.SDL_MOUSEBUTTONDOWN => { + try events.push(.{ + .mouse_down = switch (event.button.button) { + ext.SDL_BUTTON_LEFT => .left, + ext.SDL_BUTTON_RIGHT => .right, + ext.SDL_BUTTON_MIDDLE => .middle, + else => unreachable, + }, + }); + }, + + ext.SDL_MOUSEMOTION => { + try events.push(.{ + .mouse_motion = .{ + .relative_position = .{@floatFromInt(event.motion.xrel), @floatFromInt(event.motion.yrel)}, + .absolute_position = .{@floatFromInt(event.motion.x), @floatFromInt(event.motion.y)}, + }, + }); + }, + else => {}, } } diff --git a/src/gfx/rendering.zig b/src/gfx/rendering.zig index 3c9775b..161a991 100644 --- a/src/gfx/rendering.zig +++ b/src/gfx/rendering.zig @@ -94,7 +94,7 @@ const Frame = struct { try self.texture_batch_buffers.push_grow(instance_buffer); } - _ = sokol.gfx.appendBuffer(self.texture_batch_buffers.get().?, sokol.gfx.asRange(&DrawTexture{ + _ = sokol.gfx.appendBuffer(self.texture_batch_buffers.get().?.*, sokol.gfx.asRange(&DrawTexture{ .transform = command.transform, })); diff --git a/src/hid/hid.zig b/src/hid/hid.zig index 2a68406..92e6775 100644 --- a/src/hid/hid.zig +++ b/src/hid/hid.zig @@ -3,15 +3,19 @@ const ona = @import("ona"); const std = @import("std"); pub const Axis = struct { - keys: ?[2]Key = null, + has_key_scancodes: ?[2]KeyScancode = null, + has_mouse_buttons: ?[2]MouseButton = null, }; pub const Event = union (enum) { - key_up: Key, - key_down: Key, + key_up: KeyScancode, + key_down: KeyScancode, + mouse_up: MouseButton, + mouse_down: MouseButton, + mouse_motion: MouseMotion, }; -pub const Key = enum (u32) { +pub const KeyScancode = enum (u32) { no_event = 0x00, error_rollover = 0x01, post_fail = 0x02, @@ -189,21 +193,49 @@ pub const Key = enum (u32) { }; pub const Mapping = struct { - keys_pressed: ScancodeSet = ScancodeSet.initEmpty(), - keys_held: ScancodeSet = ScancodeSet.initEmpty(), + key_scancodes: ActionSets(512) = .{}, + mouse_buttons: ActionSets(std.enums.values(MouseButton).len) = .{}, + mouse_position: MousePosition = @splat(0), - const ScancodeSet = std.bit_set.StaticBitSet(512); + fn ActionSets(comptime len: usize) type { + const Set = std.bit_set.StaticBitSet(len); + + return struct { + released: Set = Set.initEmpty(), + pressed: Set = Set.initEmpty(), + held: Set = Set.initEmpty(), + + const Self = @This(); + + fn expire_frame(self: *Self) void { + self.pressed = Set.initEmpty(); + self.released = Set.initEmpty(); + } + }; + } pub fn axis_strength(self: Mapping, axis: Axis) f32 { - if (axis.keys) |keys| { - const key_down, const key_up = keys; - const is_key_down_held = self.keys_held.isSet(@intFromEnum(key_down)); - const is_key_up_held = self.keys_held.isSet(@intFromEnum(key_up)); + if (axis.has_key_scancodes) |key_scancodes| { + const neg_scancode, const pos_scancode = key_scancodes; + const is_neg_held = self.key_scancodes.held.isSet(@intFromEnum(neg_scancode)); + const is_pos_held = self.key_scancodes.held.isSet(@intFromEnum(pos_scancode)); - if (is_key_down_held or is_key_up_held) { + if (is_neg_held or is_pos_held) { return - @as(f32, @floatFromInt(@intFromBool(is_key_up_held))) - - @as(f32, @floatFromInt(@intFromBool(is_key_down_held))); + @as(f32, @floatFromInt(@intFromBool(is_pos_held))) - + @as(f32, @floatFromInt(@intFromBool(is_neg_held))); + } + } + + if (axis.has_mouse_buttons) |mouse_buttons| { + const neg_button, const pos_button = mouse_buttons; + const is_neg_held = self.mouse_buttons.held.isSet(@intFromEnum(neg_button)); + const is_pos_held = self.mouse_buttons.held.isSet(@intFromEnum(pos_button)); + + if (is_neg_held or is_pos_held) { + return + @as(f32, @floatFromInt(@intFromBool(is_pos_held))) - + @as(f32, @floatFromInt(@intFromBool(is_neg_held))); } } @@ -211,9 +243,22 @@ pub const Mapping = struct { } }; +pub const MouseButton = enum { + left, + right, + middle, +}; + +pub const MouseMotion = struct { + relative_position: MousePosition, + absolute_position: MousePosition, +}; + +pub const MousePosition = @Vector(2, f32); + test "mapping values" { const axis = Axis{ - .keys = .{.minus, .equal}, + .has_key_scancodes = .{.minus, .equal}, }; { @@ -225,7 +270,7 @@ test "mapping values" { { var mapping = Mapping{}; - mapping.keys_held.set(@intFromEnum(Key.equal)); + mapping.key_scancodes.held.set(@intFromEnum(KeyScancode.equal)); try std.testing.expectEqual(mapping.axis_strength(axis), 1); } @@ -233,7 +278,7 @@ test "mapping values" { { var mapping = Mapping{}; - mapping.keys_held.set(@intFromEnum(Key.minus)); + mapping.key_scancodes.held.set(@intFromEnum(KeyScancode.minus)); try std.testing.expectEqual(mapping.axis_strength(axis), -1); } @@ -241,8 +286,8 @@ test "mapping values" { { var mapping = Mapping{}; - mapping.keys_held.set(@intFromEnum(Key.minus)); - mapping.keys_held.set(@intFromEnum(Key.equal)); + mapping.key_scancodes.held.set(@intFromEnum(KeyScancode.minus)); + mapping.key_scancodes.held.set(@intFromEnum(KeyScancode.equal)); try std.testing.expectEqual(mapping.axis_strength(axis), 0); } @@ -256,18 +301,34 @@ pub fn setup(world: *ona.World, events: ona.App.Events) std.mem.Allocator.Error! }); } -pub fn update(inputs: ona.msg.Receive(ona.gfx.Input), mapping: ona.Write(Mapping)) void { - mapping.state.keys_pressed = Mapping.ScancodeSet.initEmpty(); +pub fn update(inputs: ona.Receive(Event), mapping: ona.Write(Mapping)) void { + mapping.state.key_scancodes.expire_frame(); + mapping.state.mouse_buttons.expire_frame(); for (inputs.messages()) |message| { switch (message) { - .key_down => |key| { - mapping.state.keys_pressed.set(key.scancode()); - mapping.state.keys_held.set(key.scancode()); + .key_down => |scancode| { + mapping.state.key_scancodes.pressed.set(@intFromEnum(scancode)); + mapping.state.key_scancodes.held.set(@intFromEnum(scancode)); }, - .key_up => |key| { - mapping.state.keys_held.unset(key.scancode()); + .key_up => |scancode| { + mapping.state.key_scancodes.held.unset(@intFromEnum(scancode)); + mapping.state.key_scancodes.released.set(@intFromEnum(scancode)); + }, + + .mouse_down => |button| { + mapping.state.mouse_buttons.pressed.unset(@intFromEnum(button)); + mapping.state.mouse_buttons.held.set(@intFromEnum(button)); + }, + + .mouse_up => |button| { + mapping.state.key_scancodes.held.unset(@intFromEnum(button)); + mapping.state.key_scancodes.released.set(@intFromEnum(button)); + }, + + .mouse_motion => |motion| { + mapping.state.mouse_position = motion.absolute_position; }, } } diff --git a/src/ona/World.zig b/src/ona/World.zig index 989ff16..a68b3ff 100644 --- a/src/ona/World.zig +++ b/src/ona/World.zig @@ -14,7 +14,7 @@ pub const BindContext = struct { world: *Self, pub fn accesses_state(self: BindContext, access: std.meta.Tag(StateAccess), id: ona.TypeID) bool { - const resource_accesses = &self.systems.graph.get_ptr(self.node).?.resource_accesses; + const resource_accesses = &self.systems.graph.get(self.node).?.resource_accesses; for (resource_accesses.values) |resource_access| { switch (resource_access) { @@ -43,7 +43,7 @@ pub const BindContext = struct { const id = ona.type_id(Resource); if (!self.accesses_state(.read_write, id)) { - try self.systems.graph.get_ptr(self.node).?.resource_accesses.push_grow(.{.read_write = id}); + try self.systems.graph.get(self.node).?.resource_accesses.push_grow(.{.read_write = id}); } const read_write_resource_nodes = lazily_create: { @@ -71,7 +71,7 @@ pub const BindContext = struct { const id = ona.type_id(Resource); if (!self.accesses_state(.read_only, id)) { - try self.systems.graph.get_ptr(self.node).?.resource_accesses.push_grow(.{.read_only = id}); + try self.systems.graph.get(self.node).?.resource_accesses.push_grow(.{.read_only = id}); } const read_only_resource_nodes = lazily_create: { @@ -167,7 +167,7 @@ const Schedule = struct { var nodes = self.graph.nodes(); while (nodes.next()) |node| { - const system = self.graph.get_ptr(node).?; + const system = self.graph.get(node).?; for (system.info.used_parameters(), system.parameter_states[0 .. system.info.parameter_count]) |parameter, state| { parameter.unbind(self.arena.allocator(), state, .{ @@ -250,7 +250,7 @@ const Schedule = struct { .resource_accesses = .{.allocator = ona.heap.allocator}, }); - const system_node = schedule.graph.get_ptr(node).?; + const system_node = schedule.graph.get(node).?; const system_parameter_states = system_node.parameter_states[0 .. system.info.parameter_count]; errdefer { @@ -281,7 +281,7 @@ const Schedule = struct { var nodes = schedule.graph.nodes(); while (nodes.next()) |node| { - const system = schedule.graph.get_ptr(node).?; + const system = schedule.graph.get(node).?; for (system.dependencies) |order| { const dependencies = schedule.system_id_nodes.get(@intFromPtr(system.info)) orelse { @@ -363,7 +363,7 @@ const Schedule = struct { try schedule.parallel_work_bundles.push_grow(.{.allocator = ona.heap.allocator}); - const bundle = schedule.parallel_work_bundles.get_ptr().?; + const bundle = schedule.parallel_work_bundles.get().?; errdefer { bundle.deinit(); @@ -379,7 +379,7 @@ const Schedule = struct { while (index < work.len()) : (index += 1) { const node = work.values[index]; - switch (schedule.graph.get_ptr(node).?.info.thread_restriction) { + switch (schedule.graph.get(node).?.info.thread_restriction) { .none => continue, .main => { @@ -408,7 +408,7 @@ const Schedule = struct { defer work_group.finish(); for (bundle.values) |node| { - const system = graph.get_ptr(node).?; + const system = graph.get(node).?; // TODO: std lib thread pool sucks for many reasons and this is one of them. system.info.execute(system.info.used_parameters(), &system.parameter_states) catch unreachable; @@ -428,7 +428,7 @@ const Schedule = struct { } else { for (self.parallel_work_bundles.values) |bundle| { for (bundle.values) |node| { - const system = self.graph.get_ptr(node).?; + const system = self.graph.get(node).?; try system.info.execute(system.info.used_parameters(), &system.parameter_states); } @@ -436,7 +436,7 @@ const Schedule = struct { } for (self.blocking_work.values) |node| { - const system = self.graph.get_ptr(node).?; + const system = self.graph.get(node).?; try system.info.execute(system.info.used_parameters(), &system.parameter_states); } diff --git a/src/ona/dag.zig b/src/ona/dag.zig index f1ed7f7..50c8694 100644 --- a/src/ona/dag.zig +++ b/src/ona/dag.zig @@ -50,19 +50,23 @@ pub fn Graph(comptime Payload: type) type { return null; } - return self.table.values.get_ptr(.edges, @intFromEnum(node)).?.values; + return self.table.values.get(.edges, @intFromEnum(node)).?.values; } pub fn exists(self: Self, node: Node) bool { - return self.table.values.get(.is_occupied, @intFromEnum(node)) orelse false; + if (self.table.values.get(.is_occupied, @intFromEnum(node))) |is_occupied| { + return is_occupied.*; + } + + return false; } - pub fn get_ptr(self: Self, node: Node) ?*Payload { + pub fn get(self: Self, node: Node) ?*Payload { if (!self.exists(node)) { return null; } - return self.table.values.get_ptr(.payload, @intFromEnum(node)).?; + return self.table.values.get(.payload, @intFromEnum(node)).?; } pub fn init(allocator: std.mem.Allocator) Self { @@ -76,7 +80,7 @@ pub fn Graph(comptime Payload: type) type { return false; } - const edges = self.table.values.get_ptr(.edges, @intFromEnum(dependant_node)) orelse { + const edges = self.table.values.get(.edges, @intFromEnum(dependant_node)) orelse { return false; }; @@ -114,10 +118,10 @@ pub fn Graph(comptime Payload: type) type { const node_index = @intFromEnum(node); - self.table.values.get_ptr(.is_occupied, node_index).?.* = false; + self.table.values.get(.is_occupied, node_index).?.* = false; self.node_count -= 1; - return self.table.values.get(.payload, node_index).?; + return self.table.values.get(.payload, node_index).?.*; } pub fn reset_visited(self: *Self) void { @@ -129,7 +133,7 @@ pub fn Graph(comptime Payload: type) type { return null; } - return self.table.values.get(.is_visited, @intFromEnum(node)).?; + return self.table.values.get(.is_visited, @intFromEnum(node)).?.*; } }; } diff --git a/src/ona/ona.zig b/src/ona/ona.zig index 55ef7f2..386901a 100644 --- a/src/ona/ona.zig +++ b/src/ona/ona.zig @@ -32,6 +32,7 @@ pub const App = struct { events: *const Events, target_frame_time: f64, elapsed_time: f64, + delta_time: f64, is_running: bool, pub const Events = struct { @@ -114,6 +115,7 @@ pub const App = struct { .events = &events, .target_frame_time = 1.0 / 60.0, .elapsed_time = 0, + .delta_time = 0, .is_running = true, }); @@ -127,11 +129,11 @@ pub const App = struct { 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.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; + accumulated_time += app.delta_time; try world.run_event(events.pre_update); @@ -519,6 +521,18 @@ pub fn Receive(comptime Message: type) type { .channel = (try context.register_readable_state_access(TypedChannel)) orelse set: { try context.world.set_state(TypedChannel.init(heap.allocator)); + const app = context.world.get_state(App) orelse { + @panic("Send system parameters depend on a " ++ @typeName(App) ++ " state to work"); + }; + + try context.world.on_event(app.events.post_update, system_fn(TypedChannel.swap), .{ + .label = "swap channel of " ++ @typeName(Message), + }); + + try context.world.on_event(app.events.exit, system_fn(TypedChannel.cleanup), .{ + .label = "clean up channel of " ++ @typeName(Message), + }); + break: set (try context.register_readable_state_access(TypedChannel)).?; }, }; diff --git a/src/ona/slices.zig b/src/ona/slices.zig index f21adee..42defe9 100644 --- a/src/ona/slices.zig +++ b/src/ona/slices.zig @@ -57,15 +57,7 @@ pub fn Parallel(comptime Type: type) type { return sliced; } - pub fn get(self: Self, comptime field: Field, index: usize) ?Element(field) { - if (index >= self.len) { - return null; - } - - return self.ptr(field)[index]; - } - - pub fn get_ptr(self: Self, comptime field: Field, index: usize) ?*Element(field) { + pub fn get(self: Self, comptime field: Field, index: usize) ?*Element(field) { if (index >= self.len) { return null; } @@ -105,14 +97,6 @@ pub fn get(slice: anytype, index: usize) ?@typeInfo(@TypeOf(slice)).Pointer.chil return slice[index]; } -pub fn get_ptr(slice: anytype, index: usize) ?ElementPtr(@TypeOf(slice)) { - if (index >= slice.len) { - return null; - } - - return &slice[index]; -} - pub fn parallel_alloc(comptime Element: type, allocator: std.mem.Allocator, n: usize) std.mem.Allocator.Error!Parallel(Element) { const alignment = @alignOf(Element); const Slices = Parallel(Element); diff --git a/src/ona/stack.zig b/src/ona/stack.zig index 45237e0..e9657e1 100644 --- a/src/ona/stack.zig +++ b/src/ona/stack.zig @@ -47,15 +47,7 @@ pub fn Sequential(comptime Value: type) type { return self.values.len == 0; } - pub fn get(self: Self) ?Value { - if (self.get_ptr()) |value| { - return value.*; - } - - return null; - } - - pub fn get_ptr(self: Self) ?*Value { + pub fn get(self: Self) ?*Value { if (self.values.len == 0) { return null; } @@ -208,7 +200,7 @@ pub fn Parallel(comptime Value: type) type { const alignment = @alignOf(Value); return struct { - allocator: std.mem.Allocator, + allocator: std.mem.Allocator = ona.heap.allocator, values: Slices = .{}, cap: usize = 0, @@ -230,7 +222,7 @@ pub fn Parallel(comptime Value: type) type { self.* = undefined; } - pub fn get_ptr(self: Self, comptime field: Slices.Field) ?*align (alignment) Slices.Element(field) { + pub fn get(self: Self, comptime field: Slices.Field) ?*align (alignment) Slices.Element(field) { if (self.len() == 0) { return null; } @@ -255,6 +247,16 @@ pub fn Parallel(comptime Value: type) type { return self.values.len; } + pub fn pop_many(self: *Self, n: usize) bool { + const new_length = ona.scalars.sub(self.values.len, n) orelse { + return false; + }; + + self.values = self.values.slice_all(0, new_length).?; + + return true; + } + pub fn push_grow(self: *Self, value: Value) std.mem.Allocator.Error!void { if (self.len() == self.cap) { try self.grow(@max(1, self.cap));