zig8/src/scheduler.zig

123 lines
3.3 KiB
Zig

const std = @import("std");
const disp = @import("display.zig");
const Chip8 = @import("chip8.zig").Chip8;
const Order = std.math.Order;
const Allocator = std.mem.Allocator;
const PriorityQueue = std.PriorityQueue;
const Display = disp.Display;
pub const OPS_PER_HZ = 500;
const PIXELBUF_LEN = disp.PIXELBUF_LEN;
pub const Scheduler = struct {
pixels_ptr: *[PIXELBUF_LEN]u8,
timestamp: u64,
queue: PriorityQueue(Event, lessThan),
pub fn new(alloc: Allocator, pixels_ptr: *[PIXELBUF_LEN]u8) Scheduler {
var queue = Scheduler{
.timestamp = 0,
.pixels_ptr = pixels_ptr,
.queue = PriorityQueue(Event, lessThan).init(alloc),
};
queue.pushEvent(.{
.kind = EventKind.HeatDeath,
.timestamp = std.math.maxInt(u64),
});
return queue;
}
pub fn now(self: *const Scheduler) u64 {
return self.timestamp;
}
pub fn push(self: *Scheduler, kind: EventKind, when: u64) void {
self.pushEvent(Event{ .kind = kind, .timestamp = when });
}
pub fn replaceOrPush(self: *Scheduler, kind: EventKind, when: u64) void {
if (self.find(kind)) |event| {
self.queue.update(event, Event{ .kind = kind, .timestamp = when }) catch unreachable;
} else {
self.push(kind, when);
}
}
fn pushEvent(self: *Scheduler, event: Event) void {
self.queue.add(event) catch unreachable;
}
pub fn find(self: *Scheduler, kind: EventKind) ?Event {
var it = self.queue.iterator();
while (it.next()) |e| {
if (e.kind == kind) return e;
}
return null;
}
fn handleEvent(self: *Scheduler, chip8: *Chip8, event: Event) void {
switch (event.kind) {
.HeatDeath => {
std.debug.panic("Reached u64 overflow somehow", .{});
},
.RequestRedraw => draw(&chip8.disp, self.pixels_ptr),
.DelayTimer => {
std.log.debug("{} | Delay Timer Expire", .{self.timestamp});
},
.SoundTimer => {
std.log.debug("{} | Sound Timer Expire", .{self.timestamp});
},
}
}
};
const Event = struct {
kind: EventKind,
timestamp: u64,
};
pub const EventKind = enum {
HeatDeath,
RequestRedraw,
SoundTimer,
DelayTimer,
};
fn lessThan(a: Event, b: Event) Order {
return std.math.order(a.timestamp, b.timestamp);
}
pub fn run_until(sched: *Scheduler, chip8: *Chip8, timestamp: u64) void {
while (sched.timestamp <= timestamp) {
sched.timestamp += chip8.step();
const should_handle = if (sched.queue.peek()) |e| sched.timestamp >= e.timestamp else false;
if (should_handle) {
const event = sched.queue.remove();
sched.handleEvent(chip8, event);
}
}
}
fn draw(display: *const Display, buf: *[PIXELBUF_LEN]u8) void {
const WHITE = [_]u8{ 0xFF, 0xFF, 0xFF, 0xFF };
const BLACK = [_]u8{ 0xFF, 0x00, 0x00, 0x00 };
var i: usize = 0;
while (i < display.buf.len) : (i += 1) {
var px_i = i * 4;
if (display.buf[i] == 0x01) {
std.mem.copy(u8, buf[px_i..(px_i + 4)], &WHITE);
} else {
std.mem.copy(u8, buf[px_i..(px_i + 4)], &BLACK);
}
}
}