From a6da26dd76af0acedf81525b6ba3c47f11b4af4b Mon Sep 17 00:00:00 2001 From: Charles Magahern Date: Fri, 4 Aug 2023 23:54:51 -0700 Subject: [PATCH] Add FPS counter --- src/application.rs | 13 +++++++-- src/components/fps.rs | 61 +++++++++++++++++++++++++++++++++++++++++++ src/components/mod.rs | 1 + src/engine.rs | 2 ++ src/entity.rs | 3 +++ src/main.rs | 9 ++++++- 6 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 src/components/fps.rs diff --git a/src/application.rs b/src/application.rs index 3f44d03..1535c63 100644 --- a/src/application.rs +++ b/src/application.rs @@ -1,4 +1,6 @@ use sdl2::event::Event; +use std::time::{Duration, Instant}; +use std::thread; use crate::engine::Engine; use crate::error::*; @@ -6,6 +8,8 @@ use crate::input_context::InputContext; use crate::sdl::SDLContext; use crate::window::Window; +const FRAME_INTERVAL: Duration = Duration::new(0, 1_000_000_000 / 60); // 60Hz + pub struct Application { pub engine: Engine, } @@ -22,6 +26,8 @@ impl Application { let mut event_pump = sdl_ctx.sdl.event_pump()?; 'main: loop { + let next_frame_time = Instant::now() + FRAME_INTERVAL; + let mut input_ctx = InputContext::new(); input_ctx.set_touch_plane_size(window.render_ctx.viewport_size); @@ -36,8 +42,11 @@ impl Application { render_ctx.clear(); self.engine.frame(render_ctx, &mut input_ctx); - - window.swap(); /* will block until next vsync */ + window.swap(); + + // sleep until next frame + let sleep_duration = next_frame_time.saturating_duration_since(Instant::now()); + thread::sleep(sleep_duration); } Ok(()) diff --git a/src/components/fps.rs b/src/components/fps.rs new file mode 100644 index 0000000..a263740 --- /dev/null +++ b/src/components/fps.rs @@ -0,0 +1,61 @@ +use crate::components::{ + quad::QuadComponent, + text::TextComponent, +}; +use crate::geometry::Rect; +use crate::input_context::InputContext; +use crate::render_context::RenderContext; +use crate::scene::Scene; + +use std::time::Instant; + +pub struct FPSComponent { + fps: usize, + frames: usize, + last_latch_time: Option, +} + +impl FPSComponent { + pub fn new() -> Self { + Self { + fps: 0, + frames: 0, + last_latch_time: None, + } + } +} + +pub fn fps_system(scene: &mut Scene, _: &mut RenderContext, _: &mut InputContext) { + for entity in &mut scene.entities { + let fps = match &mut entity.fps { None => continue, Some(c) => c }; + + // initialize text component + if entity.text.is_none() { + entity.text = Some(TextComponent::new("FPS: 0")); + } + + // initialize quad component + if entity.quad.is_none() { + entity.quad = Some(QuadComponent::new(&Rect::default())); + } + + // calculate FPS and update text + fps.frames += 1; + match fps.last_latch_time { + Some(last_latch_time) => { + if last_latch_time.elapsed().as_secs() >= 1 { + fps.fps = fps.frames; + fps.frames = 0; + fps.last_latch_time = Some(Instant::now()); + } + }, + + None => { + fps.last_latch_time = Some(Instant::now()); + } + } + + let text = &mut entity.text.as_mut().unwrap(); + text.set_text(&format!("FPS: {:}", fps.fps)); + } +} diff --git a/src/components/mod.rs b/src/components/mod.rs index 554be18..7ead4bc 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -1,5 +1,6 @@ pub mod camera; pub mod clock; +pub mod fps; pub mod material; pub mod path; pub mod quad; diff --git a/src/engine.rs b/src/engine.rs index 0872ffc..02a7ba2 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -4,6 +4,7 @@ use crate::scene::Scene; use crate::components::{ camera::camera_system, clock::clock_system, + fps::fps_system, material::material_system, path::path_system, quad::quad_system, @@ -37,6 +38,7 @@ impl Engine { // ordering matters a little less here. Box::new(clock_system), + Box::new(fps_system), ], } } diff --git a/src/entity.rs b/src/entity.rs index 8b497e2..152b687 100644 --- a/src/entity.rs +++ b/src/entity.rs @@ -7,6 +7,7 @@ use ultraviolet::{Mat4, Vec3}; use crate::components::{ camera::CameraComponent, clock::ClockComponent, + fps::FPSComponent, material::{Material, MaterialComponent}, path::PathComponent, quad::QuadComponent, @@ -37,6 +38,7 @@ pub struct Entity { /* auxiliary components */ pub clock: Option, + pub fps: Option, event_handler: Option>, } @@ -56,6 +58,7 @@ impl Entity { path: None, clock: None, + fps: None, event_handler: None, } diff --git a/src/main.rs b/src/main.rs index cce5d8f..f0f21ce 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,11 +19,11 @@ mod util; mod vertex_array; mod window; - use crate::{ components::{ camera::CameraComponent, clock::ClockComponent, + fps::FPSComponent, material::MaterialComponent, touch::TouchComponent, transform::TransformComponent, @@ -125,6 +125,13 @@ fn main() { let square = scene.find_entity_mut(square_id).unwrap(); square.transform.as_mut().unwrap().rotation = Rotor3::from_rotation_xy(theta); }); + + // FPS counter + let mut fps = Entity::new(); + fps.transform = Some(TransformComponent::new()); + fps.material = Some(MaterialComponent::with_color(&Color::WHITE)); + fps.fps = Some(FPSComponent::new()); + scene.add_entity(fps); // run the scene app.engine.scene = Some(scene); -- 2.45.2