From be2cca79b07dbbc6b1eaf6c13d1061b3e02a1934 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 10 Jan 2024 18:53:19 -0800 Subject: [PATCH] Added fps counter --- Cargo.lock | 14 ++-- Cargo.toml | 2 +- crates/galactica/Cargo.toml | 2 +- crates/galactica/src/game.rs | 16 +++-- crates/galactica/src/main.rs | 2 +- crates/packer/Cargo.toml | 2 +- crates/render/Cargo.toml | 2 +- crates/render/src/datastructs.rs | 7 +- crates/render/src/globaluniform/atlas.rs | 2 +- .../render/src/globaluniform/globaluniform.rs | 2 +- crates/render/src/globaluniform/object.rs | 2 +- crates/render/src/globaluniform/sprite.rs | 2 +- crates/render/src/gpustate/new.rs | 65 ++++++++---------- crates/render/src/gpustate/render.rs | 37 +++------- crates/render/src/gpustate/systemsim.rs | 15 ++-- crates/render/src/starfield.rs | 32 ++++----- crates/render/src/texturearray.rs | 2 +- crates/render/src/ui/fpsindicator.rs | 68 +++++++++++++++++++ crates/render/src/ui/manager.rs | 13 +++- crates/render/src/ui/mod.rs | 7 +- crates/render/src/ui/radar.rs | 26 +++---- crates/render/src/ui/status.rs | 14 ++-- crates/{constants => util}/Cargo.toml | 2 +- .../src/lib.rs => util/src/constants.rs} | 3 +- crates/util/src/lib.rs | 6 ++ crates/util/src/timing.rs | 44 ++++++++++++ 26 files changed, 239 insertions(+), 150 deletions(-) create mode 100644 crates/render/src/ui/fpsindicator.rs rename crates/{constants => util}/Cargo.toml (93%) rename crates/{constants/src/lib.rs => util/src/constants.rs} (99%) create mode 100644 crates/util/src/lib.rs create mode 100644 crates/util/src/timing.rs diff --git a/Cargo.lock b/Cargo.lock index d1ea7b2..7052ceb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -642,20 +642,16 @@ version = "0.0.0" dependencies = [ "anyhow", "cgmath", - "galactica-constants", "galactica-content", "galactica-galaxy", "galactica-render", "galactica-systemsim", + "galactica-util", "pollster", "wgpu", "winit", ] -[[package]] -name = "galactica-constants" -version = "0.0.0" - [[package]] name = "galactica-content" version = "0.0.0" @@ -684,7 +680,7 @@ name = "galactica-packer" version = "0.0.0" dependencies = [ "anyhow", - "galactica-constants", + "galactica-util", "image", "serde", "toml", @@ -698,11 +694,11 @@ dependencies = [ "anyhow", "bytemuck", "cgmath", - "galactica-constants", "galactica-content", "galactica-galaxy", "galactica-packer", "galactica-systemsim", + "galactica-util", "glyphon", "image", "rand", @@ -723,6 +719,10 @@ dependencies = [ "rapier2d", ] +[[package]] +name = "galactica-util" +version = "0.0.0" + [[package]] name = "getrandom" version = "0.2.11" diff --git a/Cargo.toml b/Cargo.toml index 6cc6848..ce79fb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ readme = "" [workspace.lints] [workspace.dependencies] -galactica-constants = { path = "crates/constants" } +galactica-util = { path = "crates/util" } galactica-content = { path = "crates/content" } galactica-render = { path = "crates/render" } galactica-systemsim = { path = "crates/systemsim" } diff --git a/crates/galactica/Cargo.toml b/crates/galactica/Cargo.toml index bc1cc8b..27c65e7 100644 --- a/crates/galactica/Cargo.toml +++ b/crates/galactica/Cargo.toml @@ -23,7 +23,7 @@ workspace = true [dependencies] galactica-content = { workspace = true } galactica-render = { workspace = true } -galactica-constants = { workspace = true } +galactica-util = { workspace = true } galactica-systemsim = { workspace = true } galactica-galaxy = { workspace = true } diff --git a/crates/galactica/src/game.rs b/crates/galactica/src/game.rs index 7829fca..0b01177 100644 --- a/crates/galactica/src/game.rs +++ b/crates/galactica/src/game.rs @@ -1,12 +1,14 @@ use galactica_content::{Content, FactionHandle, OutfitHandle, ShipHandle, SystemHandle}; use galactica_galaxy::{ship::ShipPersonality, Galaxy, GxShipHandle}; +use galactica_util::{ + constants::{ZOOM_MAX, ZOOM_MIN}, + timing::Timing, +}; use std::time::Instant; use winit::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode}; use crate::camera::Camera; use crate::inputstatus::InputStatus; - -use galactica_constants; use galactica_render::RenderInput; use galactica_systemsim::{objects::ShipControls, util, ParticleBuilder, StepResources, SystemSim}; @@ -24,6 +26,7 @@ pub struct Game { systemsim: SystemSim, new_particles: Vec, + timing: Timing, } impl Game { @@ -86,6 +89,7 @@ impl Game { galaxy, content: ct, new_particles: Vec::new(), + timing: Timing::new(), } } @@ -117,8 +121,11 @@ impl Game { pub fn update(&mut self) { let t: f32 = self.last_update.elapsed().as_secs_f32() * self.time_scale; + self.timing.start(); self.galaxy.step(t); + self.timing.mark_galaxy(); + self.timing.start(); self.systemsim.step(StepResources { player: self.player, player_controls: ShipControls { @@ -132,10 +139,10 @@ impl Game { particles: &mut self.new_particles, t, }); + self.timing.mark_physics(); if self.input.v_scroll != 0.0 { - self.camera.zoom = (self.camera.zoom + self.input.v_scroll) - .clamp(galactica_constants::ZOOM_MIN, galactica_constants::ZOOM_MAX); + self.camera.zoom = (self.camera.zoom + self.input.v_scroll).clamp(ZOOM_MIN, ZOOM_MAX); self.input.v_scroll = 0.0; } @@ -159,6 +166,7 @@ impl Game { player_data: self.player, data: &self.galaxy, current_system: SystemHandle { index: 0 }, + timing: &self.timing, } } } diff --git a/crates/galactica/src/main.rs b/crates/galactica/src/main.rs index dffee97..22ba264 100644 --- a/crates/galactica/src/main.rs +++ b/crates/galactica/src/main.rs @@ -3,8 +3,8 @@ mod game; mod inputstatus; use anyhow::{bail, Result}; -use galactica_constants::{ASSET_CACHE, CONTENT_ROOT, IMAGE_ROOT, STARFIELD_SPRITE_NAME}; use galactica_content::Content; +use galactica_util::constants::{ASSET_CACHE, CONTENT_ROOT, IMAGE_ROOT, STARFIELD_SPRITE_NAME}; use std::{ fs, path::{Path, PathBuf}, diff --git a/crates/packer/Cargo.toml b/crates/packer/Cargo.toml index 0462360..84826a6 100644 --- a/crates/packer/Cargo.toml +++ b/crates/packer/Cargo.toml @@ -21,7 +21,7 @@ readme = { workspace = true } workspace = true [dependencies] -galactica-constants = { workspace = true } +galactica-util = { workspace = true } image = { workspace = true } toml = { workspace = true } diff --git a/crates/render/Cargo.toml b/crates/render/Cargo.toml index e2220d4..fe0d241 100644 --- a/crates/render/Cargo.toml +++ b/crates/render/Cargo.toml @@ -18,7 +18,7 @@ workspace = true [dependencies] galactica-content = { workspace = true } -galactica-constants = { workspace = true } +galactica-util = { workspace = true } galactica-packer = { workspace = true } galactica-systemsim = { workspace = true } galactica-galaxy = { workspace = true } diff --git a/crates/render/src/datastructs.rs b/crates/render/src/datastructs.rs index 959051a..a72ba02 100644 --- a/crates/render/src/datastructs.rs +++ b/crates/render/src/datastructs.rs @@ -2,7 +2,8 @@ use cgmath::Point2; use galactica_content::{Content, SystemHandle}; use galactica_galaxy::{Galaxy, GxShipHandle}; use galactica_systemsim::{ParticleBuilder, SystemSim}; -use glyphon::{Buffer, FontSystem, SwashCache, TextAtlas, TextRenderer}; +use galactica_util::timing::Timing; +use glyphon::{FontSystem, SwashCache, TextAtlas, TextRenderer}; use std::rc::Rc; use wgpu::BufferAddress; use winit::window::Window; @@ -38,6 +39,9 @@ pub struct RenderInput<'a> { /// Particles to spawn during this frame pub particles: &'a mut Vec, + + /// Time we spent in each part of the game loop + pub timing: &'a Timing, } /// Renderer state. A reference to this struct is often passed to helper functions. @@ -54,7 +58,6 @@ pub(crate) struct RenderState { pub text_cache: SwashCache, pub text_atlas: TextAtlas, pub text_renderer: TextRenderer, - pub text_buffer: Buffer, } /// Vertex buffers diff --git a/crates/render/src/globaluniform/atlas.rs b/crates/render/src/globaluniform/atlas.rs index 2f8edbf..c099d8e 100644 --- a/crates/render/src/globaluniform/atlas.rs +++ b/crates/render/src/globaluniform/atlas.rs @@ -1,5 +1,5 @@ use bytemuck::{Pod, Zeroable}; -use galactica_constants::IMAGE_LIMIT; +use galactica_util::constants::IMAGE_LIMIT; use std::mem; use wgpu; diff --git a/crates/render/src/globaluniform/globaluniform.rs b/crates/render/src/globaluniform/globaluniform.rs index aff5a78..dc6122e 100644 --- a/crates/render/src/globaluniform/globaluniform.rs +++ b/crates/render/src/globaluniform/globaluniform.rs @@ -1,4 +1,4 @@ -use galactica_constants::{IMAGE_LIMIT, OBJECT_SPRITE_INSTANCE_LIMIT, SPRITE_LIMIT}; +use galactica_util::constants::{IMAGE_LIMIT, OBJECT_SPRITE_INSTANCE_LIMIT, SPRITE_LIMIT}; use wgpu; use super::{object::ObjectLocationArray, AtlasArray, GlobalDataContent, SpriteDataArray}; diff --git a/crates/render/src/globaluniform/object.rs b/crates/render/src/globaluniform/object.rs index c99a23a..61fb748 100644 --- a/crates/render/src/globaluniform/object.rs +++ b/crates/render/src/globaluniform/object.rs @@ -1,5 +1,5 @@ use bytemuck::{Pod, Zeroable}; -use galactica_constants::OBJECT_SPRITE_INSTANCE_LIMIT; +use galactica_util::constants::OBJECT_SPRITE_INSTANCE_LIMIT; use std::mem; use wgpu; diff --git a/crates/render/src/globaluniform/sprite.rs b/crates/render/src/globaluniform/sprite.rs index 43299a4..7e04aed 100644 --- a/crates/render/src/globaluniform/sprite.rs +++ b/crates/render/src/globaluniform/sprite.rs @@ -1,5 +1,5 @@ use bytemuck::{Pod, Zeroable}; -use galactica_constants::SPRITE_LIMIT; +use galactica_util::constants::SPRITE_LIMIT; use std::mem; use wgpu; diff --git a/crates/render/src/gpustate/new.rs b/crates/render/src/gpustate/new.rs index 73e67e0..64adb17 100644 --- a/crates/render/src/gpustate/new.rs +++ b/crates/render/src/gpustate/new.rs @@ -1,8 +1,10 @@ use anyhow::Result; use galactica_content::Content; -use glyphon::{ - Attrs, Buffer, Family, FontSystem, Metrics, Shaping, SwashCache, TextAtlas, TextRenderer, +use galactica_util::constants::{ + OBJECT_SPRITE_INSTANCE_LIMIT, PARTICLE_SPRITE_INSTANCE_LIMIT, STARFIELD_SPRITE_INSTANCE_LIMIT, + UI_SPRITE_INSTANCE_LIMIT, }; +use glyphon::{FontSystem, SwashCache, TextAtlas, TextRenderer}; use std::rc::Rc; use crate::{ @@ -100,7 +102,7 @@ impl GPUState { &device, Some(SPRITE_VERTICES), Some(SPRITE_INDICES), - galactica_constants::OBJECT_SPRITE_INSTANCE_LIMIT, + OBJECT_SPRITE_INSTANCE_LIMIT, )), starfield: Rc::new(VertexBuffer::new::( @@ -108,7 +110,7 @@ impl GPUState { &device, Some(SPRITE_VERTICES), Some(SPRITE_INDICES), - galactica_constants::STARFIELD_SPRITE_INSTANCE_LIMIT, + STARFIELD_SPRITE_INSTANCE_LIMIT, )), ui: Rc::new(VertexBuffer::new::( @@ -116,7 +118,7 @@ impl GPUState { &device, Some(SPRITE_VERTICES), Some(SPRITE_INDICES), - galactica_constants::UI_SPRITE_INSTANCE_LIMIT, + UI_SPRITE_INSTANCE_LIMIT, )), particle: Rc::new(VertexBuffer::new::( @@ -124,7 +126,7 @@ impl GPUState { &device, Some(SPRITE_VERTICES), Some(SPRITE_INDICES), - galactica_constants::PARTICLE_SPRITE_INSTANCE_LIMIT, + PARTICLE_SPRITE_INSTANCE_LIMIT, )), radialbar: Rc::new(VertexBuffer::new::( @@ -148,7 +150,7 @@ impl GPUState { // Text renderer let mut text_atlas = TextAtlas::new(&device, &queue, wgpu::TextureFormat::Bgra8UnormSrgb); - let mut text_font_system = FontSystem::new(); + let text_font_system = FontSystem::new(); let text_cache = SwashCache::new(); let text_renderer = TextRenderer::new( @@ -157,18 +159,6 @@ impl GPUState { wgpu::MultisampleState::default(), None, ); - let text_buffer = { - let mut buffer = Buffer::new(&mut text_font_system, Metrics::new(30.0, 42.0)); - - buffer.set_size( - &mut text_font_system, - window_size.width as f32, - window_size.height as f32, - ); - buffer.set_text(&mut text_font_system, "Hello world! 👋\nThis is rendered with 🦅 glyphon 🦁\nThe text below should be partially clipped.\na b c d e f g h i j k l m n o p q r s t u v w x y z", Attrs::new().family(Family::SansSerif), Shaping::Advanced); - buffer.shape_until_scroll(&mut text_font_system); - buffer - }; // Create render pipelines let object_pipeline = PipelineBuilder::new("object", &device) @@ -250,25 +240,24 @@ impl GPUState { let mut starfield = Starfield::new(); starfield.regenerate(); + let mut state = RenderState { + queue, + + window, + window_size, + window_aspect, + global_uniform, + + vertex_buffers, + + text_atlas, + text_cache, + text_font_system, + text_renderer, + }; + return Ok(Self { - state: RenderState { - queue, - - window, - window_size, - window_aspect, - global_uniform, - - vertex_buffers, - - text_atlas, - text_buffer, - text_cache, - text_font_system, - text_renderer, - }, - - ui: UiManager::new(), + ui: UiManager::new(&mut state), device, config, surface, @@ -279,6 +268,8 @@ impl GPUState { ui_pipeline, particle_pipeline, radialbar_pipeline, + + state, }); } } diff --git a/crates/render/src/gpustate/render.rs b/crates/render/src/gpustate/render.rs index 00ae193..2ebd2d1 100644 --- a/crates/render/src/gpustate/render.rs +++ b/crates/render/src/gpustate/render.rs @@ -1,9 +1,11 @@ use anyhow::Result; use bytemuck; use cgmath::Point2; -use galactica_constants; - -use glyphon::{Color, Resolution, TextArea, TextBounds}; +use galactica_util::constants::{ + PARTICLE_SPRITE_INSTANCE_LIMIT, STARFIELD_SIZE, STARFIELD_SIZE_MAX, STARFIELD_SIZE_MIN, + ZOOM_MAX, ZOOM_MIN, +}; +use glyphon::Resolution; use rand::seq::SliceRandom; use std::iter; use wgpu; @@ -63,7 +65,7 @@ impl super::GPUState { bytemuck::cast_slice(&[GlobalDataContent { camera_position: input.camera_pos.into(), camera_zoom: [input.camera_zoom, 0.0], - camera_zoom_limits: [galactica_constants::ZOOM_MIN, galactica_constants::ZOOM_MAX], + camera_zoom_limits: [ZOOM_MIN, ZOOM_MAX], window_size: [ self.state.window_size.width as f32, self.state.window_size.height as f32, @@ -71,11 +73,8 @@ impl super::GPUState { window_scale: [self.state.window.scale_factor() as f32, 0.0], window_aspect: [self.state.window_aspect, 0.0], starfield_sprite: [s.get_index(), 0], - starfield_tile_size: [galactica_constants::STARFIELD_SIZE as f32, 0.0], - starfield_size_limits: [ - galactica_constants::STARFIELD_SIZE_MIN, - galactica_constants::STARFIELD_SIZE_MAX, - ], + starfield_tile_size: [STARFIELD_SIZE as f32, 0.0], + starfield_size_limits: [STARFIELD_SIZE_MIN, STARFIELD_SIZE_MAX], current_time: [input.current_time, 0.0], }]), ); @@ -99,9 +98,7 @@ impl super::GPUState { }]), ); self.state.vertex_buffers.particle_counter += 1; - if self.state.vertex_buffers.particle_counter - == galactica_constants::PARTICLE_SPRITE_INSTANCE_LIMIT - { + if self.state.vertex_buffers.particle_counter == PARTICLE_SPRITE_INSTANCE_LIMIT { self.state.vertex_buffers.particle_counter = 0; } } @@ -164,7 +161,7 @@ impl super::GPUState { render_pass.draw_indexed( 0..SPRITE_INDICES.len() as u32, 0, - 0..galactica_constants::PARTICLE_SPRITE_INSTANCE_LIMIT as _, + 0..PARTICLE_SPRITE_INSTANCE_LIMIT as _, ); // Ui pipeline @@ -200,19 +197,7 @@ impl super::GPUState { width: self.state.window_size.width, height: self.state.window_size.height, }, - [TextArea { - buffer: &self.state.text_buffer, - left: 10.0, - top: 10.0, - scale: 1.0, - bounds: TextBounds { - left: 0, - top: 0, - right: 600, - bottom: 160, - }, - default_color: Color::rgb(255, 255, 255), - }], + self.ui.get_textareas(), &mut self.state.text_cache, ) .unwrap(); diff --git a/crates/render/src/gpustate/systemsim.rs b/crates/render/src/gpustate/systemsim.rs index a01a247..97e94d0 100644 --- a/crates/render/src/gpustate/systemsim.rs +++ b/crates/render/src/gpustate/systemsim.rs @@ -3,6 +3,7 @@ use bytemuck; use cgmath::{EuclideanSpace, InnerSpace, Point2, Vector2}; use galactica_systemsim::util; +use galactica_util::constants::OBJECT_SPRITE_INSTANCE_LIMIT; use crate::{ globaluniform::ObjectData, @@ -63,9 +64,7 @@ impl GPUState { ); // Enforce buffer limit - if self.state.vertex_buffers.object_counter as u64 - > galactica_constants::OBJECT_SPRITE_INSTANCE_LIMIT - { + if self.state.vertex_buffers.object_counter as u64 > OBJECT_SPRITE_INSTANCE_LIMIT { // TODO: no panic, handle this better. panic!("Sprite limit exceeded!") } @@ -109,7 +108,7 @@ impl GPUState { // Enforce buffer limit if self.state.vertex_buffers.object_counter as u64 - > galactica_constants::OBJECT_SPRITE_INSTANCE_LIMIT + > OBJECT_SPRITE_INSTANCE_LIMIT { // TODO: no panic, handle this better. panic!("Sprite limit exceeded!") @@ -181,9 +180,7 @@ impl GPUState { ); // Enforce buffer limit - if self.state.vertex_buffers.object_counter as u64 - > galactica_constants::OBJECT_SPRITE_INSTANCE_LIMIT - { + if self.state.vertex_buffers.object_counter as u64 > OBJECT_SPRITE_INSTANCE_LIMIT { // TODO: no panic, handle this better. panic!("Sprite limit exceeded!") } @@ -251,9 +248,7 @@ impl GPUState { ); // Enforce buffer limit - if self.state.vertex_buffers.object_counter as u64 - > galactica_constants::OBJECT_SPRITE_INSTANCE_LIMIT - { + if self.state.vertex_buffers.object_counter as u64 > OBJECT_SPRITE_INSTANCE_LIMIT { // TODO: no panic, handle this better. panic!("Sprite limit exceeded!") } diff --git a/crates/render/src/starfield.rs b/crates/render/src/starfield.rs index a762fd4..6ae7c7d 100644 --- a/crates/render/src/starfield.rs +++ b/crates/render/src/starfield.rs @@ -1,5 +1,8 @@ use cgmath::{Point2, Point3, Vector2, Vector3}; -use galactica_constants; +use galactica_util::constants::{ + STARFIELD_COUNT, STARFIELD_SIZE, STARFIELD_SIZE_MAX, STARFIELD_SIZE_MIN, + STARFIELD_SPRITE_INSTANCE_LIMIT, STARFIELD_Z_MAX, STARFIELD_Z_MIN, ZOOM_MAX, +}; use rand::{self, Rng}; use crate::vertexbuffer::types::StarfieldInstance; @@ -34,20 +37,15 @@ impl Starfield { pub fn regenerate(&mut self) { // TODO: save seed in system, regenerate on jump let mut rng = rand::thread_rng(); - let sz = galactica_constants::STARFIELD_SIZE as f32 / 2.0; - self.stars = (0..galactica_constants::STARFIELD_COUNT) + let sz = STARFIELD_SIZE as f32 / 2.0; + self.stars = (0..STARFIELD_COUNT) .map(|_| StarfieldStar { pos: Point3 { x: rng.gen_range(-sz..=sz), y: rng.gen_range(-sz..=sz), - z: rng.gen_range( - galactica_constants::STARFIELD_Z_MIN..galactica_constants::STARFIELD_Z_MAX, - ), + z: rng.gen_range(STARFIELD_Z_MIN..STARFIELD_Z_MAX), }, - size: rng.gen_range( - galactica_constants::STARFIELD_SIZE_MIN - ..galactica_constants::STARFIELD_SIZE_MAX, - ), + size: rng.gen_range(STARFIELD_SIZE_MIN..STARFIELD_SIZE_MAX), tint: Vector2 { x: rng.gen_range(0.0..=1.0), y: rng.gen_range(0.0..=1.0), @@ -57,17 +55,17 @@ impl Starfield { } pub fn make_instances(&mut self, aspect: f32) -> Vec { - let sz = galactica_constants::STARFIELD_SIZE as f32; + let sz = STARFIELD_SIZE as f32; // Compute window size in starfield tiles let mut nw_tile: Point2 = { // Game coordinates (relative to camera) of nw corner of screen. - let clip_nw = Point2::from((aspect, 1.0)) * galactica_constants::ZOOM_MAX; + let clip_nw = Point2::from((aspect, 1.0)) * ZOOM_MAX; // Parallax correction. // Also, adjust v for mod to work properly // (v is centered at 0) - let v: Point2 = clip_nw * galactica_constants::STARFIELD_Z_MIN; + let v: Point2 = clip_nw * STARFIELD_Z_MIN; let v_adj: Point2 = (v.x + (sz / 2.0), v.y + (sz / 2.0)).into(); #[rustfmt::skip] @@ -91,10 +89,8 @@ impl Starfield { // Truncate tile grid to buffer size // (The window won't be full of stars if our instance limit is too small) - while ((nw_tile.x * 2 + 1) - * (nw_tile.y * 2 + 1) - * galactica_constants::STARFIELD_COUNT as i32) - > galactica_constants::STARFIELD_SPRITE_INSTANCE_LIMIT as i32 + while ((nw_tile.x * 2 + 1) * (nw_tile.y * 2 + 1) * STARFIELD_COUNT as i32) + > STARFIELD_SPRITE_INSTANCE_LIMIT as i32 { nw_tile -= Vector2::from((1, 1)); } @@ -119,7 +115,7 @@ impl Starfield { } // Enforce starfield limit - if instances.len() as u64 > galactica_constants::STARFIELD_SPRITE_INSTANCE_LIMIT { + if instances.len() as u64 > STARFIELD_SPRITE_INSTANCE_LIMIT { unreachable!("Starfield limit exceeded!") } self.instance_count = instances.len() as u32; diff --git a/crates/render/src/texturearray.rs b/crates/render/src/texturearray.rs index f239ea4..4c8bfba 100644 --- a/crates/render/src/texturearray.rs +++ b/crates/render/src/texturearray.rs @@ -1,9 +1,9 @@ use crate::globaluniform::{AtlasArray, AtlasImageLocation, SpriteData, SpriteDataArray}; use anyhow::Result; use bytemuck::Zeroable; -use galactica_constants::ASSET_CACHE; use galactica_content::Content; use galactica_packer::SpriteAtlasImage; +use galactica_util::constants::ASSET_CACHE; use image::GenericImageView; use std::{fs::File, io::Read, num::NonZeroU32, path::Path}; use wgpu::BindGroupLayout; diff --git a/crates/render/src/ui/fpsindicator.rs b/crates/render/src/ui/fpsindicator.rs new file mode 100644 index 0000000..3d78f2c --- /dev/null +++ b/crates/render/src/ui/fpsindicator.rs @@ -0,0 +1,68 @@ +use glyphon::{Attrs, Buffer, Color, Family, Metrics, Shaping, TextArea, TextBounds}; +use std::time::Instant; + +use crate::{datastructs::RenderState, RenderInput}; + +pub(super) struct FpsIndicator { + buffer: Buffer, + last_update: Instant, + update_counter: u32, +} + +impl FpsIndicator { + pub fn new(state: &mut RenderState) -> Self { + let mut buffer = Buffer::new(&mut state.text_font_system, Metrics::new(12.0, 20.0)); + buffer.set_size( + &mut state.text_font_system, + state.window_size.width as f32, + state.window_size.height as f32, + ); + buffer.shape_until_scroll(&mut state.text_font_system); + + Self { + buffer, + last_update: Instant::now(), + update_counter: 0, + } + } +} + +impl FpsIndicator { + pub fn update(&mut self, input: &RenderInput, state: &mut RenderState) { + // Update once every n frames + if self.update_counter > 0 { + self.update_counter -= 1; + return; + } + self.update_counter = 100; + + self.buffer.set_text( + &mut state.text_font_system, + &format!( + "Game: {:.02?}\nPhys: {:.02?}\nRender: {:.02?}", + 1.0 / input.timing.galaxy, + 1.0 / input.timing.physics, + 1.0 / (self.last_update.elapsed().as_secs_f32() / 100.0) + ), + Attrs::new().family(Family::SansSerif), + Shaping::Basic, + ); + self.last_update = Instant::now(); + } + + pub fn get_textarea(&self) -> TextArea { + TextArea { + buffer: &self.buffer, + left: 10.0, + top: 400.0, + scale: 1.0, + bounds: TextBounds { + left: 10, + top: 400, + right: 300, + bottom: 800, + }, + default_color: Color::rgb(255, 255, 255), + } + } +} diff --git a/crates/render/src/ui/manager.rs b/crates/render/src/ui/manager.rs index 7b78515..6ed0c87 100644 --- a/crates/render/src/ui/manager.rs +++ b/crates/render/src/ui/manager.rs @@ -1,17 +1,21 @@ +use glyphon::TextArea; + use crate::{datastructs::RenderState, RenderInput}; -use super::{radar::Radar, status::Status, UiElement}; +use super::{fpsindicator::FpsIndicator, radar::Radar, status::Status}; pub struct UiManager { radar: Radar, status: Status, + fps: FpsIndicator, } impl UiManager { - pub fn new() -> Self { + pub fn new(state: &mut RenderState) -> Self { Self { radar: Radar::new(), status: Status::new(), + fps: FpsIndicator::new(state), } } @@ -19,5 +23,10 @@ impl UiManager { pub fn draw(&mut self, input: &RenderInput, state: &mut RenderState) { self.radar.draw(input, state); self.status.draw(input, state); + self.fps.update(input, state); + } + + pub fn get_textareas(&self) -> impl Iterator { + (0..1).map(|_| self.fps.get_textarea()) } } diff --git a/crates/render/src/ui/mod.rs b/crates/render/src/ui/mod.rs index 0cd403e..2d7f597 100644 --- a/crates/render/src/ui/mod.rs +++ b/crates/render/src/ui/mod.rs @@ -1,11 +1,6 @@ -use crate::{datastructs::RenderState, RenderInput}; - +mod fpsindicator; mod manager; mod radar; mod status; pub use manager::UiManager; - -trait UiElement { - fn draw(&mut self, input: &RenderInput, state: &mut RenderState); -} diff --git a/crates/render/src/ui/radar.rs b/crates/render/src/ui/radar.rs index 41dd239..69bcfdd 100644 --- a/crates/render/src/ui/radar.rs +++ b/crates/render/src/ui/radar.rs @@ -1,13 +1,13 @@ use cgmath::{Deg, InnerSpace, Point2, Rad, Vector2}; use galactica_systemsim::util; +use galactica_util::constants::UI_SPRITE_INSTANCE_LIMIT; use crate::{ + datastructs::RenderState, vertexbuffer::{types::UiInstance, BufferObject}, PositionAnchor, RenderInput, }; -use super::RenderState; - pub(super) struct Radar {} impl Radar { @@ -16,8 +16,8 @@ impl Radar { } } -impl super::UiElement for Radar { - fn draw(&mut self, input: &RenderInput, state: &mut RenderState) { +impl Radar { + pub fn draw(&mut self, input: &RenderInput, state: &mut RenderState) { let radar_range = 4000.0; let radar_size = 300.0; let hide_range = 0.85; @@ -37,7 +37,7 @@ impl super::UiElement for Radar { let arrow_sprite = input.content.get_sprite_handle("ui::centerarrow"); // Enforce buffer limit - if state.vertex_buffers.ui_counter as u64 > galactica_constants::UI_SPRITE_INSTANCE_LIMIT { + if state.vertex_buffers.ui_counter as u64 > UI_SPRITE_INSTANCE_LIMIT { // TODO: no panic, handle this better. panic!("UI limit exceeded!") } @@ -77,9 +77,7 @@ impl super::UiElement for Radar { } // Enforce buffer limit - if state.vertex_buffers.ui_counter as u64 - > galactica_constants::UI_SPRITE_INSTANCE_LIMIT - { + if state.vertex_buffers.ui_counter as u64 > UI_SPRITE_INSTANCE_LIMIT { // TODO: no panic, handle this better. panic!("UI limit exceeded!") } @@ -138,9 +136,7 @@ impl super::UiElement for Radar { // Enforce buffer limit // TODO: cleaner solution. don't do this everywhere. - if state.vertex_buffers.ui_counter as u64 - > galactica_constants::UI_SPRITE_INSTANCE_LIMIT - { + if state.vertex_buffers.ui_counter as u64 > UI_SPRITE_INSTANCE_LIMIT { // TODO: no panic, handle this better. panic!("UI limit exceeded!") } @@ -175,9 +171,7 @@ impl super::UiElement for Radar { let size = 7.0f32.min((0.8 - m) * 70.0); // Enforce buffer limit (this section adds four items) - if state.vertex_buffers.ui_counter as u64 + 4 - > galactica_constants::UI_SPRITE_INSTANCE_LIMIT - { + if state.vertex_buffers.ui_counter as u64 + 4 > UI_SPRITE_INSTANCE_LIMIT { // TODO: no panic, handle this better. panic!("UI limit exceeded!") } @@ -266,9 +260,7 @@ impl super::UiElement for Radar { y: radar_size / -2.0 - 10.0, } + ((q.normalize() * 0.865) * (radar_size / 2.0)); - if state.vertex_buffers.ui_counter as u64 - > galactica_constants::UI_SPRITE_INSTANCE_LIMIT - { + if state.vertex_buffers.ui_counter as u64 > UI_SPRITE_INSTANCE_LIMIT { // TODO: no panic, handle this better. panic!("UI limit exceeded!") } diff --git a/crates/render/src/ui/status.rs b/crates/render/src/ui/status.rs index 2fd59c2..fb41794 100644 --- a/crates/render/src/ui/status.rs +++ b/crates/render/src/ui/status.rs @@ -1,5 +1,7 @@ use std::f32::consts::TAU; +use galactica_util::constants::{RADIALBAR_SPRITE_INSTANCE_LIMIT, UI_SPRITE_INSTANCE_LIMIT}; + use crate::{ datastructs::RenderState, vertexbuffer::{ @@ -9,8 +11,6 @@ use crate::{ PositionAnchor, RenderInput, }; -use super::UiElement; - pub(super) struct Status {} impl Status { pub fn new() -> Self { @@ -18,9 +18,9 @@ impl Status { } } -impl UiElement for Status { - fn draw(&mut self, input: &RenderInput, state: &mut RenderState) { - if state.vertex_buffers.ui_counter as u64 > galactica_constants::UI_SPRITE_INSTANCE_LIMIT { +impl Status { + pub fn draw(&mut self, input: &RenderInput, state: &mut RenderState) { + if state.vertex_buffers.ui_counter as u64 > UI_SPRITE_INSTANCE_LIMIT { // TODO: no panic, handle this better. panic!("UI limit exceeded!") } @@ -51,9 +51,7 @@ impl UiElement for Status { state.vertex_buffers.ui_counter += 1; // We add two items here, so +2 - if state.vertex_buffers.radialbar_counter as u64 + 2 - > galactica_constants::RADIALBAR_SPRITE_INSTANCE_LIMIT - { + if state.vertex_buffers.radialbar_counter as u64 + 2 > RADIALBAR_SPRITE_INSTANCE_LIMIT { // TODO: no panic, handle this better. panic!("Radialbar limit exceeded!") } diff --git a/crates/constants/Cargo.toml b/crates/util/Cargo.toml similarity index 93% rename from crates/constants/Cargo.toml rename to crates/util/Cargo.toml index 3c3d188..9257ba4 100644 --- a/crates/constants/Cargo.toml +++ b/crates/util/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "galactica-constants" +name = "galactica-util" description = "Compile-time parameters for Galactica" categories = { workspace = true } keywords = { workspace = true } diff --git a/crates/constants/src/lib.rs b/crates/util/src/constants.rs similarity index 99% rename from crates/constants/src/lib.rs rename to crates/util/src/constants.rs index 3ad352b..73fc453 100644 --- a/crates/constants/src/lib.rs +++ b/crates/util/src/constants.rs @@ -1,6 +1,5 @@ -#![warn(missing_docs)] - //! Compile-time parameters + // TODO: many of these should be moved to a config file or cli option /// Minimum zoom level diff --git a/crates/util/src/lib.rs b/crates/util/src/lib.rs new file mode 100644 index 0000000..4753b11 --- /dev/null +++ b/crates/util/src/lib.rs @@ -0,0 +1,6 @@ +#![warn(missing_docs)] + +//! Various utilities + +pub mod constants; +pub mod timing; diff --git a/crates/util/src/timing.rs b/crates/util/src/timing.rs new file mode 100644 index 0000000..0531a98 --- /dev/null +++ b/crates/util/src/timing.rs @@ -0,0 +1,44 @@ +//! Keep track of the time we spent in each part of the game loop. +use std::time::Instant; + +/// Utility struct. +/// Keeps track of the time we spent in each part of the game loop. +pub struct Timing { + timer: Option, + + /// The time we spent simulating game state + pub galaxy: f32, + + /// The time we spent simulating physics + pub physics: f32, +} + +impl Timing { + /// Create a new timing struct + pub fn new() -> Self { + Self { + timer: None, + galaxy: f32::NAN, + physics: f32::NAN, + } + } + + /// Start the timer + pub fn start(&mut self) { + self.timer = Some(Instant::now()); + } + + /// Clear timer and record galaxy simulation time. + /// Assumes timer has been started + pub fn mark_galaxy(&mut self) { + self.galaxy = self.timer.unwrap().elapsed().as_secs_f32(); + self.timer = None; + } + + /// Clear timer and record physics simulation time + /// Asumes timer has been started + pub fn mark_physics(&mut self) { + self.physics = self.timer.unwrap().elapsed().as_secs_f32(); + self.timer = None; + } +}