mindustry logic execution, map- and schematic- parsing and rendering
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | src/block/distribution.rs | 14 | ||||
| -rw-r--r-- | src/block/drills.rs | 8 | ||||
| -rw-r--r-- | src/block/liquid.rs | 6 | ||||
| -rw-r--r-- | src/block/logic.rs | 4 | ||||
| -rw-r--r-- | src/block/power.rs | 2 | ||||
| -rw-r--r-- | src/block/turrets.rs | 2 | ||||
| -rw-r--r-- | src/block/units.rs | 28 | ||||
| -rw-r--r-- | src/data/map.rs | 7 | ||||
| -rw-r--r-- | src/data/renderer.rs | 26 | ||||
| -rw-r--r-- | src/utils/image.rs | 27 |
11 files changed, 70 insertions, 56 deletions
@@ -1,6 +1,6 @@ [package] name = "mindus" -version = "1.4.2" +version = "1.4.3" edition = "2021" description = "A library for working with mindustry data formats (eg schematics and maps) (fork of plandustry)" authors = [ diff --git a/src/block/distribution.rs b/src/block/distribution.rs index fc4ae41..baa6ee6 100644 --- a/src/block/distribution.rs +++ b/src/block/distribution.rs @@ -54,7 +54,7 @@ make_simple!(SimpleDuctBlock, |_, _, name, _, _, rot: Rotation| { let mut base = load("distribution/ducts", "duct-base").unwrap().clone(); let mut top = load("distribution/ducts", name).unwrap().clone(); top.rotate(rot.rotated(false).count()); - base.overlay(&top, 0, 0); + base.overlay(&top); Some(ImageHolder::from(base)) }); @@ -79,7 +79,7 @@ fn draw_stack( } let mut edge = edge.clone(); edge.rotate(i); - to.overlay(&edge, 0, 0); + to.overlay(&edge); } }; let gimme = |n: u8| { @@ -115,7 +115,7 @@ fn draw_stack( if (mask.into_u8() & i) == 0 && (going != r || empty) { let mut edge = edge.clone(); edge.rotate(r); - base.overlay(&edge, 0, 0); + base.overlay(&edge); } } base @@ -261,7 +261,7 @@ impl BlockLogic for ItemBlock { ) .unwrap() .clone(); - p.overlay(top.tint(s.color()), 0, 0); + p.overlay(top.tint(s.color())); return Some(ImageHolder::from(p)); } } @@ -277,13 +277,13 @@ impl BlockLogic for ItemBlock { .to_owned(); // this rotate call could be omitted if rotation == Right to save a clone top.rotate(rot.rotated(false).count()); - null.overlay(&top, 0, 0); + null.overlay(&top); } - p.overlay(&null, 0, 0); + p.overlay(&null); Some(ImageHolder::from(p)) } else { let mut null = load("distribution", "cross-full").unwrap().clone(); - null.overlay(&p, 0, 0); + null.overlay(&p); Some(ImageHolder::from(null)) } } diff --git a/src/block/drills.rs b/src/block/drills.rs index 98b49fd..5d8ac30 100644 --- a/src/block/drills.rs +++ b/src/block/drills.rs @@ -10,11 +10,11 @@ make_simple!( let mut base = load("drills", name).unwrap().clone(); let top = load("drills", &format!("{name}-top")).unwrap(); if rot == Rotation::Right { - base.overlay(&top, 0, 0); + base.overlay(&top); } else { let mut top = top.clone(); top.rotate(rot.rotated(false).count()); - base.overlay(&top, 0, 0); + base.overlay(&top); } return Some(ImageHolder::from(base)); } @@ -27,11 +27,11 @@ make_simple!(WallCrafter, |_, _, _, _, _, rot: Rotation| { let mut base = load("drills", "cliff-crusher").unwrap().clone(); let top = load("drills", "cliff-crusher-top").unwrap(); if rot == Rotation::Right { - base.overlay(&top, 0, 0); + base.overlay(&top); } else { let mut top = top.clone(); top.rotate(rot.rotated(false).count()); - base.overlay(&top, 0, 0); + base.overlay(&top); } Some(ImageHolder::from(base)) }); diff --git a/src/block/liquid.rs b/src/block/liquid.rs index 22961ed..0a8a566 100644 --- a/src/block/liquid.rs +++ b/src/block/liquid.rs @@ -28,7 +28,7 @@ make_simple!( .to_owned(); flrot(flip, rot, &mut bottom); bottom.tint(image::Rgb([74, 75, 83])); - bottom.overlay(tile.borrow(), 0, 0); + bottom.overlay(tile.borrow()); // TODO caps. stopped trying bcz too complex Some(ImageHolder::from(bottom)) }, @@ -132,12 +132,12 @@ impl BlockLogic for FluidBlock { if let Some(state) = state { if let Some(s) = Self::get_state(state) { let mut top = load("distribution", "center").unwrap().clone(); - p.overlay(top.tint(s.color()), 0, 0); + p.overlay(top.tint(s.color())); return Some(ImageHolder::Own(p)); } } let mut null = load("distribution", "cross-full").unwrap().clone(); - null.overlay(&p, 0, 0); + null.overlay(&p); Some(ImageHolder::Own(null)) } diff --git a/src/block/logic.rs b/src/block/logic.rs index ee9445e..ce202bc 100644 --- a/src/block/logic.rs +++ b/src/block/logic.rs @@ -170,7 +170,7 @@ impl BlockLogic for CanvasBlock { .scale((self.size as u32 * 32) - 14) }; let mut borders = load(c, n).unwrap().to_owned(); - borders.overlay(&p, 7, 7); + borders.overlay_at(&p, 7, 7); return Some(ImageHolder::from(borders)); } @@ -333,7 +333,7 @@ impl BlockLogic for SwitchLogic { if *Self::get_state(state) { let mut base = base.clone(); let on = load("logic", "switch-on").unwrap(); - base.overlay(&on, 0, 0); + base.overlay(&on); return Some(ImageHolder::from(base)); } } diff --git a/src/block/power.rs b/src/block/power.rs index 1f67a6f..566a710 100644 --- a/src/block/power.rs +++ b/src/block/power.rs @@ -18,7 +18,7 @@ make_simple!(DiodeBlock, |_, _, _, _, _, rot: Rotation| { let mut base = base.clone(); let mut top = load("power", "diode-arrow").unwrap().clone(); top.rotate(rot.rotated(false).count()); - base.overlay(&top, 0, 0); + base.overlay(&top); Some(ImageHolder::from(base)) }); diff --git a/src/block/turrets.rs b/src/block/turrets.rs index fda1225..061074c 100644 --- a/src/block/turrets.rs +++ b/src/block/turrets.rs @@ -51,7 +51,7 @@ fn draw_turret( _ => format!("bases/block-{}", me.get_size()), }; let mut base = load("turrets", &path).unwrap().value().clone(); - base.overlay(load("turrets", name).unwrap().value(), 0, 0); + base.overlay(load("turrets", name).unwrap().value()); Some(ImageHolder::from(base)) } diff --git a/src/block/units.rs b/src/block/units.rs index 162744f..5bcda05 100644 --- a/src/block/units.rs +++ b/src/block/units.rs @@ -53,9 +53,9 @@ make_simple!( if times != 0 { let mut out = out.clone(); out.rotate(times); - base.overlay(&out, 0, 0); + base.overlay(&out); } else { - base.overlay(&out, 0, 0); + base.overlay(&out); } } { @@ -73,9 +73,9 @@ make_simple!( if times != 0 { let mut input = input.clone(); input.rotate(times); - base.overlay(&input, 0, 0); + base.overlay(&input); } else { - base.overlay(&input, 0, 0); + base.overlay(&input); } } // TODO: the context cross is too small @@ -93,21 +93,21 @@ make_simple!( // .rotated(false); // let mut input = input.clone(); // input.rotate(r.count()); - // base.overlay(&input, 0, 0); + // base.overlay(&input); // } // } // } - { - base.overlay(&load("units", &format!("{name}-top")).unwrap(), 0, 0); - } + + base.overlay(&load("units", &format!("{name}-top")).unwrap()); + if matches!(name, "mech-assembler" | "tank-assembler" | "ship-assembler") { let side = load("units", &format!("{name}-side")).unwrap(); if times != 0 { let mut side = side.clone(); side.rotate(times); - base.overlay(&side, 0, 0); + base.overlay(&side); } else { - base.overlay(&side, 0, 0); + base.overlay(&side); } } Some(ImageHolder::from(base)) @@ -250,9 +250,9 @@ impl BlockLogic for AssemblerBlock { if times != 0 { let mut out = out.clone(); out.rotate(times); - base.overlay(&out, 0, 0); + base.overlay(&out); } else { - base.overlay(&out, 0, 0); + base.overlay(&out); } base.overlay( &load( @@ -267,9 +267,7 @@ impl BlockLogic for AssemblerBlock { _ => format!("{name}-top"), }, ) - .unwrap(), - 0, - 0, + .unwrap() ); Some(ImageHolder::from(base)) } diff --git a/src/data/map.rs b/src/data/map.rs index 20b5a23..f32b039 100644 --- a/src/data/map.rs +++ b/src/data/map.rs @@ -145,7 +145,7 @@ impl<'l> Tile<'l> { pub fn floor_image(&self, context: Option<&RenderingContext>) -> ImageHolder { let mut i = self.floor.image(None, context, Rotation::Up).own(); if let Some(ore) = self.ore { - i.overlay(ore.image(None, context, Rotation::Up).borrow(), 0, 0); + i.overlay(ore.image(None, context, Rotation::Up).borrow()); } ImageHolder::from(i) } @@ -580,10 +580,7 @@ impl<'l> Serializer<Map<'l>> for MapSerializer<'l> { output.copy_from_slice(&buff.data[..2]); let _ = buff.read_chunk(false, |buff| { #[cfg(debug_assertions)] - println!( - "reading {:?}", - map[i].build.as_ref().unwrap() - ); + println!("reading {:?}", map[i].build.as_ref().unwrap()); let _ = buff.read_i8()?; map[i] diff --git a/src/data/renderer.rs b/src/data/renderer.rs index f020e5f..e20b75a 100644 --- a/src/data/renderer.rs +++ b/src/data/renderer.rs @@ -155,10 +155,10 @@ where for suffix in suffixes { if let Some(p) = load(category, &format!("{name}{suffix}")) { if suffix == &"-team" { - c.overlay(p.clone().tint(SHARDED.color()), 0, 0); + c.overlay(p.clone().tint(SHARDED.color())); continue; } - c.overlay(&p, 0, 0); + c.overlay(&p); } } c @@ -205,23 +205,20 @@ impl Renderable for Schematic<'_> { } else { None }; - #[cfg(debug_assertions)] - println!("rendering {tile:?} ({x}, {y}) [+{}]", tile.block.get_size()); 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; - canvas.overlay( + canvas.overlay_at( tile.image(ctx.as_ref(), tile.get_rotation().unwrap_or(Rotation::Up)) .borrow(), (x + 1) * 32, (y + 1) * 32, ); - // canvas.save("tmp.png").unwrap(); } - #[cfg(debug_assertions)] - println!("finishing up"); + #[cfg(feature = "schem_shadow")] - canvas.shadow(); - image::imageops::overlay(&mut bg, &canvas, 0, 0); + image::imageops::overlay(&mut bg, canvas.shadow(), 0, 0); + #[cfg(not(feature = "schem_shadow"))] + bg.overlay(&canvas); bg } } @@ -246,7 +243,7 @@ impl Renderable for Map<'_> { ) }) { // draw the floor first. - floor.overlay( + floor.overlay_at( // SAFETY: [`load_raw`] forces nonzero image size unsafe { &tile.floor_image(None).own().scale(scale) }, x as u32 * scale, @@ -271,7 +268,7 @@ impl Renderable for Map<'_> { }; Some(rctx) })(); - top.overlay( + top.overlay_at( // SAFETY: tile.size can never be 0, and [`load_raw`] forces nonzero. unsafe { &tile @@ -285,8 +282,9 @@ impl Renderable for Map<'_> { } } #[cfg(feature = "map_shadow")] - top.shadow(); - image::imageops::overlay(&mut floor, &top, 0, 0); + image::imageops::overlay(&mut floor, top.shadow(), 0, 0); + #[cfg(not(feature = "map_shadow"))] + floor.overlay(&top); floor } } diff --git a/src/utils/image.rs b/src/utils/image.rs index 85a8266..1b54d61 100644 --- a/src/utils/image.rs +++ b/src/utils/image.rs @@ -8,7 +8,9 @@ pub trait ImageUtils { /// Repeat with over self fn repeat(&mut self, with: &Self) -> &mut Self; /// Overlay with onto self (does not blend) - fn overlay(&mut self, with: &Self, x: u32, y: u32) -> &mut Self; + fn overlay(&mut self, with: &Self) -> &mut Self; + /// Overlay with onto self at coordinates x, y, without blending + fn overlay_at(&mut self, with: &Self, x: u32, y: u32) -> &mut Self; /// rotate fn rotate(&mut self, times: u8) -> &mut Self; /// shadow @@ -52,13 +54,13 @@ impl ImageUtils for RgbaImage { fn repeat(&mut self, with: &RgbaImage) -> &mut Self { for x in 0..(self.width() / with.width()) { for y in 0..(self.height() / with.height()) { - self.overlay(with, x * with.width(), y * with.height()); + self.overlay_at(with, x * with.width(), y * with.height()); } } self } - fn overlay(&mut self, with: &RgbaImage, x: u32, y: u32) -> &mut Self { + fn overlay_at(&mut self, with: &RgbaImage, x: u32, y: u32) -> &mut Self { for j in 0..with.height() { for i in 0..with.width() { let get = with.get_pixel(i, j); @@ -70,6 +72,25 @@ impl ImageUtils for RgbaImage { self } + fn overlay(&mut self, with: &RgbaImage) -> &mut Self { + let w = self.width(); + let h = self.height(); + let local = std::mem::take(self); + let mut own = local.into_raw(); + let other = with.as_raw(); + if own.len() % 4 != 0 || other.len() % 4 != 0 { + unsafe { std::hint::unreachable_unchecked(); } + } + for (i, other_pixels) in other.chunks_exact(4).enumerate() { + if other_pixels[3] > 128 { + let own_pixels = &mut own[i * 4..i * 4 + 4]; + own_pixels.copy_from_slice(other_pixels); + } + } + *self = image::RgbaImage::from_raw(w, h, own).unwrap(); + self + } + unsafe fn scale(self, to: u32) -> Self { debug_assert_ne!(to, 0); debug_assert_ne!(self.width(), 0); |