feat(render-demo): добавить отображение FPS в заголовок окна и stdout в интерактивном режиме
Some checks failed
Test / Lint (push) Failing after 1m16s
Test / Test (push) Has been skipped
Test / Render parity (push) Has been skipped

This commit is contained in:
2026-02-19 10:27:10 +00:00
parent 7346e695c4
commit cb0ca2f2f0
2 changed files with 29 additions and 4 deletions

View File

@@ -37,6 +37,7 @@ brew install sdl2 pkg-config
- `--width`, `--height` (опционально, default `1280x720`). - `--width`, `--height` (опционально, default `1280x720`).
- `--angle` (опционально): фиксированный угол поворота вокруг Y (в радианах). - `--angle` (опционально): фиксированный угол поворота вокруг Y (в радианах).
- `--spin-rate` (опционально, default `0.35`): скорость вращения в интерактивном режиме. - `--spin-rate` (опционально, default `0.35`): скорость вращения в интерактивном режиме.
- В интерактивном режиме FPS выводится в заголовок окна и в stdout (обновление примерно каждые 0.5 сек).
- `--texture <name>`: явное имя `Texm` (override авто-резолва). - `--texture <name>`: явное имя `Texm` (override авто-резолва).
- `--texture-archive <path>`: путь к архиву текстур (по умолчанию `textures.lib` рядом с `--archive`). - `--texture-archive <path>`: путь к архиву текстур (по умолчанию `textures.lib` рядом с `--archive`).
- `--material-archive <path>`: путь к `material.lib` (по умолчанию соседний `material.lib`). - `--material-archive <path>`: путь к `material.lib` (по умолчанию соседний `material.lib`).

View File

@@ -1,8 +1,9 @@
use glow::HasContext as _; use glow::HasContext as _;
use render_core::{build_render_mesh, compute_bounds_for_mesh}; use render_core::{build_render_mesh, compute_bounds_for_mesh};
use render_demo::{load_model_with_name_from_archive, resolve_texture_for_model, LoadedTexture}; use render_demo::{load_model_with_name_from_archive, resolve_texture_for_model, LoadedTexture};
use std::io::Write as _;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::time::Instant; use std::time::{Duration, Instant};
struct Args { struct Args {
archive: PathBuf, archive: PathBuf,
@@ -271,7 +272,7 @@ fn run(args: Args) -> Result<(), String> {
.video() .video()
.map_err(|err| format!("failed to init SDL2 video: {err}"))?; .map_err(|err| format!("failed to init SDL2 video: {err}"))?;
let (window, _gl_ctx, gl_backend) = create_window_and_context(&video, &args)?; let (mut window, _gl_ctx, gl_backend) = create_window_and_context(&video, &args)?;
let _ = if args.capture.is_some() { let _ = if args.capture.is_some() {
video.gl_set_swap_interval(0) video.gl_set_swap_interval(0)
} else { } else {
@@ -342,7 +343,7 @@ fn run(args: Args) -> Result<(), String> {
} else { } else {
run_interactive( run_interactive(
&sdl, &sdl,
&window, &mut window,
&gl, &gl,
program, program,
u_mvp.as_ref(), u_mvp.as_ref(),
@@ -587,7 +588,7 @@ fn run_capture(
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn run_interactive( fn run_interactive(
sdl: &sdl2::Sdl, sdl: &sdl2::Sdl,
window: &sdl2::video::Window, window: &mut sdl2::video::Window,
gl: &glow::Context, gl: &glow::Context,
program: glow::NativeProgram, program: glow::NativeProgram,
u_mvp: Option<&glow::NativeUniformLocation>, u_mvp: Option<&glow::NativeUniformLocation>,
@@ -608,6 +609,10 @@ fn run_interactive(
.event_pump() .event_pump()
.map_err(|err| format!("failed to get SDL event pump: {err}"))?; .map_err(|err| format!("failed to get SDL event pump: {err}"))?;
let start = Instant::now(); let start = Instant::now();
let mut fps_window_start = Instant::now();
let mut fps_frames: u32 = 0;
let mut fps_printed = false;
let base_title = "Parkan Render Demo (SDL2 + OpenGL)";
'main_loop: loop { 'main_loop: loop {
for event in events.poll_iter() { for event in events.poll_iter() {
@@ -647,6 +652,25 @@ fn run_interactive(
); );
} }
window.gl_swap_window(); window.gl_swap_window();
fps_frames = fps_frames.saturating_add(1);
let elapsed = fps_window_start.elapsed();
if elapsed >= Duration::from_millis(500) {
let fps = fps_frames as f32 / elapsed.as_secs_f32().max(0.000_1);
let frame_time_ms = 1000.0 / fps.max(0.000_1);
let _ = window.set_title(&format!(
"{base_title} | FPS: {fps:.1} ({frame_time_ms:.2} ms)"
));
print!("\rFPS: {fps:.1} ({frame_time_ms:.2} ms)");
let _ = std::io::stdout().flush();
fps_printed = true;
fps_frames = 0;
fps_window_start = Instant::now();
}
}
if fps_printed {
println!();
} }
Ok(()) Ok(())