Add support for cropping map renders

This commit is contained in:
Tad Hardesty 2018-01-16 04:48:54 -08:00
parent 6ff55e8e8d
commit ab67f4eab9
3 changed files with 98 additions and 14 deletions

View file

@ -6,6 +6,8 @@ extern crate structopt;
extern crate dreammaker as dm;
#[macro_use] extern crate dmm_tools;
use std::fmt;
use structopt::StructOpt;
use dmm_tools::*;
@ -35,6 +37,14 @@ struct Opt {
#[structopt(long="reformat")]
reformat: bool,
/// Set the minimum x,y or x,y,z coordinate to act upon (1-indexed, inclusive).
#[structopt(long="min")]
min: Option<CoordArg>,
/// Set the maximum x,y or x,y,z coordinate to act upon (1-indexed, inclusive).
#[structopt(long="max")]
max: Option<CoordArg>,
/// The list of files to process.
files: Vec<String>,
}
@ -67,9 +77,27 @@ fn main() {
}
if opt.minimap {
for z in 0..map.dim_z() {
let (dim_x, dim_y, dim_z) = map.dim_xyz();
let mut min = opt.min.unwrap_or(CoordArg { x: 0, y: 0, z: 0 });
let mut max = opt.max.unwrap_or(CoordArg { x: dim_x + 1, y: dim_y + 1, z: dim_z + 1 });
min.x = clamp(min.x, 1, dim_x);
min.y = clamp(min.y, 1, dim_y);
min.z = clamp(min.z, 1, dim_z);
max.x = clamp(max.x, min.x, dim_x);
max.y = clamp(max.y, min.y, dim_y);
max.z = clamp(max.z, min.z, dim_z);
println!(" rendering from {} to {}", min, max);
for z in (min.z - 1)..(max.z) {
println!(" generating z={}", 1 + z);
let image = minimap::generate(&objtree, &map, z, &mut icon_cache).unwrap();
let context = minimap::Context {
objtree: &objtree,
map: &map,
grid: map.z_level(z),
min: (min.x - 1, min.y - 1),
max: (max.x - 1, max.y - 1),
};
let image = minimap::generate(context, &mut icon_cache).unwrap();
let output = format!("{}/{}-{}.png", opt.output, path.file_stem().unwrap().to_string_lossy(), 1 + z);
if !opt.dry_run {
println!(" saving {}", output);
@ -84,3 +112,47 @@ fn main() {
flame::dump_html(&mut std::io::BufWriter::new(std::fs::File::create(format!("{}/flame-graph.html", opt.output)).unwrap())).unwrap();
}
}
#[derive(Debug, Copy, Clone)]
struct CoordArg {
x: usize,
y: usize,
z: usize,
}
impl fmt::Display for CoordArg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.z != 0 {
write!(f, "{},{},{}", self.x, self.y, self.z)
} else {
write!(f, "{},{}", self.x, self.y)
}
}
}
impl std::str::FromStr for CoordArg {
type Err = String;
fn from_str(s: &str) -> Result<Self, String> {
match s.split(",").map(|x| x.parse()).collect::<Result<Vec<_>, std::num::ParseIntError>>() {
Ok(ref vec) if vec.len() == 2 => {
Ok(CoordArg { x: vec[0], y: vec[1], z: 0 })
}
Ok(ref vec) if vec.len() == 3 => {
Ok(CoordArg { x: vec[0], y: vec[1], z: vec[2] })
}
Ok(_) => Err("must specify 2 or 3 coordinates".into()),
Err(e) => Err(e.to_string()),
}
}
}
fn clamp(val: usize, min: usize, max: usize) -> usize {
if val < min {
min
} else if val > max {
max
} else {
val
}
}

View file

@ -45,6 +45,12 @@ impl Map {
save_tgm(self, File::create(path)?)
}
#[inline]
pub fn dim_xyz(&self) -> (usize, usize, usize) {
let dim = self.grid.dim();
(dim.2, dim.1, dim.0)
}
#[inline]
pub fn dim_z(&self) -> usize {
self.grid.dim().0

View file

@ -17,31 +17,37 @@ const LEGIT_POSTERS: u32 = 35;
// Main minimap code
#[derive(Clone, Copy)]
struct Context<'a> {
objtree: &'a ObjectTree,
map: &'a Map,
grid: Grid<'a>,
pub struct Context<'a> {
pub objtree: &'a ObjectTree,
pub map: &'a Map,
pub grid: Grid<'a>,
pub min: (usize, usize),
pub max: (usize, usize),
}
pub fn generate(
objtree: &ObjectTree,
map: &Map,
z: usize,
ctx: Context,
icon_cache: &mut HashMap<PathBuf, IconFile>,
) -> Result<Image, ()> {
use rand::Rng;
flame!("minimap");
let grid = map.z_level(z);
let (len_x, len_y) = grid.dim();
let ctx = Context { objtree, map, grid };
let Context { objtree, map, grid, .. } = ctx;
// transform min/max from bottom-left-based to top-left-based
// probably doesn't belong here
let (_, len_y) = ctx.grid.dim();
let (min_y, max_y) = (len_y - ctx.max.1 - 1, len_y - ctx.min.1 - 1);
let (len_x, len_y) = (ctx.max.0 - ctx.min.0 + 1, ctx.max.1 - ctx.min.1 + 1);
// loads atoms from the prefabs on the map and adds overlays and smoothing
let mut atoms = Vec::new();
let mut overlays = Vec::new();
//flame!("collect");
for (y, row) in grid.axis_iter(Axis(0)).enumerate() {
if y < min_y || y > max_y { continue }
for (x, e) in row.iter().enumerate() {
if x < ctx.min.0 || x > ctx.max.0 { continue }
for mut atom in get_atom_list(objtree, &map.dictionary[e], (x as u32, y as u32)) {
// icons which differ from their map states
let p = &atom.type_.path;
@ -189,8 +195,8 @@ pub fn generate(
let pixel_y = atom.get_var("pixel_y", ctx.objtree).to_int().unwrap_or(0) +
icon_file.metadata.height as i32;
let mut loc = (
(atom.loc.0 * TILE_SIZE) as i32 + pixel_x,
(atom.loc.1 * TILE_SIZE + TILE_SIZE) as i32 - pixel_y
((atom.loc.0 - ctx.min.0 as u32) * TILE_SIZE) as i32 + pixel_x,
((atom.loc.1 + 1 - min_y as u32) * TILE_SIZE) as i32 - pixel_y
);
// OOB handling