|
|
@ -1,7 +1,7 @@ |
|
|
|
use std::ops::Sub; |
|
|
|
use std::ops::Sub; |
|
|
|
use std::time::{Duration, Instant}; |
|
|
|
use std::time::{Duration, Instant}; |
|
|
|
|
|
|
|
|
|
|
|
use minifb::{ScaleMode, Window, WindowOptions}; |
|
|
|
use minifb::{ScaleMode, Window, WindowOptions, MouseMode, Key, MouseButton}; |
|
|
|
|
|
|
|
|
|
|
|
use crsn::asm::data::literal::Value; |
|
|
|
use crsn::asm::data::literal::Value; |
|
|
|
use crsn::asm::instr::Cond; |
|
|
|
use crsn::asm::instr::Cond; |
|
|
@ -61,7 +61,17 @@ impl OpTrait for ScreenOp { |
|
|
|
let h = state.read(*height)?; |
|
|
|
let h = state.read(*height)?; |
|
|
|
init(state, w, h)?; |
|
|
|
init(state, w, h)?; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ScreenOp::Erase { color } => { |
|
|
|
|
|
|
|
let color = (state.read(*color)? & 0xffffff) as u32; |
|
|
|
|
|
|
|
let backend: &mut Backend = state.ext_mut(); |
|
|
|
|
|
|
|
for n in 0..(backend.buffer.len()) { |
|
|
|
|
|
|
|
backend.buffer[n] = color; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ScreenOp::SetOpt { opt, val } => { |
|
|
|
ScreenOp::SetOpt { opt, val } => { |
|
|
|
|
|
|
|
state.clear_status(); |
|
|
|
let opt = state.read(*opt)?; |
|
|
|
let opt = state.read(*opt)?; |
|
|
|
let val = state.read(*val)?; |
|
|
|
let val = state.read(*val)?; |
|
|
|
let backend: &mut Backend = state.ext_mut(); |
|
|
|
let backend: &mut Backend = state.ext_mut(); |
|
|
@ -81,6 +91,7 @@ impl OpTrait for ScreenOp { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ScreenOp::Blit { force } => { |
|
|
|
ScreenOp::Blit { force } => { |
|
|
|
let force = state.read(*force)?; |
|
|
|
let force = state.read(*force)?; |
|
|
|
let backend: &mut Backend = state.ext_mut(); |
|
|
|
let backend: &mut Backend = state.ext_mut(); |
|
|
@ -91,7 +102,21 @@ impl OpTrait for ScreenOp { |
|
|
|
blit_maybe(backend) |
|
|
|
blit_maybe(backend) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ScreenOp::Update => { |
|
|
|
|
|
|
|
let backend: &mut Backend = state.ext_mut(); |
|
|
|
|
|
|
|
match &mut backend.window { |
|
|
|
|
|
|
|
Some(w) => { |
|
|
|
|
|
|
|
w.update(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
None => { |
|
|
|
|
|
|
|
state.set_flag(Cond::Invalid, true); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ScreenOp::SetPixel { x, y, color } => { |
|
|
|
ScreenOp::SetPixel { x, y, color } => { |
|
|
|
|
|
|
|
state.clear_status(); |
|
|
|
let x = state.read(*x)?; |
|
|
|
let x = state.read(*x)?; |
|
|
|
let y = state.read(*y)?; |
|
|
|
let y = state.read(*y)?; |
|
|
|
let color = state.read(*color)?; |
|
|
|
let color = state.read(*color)?; |
|
|
@ -122,6 +147,83 @@ impl OpTrait for ScreenOp { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ScreenOp::GetMouse { x, y } => { |
|
|
|
|
|
|
|
state.clear_status(); |
|
|
|
|
|
|
|
let backend: &mut Backend = state.ext_mut(); |
|
|
|
|
|
|
|
match &mut backend.window { |
|
|
|
|
|
|
|
Some(w) => { |
|
|
|
|
|
|
|
let mp = w.get_mouse_pos(MouseMode::Discard); |
|
|
|
|
|
|
|
debug!("mp = {:?}", mp); |
|
|
|
|
|
|
|
match mp { |
|
|
|
|
|
|
|
None => { |
|
|
|
|
|
|
|
state.set_flag(Cond::Overflow, true); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Some((xf, yf)) => { |
|
|
|
|
|
|
|
let xval = xf.round() as u64; |
|
|
|
|
|
|
|
let yval = yf.round() as u64; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
state.write(*x, xval); |
|
|
|
|
|
|
|
state.write(*y, yval); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
None => { |
|
|
|
|
|
|
|
state.set_flag(Cond::Invalid, true); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ScreenOp::TestKey { pressed, code } => { |
|
|
|
|
|
|
|
state.clear_status(); |
|
|
|
|
|
|
|
let num = num2key(state.read(*code)?); |
|
|
|
|
|
|
|
let backend: &mut Backend = state.ext_mut(); |
|
|
|
|
|
|
|
match &mut backend.window { |
|
|
|
|
|
|
|
Some(w) => { |
|
|
|
|
|
|
|
match num { |
|
|
|
|
|
|
|
None => { |
|
|
|
|
|
|
|
state.set_flag(Cond::Invalid, true); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Some(kn) => { |
|
|
|
|
|
|
|
let down = w.is_key_down(kn) as u64; |
|
|
|
|
|
|
|
state.write(*pressed, down)?; |
|
|
|
|
|
|
|
state.update_status(down); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
None => { |
|
|
|
|
|
|
|
state.set_flag(Cond::Invalid, true); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ScreenOp::TestMouse { pressed, button } => { |
|
|
|
|
|
|
|
state.clear_status(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let omb = match state.read(*button)? { |
|
|
|
|
|
|
|
0 => Some(MouseButton::Left), |
|
|
|
|
|
|
|
1 => Some(MouseButton::Right), |
|
|
|
|
|
|
|
2 => Some(MouseButton::Middle), |
|
|
|
|
|
|
|
_ => { |
|
|
|
|
|
|
|
state.set_flag(Cond::Invalid, true); |
|
|
|
|
|
|
|
None |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let backend: &mut Backend = state.ext_mut(); |
|
|
|
|
|
|
|
match &mut backend.window { |
|
|
|
|
|
|
|
Some(w) => { |
|
|
|
|
|
|
|
if let Some(mb) = omb { |
|
|
|
|
|
|
|
let is_pressed = w.get_mouse_down(mb) as u64; |
|
|
|
|
|
|
|
state.write(*pressed, is_pressed)?; |
|
|
|
|
|
|
|
state.update_status(is_pressed); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
None => { |
|
|
|
|
|
|
|
state.set_flag(Cond::Invalid, true); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Ok(eres) |
|
|
|
Ok(eres) |
|
|
@ -132,7 +234,12 @@ impl OpTrait for ScreenOp { |
|
|
|
ScreenOp::SetOpt { opt, val } => sexp::list(&[A("sc-opt"), A(opt), A(val)]), |
|
|
|
ScreenOp::SetOpt { opt, val } => sexp::list(&[A("sc-opt"), A(opt), A(val)]), |
|
|
|
ScreenOp::ScreenInit { width, height } => sexp::list(&[A("sc-init"), A(width), A(height)]), |
|
|
|
ScreenOp::ScreenInit { width, height } => sexp::list(&[A("sc-init"), A(width), A(height)]), |
|
|
|
ScreenOp::SetPixel { x, y, color } => sexp::list(&[A("sc-px"), A(x), A(y), A(color)]), |
|
|
|
ScreenOp::SetPixel { x, y, color } => sexp::list(&[A("sc-px"), A(x), A(y), A(color)]), |
|
|
|
ScreenOp::Blit { force } => sexp::list(&[A("sc-blit"), A(force)]) |
|
|
|
ScreenOp::Blit { force } => sexp::list(&[A("sc-blit"), A(force)]), |
|
|
|
|
|
|
|
ScreenOp::Update => sexp::list(&[A("sc-poll")]), |
|
|
|
|
|
|
|
ScreenOp::GetMouse { x, y } => sexp::list(&[A("sc-mouse"), A(x), A(y)]), |
|
|
|
|
|
|
|
ScreenOp::TestKey { pressed, code } => sexp::list(&[A("sc-key"), A(pressed), A(code)]), |
|
|
|
|
|
|
|
ScreenOp::TestMouse { pressed, button } => sexp::list(&[A("sc-mbtn"), A(pressed), A(button)]), |
|
|
|
|
|
|
|
ScreenOp::Erase { color } => sexp::list(&[A("sc-erase"), A(color)]), |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -160,9 +267,6 @@ fn init(state: &mut RunState, width: Value, height: Value) -> Result<(), Fault> |
|
|
|
backend.height = height as usize; |
|
|
|
backend.height = height as usize; |
|
|
|
backend.buffer = vec![0; (width * height) as usize]; |
|
|
|
backend.buffer = vec![0; (width * height) as usize]; |
|
|
|
|
|
|
|
|
|
|
|
// window.limit_update_rate(Some(std::time::Duration::from_micros(16600)));
|
|
|
|
|
|
|
|
// window.limit_update_rate(None);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend.window = Some(window); |
|
|
|
backend.window = Some(window); |
|
|
|
|
|
|
|
|
|
|
|
blit_maybe(backend); |
|
|
|
blit_maybe(backend); |
|
|
@ -177,9 +281,142 @@ fn blit_maybe(backend: &mut Backend) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn blit(backend: &mut Backend) { |
|
|
|
fn blit(backend: &mut Backend) { |
|
|
|
backend.window.as_mut().unwrap() |
|
|
|
let w = backend.window.as_mut().unwrap(); |
|
|
|
.update_with_buffer(&backend.buffer, backend.width, backend.height) |
|
|
|
|
|
|
|
|
|
|
|
if !w.is_open() { |
|
|
|
|
|
|
|
// TODO...
|
|
|
|
|
|
|
|
std::process::exit(0); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
w.update_with_buffer(&backend.buffer, backend.width, backend.height) |
|
|
|
.expect("Update screen"); // TODO fault
|
|
|
|
.expect("Update screen"); // TODO fault
|
|
|
|
|
|
|
|
|
|
|
|
backend.last_render = Instant::now(); |
|
|
|
backend.last_render = Instant::now(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn num2key(num : Value) -> Option<Key> { |
|
|
|
|
|
|
|
let remap = [ |
|
|
|
|
|
|
|
Key::Key0, |
|
|
|
|
|
|
|
Key::Key1, |
|
|
|
|
|
|
|
Key::Key2, |
|
|
|
|
|
|
|
Key::Key3, |
|
|
|
|
|
|
|
Key::Key4, |
|
|
|
|
|
|
|
Key::Key5, |
|
|
|
|
|
|
|
Key::Key6, |
|
|
|
|
|
|
|
Key::Key7, |
|
|
|
|
|
|
|
Key::Key8, |
|
|
|
|
|
|
|
Key::Key9, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Key::A, // 10
|
|
|
|
|
|
|
|
Key::B, |
|
|
|
|
|
|
|
Key::C, |
|
|
|
|
|
|
|
Key::D, |
|
|
|
|
|
|
|
Key::E, |
|
|
|
|
|
|
|
Key::F, |
|
|
|
|
|
|
|
Key::G, |
|
|
|
|
|
|
|
Key::H, |
|
|
|
|
|
|
|
Key::I, |
|
|
|
|
|
|
|
Key::J, |
|
|
|
|
|
|
|
Key::K, |
|
|
|
|
|
|
|
Key::L, |
|
|
|
|
|
|
|
Key::M, |
|
|
|
|
|
|
|
Key::N, |
|
|
|
|
|
|
|
Key::O, |
|
|
|
|
|
|
|
Key::P, |
|
|
|
|
|
|
|
Key::Q, |
|
|
|
|
|
|
|
Key::R, |
|
|
|
|
|
|
|
Key::S, |
|
|
|
|
|
|
|
Key::T, |
|
|
|
|
|
|
|
Key::U, |
|
|
|
|
|
|
|
Key::V, |
|
|
|
|
|
|
|
Key::W, |
|
|
|
|
|
|
|
Key::X, |
|
|
|
|
|
|
|
Key::Y, |
|
|
|
|
|
|
|
Key::Z, // 35
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Key::F1, // 36
|
|
|
|
|
|
|
|
Key::F2, |
|
|
|
|
|
|
|
Key::F3, |
|
|
|
|
|
|
|
Key::F4, |
|
|
|
|
|
|
|
Key::F5, |
|
|
|
|
|
|
|
Key::F6, |
|
|
|
|
|
|
|
Key::F7, |
|
|
|
|
|
|
|
Key::F8, |
|
|
|
|
|
|
|
Key::F9, |
|
|
|
|
|
|
|
Key::F10, |
|
|
|
|
|
|
|
Key::F11, |
|
|
|
|
|
|
|
Key::F12, |
|
|
|
|
|
|
|
Key::F13, |
|
|
|
|
|
|
|
Key::F14, |
|
|
|
|
|
|
|
Key::F15, // 50
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Key::Down, // 51
|
|
|
|
|
|
|
|
Key::Left, |
|
|
|
|
|
|
|
Key::Right, |
|
|
|
|
|
|
|
Key::Up, |
|
|
|
|
|
|
|
Key::Apostrophe, |
|
|
|
|
|
|
|
Key::Backquote, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Key::Backslash, // 57
|
|
|
|
|
|
|
|
Key::Comma, |
|
|
|
|
|
|
|
Key::Equal, |
|
|
|
|
|
|
|
Key::LeftBracket, |
|
|
|
|
|
|
|
Key::Minus, |
|
|
|
|
|
|
|
Key::Period, |
|
|
|
|
|
|
|
Key::RightBracket, |
|
|
|
|
|
|
|
Key::Semicolon, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Key::Slash, // 65
|
|
|
|
|
|
|
|
Key::Backspace, |
|
|
|
|
|
|
|
Key::Delete, |
|
|
|
|
|
|
|
Key::End, |
|
|
|
|
|
|
|
Key::Enter, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Key::Escape, // 70
|
|
|
|
|
|
|
|
Key::Home, |
|
|
|
|
|
|
|
Key::Insert, |
|
|
|
|
|
|
|
Key::Menu, |
|
|
|
|
|
|
|
Key::PageDown, |
|
|
|
|
|
|
|
Key::PageUp, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Key::Pause, // 76
|
|
|
|
|
|
|
|
Key::Space, |
|
|
|
|
|
|
|
Key::Tab, |
|
|
|
|
|
|
|
Key::NumLock, |
|
|
|
|
|
|
|
Key::CapsLock, |
|
|
|
|
|
|
|
Key::ScrollLock, |
|
|
|
|
|
|
|
Key::LeftShift, |
|
|
|
|
|
|
|
Key::RightShift, |
|
|
|
|
|
|
|
Key::LeftCtrl, |
|
|
|
|
|
|
|
Key::RightCtrl, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Key::NumPad0, // 86
|
|
|
|
|
|
|
|
Key::NumPad1, |
|
|
|
|
|
|
|
Key::NumPad2, |
|
|
|
|
|
|
|
Key::NumPad3, |
|
|
|
|
|
|
|
Key::NumPad4, |
|
|
|
|
|
|
|
Key::NumPad5, |
|
|
|
|
|
|
|
Key::NumPad6, |
|
|
|
|
|
|
|
Key::NumPad7, |
|
|
|
|
|
|
|
Key::NumPad8, |
|
|
|
|
|
|
|
Key::NumPad9, |
|
|
|
|
|
|
|
Key::NumPadDot, |
|
|
|
|
|
|
|
Key::NumPadSlash, |
|
|
|
|
|
|
|
Key::NumPadAsterisk, |
|
|
|
|
|
|
|
Key::NumPadMinus, |
|
|
|
|
|
|
|
Key::NumPadPlus, |
|
|
|
|
|
|
|
Key::NumPadEnter, // 100
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Key::LeftAlt, |
|
|
|
|
|
|
|
Key::RightAlt, |
|
|
|
|
|
|
|
Key::LeftSuper, |
|
|
|
|
|
|
|
Key::RightSuper, |
|
|
|
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if num < remap.len() as u64 { |
|
|
|
|
|
|
|
Some(remap[num as usize]) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
None |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|