mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 02:56:17 -10:00
screenshot-sequence: STEP_MS in decimal milliseconds
16.666667 steps a 60 fps clock. STEP_MS is a finite number more than 0, and the reply gives it back as given. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
8650e51ddb
commit
94a66c81d4
6 files changed
+26
-21
No files matched your search
@@ -589,8 +589,8 @@ pub const COMMANDS: &[Cmd] = &[
|
||||
["horizon-ctl trace /tmp/frame.json 10", "horizon-ctl trace stop"], &[], mcp: false, local: false),
|
||||
cmd!("screenshot-sequence", Scripting, "screenshot-sequence FRAMES STEP_MS PATH|cancel", "draw a shader pack's first FRAMES frames on a set clock and write the last as a PNG",
|
||||
"Needs HORIZON_STILL and a frozen world (docs/agent-control.md). The pack starts over, frame n's clock is n frames and (n - 1) × STEP_MS milliseconds, the PNG is written as screenshot PATH writes it, and the reply comes once it is. Relative paths are taken from horizon-ctl's directory. cancel stops a running sequence.",
|
||||
["horizon-ctl screenshot-sequence 64 50 frame64.png", "horizon-ctl screenshot-sequence cancel"],
|
||||
&[p("frames", Ty::Str, "frames to draw, 1 to 10000, or cancel"), opt("step_ms", Ty::Int, "milliseconds between frames on the pack's clock"), opt("path", Ty::Rest, "the PNG to write")], mcp: false, local: false),
|
||||
["horizon-ctl screenshot-sequence 64 50 frame64.png", "horizon-ctl screenshot-sequence 64 16.666667 frame64.png", "horizon-ctl screenshot-sequence cancel"],
|
||||
&[p("frames", Ty::Str, "frames to draw, 1 to 10000, or cancel"), opt("step_ms", Ty::Num, "milliseconds between frames on the pack's clock, more than 0 (16.666667 for 60 fps)"), opt("path", Ty::Rest, "the PNG to write")], mcp: false, local: false),
|
||||
cmd!("render-capture", Scripting, "render-capture on|off|DIR", "keep CPU copies of the meshes the renderer draws (on), or write the next frame's scene to DIR for the scene_replay example",
|
||||
"on meshes every section and far tile again so the copies are complete (HORIZON_RENDER_CAPTURE=1 keeps them from the start). DIR gets the camera, frame inputs, settings and every resident near section and far tile mesh; entities, particles, weather, the hand and the HUD are left out. See docs/graphics.md.",
|
||||
["horizon-ctl render-capture on", "horizon-ctl render-capture /tmp/scene"], &[], mcp: false, local: false),
|
||||
|
||||
@@ -17,7 +17,7 @@ const READ_ONLY: [&str; 5] = ["screenshot-sequence", "hello", "help", "status",
|
||||
|
||||
pub(super) struct Sequence {
|
||||
frames: u32,
|
||||
step_ms: u32,
|
||||
step_ms: f64,
|
||||
/// The frame drawn next, from 1.
|
||||
next: u32,
|
||||
path: PathBuf,
|
||||
@@ -34,7 +34,7 @@ impl Sequence {
|
||||
}
|
||||
|
||||
/// `FRAMES STEP_MS PATH`; the path is the rest of the line and may hold spaces.
|
||||
fn parse(args: &str) -> Result<(u32, u32, PathBuf)> {
|
||||
fn parse(args: &str) -> Result<(u32, f64, PathBuf)> {
|
||||
let usage = "screenshot-sequence FRAMES STEP_MS PATH, or screenshot-sequence cancel";
|
||||
let (frames, rest) = args.trim().split_once(char::is_whitespace).ok_or(usage)?;
|
||||
let (step_ms, path) = rest
|
||||
@@ -42,12 +42,12 @@ fn parse(args: &str) -> Result<(u32, u32, PathBuf)> {
|
||||
.split_once(char::is_whitespace)
|
||||
.ok_or(usage)?;
|
||||
let frames: u32 = frames.parse().map_err(|_| usage)?;
|
||||
let step_ms: u32 = step_ms.parse().map_err(|_| usage)?;
|
||||
let step_ms: f64 = step_ms.parse().map_err(|_| usage)?;
|
||||
if !(1..=MAX_FRAMES).contains(&frames) {
|
||||
return Err(format!("FRAMES must be 1 to {MAX_FRAMES}").into());
|
||||
}
|
||||
if step_ms == 0 {
|
||||
return Err("STEP_MS must be more than 0".into());
|
||||
if !step_ms.is_finite() || step_ms <= 0.0 {
|
||||
return Err("STEP_MS must be a number of milliseconds more than 0".into());
|
||||
}
|
||||
Ok((frames, step_ms, path.trim().into()))
|
||||
}
|
||||
@@ -296,14 +296,18 @@ mod tests {
|
||||
fn the_path_is_the_rest_of_the_line_and_the_counts_are_bounded() {
|
||||
assert_eq!(
|
||||
parse(" 64 50 /tmp/a b.png ").unwrap(),
|
||||
(64, 50, PathBuf::from("/tmp/a b.png"))
|
||||
(64, 50.0, PathBuf::from("/tmp/a b.png"))
|
||||
);
|
||||
assert_eq!(parse("10000 1 x.png").unwrap().0, 10_000);
|
||||
assert_eq!(parse("64 16.666667 x.png").unwrap().1, 16.666667);
|
||||
for bad in [
|
||||
"0 50 x.png",
|
||||
"10001 50 x.png",
|
||||
"4 0 x.png",
|
||||
"4 -1 x.png",
|
||||
"4 0.0 x.png",
|
||||
"4 NaN x.png",
|
||||
"4 inf x.png",
|
||||
"4 50",
|
||||
"x 50 a",
|
||||
] {
|
||||
|
||||
@@ -409,13 +409,13 @@ of the frame ([#8750](https://github.com/horizon-rust/horizon/issues/8750)).
|
||||
FRAMES STEP_MS PATH`: the pack starts over (its buffers, images, shadow maps, smoothed values and
|
||||
custom uniforms, or a Horizon pack's `history` and eased values) and draws FRAMES frames on a set
|
||||
clock, frame n at n frames and (n - 1) × STEP_MS milliseconds (0 since the frame before on frame
|
||||
1, STEP_MS after). The last is written as `screenshot PATH` writes it (with its `-hdr.png` under
|
||||
HDR output), and the reply, once it is, names the pack and the last frame's clock. Without a pack
|
||||
it draws the frames all the same. It needs the world frozen, far terrain (LOD Distance), TAA,
|
||||
frame generation and the shadow cache off and chunk fade 0, and says so otherwise. While it runs,
|
||||
commands that would change the scene are refused, a change to the camera, the world, the
|
||||
settings, the pack or the window's size ends it with an error, `screenshot-sequence cancel` stops
|
||||
it and `quit` quits.
|
||||
1, STEP_MS after; a decimal, `16.666667` for 60 fps). The last is written as `screenshot PATH`
|
||||
writes it (with its `-hdr.png` under HDR output), and the reply, once it is, names the pack and
|
||||
the last frame's clock. Without a pack it draws the frames all the same. It needs the world
|
||||
frozen, far terrain (LOD Distance), TAA, frame generation and the shadow cache off and chunk fade
|
||||
0, and says so otherwise. While it runs, commands that would change the scene are refused, a
|
||||
change to the camera, the world, the settings, the pack or the window's size ends it with an
|
||||
error, `screenshot-sequence cancel` stops it and `quit` quits.
|
||||
- Not covered: temporal AA and frame generation (they build on earlier frames: turn them off),
|
||||
custom entity model animations, native mods, and what eases on the wall clock for a moment
|
||||
(toasts, the boss bar's fill, chunks fading in, the spyglass): wait for them to settle. Frame
|
||||
|
||||
+4
-4
@@ -189,10 +189,10 @@ refused.
|
||||
|
||||
`horizon-ctl screenshot-sequence FRAMES STEP_MS PATH`, under `HORIZON_STILL`, starts the running pack over and draws
|
||||
its first FRAMES frames on a set clock: frame n has `frame_index` n, `time` (n - 1) × STEP_MS / 1000 and `delta_time`
|
||||
STEP_MS / 1000 (0 on frame 1), and `history` and the eased values start as in a pack just loaded. The last frame is
|
||||
written as a PNG, the same bytes every run on the same build, GPU and driver. Packs in the `shaders/` format get the
|
||||
same (`frameCounter`, `frameTimeCounter`, `frameTime`). How to use it:
|
||||
[the guide](../shaders.md#testing-a-pack-frame-by-frame).
|
||||
STEP_MS / 1000 (0 on frame 1; STEP_MS may be a decimal, `16.666667` for 60 fps), and `history` and the eased values
|
||||
start as in a pack just loaded. The last frame is written as a PNG, the same bytes every run on the same build, GPU
|
||||
and driver. Packs in the `shaders/` format get the same (`frameCounter`, `frameTimeCounter`, `frameTime`). How to use
|
||||
it: [the guide](../shaders.md#testing-a-pack-frame-by-frame).
|
||||
|
||||
## Guide, reference and examples
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ Every command `horizon-ctl` takes, its MCP tool in `horizon-ctl mcp` (the launch
|
||||
| `stats [reset] [raw]` | `stats` | Frame-time summary since the last reset | `reset` (boolean): start counting again<br>`raw` (boolean): every frame time too (frame_ms, cpu_ms, gpu_ms) |
|
||||
| `gpu-passes [on\|off]` | CLI only | Time Horizon's own render passes on the GPU, shown in F3 and in stats and bench | `mode` (on, off): on or off; without it, only reports |
|
||||
| `trace [FILE [SECONDS] \| stop]` | CLI only | Write every thread's timed spans to FILE as a timeline that ui.perfetto.dev opens, for SECONDS or until stop | none |
|
||||
| `screenshot-sequence FRAMES STEP_MS PATH\|cancel` | CLI only | Draw a shader pack's first FRAMES frames on a set clock and write the last as a PNG | `frames` (string, required): frames to draw, 1 to 10000, or cancel<br>`step_ms` (integer): milliseconds between frames on the pack's clock<br>`path` (text): the PNG to write |
|
||||
| `screenshot-sequence FRAMES STEP_MS PATH\|cancel` | CLI only | Draw a shader pack's first FRAMES frames on a set clock and write the last as a PNG | `frames` (string, required): frames to draw, 1 to 10000, or cancel<br>`step_ms` (number): milliseconds between frames on the pack's clock, more than 0 (16.666667 for 60 fps)<br>`path` (text): the PNG to write |
|
||||
| `render-capture on\|off\|DIR` | CLI only | Keep CPU copies of the meshes the renderer draws (on), or write the next frame's scene to DIR for the scene_replay example | none |
|
||||
| `fly X1 Y1 Z1 X2 Y2 Z2 SECONDS [PITCH [raw]]` | CLI only | Fly the camera along a line, then reply with the frame summary | none |
|
||||
| `record-start [NAME] [--no-world]` | `record_start` | Record input, state and the world for a bug repro | `name` (string): folder name after the timestamp (default session)<br>`--no-world` (boolean): do not copy the world (a server session) |
|
||||
|
||||
+2
-1
@@ -73,7 +73,8 @@ horizon-ctl screenshot-sequence 64 50 frame64.png
|
||||
|
||||
starts the pack over as if just loaded (black `history`, eased values from the start) and draws 64 frames 50 ms
|
||||
apart on its clock: frame n has `frame_index` n, `time` (n - 1) × 0.05 and `delta_time` 0.05 (0 on frame 1). The
|
||||
64th is written to `frame64.png` (and `frame64-hdr.png` with HDR output on) before the reply. The same build, GPU
|
||||
64th is written to `frame64.png` (and `frame64-hdr.png` with HDR output on) before the reply. STEP_MS may be a
|
||||
decimal: `16.666667` steps a 60 fps clock. The same build, GPU
|
||||
and driver write the same bytes every run, so two versions of a pack compare by a pixel diff. `screenshot-sequence
|
||||
cancel` stops one.
|
||||
|
||||
|
||||
Reference in new issue
Block a user