Add mouse input, axis mappings, and an input demo (closes #63)
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
0f2950a630
commit
9f0f565b0b
|
@ -5,7 +5,7 @@
|
||||||
"name": "Runner",
|
"name": "Runner",
|
||||||
"type": "gdb",
|
"type": "gdb",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"target": "${workspaceRoot}/demos/effects.out",
|
"target": "${workspaceRoot}/demos/inputs.out",
|
||||||
"cwd": "${workspaceRoot}/demos/",
|
"cwd": "${workspaceRoot}/demos/",
|
||||||
"valuesFormatting": "prettyPrinters",
|
"valuesFormatting": "prettyPrinters",
|
||||||
"preLaunchTask": "Build All"
|
"preLaunchTask": "Build All"
|
||||||
|
|
12
build.zig
12
build.zig
|
@ -208,7 +208,15 @@ 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 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", .{
|
const gfx_module = try project.add_module(b, "gfx", .{
|
||||||
.imports = &.{
|
.imports = &.{
|
||||||
|
@ -223,7 +231,7 @@ pub fn build(b: *std.Build) !void {
|
||||||
},
|
},
|
||||||
|
|
||||||
.{
|
.{
|
||||||
.name = "input",
|
.name = "hid",
|
||||||
.module = hid_module,
|
.module = hid_module,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -16,10 +16,10 @@ const Effects = struct {
|
||||||
crt_effect: gfx.Effect = .default,
|
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};
|
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,
|
.format = .rgba8,
|
||||||
|
|
||||||
.access = .{
|
.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.
|
pub const main = ona.App.setup.
|
||||||
|
|
|
@ -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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
pub const colors = @import("./colors.zig");
|
pub const colors = @import("./colors.zig");
|
||||||
|
|
||||||
const input = @import("input");
|
const hid = @import("hid");
|
||||||
|
|
||||||
const ona = @import("ona");
|
const ona = @import("ona");
|
||||||
|
|
||||||
|
@ -349,7 +349,32 @@ pub const Transform2D = extern struct {
|
||||||
ybasis: Vector = .{0, 1},
|
ybasis: Vector = .{0, 1},
|
||||||
origin: Vector = @splat(0),
|
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 {
|
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);
|
var event = @as(ext.SDL_Event, undefined);
|
||||||
|
|
||||||
while (ext.SDL_PollEvent(&event) != 0) {
|
while (ext.SDL_PollEvent(&event) != 0) {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
ext.SDL_QUIT => app.state.quit(),
|
ext.SDL_QUIT => {
|
||||||
ext.SDL_KEYUP => try events.push(.{.key_up = @enumFromInt(event.key.keysym.scancode)}),
|
app.state.quit();
|
||||||
ext.SDL_KEYDOWN => try events.push(.{.key_down = @enumFromInt(event.key.keysym.scancode)}),
|
},
|
||||||
|
|
||||||
|
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 => {},
|
else => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,7 @@ const Frame = struct {
|
||||||
try self.texture_batch_buffers.push_grow(instance_buffer);
|
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,
|
.transform = command.transform,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
113
src/hid/hid.zig
113
src/hid/hid.zig
|
@ -3,15 +3,19 @@ const ona = @import("ona");
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
pub const Axis = struct {
|
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) {
|
pub const Event = union (enum) {
|
||||||
key_up: Key,
|
key_up: KeyScancode,
|
||||||
key_down: Key,
|
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,
|
no_event = 0x00,
|
||||||
error_rollover = 0x01,
|
error_rollover = 0x01,
|
||||||
post_fail = 0x02,
|
post_fail = 0x02,
|
||||||
|
@ -189,21 +193,49 @@ pub const Key = enum (u32) {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Mapping = struct {
|
pub const Mapping = struct {
|
||||||
keys_pressed: ScancodeSet = ScancodeSet.initEmpty(),
|
key_scancodes: ActionSets(512) = .{},
|
||||||
keys_held: ScancodeSet = ScancodeSet.initEmpty(),
|
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 {
|
pub fn axis_strength(self: Mapping, axis: Axis) f32 {
|
||||||
if (axis.keys) |keys| {
|
if (axis.has_key_scancodes) |key_scancodes| {
|
||||||
const key_down, const key_up = keys;
|
const neg_scancode, const pos_scancode = key_scancodes;
|
||||||
const is_key_down_held = self.keys_held.isSet(@intFromEnum(key_down));
|
const is_neg_held = self.key_scancodes.held.isSet(@intFromEnum(neg_scancode));
|
||||||
const is_key_up_held = self.keys_held.isSet(@intFromEnum(key_up));
|
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
|
return
|
||||||
@as(f32, @floatFromInt(@intFromBool(is_key_up_held))) -
|
@as(f32, @floatFromInt(@intFromBool(is_pos_held))) -
|
||||||
@as(f32, @floatFromInt(@intFromBool(is_key_down_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" {
|
test "mapping values" {
|
||||||
const axis = Axis{
|
const axis = Axis{
|
||||||
.keys = .{.minus, .equal},
|
.has_key_scancodes = .{.minus, .equal},
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -225,7 +270,7 @@ test "mapping values" {
|
||||||
{
|
{
|
||||||
var mapping = Mapping{};
|
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);
|
try std.testing.expectEqual(mapping.axis_strength(axis), 1);
|
||||||
}
|
}
|
||||||
|
@ -233,7 +278,7 @@ test "mapping values" {
|
||||||
{
|
{
|
||||||
var mapping = Mapping{};
|
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);
|
try std.testing.expectEqual(mapping.axis_strength(axis), -1);
|
||||||
}
|
}
|
||||||
|
@ -241,8 +286,8 @@ test "mapping values" {
|
||||||
{
|
{
|
||||||
var mapping = Mapping{};
|
var mapping = Mapping{};
|
||||||
|
|
||||||
mapping.keys_held.set(@intFromEnum(Key.minus));
|
mapping.key_scancodes.held.set(@intFromEnum(KeyScancode.minus));
|
||||||
mapping.keys_held.set(@intFromEnum(Key.equal));
|
mapping.key_scancodes.held.set(@intFromEnum(KeyScancode.equal));
|
||||||
|
|
||||||
try std.testing.expectEqual(mapping.axis_strength(axis), 0);
|
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 {
|
pub fn update(inputs: ona.Receive(Event), mapping: ona.Write(Mapping)) void {
|
||||||
mapping.state.keys_pressed = Mapping.ScancodeSet.initEmpty();
|
mapping.state.key_scancodes.expire_frame();
|
||||||
|
mapping.state.mouse_buttons.expire_frame();
|
||||||
|
|
||||||
for (inputs.messages()) |message| {
|
for (inputs.messages()) |message| {
|
||||||
switch (message) {
|
switch (message) {
|
||||||
.key_down => |key| {
|
.key_down => |scancode| {
|
||||||
mapping.state.keys_pressed.set(key.scancode());
|
mapping.state.key_scancodes.pressed.set(@intFromEnum(scancode));
|
||||||
mapping.state.keys_held.set(key.scancode());
|
mapping.state.key_scancodes.held.set(@intFromEnum(scancode));
|
||||||
},
|
},
|
||||||
|
|
||||||
.key_up => |key| {
|
.key_up => |scancode| {
|
||||||
mapping.state.keys_held.unset(key.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;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ pub const BindContext = struct {
|
||||||
world: *Self,
|
world: *Self,
|
||||||
|
|
||||||
pub fn accesses_state(self: BindContext, access: std.meta.Tag(StateAccess), id: ona.TypeID) bool {
|
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| {
|
for (resource_accesses.values) |resource_access| {
|
||||||
switch (resource_access) {
|
switch (resource_access) {
|
||||||
|
@ -43,7 +43,7 @@ pub const BindContext = struct {
|
||||||
const id = ona.type_id(Resource);
|
const id = ona.type_id(Resource);
|
||||||
|
|
||||||
if (!self.accesses_state(.read_write, id)) {
|
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: {
|
const read_write_resource_nodes = lazily_create: {
|
||||||
|
@ -71,7 +71,7 @@ pub const BindContext = struct {
|
||||||
const id = ona.type_id(Resource);
|
const id = ona.type_id(Resource);
|
||||||
|
|
||||||
if (!self.accesses_state(.read_only, id)) {
|
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: {
|
const read_only_resource_nodes = lazily_create: {
|
||||||
|
@ -167,7 +167,7 @@ const Schedule = struct {
|
||||||
var nodes = self.graph.nodes();
|
var nodes = self.graph.nodes();
|
||||||
|
|
||||||
while (nodes.next()) |node| {
|
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| {
|
for (system.info.used_parameters(), system.parameter_states[0 .. system.info.parameter_count]) |parameter, state| {
|
||||||
parameter.unbind(self.arena.allocator(), state, .{
|
parameter.unbind(self.arena.allocator(), state, .{
|
||||||
|
@ -250,7 +250,7 @@ const Schedule = struct {
|
||||||
.resource_accesses = .{.allocator = ona.heap.allocator},
|
.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];
|
const system_parameter_states = system_node.parameter_states[0 .. system.info.parameter_count];
|
||||||
|
|
||||||
errdefer {
|
errdefer {
|
||||||
|
@ -281,7 +281,7 @@ const Schedule = struct {
|
||||||
var nodes = schedule.graph.nodes();
|
var nodes = schedule.graph.nodes();
|
||||||
|
|
||||||
while (nodes.next()) |node| {
|
while (nodes.next()) |node| {
|
||||||
const system = schedule.graph.get_ptr(node).?;
|
const system = schedule.graph.get(node).?;
|
||||||
|
|
||||||
for (system.dependencies) |order| {
|
for (system.dependencies) |order| {
|
||||||
const dependencies = schedule.system_id_nodes.get(@intFromPtr(system.info)) orelse {
|
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});
|
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 {
|
errdefer {
|
||||||
bundle.deinit();
|
bundle.deinit();
|
||||||
|
@ -379,7 +379,7 @@ const Schedule = struct {
|
||||||
while (index < work.len()) : (index += 1) {
|
while (index < work.len()) : (index += 1) {
|
||||||
const node = work.values[index];
|
const node = work.values[index];
|
||||||
|
|
||||||
switch (schedule.graph.get_ptr(node).?.info.thread_restriction) {
|
switch (schedule.graph.get(node).?.info.thread_restriction) {
|
||||||
.none => continue,
|
.none => continue,
|
||||||
|
|
||||||
.main => {
|
.main => {
|
||||||
|
@ -408,7 +408,7 @@ const Schedule = struct {
|
||||||
defer work_group.finish();
|
defer work_group.finish();
|
||||||
|
|
||||||
for (bundle.values) |node| {
|
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.
|
// 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;
|
system.info.execute(system.info.used_parameters(), &system.parameter_states) catch unreachable;
|
||||||
|
@ -428,7 +428,7 @@ const Schedule = struct {
|
||||||
} else {
|
} else {
|
||||||
for (self.parallel_work_bundles.values) |bundle| {
|
for (self.parallel_work_bundles.values) |bundle| {
|
||||||
for (bundle.values) |node| {
|
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);
|
try system.info.execute(system.info.used_parameters(), &system.parameter_states);
|
||||||
}
|
}
|
||||||
|
@ -436,7 +436,7 @@ const Schedule = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (self.blocking_work.values) |node| {
|
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);
|
try system.info.execute(system.info.used_parameters(), &system.parameter_states);
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,19 +50,23 @@ pub fn Graph(comptime Payload: type) type {
|
||||||
return null;
|
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 {
|
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)) {
|
if (!self.exists(node)) {
|
||||||
return null;
|
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 {
|
pub fn init(allocator: std.mem.Allocator) Self {
|
||||||
|
@ -76,7 +80,7 @@ pub fn Graph(comptime Payload: type) type {
|
||||||
return false;
|
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;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -114,10 +118,10 @@ pub fn Graph(comptime Payload: type) type {
|
||||||
|
|
||||||
const node_index = @intFromEnum(node);
|
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;
|
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 {
|
pub fn reset_visited(self: *Self) void {
|
||||||
|
@ -129,7 +133,7 @@ pub fn Graph(comptime Payload: type) type {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.table.values.get(.is_visited, @intFromEnum(node)).?;
|
return self.table.values.get(.is_visited, @intFromEnum(node)).?.*;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ pub const App = struct {
|
||||||
events: *const Events,
|
events: *const Events,
|
||||||
target_frame_time: f64,
|
target_frame_time: f64,
|
||||||
elapsed_time: f64,
|
elapsed_time: f64,
|
||||||
|
delta_time: f64,
|
||||||
is_running: bool,
|
is_running: bool,
|
||||||
|
|
||||||
pub const Events = struct {
|
pub const Events = struct {
|
||||||
|
@ -114,6 +115,7 @@ pub const App = struct {
|
||||||
.events = &events,
|
.events = &events,
|
||||||
.target_frame_time = 1.0 / 60.0,
|
.target_frame_time = 1.0 / 60.0,
|
||||||
.elapsed_time = 0,
|
.elapsed_time = 0,
|
||||||
|
.delta_time = 0,
|
||||||
.is_running = true,
|
.is_running = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -127,11 +129,11 @@ pub const App = struct {
|
||||||
while (app.is_running) {
|
while (app.is_running) {
|
||||||
const ticks_current = std.time.milliTimestamp();
|
const ticks_current = std.time.milliTimestamp();
|
||||||
const milliseconds_per_second = 1000.0;
|
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;
|
app.elapsed_time = @as(f64, @floatFromInt(ticks_current - ticks_initial)) / milliseconds_per_second;
|
||||||
ticks_previous = ticks_current;
|
ticks_previous = ticks_current;
|
||||||
accumulated_time += delta_time;
|
accumulated_time += app.delta_time;
|
||||||
|
|
||||||
try world.run_event(events.pre_update);
|
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: {
|
.channel = (try context.register_readable_state_access(TypedChannel)) orelse set: {
|
||||||
try context.world.set_state(TypedChannel.init(heap.allocator));
|
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)).?;
|
break: set (try context.register_readable_state_access(TypedChannel)).?;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -57,15 +57,7 @@ pub fn Parallel(comptime Type: type) type {
|
||||||
return sliced;
|
return sliced;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
return self.ptr(field)[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_ptr(self: Self, comptime field: Field, index: usize) ?*Element(field) {
|
|
||||||
if (index >= self.len) {
|
if (index >= self.len) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -105,14 +97,6 @@ pub fn get(slice: anytype, index: usize) ?@typeInfo(@TypeOf(slice)).Pointer.chil
|
||||||
return slice[index];
|
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) {
|
pub fn parallel_alloc(comptime Element: type, allocator: std.mem.Allocator, n: usize) std.mem.Allocator.Error!Parallel(Element) {
|
||||||
const alignment = @alignOf(Element);
|
const alignment = @alignOf(Element);
|
||||||
const Slices = Parallel(Element);
|
const Slices = Parallel(Element);
|
||||||
|
|
|
@ -47,15 +47,7 @@ pub fn Sequential(comptime Value: type) type {
|
||||||
return self.values.len == 0;
|
return self.values.len == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(self: Self) ?Value {
|
pub fn get(self: Self) ?*Value {
|
||||||
if (self.get_ptr()) |value| {
|
|
||||||
return value.*;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_ptr(self: Self) ?*Value {
|
|
||||||
if (self.values.len == 0) {
|
if (self.values.len == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -208,7 +200,7 @@ pub fn Parallel(comptime Value: type) type {
|
||||||
const alignment = @alignOf(Value);
|
const alignment = @alignOf(Value);
|
||||||
|
|
||||||
return struct {
|
return struct {
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator = ona.heap.allocator,
|
||||||
values: Slices = .{},
|
values: Slices = .{},
|
||||||
cap: usize = 0,
|
cap: usize = 0,
|
||||||
|
|
||||||
|
@ -230,7 +222,7 @@ pub fn Parallel(comptime Value: type) type {
|
||||||
self.* = undefined;
|
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) {
|
if (self.len() == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -255,6 +247,16 @@ pub fn Parallel(comptime Value: type) type {
|
||||||
return self.values.len;
|
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 {
|
pub fn push_grow(self: *Self, value: Value) std.mem.Allocator.Error!void {
|
||||||
if (self.len() == self.cap) {
|
if (self.len() == self.cap) {
|
||||||
try self.grow(@max(1, self.cap));
|
try self.grow(@max(1, self.cap));
|
||||||
|
|
Loading…
Reference in New Issue