mindustry logic execution, map- and schematic- parsing and rendering
Diffstat (limited to 'src/data/renderer.rs')
| -rw-r--r-- | src/data/renderer.rs | 222 |
1 files changed, 16 insertions, 206 deletions
diff --git a/src/data/renderer.rs b/src/data/renderer.rs index cb6d88d..ecbbf85 100644 --- a/src/data/renderer.rs +++ b/src/data/renderer.rs @@ -4,12 +4,13 @@ use dashmap::DashMap; use image::codecs::png::PngDecoder; pub(crate) use image::{DynamicImage, RgbaImage}; use std::io::{BufReader, Cursor}; +use std::ops::{Deref, DerefMut}; use std::path::{Path, PathBuf}; use std::sync::OnceLock; use zip::ZipArchive; +pub(crate) use super::autotile::*; use crate::block::environment::METAL_FLOOR; -use crate::block::{Block, Rotation}; use crate::team::SHARDED; pub(crate) use crate::utils::ImageUtils; use crate::Map; @@ -58,6 +59,19 @@ impl BorrowMut<RgbaImage> for ImageHolder { } } +impl Deref for ImageHolder { + type Target = RgbaImage; + fn deref(&self) -> &Self::Target { + self.borrow() + } +} + +impl DerefMut for ImageHolder { + fn deref_mut(&mut self) -> &mut Self::Target { + self.borrow_mut() + } +} + impl From<Option<Ref<'static, PathBuf, RgbaImage>>> for ImageHolder { fn from(value: Option<Ref<'static, PathBuf, RgbaImage>>) -> Self { Self::Borrow(value.unwrap()) @@ -76,61 +90,6 @@ impl From<RgbaImage> for ImageHolder { } } -pub type Cross<'l> = [Option<(&'l Block, Rotation)>; 4]; -/// holds the 4 bordering blocks -#[derive(Copy, Clone)] -pub struct RenderingContext<'l> { - pub cross: Cross<'l>, - pub rotation: Rotation, - pub position: PositionContext, -} - -/// holds positions -#[derive(Copy, Clone, Eq, PartialEq)] -pub struct PositionContext { - pub position: GridPos, - pub width: usize, - pub height: usize, -} - -impl std::fmt::Debug for PositionContext { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "PC<{:?} ({}/{})>", - self.position, self.width, self.height - ) - } -} - -impl std::fmt::Debug for RenderingContext<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Display::fmt(self, f) - } -} - -impl std::fmt::Display for RenderingContext<'_> { - /// this display impl shows RC<$directions=+own rotation> - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "RC<")?; - macro_rules! f { - ($f:expr, $z:expr, $x:literal, $at: expr, $srot: expr) => { - if let Some((_, rot)) = $z { - if (rot == $at && rot.mirrored(true, true) != $srot) { - $f.write_str($x)?; - } - } - }; - } - f!(f, self.cross[0], "N = ", Rotation::Down, self.rotation); - f!(f, self.cross[1], "E = ", Rotation::Left, self.rotation); - f!(f, self.cross[2], "S = ", Rotation::Up, self.rotation); - f!(f, self.cross[3], "W = ", Rotation::Right, self.rotation); - - write!(f, "{:?}>", self.rotation) - } -} - static CACHE: OnceLock<Cache> = OnceLock::new(); pub(crate) fn load(category: &str, name: &str) -> Option<Ref<'static, PathBuf, RgbaImage>> { let key = Path::new("blocks").join(category).join(name); @@ -199,155 +158,6 @@ where c } -pub trait RotationState { - fn get_rotation(&self) -> Option<Rotation>; -} -pub trait BlockState<'l> { - fn get_block(&'l self) -> Option<&'l Block>; -} -pub(crate) trait Crossable { - fn cross(&self, j: usize, c: &PositionContext) -> Cross; -} - -// pub(crate) trait Darray { -// type Output; -// fn n(&self, j: usize, c: &PositionContext) -> Option<&Self::Output>; -// fn e(&self, j: usize, c: &PositionContext) -> Option<&Self::Output>; -// fn s(&self, j: usize, c: &PositionContext) -> Option<&Self::Output>; -// fn w(&self, j: usize, c: &PositionContext) -> Option<&Self::Output>; -// } - -#[cfg(test)] -fn print_crosses(v: Vec<Cross<'_>>, height: usize) -> String { - let mut s = String::new(); - for c in v.chunks(height) { - for c in c { - s.push(c[0].map_or('_', |(_, r)| r.ch())); - for c in c[1..].iter() { - s.push(','); - s.push(c.map_or('_', |(_, r)| r.ch())); - } - s.push(' '); - } - s.push('\n'); - } - s -} - -#[test] -fn test_cross() { - use crate::block::distribution::define; - let mut reg = crate::block::BlockRegistry::default(); - crate::block::distribution::register(&mut reg); - let mut ss = super::schematic::SchematicSerializer(®); - macro_rules! test { - ($schem: literal => $($a:tt,$b:tt,$c:tt,$d:tt)*) => { - let s = ss.deserialize_base64($schem).unwrap(); - let mut c = vec![]; - println!("{:#?}", s.blocks); - - for (position, _) in s.block_iter() { - let pctx = PositionContext { - position, - width: s.width, - height: s.height, - }; - c.push(s.cross(&pctx)); - } - let n = s.tags.get("name").map_or("<unknown>", |x| &x); - let cc: Vec<Cross> = vec![ - $(define!($a,$b,$c,$d),)* - ]; - if cc != c { - let a = print_crosses(cc, s.height as usize); - let b = print_crosses(c, s.height as usize); - for diff in diff::lines(&a, &b) { - match diff { - diff::Result::Left(l) => println!("\x1b[38;5;1m{}", l), - diff::Result::Right(r) => println!("\x1b[38;5;2m{}", r), - diff::Result::Both(l, _) => println!("\x1b[0m{}", l), - } - } - print!("\x1b[0m"); - /* - for diff in diff::slice(&c.into_iter().enumerate().collect::<Vec<_>>(), &cc.into_iter().enumerate().collect::<Vec<_>>()) { - match diff { - diff::Result::Left((i, l)) => println!("\x1b[38;5;1m- {l:?} at {i}"), - diff::Result::Right((i, r)) => println!("\x1b[38;5;2m+ {r:?} at {i}"), - diff::Result::Both((i, l), _) => println!("\x1b[0m {l:?} at {i}"), - } - } - */ - panic!("test {n} \x1b[38;5;1mfailed\x1b[0m") - } - println!("test {n} \x1b[38;5;2mpassed\x1b[0m"); - }; - } - // crosses go from bottom left -> top left -> bottom left + 1 -> top left + 1... - // the symbols are directions (> => Right...), which mean the neighbors pointing direction - // _ = no block - - // the basic test - // ─┐ - // ─┤ - test!("bXNjaAF4nGNgYmBiZmDJS8xNZWBNSizOTGbgTkktTi7KLCjJzM9jYGBgy0lMSs0pZmCNfr9gTSwjA0dyfl5ZamV+EVCOhQEBGGEEM4hiZGAGAOb+EWA=" => - // (0, 0) (0, 1) - // n e s w borders (west void for first row) - >,v,_,_ _,v,>,_ - // (1, 0) (1, 1) - v,_,_,> _,_,v,> - ); - // the loop test - // ─│─ - // ─┼┐ - // ─└┘ - test!("bXNjaAF4nDWK4QqAIBCDd6dE0SNGP8zuh2CeaAS9fZk0xvjGBgNjYJM7BDaqy5h3qb6EfAZNAIboNokVvKyE0Wu65NbyDhM+cQv6mTtTM/WFYfqLm6m3lx9MAg7n" => - >,^,_,_ <,>,<,_ _,v,>,_ - >,<,_,< v,v,^,> _,>,>,< - v,_,_,^ >,_,<,> _,_,v,v - ); - // the snek test - // └┐ - // ─┘ - test!("bXNjaAF4nGNgYmBiZmDJS8xNZWApzkvNZuBOSS1OLsosKMnMz2NgYGDLSUxKzSlmYIqOZWTgSM7PK0utzC8CSrAwIAAjEIIQhGJkYAIARA0Ozg==" => - ^,^,_,_ _,<,>,_ - <,_,_,> _,_,^,^ - ); - - // the notile test - test!("bXNjaAF4nCWJQQqAIBREx69E0Lq994oWph8STEMj6fZpzcDjDQMCSahoDsZsdN1TYB25aucz28uniMlxsdmf3wCGYDYOBbSsAqNN8eYn5XYofJEdAtSB31tfaoIVGw==" => - <,>,_,_ _,^,v,_ - ^,_,_,v _,_,>,< - ); - // the asymmetrical test - // <─── - // ───> - test!("bXNjaAF4nEXJwQqAIBAE0HGVCPrE6GC2B0HdcCPw78MKnMMwj4EFWbjiM8N5bRnLwRpqPK8oBcCU/M5JQetmMAcpNzep/cCIAfX69yv6RF0PFy0O4Q==" => - <,>,_,_ _,<,>,_ - <,>,_,> _,<,>,< - // <,_,_,> _,_,>,< - <,_,_,> _,_,>,< - ); - - // the complex test - // ─┬─│││─ - // ─┤─┘─┘─ - // ─┤┌─│─┐ - // ─┼┘─┴─│ - test!("bXNjaAF4nEWOUQ7CIBBEh2VZTbyCx/A2xg9a+WiC0LTGxNvb7Wjk5wEzb7M4QCO05UdBqj3PF5zuZR2XaX5OvQGwmodSV8j1FnAce3uVd1+24Iz/CYQQ8fcVHYEQIjqEXWEm9LwgX9kR+PLSbm2BMlN6Sk/3LhJnJu6S6CVmxl2MntEzv38AchUPug==" => - >,v,_,_ >,v,>,_ >,v,>,_ _,v,>,_ - v,<,_,> v,v,v,> v,>,v,> _,<,v,> - v,>,_,v >,<,<,v <,^,v,v _,v,>,v - <,>,_,< ^,v,>,v v,>,<,> _,^,^,< - v,<,_,> >,>,>,< ^,^,v,^ _,^,>,v - >,v,_,> ^,v,<,v ^,>,>,> _,>,^,^ - // <,_,_,< ^,_,>,v v,_,<,> _,_,^,< - // v,_,_,> >,_,>,< ^,_,v,^ _,_,>,v - // >,_,_,> ^,_,<,v ^,_,>,> _,_,^,^ - v,_,_,< >,_,v,> >,_,v,^ _,_,>,^ - ); -} - /// trait for renderable objects pub trait Renderable { /// creates a picture of a schematic. Bridges and node connections are not drawn. @@ -501,7 +311,7 @@ fn all_blocks() { None, Some(&RenderingContext { cross: [None; 4], - rotation: Rotation::Up, + rotation: crate::block::Rotation::Up, position: PositionContext { position: GridPos(0, 0), width: 5, |