Skip to content

Commit

Permalink
wip: change rendering approach
Browse files Browse the repository at this point in the history
  • Loading branch information
adamws committed Nov 24, 2024
1 parent 878c0c4 commit 198235d
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 131 deletions.
112 changes: 97 additions & 15 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ const KeyOnScreen = struct {
pressed: bool,
};

pub const KeyData = struct {
pub const KeyData = extern struct {
pressed: bool,
repeated: bool,
keycode: u8,
Expand Down Expand Up @@ -151,6 +151,49 @@ const CodepointBuffer = struct {
}
};

const KeyDataProducer = struct {
reader: std.io.AnyReader,
frame_read: bool,
next_frame: usize = 0,

pub fn init(reader: std.io.AnyReader) KeyDataProducer {
return .{
.reader = reader,
.frame_read = true,
};
}

fn nextFrame(self: *KeyDataProducer) !usize {
if (self.frame_read) {
self.next_frame = try self.reader.readInt(usize, .little);
self.frame_read = false;
}
return self.next_frame;
}

fn next(self: *KeyDataProducer) !KeyData {
const key_data = try self.reader.readStruct(KeyData);
self.frame_read = true;
return key_data;
}

pub fn getDataForFrame(self: *KeyDataProducer, frame: usize) !?KeyData {
const next_frame = try self.nextFrame();
if (next_frame == frame) {
return try self.next();
}
return null;
}
};

fn getDataForFrame(frame: usize) !?KeyData {
if (key_data_producer) |*producer| {
return try producer.getDataForFrame(frame);
}
return null;
}

var key_data_producer: ?KeyDataProducer = null;
pub var app_state: AppState = undefined;

// https://github.com/bits/UTF-8-Unicode-Test-Documents/blob/master/UTF-8_sequence_unseparated/utf8_sequence_0-0xfff_assigned_printable_unseparated.txt
Expand Down Expand Up @@ -595,18 +638,18 @@ pub fn main() !void {
}
defer if (pixels) |p| allocator.free(p);

var thread: ?std.Thread = null;
if (res.args.replay) |replay_file| {
// TODO: this will start processing events before rendering ready, add synchronization
const loop = res.args.@"replay-loop" != 0;
thread = try std.Thread.spawn(.{}, backend.producer, .{ &app_state, window_handle, replay_file, loop });
} else {
// TODO: assign to thread var when close supported, join on this thread won't work now
_ = try std.Thread.spawn(.{}, backend.listener, .{ &app_state, window_handle, res.args.record });
const file = try fs.cwd().openFile(replay_file, .{});
//defer file.close();
var buf_reader = std.io.bufferedReader(file.reader());
const reader = buf_reader.reader();
key_data_producer = KeyDataProducer.init(reader.any());
}

if (res.args.replay == null) {
// TODO: defer when close supported, join on this thread won't work now
_ = try std.Thread.spawn(.{}, backend.listener, .{ &app_state, window_handle });
}
defer if (thread) |t| {
t.join();
};

var keycap_texture = blk: {
const theme = Theme.fromString(app_config.data.theme) orelse unreachable;
Expand Down Expand Up @@ -664,6 +707,19 @@ pub fn main() !void {

var drag_reference_position = rl.getWindowPosition();

// TODO: use buffered writer, to do that we must gracefully handle this thread exit,
// otherwise there is no good place to ensure writer flush
// TODO: support full file path
var event_file: ?fs.File = null;
if (res.args.record) |record_file| {
event_file = try cwd.createFile(record_file, .{});
}
defer if(event_file) |value| value.close();

//const event_file_writer = event_file.writer();

var frame: usize = 0;

while (!exit_window) {
if (rl.windowShouldClose()) {
exit_window = true;
Expand Down Expand Up @@ -749,7 +805,36 @@ pub fn main() !void {
};
}

// replay
if (getDataForFrame(frame)) |data| {
if (data) |value| {
if (value.string[0] != 0) {
// update only for keys which produe output,
// this will not include modifiers
app_state.last_char_timestamp = std.time.timestamp();
}
std.debug.print("Push {any}\n", .{value});
_ = app_state.keys.push(value);
}
} else |err| switch (err) {
error.EndOfStream => {
std.debug.print("END OF STREAM\n", .{});
exit_window = true;
},
else => return err,
}

if (app_state.keys.pop()) |k| {
// save state (if recording)
if (event_file) |value| {
_ = try value.writeAll(std.mem.asBytes(&frame));
// TODO:
// writing full k struct is very wasteful, there is a lot of non-essential
// data (for example each release event writes 32 bytes of empty string),
// do not worry about that now, optimize for space later.
_ = try value.writeAll(std.mem.asBytes(&k));
}

app_state.updateKeyStates(@intCast(k.keycode), k.pressed);

const symbol = backend.keysymToString(k.keysym);
Expand Down Expand Up @@ -833,6 +918,7 @@ pub fn main() !void {
}
rl.endDrawing();
tracy.frameMark();
frame += 1;

if (renderer) |*r| {
const rendering = tracy.traceNamed(@src(), "render");
Expand All @@ -852,10 +938,6 @@ pub fn main() !void {
);

try r.write(pixels.?);

if (!backend.is_running) {
exit_window = true;
}
}
}

Expand Down
12 changes: 1 addition & 11 deletions src/win32.zig
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,11 @@ fn lowLevelKeyboardProc(nCode: c.INT, wParam: c.WPARAM, lParam: c.LPARAM) callco
return c.CallNextHookEx(hook.?, nCode, wParam, lParam);
}

pub fn listener(app_state: *AppState, window_handle: *anyopaque, record_file: ?[]const u8) !void {
pub fn listener(app_state: *AppState, window_handle: *anyopaque) !void {
defer is_running = false; // stopping not implemented yet
is_running = true;

_ = window_handle;
_ = record_file;

app_state_l = app_state;
layout = c.GetKeyboardLayout(0);
Expand All @@ -97,15 +96,6 @@ pub fn keysymToString(keysym: c_ulong) [*c]const u8 {
return kbd_en_vscname[@as(usize, @intCast(keysym))].ptr;
}

// uses events stored in file to reproduce them
// assumes that only expected event types are recorded
pub fn producer(app_state: *AppState, window_handle: *anyopaque, replay_file: []const u8, loop: bool) !void {
_ = app_state;
_ = window_handle;
_ = replay_file;
_ = loop;
}

// must match names used by X11:
const kbd_en_vscname = [_][]const u8 {
// zig fmt: off
Expand Down
Loading

0 comments on commit 198235d

Please sign in to comment.