~zanneth/bedside

a6da26dd76af0acedf81525b6ba3c47f11b4af4b — Charles Magahern 3 months ago 24bbe17
Add FPS counter
6 files changed, 86 insertions(+), 3 deletions(-)

M src/application.rs
A src/components/fps.rs
M src/components/mod.rs
M src/engine.rs
M src/entity.rs
M src/main.rs
M src/application.rs => src/application.rs +11 -2
@@ 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(())

A src/components/fps.rs => src/components/fps.rs +61 -0
@@ 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<Instant>,
}

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));
    }
}

M src/components/mod.rs => src/components/mod.rs +1 -0
@@ 1,5 1,6 @@
pub mod camera;
pub mod clock;
pub mod fps;
pub mod material;
pub mod path;
pub mod quad;

M src/engine.rs => src/engine.rs +2 -0
@@ 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),
            ],
        }
    }

M src/entity.rs => src/entity.rs +3 -0
@@ 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<ClockComponent>,
    pub fps:            Option<FPSComponent>,

    event_handler:      Option<Rc<EventHandler>>,
}


@@ 56,6 58,7 @@ impl Entity {
            path:          None,

            clock:         None,
            fps:           None,

            event_handler: None,
        }

M src/main.rs => src/main.rs +8 -1
@@ 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);