a
This commit is contained in:
Julia 2024-06-08 15:20:47 -05:00
parent 6477a45b8b
commit 0c2653ffaa
19 changed files with 229 additions and 139 deletions

BIN
music/3xosc.flp Normal file

Binary file not shown.

BIN
music/chips/chipbgm.mp3 Normal file

Binary file not shown.

BIN
music/chips/chips.flp Normal file

Binary file not shown.

View file

@ -3,14 +3,14 @@ const fumo = @import("fumostd.zig");
const input = @import("input.zig");
const Axis = struct {
data: f64,
data: f64 = 0,
last_pressed: u64,
last_released: u64,
last_pressed: u64 = 0,
last_released: u64 = 0,
is_down: bool,
is_held: bool,
is_up: bool,
is_down: bool = false,
is_held: bool = false,
is_up: bool = false,
};
const Bind = struct {
@ -18,37 +18,37 @@ const Bind = struct {
multiplier: f64,
};
const Controller = struct {
pub const Controller = struct {
const BindHashMap = fumo.HashMap(*Bind);
axes: []Axis,
binds: []Bind,
scancode_map: BindHashMap,
code_map: BindHashMap,
pending: [input.IO_BUF_SIZE]*Axis = undefined,
pending: [16]*Axis = undefined,
n_pending: usize = 0,
pub fn init(
arena: std.heap.ArenaAllocator,
arena: std.mem.Allocator,
n_axes: usize,
n_binds: usize,
n_scancodes: usize,
n_codes: usize,
) !@This() {
const ctrl = @This(){
.axes = try arena.alloc(Axis, n_axes),
.binds = try arena.alloc(Bind, n_binds),
.scancode_map = try BindHashMap.init(arena, n_scancodes),
.code_map = try BindHashMap.init(arena, n_codes),
};
@memset(ctrl.axes, 0);
@memset(ctrl.axes, Axis{});
return ctrl;
}
pub fn bindScancode(this: *@This(), scancode: usize, bind: usize) !void {
try this.scancode_map.set(scancode, &this.binds[bind]);
pub fn bindCode(this: *@This(), code: usize, bind: usize) !void {
try this.code_map.set(code, &this.binds[bind]);
}
pub fn bindAxis(this: *@This(), bind: usize, axis: usize, mul: f64) void {
@ -58,29 +58,28 @@ const Controller = struct {
};
}
pub fn poll(this: *@This(), record_buffer: fumo.RingBuffer(input.Record, 16)) void {
pub fn poll(this: *@This(), rec_circ: *input.RecordCircle) void {
for (this.pending[0..this.n_pending]) |axis| {
axis.is_up = false;
axis.is_down = false;
}
for (record_buffer) |*record| {
if (this.scancode_map.find(record.scancode)) |*bind| {
inline for (rec_circ.read()) |slice| for (slice) |record| {
if (this.code_map.find(record.code)) |bind| {
dispatch(bind, record);
}
}
};
}
fn dispatch(bind: *Bind, record: input.Record) void {
bind.axis.data = record.data * bind.multiplier;
if (record.is_down) {
bind.axis.is_down = true;
bind.axis.is_held = true;
bind.axis.is_down = record.data != 0;
bind.axis.is_up = record.data == 0;
if (record.data != 0) {
bind.axis.last_pressed = record.time;
} else {
bind.axis.is_up = true;
bind.axis.is_held = false;
bind.axis.last_released = record.time;
}
}

View file

@ -1,12 +1,13 @@
const std = @import("std");
const AtomicOrder = @import("std").builtin.AtomicOrder;
pub fn HashMap(comptime V: type) type {
return struct {
pub const HashMapError = error{Full};
pub const Bucket = struct {
hash: usize,
value: V,
hash: usize = 0,
value: V = undefined,
};
buckets: []Bucket,
@ -17,7 +18,7 @@ pub fn HashMap(comptime V: type) type {
.buckets = try allocator.alloc(Bucket, n),
};
@memset(map.buckets, Bucket{ .hash = 0, .value = undefined });
@memset(map.buckets, Bucket{});
return map;
}
@ -78,46 +79,63 @@ pub fn HashMap(comptime V: type) type {
};
}
pub fn RingBuffer(comptime T: type, comptime size: comptime_int) type {
pub fn Buffer(comptime T: type, comptime size: comptime_int) type {
return struct {
array: [size]T = undefined,
read_index: isize = 0,
write_index: isize = 0,
len: usize = 0,
read: usize = 0,
pub fn write(this: *@This(), slice: []T) usize {
const write_limit = @mod(this.read_index - 1, size);
var i: usize = 0;
while (i < slice.len and this.write_index != write_limit) : ({
i += 1;
}) {
this.array[this.write_index] = slice[i];
this.write_index = @mod(this.write_index + 1, size);
pub fn slice(this: *@This()) []T {
return this.array[this.read..this.len];
}
return i;
pub fn flush(this: *@This()) void {
this.len = 0;
this.read = 0;
}
};
}
pub fn CircleBuffer(comptime T: type, comptime size: comptime_int) type {
return struct {
array: [size]T = undefined,
read: usize = 0,
write: usize = 0,
pub fn write(this: *@This(), slice: []T) usize {
const read_atm: usize = @atomicLoad(usize, &this.read, AtomicOrder.acquire);
const contiguous: bool = this.write < read_atm;
const a_upper: usize = if (contiguous) read_atm else size;
const b_upper: usize = if (contiguous) 0 else read_atm;
const region_a: []T = this.array[this.write..a_upper];
const region_b: []T = this.array[0..b_upper];
const slice_a: []T = slice[0..@min(slice.len, region_a.len)];
const slice_b: []T = slice[slice_a.len..slice.len];
@memcpy(region_a, slice_a);
@memcpy(region_b, slice_b);
const written: usize = @min(slice.len, region_a.len + region_b.len);
@atomicStore(usize, &this.write, (this.write + written) % size, AtomicOrder.release);
return written;
}
pub fn read(this: *@This()) struct { []T, []T } {
const contiguous: bool = this.write_index >= this.read_index;
const write_atm: usize = @atomicLoad(usize, &this.write, AtomicOrder.acquire);
const contiguous: bool = this.read < write_atm;
const upper_1: usize = if (contiguous) this.write_index else size;
const upper_2: usize = if (contiguous) 0 else this.write_index;
const a_upper: usize = if (contiguous) write_atm else size;
const b_upper: usize = if (contiguous) 0 else write_atm;
this.read_index = this.write_index;
const region_a: []T = this.array[this.read..a_upper];
const region_b: []T = this.array[0..b_upper];
return .{
this.array[this.read_index..upper_1],
this.array[0..upper_2],
};
}
pub fn unreadLen(this: @This()) usize {
if (this.write_index >= this.read_index) {
return this.write_index - this.read_index;
} else {
return (size - this.read_index) + this.write_index;
}
const read_total: usize = region_a.len + region_b.len;
@atomicStore(usize, &this.read, (this.read + read_total) % size, AtomicOrder.release);
return struct { region_a, region_b };
}
};
}

View file

@ -1,61 +1,67 @@
const std = @import("std");
const fumo = @import("fumostd.zig");
const platform = @import("platform.zig");
const IO_BUF_SIZE: usize = 16;
const STR_BUF_SIZE: usize = IO_BUF_SIZE * 4;
pub const RecordCircle = fumo.CircleBuffer(Record, 16);
pub const StringCircle = fumo.CircleBuffer(u8, 16 * 4);
const RecordBuffer = fumo.RingBuffer(Record, IO_BUF_SIZE);
const StringBuffer = fumo.RingBuffer(u8, STR_BUF_SIZE);
pub const RecordBuffer = fumo.Buffer(Record, 16);
pub const StringBuffer = fumo.Buffer(u8, 16 * 4);
const Record = struct {
scancode: usize,
pub const Record = struct {
const Type = enum { axis, joystick };
hash: usize,
data: f64,
time: u64,
pub fn readAxis(buf: RecordBuffer, code: usize, data: f64) void {
buf.array[buf.len] = Record{
.hash = hashCode(code, Type.axis),
.data = data,
};
buf.len += 1;
}
is_down: bool,
pub fn readJoystick(buf: RecordBuffer, code: usize, x: f64, y: f64) void {
buf.array[buf.len] = .{ .code = scancode | Record.joystick_ofs, .data = x };
buf.array[buf.len + 1] = .{ .code = scancode | Record.joystick_ofs, .data = y };
buf.len += 2;
}
fn hashCode(code: usize, code_type: usize) usize {
return code | (code_type << (@bitSizeOf(usize) / 2));
}
};
const Handle = struct {
records: RecordBuffer,
string: StringBuffer,
pub const Handle = struct {
rec_circ: RecordCircle = .{},
str_circ: StringCircle = .{},
thread: std.Thread,
mutex: std.Thread.Mutex = std.Thread.Mutex{},
read_signal: std.Thread.Condition = std.Thread.Condition{},
thread: std.Thread = undefined,
signal: std.Thread.Condition = .{},
pub fn init() !Handle {
const handle = Handle{
.thread = try std.Thread.spawn(.{}, worker, .{}),
};
var handle = Handle{};
handle.thread = try std.Thread.spawn(.{}, worker, .{&handle});
return handle;
}
fn worker(this: *@This()) void {
var rec_buf: [IO_BUF_SIZE]Record = undefined;
var str_buf: [STR_BUF_SIZE]u8 = undefined;
fn worker(hand: *Handle) !void {
var rec_buf = RecordBuffer{};
var str_buf = StringBuffer{};
var n_recs: usize = 0;
var n_str: usize = 0;
while (true) {
// block platform read in
try platform.ReadInput(&rec_buf, &n_recs, &str_buf, &n_str);
this.mutex.lock();
defer this.mutex.unlock();
var w_recs: usize = 0;
var w_str: usize = 0;
while (w_recs < n_recs) : ({
this.read_signal.wait(&this.mutex);
if (this.records.read_index == this.records.write_index)
continue;
while (true) : ({
rec_buf.flush();
str_buf.flush();
}) {
w_recs += this.records.write(rec_buf[w_recs..n_recs]);
w_str += this.string.write(str_buf[w_str..n_str]);
try platform.ReadInput(&rec_buf, &str_buf);
while (rec_buf.read < rec_buf.len) : ({
hand.signal.wait(&hand.mutex);
}) {
rec_buf.read += hand.rec_circ.write(rec_buf.slice());
str_buf.read += hand.str_circ.write(str_buf.slice());
}
}
}

View file

@ -1,11 +1,25 @@
const std = @import("std");
//const fumo = @import("fumostd.zig");
const fumo = @import("fumostd.zig");
const controller = @import("controller.zig");
const input = @import("input.zig");
pub fn main() !void {
const a: isize = 0;
const b: isize = 6;
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
const allocator = arena.allocator();
std.debug.print("{}", .{@mod(a - 1, b)});
var ctrl = try controller.Controller.init(allocator, 3, 3, 3);
try ctrl.bindCode(69, 0);
ctrl.bindAxis(0, 2, 1);
var hand = try input.Handle.init();
hand.aquire();
_ = hand.rec_circ.write(input.Record.readAxis(69, 123));
ctrl.poll(&hand.rec_circ);
std.debug.print("axis index 2: {}", .{ctrl.axes[2].data});
hand.release();
}
test "dict" {}

View file

@ -10,47 +10,100 @@ const stdin = windows.GetStdHandle(windows.STD_INPUT_HANDLE);
const PlatformError = error{ReadInputCall};
pub fn ReadInput(
out_buf: *[input.IO_BUF_SIZE]input.Record,
n_out: *usize,
str_buf: *[input.STR_BUF_SIZE]u8,
n_str: *usize,
rec_buf: *input.RecordBuffer,
str_buf: *input.StringBuffer,
) !void {
var buf: [input.IO_BUF_SIZE]windows.INPUT_RECORD = undefined;
var n_buf: usize = 0;
var win_buf: [input.IO_BUF_SIZE]windows.INPUT_RECORD = undefined;
var n_win_buf: usize = 0;
const success: bool = windows.ReadConsoleInputW(
stdin,
&buf,
&win_buf,
input.IO_BUF_SIZE,
&n_buf,
&n_win_buf,
);
if (!success)
return PlatformError.ReadInputCall;
n_out.* = 0;
for (buf, out_buf) |rec, *out_rec| {}
for (win_buf) |win_rec| {
translate(win_rec, rec_buf, str_buf);
}
}
fn dispatch(win_rec: windows.INPUT_RECORD) bool {
fn translate(
win_rec: windows.INPUT_RECORD,
rec_buf: *input.RecordBuffer,
str_buf: *input.StringBuffer,
) void {
switch (win_rec.EventType) {
windows.KEY_EVENT => blk: {
out_rec.* = input.Record{
.scancode = rec.Event.KeyEvent.wVirtualScanCode,
.data = rec.Event.KeyEvent.bKeyDown,
.time = now,
.is_down = rec.Event.KeyEvent.bKeyDown,
};
windows.KEY_EVENT => {
input.Record.readAxis(
rec_buf,
win_rec.Event.KeyEvent.wVirtualKeyCode,
win_rec.Event.KeyEvent.bKeyDown,
);
if (rec.Event.KeyEvent.bKeyDown)
n_str.* += ucs2ToUtf8(str_buf + n_out, rec.Event.KeyEvent.uChar.UnicodeChar);
if (!win_rec.Event.KeyEvent.bKeyDown)
return;
break :blk true;
str_buf.len += sprintWchar(
str_buf.array + str_buf.len,
win_rec.Event.KeyEvent.uChar.UnicodeChar,
);
},
windows.WINDOW_BUFFER_SIZE_EVENT => false,
windows.MOUSE_EVENT => translateMouse(
rec_buf,
win_rec.Event.MouseEvent,
),
else => false,
windows.WINDOW_BUFFER_SIZE_EVENT => void,
else => void,
}
}
fn translateMouse(
rec_buf: *input.RecordBuffer,
win_mouse: windows.MOUSE_EVENT_RECORD,
) void {
switch (win_mouse.dwEventFlags) {
windows.MOUSE_MOVED => input.Record.readJoystick(
rec_buf,
0,
win_mouse.dwMousePosition.X,
win_mouse.dwMousePosition.Y,
),
windows.MOUSE_WHEELED => input.Record.readAxis(
rec_buf,
1,
win_mouse.dwButtonState,
),
windows.MOUSE_HWHEELED => input.Record.readAxis(
rec_buf,
2,
win_mouse.dwButtonState,
),
}
}
fn sprintWchar(buf: [*]u8, wchar: u16) usize {
if (wchar < 255) {
buf[0] = wchar;
return 1;
}
if (wchar < 2047) {
buf[0] = 0xC0 + (wchar >> 6);
buf[1] = 0x80 + (wchar & 0x3F);
return 2;
}
buf[0] = 0xE0 + (wchar >> 12);
buf[1] = 0x80 + ((wchar >> 6) & 0x3F);
buf[2] = 0x80 + (wchar & 0x3F);
return 3;
}

View file

@ -1,5 +1,5 @@
0
203 844424932407779 1716524569939084500 ec1e1d6dab6581d55ec18dff49107eaf 0 src\main.zig
231 844424932407779 1716824983055731700 4865c7439eede09c6c465fa6b8510223 0 src\main.zig
7757 281474978983955 1715741198000000000 3170fcda94ef1eb8e6ca725dff5e254d 1 std\std.zig
23040 281474978983952 1715741198000000000 da66963546b611ee7750a27396b7d1ea 1 std\start.zig
114777 281474978983653 1715741198000000000 b78cd1771bac0cee1cfa01c556ea1508 1 std\debug.zig

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.