Add separate Iron Coast mission, weapon and enemy mods with SD HD artwork and audio
This commit is contained in:
1 parent
dbb1d4596b
commit
967ba69ee8
573 files changed
+6515
No files matched your search
@@ -0,0 +1,90 @@
|
||||
//! Build game-ready logical and HD PNG canvases from the inspected generated sources.
|
||||
//! Compile with the project's image dependency, then pass equipment source, shot source.
|
||||
use image::{Rgba, RgbaImage, imageops};
|
||||
use std::{env, fs, path::Path};
|
||||
const PACKAGE: &str = "ion_lance";
|
||||
const SHOT: (u32, u32) = (4, 32);
|
||||
fn canvas(source: &RgbaImage, width: u32, height: u32, hd: bool) -> RgbaImage {
|
||||
// Only the solid silhouette defines its fitting box; faint outer glows stay bounded.
|
||||
let mut bounds = (source.width(), source.height(), 0, 0);
|
||||
for (x, y, p) in source.enumerate_pixels() {
|
||||
if p[3] >= 128 {
|
||||
bounds.0 = bounds.0.min(x);
|
||||
bounds.1 = bounds.1.min(y);
|
||||
bounds.2 = bounds.2.max(x + 1);
|
||||
bounds.3 = bounds.3.max(y + 1);
|
||||
}
|
||||
}
|
||||
assert!(
|
||||
bounds.2 > bounds.0 && bounds.3 > bounds.1,
|
||||
"source has no opaque silhouette"
|
||||
);
|
||||
let cropped = imageops::crop_imm(
|
||||
source,
|
||||
bounds.0,
|
||||
bounds.1,
|
||||
bounds.2 - bounds.0,
|
||||
bounds.3 - bounds.1,
|
||||
)
|
||||
.to_image();
|
||||
let margin = if hd { 4 } else { 1 };
|
||||
let available = (
|
||||
width.saturating_sub(margin * 2).max(1),
|
||||
height.saturating_sub(margin * 2).max(1),
|
||||
);
|
||||
let factor = (available.0 as f64 / cropped.width() as f64)
|
||||
.min(available.1 as f64 / cropped.height() as f64);
|
||||
let size = (
|
||||
(cropped.width() as f64 * factor).round().max(1.) as u32,
|
||||
(cropped.height() as f64 * factor).round().max(1.) as u32,
|
||||
);
|
||||
let filter = if hd {
|
||||
imageops::FilterType::Lanczos3
|
||||
} else {
|
||||
imageops::FilterType::Nearest
|
||||
};
|
||||
let mut scaled = imageops::resize(&cropped, size.0, size.1, filter);
|
||||
for p in scaled.pixels_mut() {
|
||||
if p[3] < (if hd { 64 } else { 128 }) {
|
||||
*p = Rgba([0, 0, 0, 0]);
|
||||
} else {
|
||||
p[3] = 255;
|
||||
}
|
||||
}
|
||||
let mut out = RgbaImage::new(width, height);
|
||||
imageops::overlay(
|
||||
&mut out,
|
||||
&scaled,
|
||||
((width - size.0) / 2) as i64,
|
||||
((height - size.1) / 2) as i64,
|
||||
);
|
||||
out
|
||||
}
|
||||
fn main() {
|
||||
let args: Vec<_> = env::args_os().collect();
|
||||
assert_eq!(
|
||||
args.len(),
|
||||
4,
|
||||
"usage: prepare_art EQUIPMENT_SOURCE SHOT_SOURCE PACKAGE_DIRECTORY"
|
||||
);
|
||||
let output = Path::new(&args[3]).join("art");
|
||||
fs::create_dir_all(&output).unwrap();
|
||||
for (kind, path, logical) in [
|
||||
("equipment", &args[1], (16, 16)),
|
||||
("projectile", &args[2], SHOT),
|
||||
] {
|
||||
let source = image::open(path).unwrap().into_rgba8();
|
||||
fs::copy(path, output.join(format!("{kind}-generated-source.png"))).unwrap();
|
||||
for (mode, scale) in [("sd", 1), ("hd", 4)] {
|
||||
let image = canvas(&source, logical.0 * scale, logical.1 * scale, scale == 4);
|
||||
let path = output.join(format!("{kind}-{mode}.png"));
|
||||
image.save(&path).unwrap();
|
||||
println!(
|
||||
"{PACKAGE}: {}×{} {}",
|
||||
image.width(),
|
||||
image.height(),
|
||||
path.display()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user