Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'src/data/renderer.rs')
| -rw-r--r-- | src/data/renderer.rs | 296 |
1 files changed, 0 insertions, 296 deletions
diff --git a/src/data/renderer.rs b/src/data/renderer.rs deleted file mode 100644 index 4bbcbe7..0000000 --- a/src/data/renderer.rs +++ /dev/null @@ -1,296 +0,0 @@ -//! schematic drawing -pub(crate) use super::autotile::*; -use super::schematic::Schematic; -use super::GridPos; -use crate::block::Rotation; -pub(crate) use crate::utils::{Image, ImageHolder, ImageUtils, Overlay, Repeat}; -use crate::Map; -include!(concat!(env!("OUT_DIR"), "/full.rs")); -include!(concat!(env!("OUT_DIR"), "/quar.rs")); -include!(concat!(env!("OUT_DIR"), "/eigh.rs")); - -#[derive(Debug, Copy, Clone)] -#[repr(u8)] -pub enum Scale { - Full, - // Half, - Quarter, - Eigth, -} - -impl Scale { - #[must_use] - pub const fn px(self) -> u8 { - match self { - Self::Full => 32, - Self::Quarter => 32 / 4, - Self::Eigth => 32 / 8, - } - } -} - -impl std::ops::Mul<u32> for Scale { - type Output = u32; - fn mul(self, rhs: u32) -> u32 { - self.px() as u32 * rhs - } -} - -#[macro_export] -macro_rules! load { - ("empty", $scale:expr) => { - ImageHolder::from(match $scale { - $crate::data::renderer::Scale::Quarter => &$crate::data::renderer::quar::EMPTY, - $crate::data::renderer::Scale::Eigth => &$crate::data::renderer::eigh::EMPTY, - $crate::data::renderer::Scale::Full => &$crate::data::renderer::full::EMPTY, - }.copy()) - }; - ($name:literal, $scale:expr) => { paste::paste! { - ImageHolder::from(match $scale { - $crate::data::renderer::Scale::Quarter => &$crate::data::renderer::quar::[<$name:snake:upper>], - $crate::data::renderer::Scale::Eigth => &$crate::data::renderer::eigh::[<$name:snake:upper>], - $crate::data::renderer::Scale::Full => &$crate::data::renderer::full::[<$name:snake:upper>], - }.copy()) - } }; - ($name: literal) => { paste::paste! { - [$crate::data::renderer::full::[<$name:snake:upper>].copy(), $crate::data::renderer::quar::[<$name:snake:upper>].copy(), $crate::data::renderer::eigh::[<$name:snake:upper>].copy()] - } }; - (from $v:ident which is [$($k:literal $(|)?)+], $scale: ident) => { - $crate::data::renderer::load!($scale -> match $v { - $($k => $k,)+ - }) - }; - // turn load!(s -> match x { "v" => "y" }) into match x { "v" => load!("y", s) } - ($scale:ident -> match $v:ident { $($k:pat => $nam:literal $(,)?)+ }) => { - match $v { - $($k => $crate::data::renderer::load!($nam, $scale),)+ - #[allow(unreachable_patterns)] - n => unreachable!("{n:?}"), - } - }; - (concat $x:literal => $v:ident which is [$($k:literal $(|)?)+], $scale: ident) => { paste::paste! { - match $v { - $($k => - ImageHolder::from(match $scale { - $crate::data::renderer::Scale::Quarter => &$crate::data::renderer::quar::[<$k:snake:upper _ $x:snake:upper>], - $crate::data::renderer::Scale::Eigth => &$crate::data::renderer::eigh::[<$k:snake:upper _ $x:snake:upper>], - $crate::data::renderer::Scale::Full => &$crate::data::renderer::full::[<$k:snake:upper _ $x:snake:upper>], - }.copy()), - )+ - #[allow(unreachable_patterns)] - n => unreachable!("{n:?}"), - } - } }; -} -pub(crate) use load; - -/// trait for renderable objects -pub trait Renderable { - /// create a picture - #[must_use = "i did so much work for you"] - fn render(&self) -> Image<Vec<u8>, 3>; -} - -impl Renderable for Schematic<'_> { - /// creates a picture of a schematic. Bridges and node connections are not drawn. - /// ``` - /// use mindus::*; - /// let mut s = Schematic::new(2, 3); - /// s.put(0, 0, &block::distribution::DISTRIBUTOR); - /// s.put(0, 2, &block::distribution::ROUTER); - /// s.put(1, 2, &block::walls::COPPER_WALL); - /// let output /*: Image */ = s.render(); - /// ``` - fn render(&self) -> Image<Vec<u8>, 3> { - // fill background - // SAFETY: metal-floor is 32x32, the output is a multiple of 32 - let mut bg = unsafe { - load!("metal-floor", Scale::Full).borrow().repeated( - ((self.width + 2) * 32) as u32, - ((self.height + 2) * 32) as u32, - ) - }; - let mut canvas = Image::alloc( - ((self.width + 2) * 32) as u32, - ((self.height + 2) * 32) as u32, - ); - for (GridPos(x, y), tile) in self.block_iter() { - let ctx = if tile.block.wants_context() { - let pctx = PositionContext { - position: GridPos(x, y), - width: self.width, - height: self.height, - }; - Some(RenderingContext { - cross: self.cross(&pctx), - position: pctx, - }) - } else { - None - }; - let x = x as u32 - ((tile.block.get_size() - 1) / 2) as u32; - let y = self.height as u32 - y as u32 - ((tile.block.get_size() / 2) + 1) as u32; - unsafe { - canvas.as_mut().overlay_at( - &tile - .image( - ctx.as_ref(), - tile.get_rotation().unwrap_or(Rotation::Up), - Scale::Full, - ) - .borrow(), - (x + 1) * 32, - (y + 1) * 32, - ) - }; - } - canvas.as_mut().shadow(); - for x in 0..canvas.width() { - for y in 0..canvas.height() { - // canvas has a shadow - let p2 = unsafe { canvas.pixel(x, y) }; - let p = unsafe { bg.pixel_mut(x, y) }; - crate::utils::image::blend(p.try_into().unwrap(), p2); - } - } - bg.remove_channel() - } -} - -impl Renderable for Map<'_> { - /// Draws a map - fn render(&self) -> Image<Vec<u8>, 3> { - let scale = if self.width + self.height < 2000 { - Scale::Quarter - } else { - Scale::Eigth - }; - // todo combine these (beware of floor drawing atop buildings) (planned solution:? ptr blocks) - let mut floor: Image<_, 3> = - Image::alloc(scale * self.width as u32, scale * self.height as u32); - let mut top: Image<_, 4> = - Image::alloc(scale * self.width as u32, scale * self.height as u32); - rayon::join( - || { - for y in 0..self.height { - for x in 0..self.width { - // Map::new() allocates w*h items - let j = x + self.width * y; - let tile = unsafe { self.tiles.get_unchecked(j) }; - let y = self.height - y - 1; - // draw the floor first. - // println!("draw {tile:?} ({x}, {y})"); - unsafe { - floor.as_mut().overlay_at( - &tile.floor(scale).borrow(), - scale * x as u32, - scale * y as u32, - ) - }; - if tile.has_ore() { - unsafe { - floor.as_mut().overlay_at( - &tile.ore(scale).borrow(), - scale * x as u32, - scale * y as u32, - ) - }; - } - } - } - }, - || { - for y in 0..self.height { - for x in 0..self.width { - // Map::new() allocates w*h items - let j = x + self.width * y; - let tile = unsafe { self.tiles.get_unchecked(j) }; - let y = self.height - y - 1; - // println!("draw {tile:?} ({x}, {y})"); - if let Some(build) = tile.build() { - let s = build.block.get_size(); - let x = x - - (match s { - 1 | 2 => 0, - 3 | 4 => 1, - 5 | 6 => 2, - 7 | 8 => 3, - 9 => 4, - // SAFETY: no block too big - _ => unsafe { std::hint::unreachable_unchecked() }, - }) as usize; - let y = y - - (match s { - 1 => 0, - 2 | 3 => 1, - 4 | 5 => 2, - 6 | 7 => 3, - 8 | 9 => 4, - // SAFETY: no block too big - _ => unsafe { std::hint::unreachable_unchecked() }, - }) as usize; - let ctx = if build.block.wants_context() { - let pctx = PositionContext { - position: GridPos(x, y), - width: self.width, - height: self.height, - }; - let rctx = RenderingContext { - cross: self.cross(j, &pctx), - position: pctx, - }; - Some(rctx) - } else { - None - }; - unsafe { - top.as_mut().overlay_at( - &tile.build_image(ctx.as_ref(), scale).borrow(), - scale * x as u32, - scale * y as u32, - ) - }; - } - } - } - }, - ); - unsafe { floor.as_mut().overlay_at(&top.as_ref(), 0, 0) }; - floor - } -} - -#[test] -fn all_blocks() { - use crate::block::content::Type; - use crate::content::Content; - let reg = crate::block::build_registry(); - for t in 19..Type::WorldMessage as u16 { - let t = Type::try_from(t).unwrap(); - if matches!(t, |Type::Empty| Type::SlagCentrifuge - | Type::HeatReactor - | Type::LegacyMechPad - | Type::LegacyUnitFactory - | Type::LegacyUnitFactoryAir - | Type::LegacyUnitFactoryGround - | Type::CommandCenter) - { - continue; - } - let name = dbg!(t.get_name()); - let t = reg.get(name).unwrap(); - let _ = t.image( - None, - Some(&RenderingContext { - cross: [None; 4], - position: PositionContext { - position: GridPos(0, 0), - width: 5, - height: 5, - }, - }), - Rotation::Up, - Scale::Quarter, - ); - } -} |