use super::keymap;
use crate::{fb_flush, fb_info, fb_write, get_time, read, sleep, STDIN};
const DOOM_RESX: usize = 640;
const DOOM_RESY: usize = 400;
const KEY_QUEUE_SIZE: usize = 64;
static mut KEY_QUEUE: [(i32, u8); KEY_QUEUE_SIZE] = [(0, 0); KEY_QUEUE_SIZE];
static mut KEY_HEAD: usize = 0;
static mut KEY_TAIL: usize = 0;
fn volatile_load_head() -> usize {
unsafe { core::ptr::read_volatile(&raw const KEY_HEAD) }
}
fn volatile_load_tail() -> usize {
unsafe { core::ptr::read_volatile(&raw const KEY_TAIL) }
}
fn volatile_store_head(v: usize) {
unsafe { core::ptr::write_volatile(&raw mut KEY_HEAD, v) }
}
fn volatile_store_tail(v: usize) {
unsafe { core::ptr::write_volatile(&raw mut KEY_TAIL, v) }
}
static mut FB_WIDTH: u32 = 0;
static mut FB_HEIGHT: u32 = 0;
unsafe extern "C" {
static mut DG_ScreenBuffer: *mut u32;
}
#[unsafe(no_mangle)]
pub extern "C" fn DG_Init() {
let (w, h) = fb_info();
unsafe {
FB_WIDTH = w;
FB_HEIGHT = h;
}
}
#[unsafe(no_mangle)]
pub extern "C" fn DG_DrawFrame() {
unsafe {
let buf = DG_ScreenBuffer;
if buf.is_null() {
return;
}
let fb_w = FB_WIDTH as usize;
let fb_h = FB_HEIGHT as usize;
let offset_x = fb_w.saturating_sub(DOOM_RESX) / 2;
let offset_y = fb_h.saturating_sub(DOOM_RESY) / 2;
let pixel_count = DOOM_RESX * DOOM_RESY;
let pixels = core::slice::from_raw_parts_mut(buf, pixel_count);
for p in pixels.iter_mut() {
*p |= 0xFF00_0000;
}
for row in 0..DOOM_RESY {
let row_ptr = buf.add(row * DOOM_RESX) as *const u8;
fb_write(
offset_x as u32,
(offset_y + row) as u32,
DOOM_RESX as u32,
1,
row_ptr,
);
}
fb_flush();
}
poll_keyboard();
}
#[unsafe(no_mangle)]
pub extern "C" fn DG_SleepMs(ms: u32) {
sleep(ms as usize);
}
#[unsafe(no_mangle)]
pub extern "C" fn DG_GetTicksMs() -> u32 {
get_time() as u32
}
#[unsafe(no_mangle)]
pub extern "C" fn DG_GetKey(pressed: *mut i32, doom_key: *mut u8) -> i32 {
poll_keyboard();
let head = volatile_load_head();
let tail = volatile_load_tail();
if head == tail {
return 0;
}
unsafe {
let idx = tail % KEY_QUEUE_SIZE;
let entry = core::ptr::read_volatile(&raw const KEY_QUEUE[idx]);
volatile_store_tail(tail + 1);
*pressed = entry.0;
*doom_key = entry.1;
1
}
}
#[unsafe(no_mangle)]
pub extern "C" fn DG_SetWindowTitle(_title: *const u8) {}
fn poll_keyboard() {
let mut buf = [0u8; 1];
loop {
let n = read(STDIN, &mut buf);
let raw = unsafe { core::ptr::read_volatile(buf.as_ptr()) };
if n <= 0 || raw == 0 {
break;
}
let pressed = (raw & 0x80) == 0;
let scancode = raw & 0x7F;
let doom_key = keymap::translate(scancode);
if doom_key != 0 {
let head = volatile_load_head();
unsafe {
let idx = head % KEY_QUEUE_SIZE;
let entry = (if pressed { 1i32 } else { 0i32 }, doom_key);
core::ptr::write_volatile(&raw mut KEY_QUEUE[idx], entry);
}
volatile_store_head(head + 1);
}
}
}