Desktop self test: DC_SHOT starts the demo map or a savegame, takes a screenshot and quits
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d7b6d6de7e
commit
04d9d719d7
1 file changed
+98
+98
@@ -945,6 +945,8 @@ async fn main() {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
audio::native::start();
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let mut shot = ShotPlan::from_env();
|
||||
loop {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
audio::native::pump();
|
||||
@@ -2160,12 +2162,108 @@ app.pending_briefing = briefing_of(&campaign, i);
|
||||
was_briefing = briefing;
|
||||
voice.update(now, if app.settings.muted { 0.0 } else { app.settings.volume });
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let shot_now = shot.as_mut().and_then(|p| p.before_frame(&mut app, &mut ui, &mut menu, &mut r3d, now));
|
||||
draw_frame(&mut app, &gfx, &mut r3d, &mut ui, &mut menu, &cloud, &inp, (mx, my), touch_mode, now);
|
||||
ui::end_frame();
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
if let Some(path) = shot_now {
|
||||
shot_capture(&path);
|
||||
}
|
||||
next_frame().await
|
||||
}
|
||||
}
|
||||
|
||||
// ---- self test and screenshots (desktop): DC_SHOT=demo or a savegame file starts it right
|
||||
// away, DC_SHOT_STYLE=hd|pixel picks the graphics style (not saved), DC_SHOT_AFTER seconds later
|
||||
// (default 10) the screen goes to DC_SHOT_OUT (default /tmp/dc-shot.png) and the game ends;
|
||||
// DC_SHOT_ZOOM sets the camera zoom, DC_SHOT_YAW its turn, DC_SHOT_AT=x,z where it looks
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
struct ShotPlan {
|
||||
load: String,
|
||||
out: String,
|
||||
after: f64,
|
||||
style: Option<u16>,
|
||||
zoom: Option<f32>,
|
||||
yaw: Option<f32>,
|
||||
at: Option<(f32, f32)>,
|
||||
started: Option<f64>,
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
impl ShotPlan {
|
||||
fn from_env() -> Option<ShotPlan> {
|
||||
let load = std::env::var("DC_SHOT").ok()?;
|
||||
let num = |k: &str| std::env::var(k).ok().and_then(|v| v.parse::<f32>().ok());
|
||||
Some(ShotPlan {
|
||||
load,
|
||||
out: std::env::var("DC_SHOT_OUT").unwrap_or_else(|_| "/tmp/dc-shot.png".into()),
|
||||
after: num("DC_SHOT_AFTER").unwrap_or(10.0) as f64,
|
||||
style: std::env::var("DC_SHOT_STYLE").ok().map(|v| if v == "pixel" { settings::PIXEL_ART_ROWS } else { settings::HIGH_RES_ROWS }),
|
||||
zoom: num("DC_SHOT_ZOOM"),
|
||||
yaw: num("DC_SHOT_YAW"),
|
||||
at: std::env::var("DC_SHOT_AT").ok().and_then(|v| {
|
||||
let (a, b) = v.split_once(',')?;
|
||||
Some((a.trim().parse().ok()?, b.trim().parse().ok()?))
|
||||
}),
|
||||
started: None,
|
||||
})
|
||||
}
|
||||
|
||||
// starts the scene on the first frame; returns the file to write once the time has come
|
||||
fn before_frame(&mut self, app: &mut App, ui: &mut Ui, menu: &mut Menu, r3d: &mut R3d, now: f64) -> Option<String> {
|
||||
match self.started {
|
||||
None => {
|
||||
if let Some(rows) = self.style {
|
||||
app.settings.pixel_rows = rows;
|
||||
}
|
||||
app.settings.hints = false;
|
||||
apply_settings(&app.settings, r3d);
|
||||
if self.load == "demo" {
|
||||
app.seed = next_seed(app.seed);
|
||||
(app.game, app.cam) = Game::new_demo_map(app.seed);
|
||||
apply_game_settings(&mut app.game, &app.settings);
|
||||
r3d.invalidate();
|
||||
} else if let Ok(bytes) = std::fs::read(&self.load) {
|
||||
app.load_bytes(&bytes, ui, menu, r3d, now);
|
||||
}
|
||||
menu.page = None;
|
||||
ui.show_help = false;
|
||||
if let Some(z) = self.zoom {
|
||||
app.cam.zoom = z;
|
||||
}
|
||||
if let Some(y) = self.yaw {
|
||||
app.cam.yaw = y;
|
||||
}
|
||||
if let Some((x, z)) = self.at {
|
||||
(app.cam.tx, app.cam.tz, app.cam.rx, app.cam.rz) = (x, z, x, z);
|
||||
}
|
||||
self.started = Some(now);
|
||||
None
|
||||
}
|
||||
Some(t0) if now - t0 >= self.after => Some(self.out.clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// writes the screen to a PNG file and ends the game
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn shot_capture(path: &str) {
|
||||
let img = get_screen_data();
|
||||
let (w, h) = (img.width as u32, img.height as u32);
|
||||
let mut out = Image::gen_image_color(w as u16, h as u16, BLACK);
|
||||
for y in 0..h {
|
||||
for x in 0..w {
|
||||
let mut p = img.get_pixel(x, y);
|
||||
p.a = 1.0;
|
||||
out.set_pixel(x, y, p);
|
||||
}
|
||||
}
|
||||
out.export_png(path);
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
// pointer: CSS pixels of the mouse or finger; touch: hover highlight and information only
|
||||
// while a finger is down or for a long-pressed point
|
||||
|
||||
Reference in new issue
Block a user