Optionally tile screenshots at smaller dimensions than the window. #440

This commit is contained in:
Dustin Carlino 2021-01-06 10:52:22 -08:00
parent 4cf133cc32
commit 92be9c57ed
6 changed files with 37 additions and 19 deletions

View File

@ -12,7 +12,7 @@ use map_model::{osm, ControlTrafficSignal, IntersectionID, NORMAL_LANE_THICKNESS
use sim::Sim; use sim::Sim;
use widgetry::{ use widgetry::{
lctrl, Btn, Cached, Checkbox, Choice, Color, DrawBaselayer, Drawable, EventCtx, GeomBatch, lctrl, Btn, Cached, Checkbox, Choice, Color, DrawBaselayer, Drawable, EventCtx, GeomBatch,
GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel, State, Text, UpdateType, GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel, ScreenDims, State, Text, UpdateType,
VerticalAlignment, Widget, VerticalAlignment, Widget,
}; };
@ -59,7 +59,7 @@ impl DebugMode {
Checkbox::switch(ctx, "show route for all agents", Key::R, false), Checkbox::switch(ctx, "show route for all agents", Key::R, false),
Widget::col(vec![ Widget::col(vec![
Btn::text_fg("unhide everything").build_def(ctx, lctrl(Key::H)), Btn::text_fg("unhide everything").build_def(ctx, lctrl(Key::H)),
Btn::text_fg("screenshot everything").build_def(ctx, None), Btn::text_fg("screenshot everything (for leaflet)").build_def(ctx, None),
Btn::text_fg("screenshot all of the everything").build_def(ctx, None), Btn::text_fg("screenshot all of the everything").build_def(ctx, None),
Btn::text_fg("search OSM metadata").build_def(ctx, Key::Slash), Btn::text_fg("search OSM metadata").build_def(ctx, Key::Slash),
Btn::text_fg("clear OSM search results").build_def(ctx, lctrl(Key::Slash)), Btn::text_fg("clear OSM search results").build_def(ctx, lctrl(Key::Slash)),
@ -222,8 +222,8 @@ impl State<App> for DebugMode {
self.search_results = None; self.search_results = None;
self.reset_info(ctx); self.reset_info(ctx);
} }
"screenshot everything" => { "screenshot everything (for leaflet)" => {
screenshot_everything(ctx, app); screenshot_everything(ctx, app, ScreenDims::new(256.0, 256.0));
return Transition::Keep; return Transition::Keep;
} }
"screenshot all of the everything" => { "screenshot all of the everything" => {
@ -784,7 +784,7 @@ impl State<App> for ScreenshotTest {
} }
} else { } else {
self.screenshot_done = true; self.screenshot_done = true;
screenshot_everything(ctx, app); screenshot_everything(ctx, app, ctx.canvas.get_window_dims());
// TODO Sometimes this still gets stuck and needs a mouse wiggle for input event? // TODO Sometimes this still gets stuck and needs a mouse wiggle for input event?
Transition::Keep Transition::Keep
} }
@ -792,10 +792,11 @@ impl State<App> for ScreenshotTest {
fn draw(&self, _: &mut GfxCtx, _: &App) {} fn draw(&self, _: &mut GfxCtx, _: &App) {}
} }
fn screenshot_everything(ctx: &mut EventCtx, app: &App) { fn screenshot_everything(ctx: &mut EventCtx, app: &App, dims: ScreenDims) {
let name = app.primary.map.get_name(); let name = app.primary.map.get_name();
ctx.request_update(UpdateType::ScreenCaptureEverything { ctx.request_update(UpdateType::ScreenCaptureEverything {
dir: format!("screenshots/{}/{}", name.city, name.map), dir: format!("screenshots/{}/{}", name.city, name.map),
zoom: 3.0, zoom: 3.0,
dims,
}); });
} }

View File

@ -363,9 +363,9 @@ impl PrerenderInnards {
self.window_adapter.draw_finished(gfc_ctx_innards) self.window_adapter.draw_finished(gfc_ctx_innards)
} }
pub(crate) fn screencap(&self, canvas: &Canvas, filename: String) -> anyhow::Result<()> { pub(crate) fn screencap(&self, dims: ScreenDims, filename: String) -> anyhow::Result<()> {
let width = canvas.window_width as u32; let width = dims.width as u32;
let height = canvas.window_height as u32; let height = dims.height as u32;
let mut img = image::DynamicImage::new_rgba8(width, height); let mut img = image::DynamicImage::new_rgba8(width, height);
let pixels = img.as_mut_rgba8().unwrap(); let pixels = img.as_mut_rgba8().unwrap();

View File

@ -15,7 +15,11 @@ pub enum UpdateType {
InputOnly, InputOnly,
Game, Game,
Pan, Pan,
ScreenCaptureEverything { dir: String, zoom: f64 }, ScreenCaptureEverything {
dir: String,
zoom: f64,
dims: ScreenDims,
},
} }
pub struct EventCtx<'a> { pub struct EventCtx<'a> {

View File

@ -25,6 +25,8 @@
//#![warn(missing_docs)] //#![warn(missing_docs)]
#[macro_use]
extern crate anyhow;
#[macro_use] #[macro_use]
extern crate log; extern crate log;

View File

@ -124,7 +124,7 @@ impl<A: SharedAppState> State<A> {
} }
} }
// Returns naming hint. Logically consumes the number of uploads. /// Returns naming hint. Logically consumes the number of uploads.
pub(crate) fn draw(&mut self, prerender: &Prerender, screenshot: bool) -> Option<String> { pub(crate) fn draw(&mut self, prerender: &Prerender, screenshot: bool) -> Option<String> {
let mut g = GfxCtx::new(prerender, &self.canvas, &self.style, screenshot); let mut g = GfxCtx::new(prerender, &self.canvas, &self.style, screenshot);
@ -358,8 +358,10 @@ pub fn run<
running = true; running = true;
} }
UpdateType::Pan => {} UpdateType::Pan => {}
UpdateType::ScreenCaptureEverything { dir, zoom } => { UpdateType::ScreenCaptureEverything { dir, zoom, dims } => {
if let Err(err) = screenshot_everything(&mut state, &dir, &prerender, zoom) { if let Err(err) =
screenshot_everything(&mut state, &dir, &prerender, zoom, dims)
{
error!("Couldn't screenshot everything: {}", err); error!("Couldn't screenshot everything: {}", err);
} }
} }

View File

@ -1,7 +1,7 @@
use abstutil::Timer; use abstutil::Timer;
use crate::runner::State; use crate::runner::State;
use crate::{Prerender, SharedAppState}; use crate::{Prerender, ScreenDims, SharedAppState};
/// Take a screenshot of the entire canvas, tiling it based on the window's width and height. /// Take a screenshot of the entire canvas, tiling it based on the window's width and height.
pub(crate) fn screenshot_everything<A: SharedAppState>( pub(crate) fn screenshot_everything<A: SharedAppState>(
@ -9,10 +9,19 @@ pub(crate) fn screenshot_everything<A: SharedAppState>(
dir_path: &str, dir_path: &str,
prerender: &Prerender, prerender: &Prerender,
zoom: f64, zoom: f64,
dims: ScreenDims,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
if dims.width > state.canvas.window_width || dims.height > state.canvas.window_height {
bail!(
"Can't take screenshots of dims {:?} when the window is only {:?}",
dims,
state.canvas.get_window_dims()
);
}
let mut timer = Timer::new("capturing screen"); let mut timer = Timer::new("capturing screen");
let num_tiles_x = (state.canvas.map_dims.0 * zoom / state.canvas.window_width).ceil() as usize; let num_tiles_x = (state.canvas.map_dims.0 * zoom / dims.width).ceil() as usize;
let num_tiles_y = (state.canvas.map_dims.1 * zoom / state.canvas.window_height).ceil() as usize; let num_tiles_y = (state.canvas.map_dims.1 * zoom / dims.height).ceil() as usize;
let orig_zoom = state.canvas.cam_zoom; let orig_zoom = state.canvas.cam_zoom;
let orig_x = state.canvas.cam_x; let orig_x = state.canvas.cam_x;
let orig_y = state.canvas.cam_y; let orig_y = state.canvas.cam_y;
@ -26,8 +35,8 @@ pub(crate) fn screenshot_everything<A: SharedAppState>(
for tile_y in 0..num_tiles_y { for tile_y in 0..num_tiles_y {
for tile_x in 0..num_tiles_x { for tile_x in 0..num_tiles_x {
timer.next(); timer.next();
state.canvas.cam_x = (tile_x as f64) * state.canvas.window_width; state.canvas.cam_x = (tile_x as f64) * dims.width;
state.canvas.cam_y = (tile_y as f64) * state.canvas.window_height; state.canvas.cam_y = (tile_y as f64) * dims.height;
let suffix = state.draw(prerender, true).unwrap_or_else(String::new); let suffix = state.draw(prerender, true).unwrap_or_else(String::new);
let filename = format!( let filename = format!(
@ -37,7 +46,7 @@ pub(crate) fn screenshot_everything<A: SharedAppState>(
tile_y + 1, tile_y + 1,
suffix suffix
); );
prerender.inner.screencap(&state.canvas, filename)?; prerender.inner.screencap(dims, filename)?;
} }
} }