mindustry logic execution, map- and schematic- parsing and rendering
add `draw poly` and add stroke
bendn 2023-09-29
parent 6ce3a99 · commit b11ad85
-rw-r--r--lemu/Cargo.toml4
-rw-r--r--lemu/src/executor/builder.rs1
-rw-r--r--lemu/src/executor/mod.rs4
-rw-r--r--lemu/src/instructions/draw.rs67
-rw-r--r--lemu/src/parser/mod.rs44
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())