mindustry logic execution, map- and schematic- parsing and rendering
add `draw poly` and add stroke
| -rw-r--r-- | lemu/Cargo.toml | 4 | ||||
| -rw-r--r-- | lemu/src/executor/builder.rs | 1 | ||||
| -rw-r--r-- | lemu/src/executor/mod.rs | 4 | ||||
| -rw-r--r-- | lemu/src/instructions/draw.rs | 67 | ||||
| -rw-r--r-- | lemu/src/parser/mod.rs | 44 |
5 files changed, 93 insertions, 27 deletions
diff --git a/lemu/Cargo.toml b/lemu/Cargo.toml index cc69700..130e8cc 100644 --- a/lemu/Cargo.toml +++ b/lemu/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lemu" -version = "0.2.10" +version = "0.2.11" edition = "2021" description = "M-LOG runner" authors = ["bend-n <[email protected]>"] @@ -12,7 +12,7 @@ keywords = ["mindustry", "logic", "emulator", "executor"] [dependencies] thiserror = "1.0" enum_dispatch = "0.3" -fimg = { version = "0.4.3", default-features = false } +fimg = { version = "0.4.10", default-features = false } logos = "0.13.0" rust-fuzzy-search = { version = "0.1.1", optional = true } beef = "0.5" diff --git a/lemu/src/executor/builder.rs b/lemu/src/executor/builder.rs index 4d35a36..bd5b527 100644 --- a/lemu/src/executor/builder.rs +++ b/lemu/src/executor/builder.rs @@ -59,6 +59,7 @@ impl<'s, W: Wr> ExecutorBuilderInternal<'s, W> { assert!(n != 0); if n * BANK_SIZE > self.banks.len() { self.banks.resize(n * BANK_SIZE, 0.0); + println!("resized"); } Memory::Bank(((self.banks.len() - BANK_SIZE) / BANK_SIZE) as u8) } diff --git a/lemu/src/executor/mod.rs b/lemu/src/executor/mod.rs index db9b7f9..9c0553b 100644 --- a/lemu/src/executor/mod.rs +++ b/lemu/src/executor/mod.rs @@ -186,7 +186,7 @@ impl Default for DisplayState { fn default() -> Self { Self { color: Default::default(), - stroke: 1.0, + stroke: 5.0, } } } @@ -216,7 +216,7 @@ impl<'s, W: Write> ExecutorContext<'s, W> { pub fn mem(&mut self, m: Memory) -> &mut [f64] { match m { Memory::Bank(m) => &mut self.banks[m as usize], - Memory::Cell(m) => &mut self.banks[m as usize], + Memory::Cell(m) => &mut self.cells[m as usize], } } diff --git a/lemu/src/instructions/draw.rs b/lemu/src/instructions/draw.rs index 2dff764..8735260 100644 --- a/lemu/src/instructions/draw.rs +++ b/lemu/src/instructions/draw.rs @@ -8,7 +8,7 @@ use fimg::Image; use std::fmt::{self, Display as Disp, Formatter}; pub const INSTRS: &[&str] = &[ - "clear", "color", "col", "stroke", "line", "rect", "lineRect", "triangle", + "clear", "color", "col", "stroke", "line", "rect", "lineRect", "triangle", "poly", ]; #[enum_dispatch] @@ -24,24 +24,27 @@ pub trait DrawInstruction<'v>: Disp { #[derive(Debug)] #[enum_dispatch(DrawInstruction)] pub enum DrawInstr<'v> { - DrawLine(Line<'v>), - DrawRectBordered(RectBordered<'v>), - DrawRectFilled(RectFilled<'v>), - DrawTriangle(Triangle<'v>), + Line(Line<'v>), + RectBordered(RectBordered<'v>), + RectFilled(RectFilled<'v>), + Triangle(Triangle<'v>), Clear(Clear<'v>), SetColor(SetColor<'v>), SetStroke(SetStroke<'v>), + Poly(Poly<'v>), } + impl Disp for DrawInstr<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { - Self::DrawLine(i) => write!(f, "{i}"), - Self::DrawRectBordered(i) => write!(f, "{i}"), - Self::DrawRectFilled(i) => write!(f, "{i}"), - Self::DrawTriangle(i) => write!(f, "{i}"), + Self::Line(i) => write!(f, "{i}"), + Self::RectBordered(i) => write!(f, "{i}"), + Self::RectFilled(i) => write!(f, "{i}"), + Self::Triangle(i) => write!(f, "{i}"), Self::Clear(i) => write!(f, "{i}"), Self::SetColor(i) => write!(f, "{i}"), Self::SetStroke(i) => write!(f, "{i}"), + Self::Poly(i) => write!(f, "{i}"), } } } @@ -151,10 +154,9 @@ impl<'v> DrawInstruction<'v> for Line<'v> { image: &mut Image<&mut [u8], 4>, state: &mut DisplayState, ) { - // i will happily ignore that stroke specifys the stroke of lines - let a = map!(point!([email protected]_a), |n| n as i32); - let b = map!(point!([email protected]_b), |n| n as i32); - image.line(a, b, state.col()); + let a = map!(point!([email protected]_a), |n| n as f32); + let b = map!(point!([email protected]_b), |n| n as f32); + image.thick_line(a, b, state.stroke as f32, state.col()); } } @@ -223,11 +225,10 @@ impl<'v> DrawInstruction<'v> for RectBordered<'v> { image: &mut Image<&mut [u8], 4>, state: &mut DisplayState, ) { - // happily ignoring that state specifies box stroke width let pos = map!(point!([email protected]), |n| n as u32); let width = get_num!(mem.get(&self.width)) as u32; let height = get_num!(mem.get(&self.height)) as u32; - image.r#box(pos, width, height, state.col()); + image.stroked_box(pos, width, height, state.stroke.round() as u32, state.col()); } } @@ -261,6 +262,42 @@ impl Disp for Triangle<'_> { } } +#[derive(Debug)] +pub struct Poly<'v> { + pub(crate) pos: Point<'v>, + pub(crate) sides: LAddress<'v>, + pub(crate) radius: LAddress<'v>, + pub(crate) rot: LAddress<'v>, +} + +impl<'v> DrawInstruction<'v> for Poly<'v> { + fn draw( + &self, + mem: &mut LRegistry<'v>, + image: &mut Image<&mut [u8], 4>, + state: &mut DisplayState, + ) { + let pos = map!(point!([email protected]), |n| n as f32); + image.poly( + pos, + get_num!(mem.get(&self.sides)).round() as usize, + get_num!(mem.get(&self.radius)) as f32, + get_num!(mem.get(&self.rot)) as f32, + state.col(), + ); + } +} + +impl Disp for Poly<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!( + f, + "draw poly {} {} {} {} {}", + self.pos.0, self.pos.1, self.sides, self.radius, self.rot + ) + } +} + #[derive(Debug, Default)] pub struct Flush { pub(crate) display: Display, diff --git a/lemu/src/parser/mod.rs b/lemu/src/parser/mod.rs index 8d4e9ab..31faf7f 100644 --- a/lemu/src/parser/mod.rs +++ b/lemu/src/parser/mod.rs @@ -6,7 +6,7 @@ pub use error::Error; use super::{ executor::{ExecutorBuilderInternal, Instruction, UPInstr}, instructions::{ - draw::{Clear, Flush, Line, RectBordered, RectFilled, SetColor, SetStroke, Triangle}, + draw::{Clear, Flush, Line, Poly, RectBordered, RectFilled, SetColor, SetStroke, Triangle}, io::{Print, Read, Write}, AlwaysJump, ConditionOp, DynJump, End, Instr, Jump, MathOp1, MathOp2, Op1, Op2, Set, Stop, }, @@ -129,9 +129,13 @@ pub fn parse<'source, W: Wr>( let t = tok!()?; let container = take_ident!(t.clone())?; let mut out = String::new(); - for ch in container.bytes() { - if matches!(ch, b'0'..=b'9') { - out.push(ch as char); + for ch in container.chars() { + if matches!(ch, '0'..='9') { + out.push(ch); + continue; + } + if out.len() != 0 { + yeet!(InvalidMemoryType(container)); } } let container = &container[..container.len() - out.len()]; @@ -325,6 +329,8 @@ pub fn parse<'source, W: Wr>( #[rustfmt::skip] macro_rules! four { ($a:expr) => { ($a, $a, $a, $a) }; } #[rustfmt::skip] + macro_rules! five { ($a:expr) => { ($a, $a, $a, $a, $a) }; } + #[rustfmt::skip] macro_rules! six { ($a:expr) => { ($a, $a, $a, $a, $a, $a) }; } match instr { "clear" => { @@ -381,20 +387,42 @@ pub fn parse<'source, W: Wr>( points: ((x, y), (x2, y2), (x3, y3)), }); } - // poly is TODO, image is WONTFIX + "poly" => { + let (x, y, sides, radius, rot) = five! { take_numvar!(tok!()?)? }; + executor.draw(Poly { + pos: (x, y), + sides, + radius, + rot, + }) + } + // image is WONTFIX i => yeet!(UnsupportedImageOp(i)), } } Token::DrawFlush => { let t = tok!(); if let Ok(t) = t && t != Token::Newline { - let screen = take_ident!(t)?; + let screen = take_ident!(t.clone())?; + let mut out = String::new(); + for ch in screen.chars() { + if matches!(ch, '0'..='9') { + out.push(ch); + continue; + } + if out.len() != 0 { + yeet!(InvalidDisplayType(screen)); + } + } + let screen = &screen[..screen.len() - out.len()]; if screen != "display" { yeet!(InvalidDisplayType(screen)); } + let n_span = tokens.span().start + screen.len()..tokens.span().end; + let screen_n = out.parse::<usize>().map_err(|_| Error::ExpectedInt(t, n_span.clone()))?; let display = executor - .display(take_int!(tok!()?)?) - .map_err(|n| err!(NoDisplay(n)))?; + .display(screen_n) + .map_err(|n| Error::NoDisplay(n, n_span))?; executor.add(Flush { display }); } else { executor.add(Flush::default()) |