diff --git a/crsn/src/asm/instr/flatten.rs b/crsn/src/asm/instr/flatten.rs index aae5f2b..e2c8312 100644 --- a/crsn/src/asm/instr/flatten.rs +++ b/crsn/src/asm/instr/flatten.rs @@ -73,7 +73,7 @@ impl Flatten for Vec> { for item in self.into_iter() { ops.extend(item.flatten(label_num)?); } - labels_to_skips(ops) + Ok(ops) } } diff --git a/crsn/src/asm/instr/mod.rs b/crsn/src/asm/instr/mod.rs index de5a2de..6cf8a29 100644 --- a/crsn/src/asm/instr/mod.rs +++ b/crsn/src/asm/instr/mod.rs @@ -6,7 +6,7 @@ use crate::asm::data::literal::RoutineName; pub mod op; pub mod cond; -mod flatten; +pub mod flatten; /// A higher-level instruction #[derive(Debug)] diff --git a/crsn/src/asm/mod.rs b/crsn/src/asm/mod.rs index f4eb875..9c420c8 100644 --- a/crsn/src/asm/mod.rs +++ b/crsn/src/asm/mod.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use crate::asm::parse::{ParserContext, ParserState}; use crate::module::CrsnExtension; use crate::runtime::program::Program; +use crate::asm::instr::flatten::labels_to_skips; pub mod data; pub mod error; @@ -23,6 +24,7 @@ pub fn assemble(source: &str, parsers: Arc>>) -> Resu }; let ops = parse::parse(source, &pcx)?; + let ops = labels_to_skips(ops)?; Ok(Program::new(ops, parsers)?) } diff --git a/crsn_screen/src/defs.rs b/crsn_screen/src/defs.rs index cb61d58..d309804 100644 --- a/crsn_screen/src/defs.rs +++ b/crsn_screen/src/defs.rs @@ -1,4 +1,4 @@ -use crsn::asm::data::Rd; +use crsn::asm::data::{Rd, Wr}; #[derive(Clone, Debug, Eq, PartialEq)] pub enum ScreenOp { @@ -11,6 +11,22 @@ pub enum ScreenOp { y: Rd, color: Rd, }, + GetMouse { + x: Wr, + y: Wr, + }, + TestKey { + pressed: Wr, + code: Rd, + }, + TestMouse { + pressed: Wr, + button: Rd, + }, + Update, + Erase { + color: Rd, + }, Blit { force: Rd, }, diff --git a/crsn_screen/src/exec.rs b/crsn_screen/src/exec.rs index b567540..e8ae861 100644 --- a/crsn_screen/src/exec.rs +++ b/crsn_screen/src/exec.rs @@ -1,7 +1,7 @@ use std::ops::Sub; 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::instr::Cond; @@ -61,7 +61,17 @@ impl OpTrait for ScreenOp { let h = state.read(*height)?; 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 } => { + state.clear_status(); let opt = state.read(*opt)?; let val = state.read(*val)?; let backend: &mut Backend = state.ext_mut(); @@ -81,6 +91,7 @@ impl OpTrait for ScreenOp { } } } + ScreenOp::Blit { force } => { let force = state.read(*force)?; let backend: &mut Backend = state.ext_mut(); @@ -91,7 +102,21 @@ impl OpTrait for ScreenOp { 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 } => { + state.clear_status(); let x = state.read(*x)?; let y = state.read(*y)?; 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) @@ -132,7 +234,12 @@ impl OpTrait for ScreenOp { 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::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.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); blit_maybe(backend); @@ -177,9 +281,142 @@ fn blit_maybe(backend: &mut Backend) { } fn blit(backend: &mut Backend) { - backend.window.as_mut().unwrap() - .update_with_buffer(&backend.buffer, backend.width, backend.height) + let w = backend.window.as_mut().unwrap(); + + if !w.is_open() { + // TODO... + std::process::exit(0); + } + + w.update_with_buffer(&backend.buffer, backend.width, backend.height) .expect("Update screen"); // TODO fault backend.last_render = Instant::now(); } + +fn num2key(num : Value) -> Option { + 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 + } +} + diff --git a/crsn_screen/src/parse.rs b/crsn_screen/src/parse.rs index 9eb8700..1d10887 100644 --- a/crsn_screen/src/parse.rs +++ b/crsn_screen/src/parse.rs @@ -1,4 +1,4 @@ -use crsn::asm::data::Rd; +use crsn::asm::data::{Rd, RdData}; use crsn::asm::error::CrsnError; use crsn::asm::instr::op::OpKind; use crsn::asm::parse::arg_parser::TokenParser; @@ -15,6 +15,16 @@ pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result { + ScreenOp::Erase { + color: if args.len() > 0 { + args.next_rd()? + } else { + Rd::immediate(0) // black + }, + } + } + "sc-px" => { ScreenOp::SetPixel { x: args.next_rd()?, @@ -40,6 +50,31 @@ pub(crate) fn parse<'a>(keyword: &str, mut args: TokenParser<'a>) -> Result { + ScreenOp::Update + } + + "sc-mouse" => { + ScreenOp::GetMouse { + x: args.next_wr()?, + y: args.next_wr()?, + } + } + + "sc-key" => { + ScreenOp::TestKey { + pressed: args.next_wr()?, + code: args.next_rd()? + } + } + + "sc-mbtn" => { + ScreenOp::TestMouse { + pressed: args.next_wr()?, + button: args.next_rd()? + } + } + _other => { return Ok(ParseRes::Unknown(args)); } diff --git a/examples/mouse.csn b/examples/mouse.csn new file mode 100644 index 0000000..355b9a4 --- /dev/null +++ b/examples/mouse.csn @@ -0,0 +1,40 @@ +( + (sc-init 640 480) + + (sym x r6) + (sym y r7) + + (def BOXSIZE 10) + + (:loop) + (sc-poll) + (sc-mouse x y + (ov? (j :next))) + + (sc-mbtn r0 0 (z? (j :next))) + + (sym vx r0) + (sym vy r1) + (sym endx r2) + (sym endy r3) + + (add endx x BOXSIZE) + (add endy y BOXSIZE) + + (sub vy y BOXSIZE) + + (:nextline) + (cmp vy endy (eq? (j :endbox))) + (sub vx x BOXSIZE) + (:nextpx) + (sc-px vx vy 0xffffff) + (inc vx) + (cmp vx endx + (eq? (inc vy)(j :nextline))) + (j :nextpx) + (:endbox) + + (:next) + (sleep 20000) + (j :loop) +)