mindustry logic execution, map- and schematic- parsing and rendering
-rw-r--r--Cargo.toml2
-rw-r--r--src/block/distribution.rs14
-rw-r--r--src/block/drills.rs8
-rw-r--r--src/block/liquid.rs6
-rw-r--r--src/block/logic.rs4
-rw-r--r--src/block/power.rs2
-rw-r--r--src/block/turrets.rs2
-rw-r--r--src/block/units.rs28
-rw-r--r--src/data/map.rs7
-rw-r--r--src/data/renderer.rs26
-rw-r--r--src/utils/image.rs27
11 files changed, 70 insertions, 56 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 60e7a51..165bafb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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);