Added fps counter

master
Mark 2024-01-10 18:53:19 -08:00
parent 08e9958f2d
commit be2cca79b0
Signed by: Mark
GPG Key ID: C6D63995FE72FD80
26 changed files with 239 additions and 150 deletions

14
Cargo.lock generated
View File

@ -642,20 +642,16 @@ version = "0.0.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cgmath", "cgmath",
"galactica-constants",
"galactica-content", "galactica-content",
"galactica-galaxy", "galactica-galaxy",
"galactica-render", "galactica-render",
"galactica-systemsim", "galactica-systemsim",
"galactica-util",
"pollster", "pollster",
"wgpu", "wgpu",
"winit", "winit",
] ]
[[package]]
name = "galactica-constants"
version = "0.0.0"
[[package]] [[package]]
name = "galactica-content" name = "galactica-content"
version = "0.0.0" version = "0.0.0"
@ -684,7 +680,7 @@ name = "galactica-packer"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"galactica-constants", "galactica-util",
"image", "image",
"serde", "serde",
"toml", "toml",
@ -698,11 +694,11 @@ dependencies = [
"anyhow", "anyhow",
"bytemuck", "bytemuck",
"cgmath", "cgmath",
"galactica-constants",
"galactica-content", "galactica-content",
"galactica-galaxy", "galactica-galaxy",
"galactica-packer", "galactica-packer",
"galactica-systemsim", "galactica-systemsim",
"galactica-util",
"glyphon", "glyphon",
"image", "image",
"rand", "rand",
@ -723,6 +719,10 @@ dependencies = [
"rapier2d", "rapier2d",
] ]
[[package]]
name = "galactica-util"
version = "0.0.0"
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.11" version = "0.2.11"

View File

@ -42,7 +42,7 @@ readme = ""
[workspace.lints] [workspace.lints]
[workspace.dependencies] [workspace.dependencies]
galactica-constants = { path = "crates/constants" } galactica-util = { path = "crates/util" }
galactica-content = { path = "crates/content" } galactica-content = { path = "crates/content" }
galactica-render = { path = "crates/render" } galactica-render = { path = "crates/render" }
galactica-systemsim = { path = "crates/systemsim" } galactica-systemsim = { path = "crates/systemsim" }

View File

@ -23,7 +23,7 @@ workspace = true
[dependencies] [dependencies]
galactica-content = { workspace = true } galactica-content = { workspace = true }
galactica-render = { workspace = true } galactica-render = { workspace = true }
galactica-constants = { workspace = true } galactica-util = { workspace = true }
galactica-systemsim = { workspace = true } galactica-systemsim = { workspace = true }
galactica-galaxy = { workspace = true } galactica-galaxy = { workspace = true }

View File

@ -1,12 +1,14 @@
use galactica_content::{Content, FactionHandle, OutfitHandle, ShipHandle, SystemHandle}; use galactica_content::{Content, FactionHandle, OutfitHandle, ShipHandle, SystemHandle};
use galactica_galaxy::{ship::ShipPersonality, Galaxy, GxShipHandle}; use galactica_galaxy::{ship::ShipPersonality, Galaxy, GxShipHandle};
use galactica_util::{
constants::{ZOOM_MAX, ZOOM_MIN},
timing::Timing,
};
use std::time::Instant; use std::time::Instant;
use winit::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode}; use winit::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode};
use crate::camera::Camera; use crate::camera::Camera;
use crate::inputstatus::InputStatus; use crate::inputstatus::InputStatus;
use galactica_constants;
use galactica_render::RenderInput; use galactica_render::RenderInput;
use galactica_systemsim::{objects::ShipControls, util, ParticleBuilder, StepResources, SystemSim}; use galactica_systemsim::{objects::ShipControls, util, ParticleBuilder, StepResources, SystemSim};
@ -24,6 +26,7 @@ pub struct Game {
systemsim: SystemSim, systemsim: SystemSim,
new_particles: Vec<ParticleBuilder>, new_particles: Vec<ParticleBuilder>,
timing: Timing,
} }
impl Game { impl Game {
@ -86,6 +89,7 @@ impl Game {
galaxy, galaxy,
content: ct, content: ct,
new_particles: Vec::new(), new_particles: Vec::new(),
timing: Timing::new(),
} }
} }
@ -117,8 +121,11 @@ impl Game {
pub fn update(&mut self) { pub fn update(&mut self) {
let t: f32 = self.last_update.elapsed().as_secs_f32() * self.time_scale; let t: f32 = self.last_update.elapsed().as_secs_f32() * self.time_scale;
self.timing.start();
self.galaxy.step(t); self.galaxy.step(t);
self.timing.mark_galaxy();
self.timing.start();
self.systemsim.step(StepResources { self.systemsim.step(StepResources {
player: self.player, player: self.player,
player_controls: ShipControls { player_controls: ShipControls {
@ -132,10 +139,10 @@ impl Game {
particles: &mut self.new_particles, particles: &mut self.new_particles,
t, t,
}); });
self.timing.mark_physics();
if self.input.v_scroll != 0.0 { if self.input.v_scroll != 0.0 {
self.camera.zoom = (self.camera.zoom + self.input.v_scroll) self.camera.zoom = (self.camera.zoom + self.input.v_scroll).clamp(ZOOM_MIN, ZOOM_MAX);
.clamp(galactica_constants::ZOOM_MIN, galactica_constants::ZOOM_MAX);
self.input.v_scroll = 0.0; self.input.v_scroll = 0.0;
} }
@ -159,6 +166,7 @@ impl Game {
player_data: self.player, player_data: self.player,
data: &self.galaxy, data: &self.galaxy,
current_system: SystemHandle { index: 0 }, current_system: SystemHandle { index: 0 },
timing: &self.timing,
} }
} }
} }

View File

@ -3,8 +3,8 @@ mod game;
mod inputstatus; mod inputstatus;
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use galactica_constants::{ASSET_CACHE, CONTENT_ROOT, IMAGE_ROOT, STARFIELD_SPRITE_NAME};
use galactica_content::Content; use galactica_content::Content;
use galactica_util::constants::{ASSET_CACHE, CONTENT_ROOT, IMAGE_ROOT, STARFIELD_SPRITE_NAME};
use std::{ use std::{
fs, fs,
path::{Path, PathBuf}, path::{Path, PathBuf},

View File

@ -21,7 +21,7 @@ readme = { workspace = true }
workspace = true workspace = true
[dependencies] [dependencies]
galactica-constants = { workspace = true } galactica-util = { workspace = true }
image = { workspace = true } image = { workspace = true }
toml = { workspace = true } toml = { workspace = true }

View File

@ -18,7 +18,7 @@ workspace = true
[dependencies] [dependencies]
galactica-content = { workspace = true } galactica-content = { workspace = true }
galactica-constants = { workspace = true } galactica-util = { workspace = true }
galactica-packer = { workspace = true } galactica-packer = { workspace = true }
galactica-systemsim = { workspace = true } galactica-systemsim = { workspace = true }
galactica-galaxy = { workspace = true } galactica-galaxy = { workspace = true }

View File

@ -2,7 +2,8 @@ use cgmath::Point2;
use galactica_content::{Content, SystemHandle}; use galactica_content::{Content, SystemHandle};
use galactica_galaxy::{Galaxy, GxShipHandle}; use galactica_galaxy::{Galaxy, GxShipHandle};
use galactica_systemsim::{ParticleBuilder, SystemSim}; 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 std::rc::Rc;
use wgpu::BufferAddress; use wgpu::BufferAddress;
use winit::window::Window; use winit::window::Window;
@ -38,6 +39,9 @@ pub struct RenderInput<'a> {
/// Particles to spawn during this frame /// Particles to spawn during this frame
pub particles: &'a mut Vec<ParticleBuilder>, pub particles: &'a mut Vec<ParticleBuilder>,
/// 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. /// 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_cache: SwashCache,
pub text_atlas: TextAtlas, pub text_atlas: TextAtlas,
pub text_renderer: TextRenderer, pub text_renderer: TextRenderer,
pub text_buffer: Buffer,
} }
/// Vertex buffers /// Vertex buffers

View File

@ -1,5 +1,5 @@
use bytemuck::{Pod, Zeroable}; use bytemuck::{Pod, Zeroable};
use galactica_constants::IMAGE_LIMIT; use galactica_util::constants::IMAGE_LIMIT;
use std::mem; use std::mem;
use wgpu; use wgpu;

View File

@ -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 wgpu;
use super::{object::ObjectLocationArray, AtlasArray, GlobalDataContent, SpriteDataArray}; use super::{object::ObjectLocationArray, AtlasArray, GlobalDataContent, SpriteDataArray};

View File

@ -1,5 +1,5 @@
use bytemuck::{Pod, Zeroable}; use bytemuck::{Pod, Zeroable};
use galactica_constants::OBJECT_SPRITE_INSTANCE_LIMIT; use galactica_util::constants::OBJECT_SPRITE_INSTANCE_LIMIT;
use std::mem; use std::mem;
use wgpu; use wgpu;

View File

@ -1,5 +1,5 @@
use bytemuck::{Pod, Zeroable}; use bytemuck::{Pod, Zeroable};
use galactica_constants::SPRITE_LIMIT; use galactica_util::constants::SPRITE_LIMIT;
use std::mem; use std::mem;
use wgpu; use wgpu;

View File

@ -1,8 +1,10 @@
use anyhow::Result; use anyhow::Result;
use galactica_content::Content; use galactica_content::Content;
use glyphon::{ use galactica_util::constants::{
Attrs, Buffer, Family, FontSystem, Metrics, Shaping, SwashCache, TextAtlas, TextRenderer, 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 std::rc::Rc;
use crate::{ use crate::{
@ -100,7 +102,7 @@ impl GPUState {
&device, &device,
Some(SPRITE_VERTICES), Some(SPRITE_VERTICES),
Some(SPRITE_INDICES), Some(SPRITE_INDICES),
galactica_constants::OBJECT_SPRITE_INSTANCE_LIMIT, OBJECT_SPRITE_INSTANCE_LIMIT,
)), )),
starfield: Rc::new(VertexBuffer::new::<TexturedVertex, StarfieldInstance>( starfield: Rc::new(VertexBuffer::new::<TexturedVertex, StarfieldInstance>(
@ -108,7 +110,7 @@ impl GPUState {
&device, &device,
Some(SPRITE_VERTICES), Some(SPRITE_VERTICES),
Some(SPRITE_INDICES), Some(SPRITE_INDICES),
galactica_constants::STARFIELD_SPRITE_INSTANCE_LIMIT, STARFIELD_SPRITE_INSTANCE_LIMIT,
)), )),
ui: Rc::new(VertexBuffer::new::<TexturedVertex, UiInstance>( ui: Rc::new(VertexBuffer::new::<TexturedVertex, UiInstance>(
@ -116,7 +118,7 @@ impl GPUState {
&device, &device,
Some(SPRITE_VERTICES), Some(SPRITE_VERTICES),
Some(SPRITE_INDICES), Some(SPRITE_INDICES),
galactica_constants::UI_SPRITE_INSTANCE_LIMIT, UI_SPRITE_INSTANCE_LIMIT,
)), )),
particle: Rc::new(VertexBuffer::new::<TexturedVertex, ParticleInstance>( particle: Rc::new(VertexBuffer::new::<TexturedVertex, ParticleInstance>(
@ -124,7 +126,7 @@ impl GPUState {
&device, &device,
Some(SPRITE_VERTICES), Some(SPRITE_VERTICES),
Some(SPRITE_INDICES), Some(SPRITE_INDICES),
galactica_constants::PARTICLE_SPRITE_INSTANCE_LIMIT, PARTICLE_SPRITE_INSTANCE_LIMIT,
)), )),
radialbar: Rc::new(VertexBuffer::new::<TexturedVertex, RadialBarInstance>( radialbar: Rc::new(VertexBuffer::new::<TexturedVertex, RadialBarInstance>(
@ -148,7 +150,7 @@ impl GPUState {
// Text renderer // Text renderer
let mut text_atlas = TextAtlas::new(&device, &queue, wgpu::TextureFormat::Bgra8UnormSrgb); 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_cache = SwashCache::new();
let text_renderer = TextRenderer::new( let text_renderer = TextRenderer::new(
@ -157,18 +159,6 @@ impl GPUState {
wgpu::MultisampleState::default(), wgpu::MultisampleState::default(),
None, 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 // Create render pipelines
let object_pipeline = PipelineBuilder::new("object", &device) let object_pipeline = PipelineBuilder::new("object", &device)
@ -250,8 +240,7 @@ impl GPUState {
let mut starfield = Starfield::new(); let mut starfield = Starfield::new();
starfield.regenerate(); starfield.regenerate();
return Ok(Self { let mut state = RenderState {
state: RenderState {
queue, queue,
window, window,
@ -262,13 +251,13 @@ impl GPUState {
vertex_buffers, vertex_buffers,
text_atlas, text_atlas,
text_buffer,
text_cache, text_cache,
text_font_system, text_font_system,
text_renderer, text_renderer,
}, };
ui: UiManager::new(), return Ok(Self {
ui: UiManager::new(&mut state),
device, device,
config, config,
surface, surface,
@ -279,6 +268,8 @@ impl GPUState {
ui_pipeline, ui_pipeline,
particle_pipeline, particle_pipeline,
radialbar_pipeline, radialbar_pipeline,
state,
}); });
} }
} }

View File

@ -1,9 +1,11 @@
use anyhow::Result; use anyhow::Result;
use bytemuck; use bytemuck;
use cgmath::Point2; use cgmath::Point2;
use galactica_constants; use galactica_util::constants::{
PARTICLE_SPRITE_INSTANCE_LIMIT, STARFIELD_SIZE, STARFIELD_SIZE_MAX, STARFIELD_SIZE_MIN,
use glyphon::{Color, Resolution, TextArea, TextBounds}; ZOOM_MAX, ZOOM_MIN,
};
use glyphon::Resolution;
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use std::iter; use std::iter;
use wgpu; use wgpu;
@ -63,7 +65,7 @@ impl super::GPUState {
bytemuck::cast_slice(&[GlobalDataContent { bytemuck::cast_slice(&[GlobalDataContent {
camera_position: input.camera_pos.into(), camera_position: input.camera_pos.into(),
camera_zoom: [input.camera_zoom, 0.0], 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: [ window_size: [
self.state.window_size.width as f32, self.state.window_size.width as f32,
self.state.window_size.height 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_scale: [self.state.window.scale_factor() as f32, 0.0],
window_aspect: [self.state.window_aspect, 0.0], window_aspect: [self.state.window_aspect, 0.0],
starfield_sprite: [s.get_index(), 0], starfield_sprite: [s.get_index(), 0],
starfield_tile_size: [galactica_constants::STARFIELD_SIZE as f32, 0.0], starfield_tile_size: [STARFIELD_SIZE as f32, 0.0],
starfield_size_limits: [ starfield_size_limits: [STARFIELD_SIZE_MIN, STARFIELD_SIZE_MAX],
galactica_constants::STARFIELD_SIZE_MIN,
galactica_constants::STARFIELD_SIZE_MAX,
],
current_time: [input.current_time, 0.0], current_time: [input.current_time, 0.0],
}]), }]),
); );
@ -99,9 +98,7 @@ impl super::GPUState {
}]), }]),
); );
self.state.vertex_buffers.particle_counter += 1; self.state.vertex_buffers.particle_counter += 1;
if self.state.vertex_buffers.particle_counter if self.state.vertex_buffers.particle_counter == PARTICLE_SPRITE_INSTANCE_LIMIT {
== galactica_constants::PARTICLE_SPRITE_INSTANCE_LIMIT
{
self.state.vertex_buffers.particle_counter = 0; self.state.vertex_buffers.particle_counter = 0;
} }
} }
@ -164,7 +161,7 @@ impl super::GPUState {
render_pass.draw_indexed( render_pass.draw_indexed(
0..SPRITE_INDICES.len() as u32, 0..SPRITE_INDICES.len() as u32,
0, 0,
0..galactica_constants::PARTICLE_SPRITE_INSTANCE_LIMIT as _, 0..PARTICLE_SPRITE_INSTANCE_LIMIT as _,
); );
// Ui pipeline // Ui pipeline
@ -200,19 +197,7 @@ impl super::GPUState {
width: self.state.window_size.width, width: self.state.window_size.width,
height: self.state.window_size.height, height: self.state.window_size.height,
}, },
[TextArea { self.ui.get_textareas(),
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),
}],
&mut self.state.text_cache, &mut self.state.text_cache,
) )
.unwrap(); .unwrap();

View File

@ -3,6 +3,7 @@
use bytemuck; use bytemuck;
use cgmath::{EuclideanSpace, InnerSpace, Point2, Vector2}; use cgmath::{EuclideanSpace, InnerSpace, Point2, Vector2};
use galactica_systemsim::util; use galactica_systemsim::util;
use galactica_util::constants::OBJECT_SPRITE_INSTANCE_LIMIT;
use crate::{ use crate::{
globaluniform::ObjectData, globaluniform::ObjectData,
@ -63,9 +64,7 @@ impl GPUState {
); );
// Enforce buffer limit // Enforce buffer limit
if self.state.vertex_buffers.object_counter as u64 if self.state.vertex_buffers.object_counter as u64 > OBJECT_SPRITE_INSTANCE_LIMIT {
> galactica_constants::OBJECT_SPRITE_INSTANCE_LIMIT
{
// TODO: no panic, handle this better. // TODO: no panic, handle this better.
panic!("Sprite limit exceeded!") panic!("Sprite limit exceeded!")
} }
@ -109,7 +108,7 @@ impl GPUState {
// Enforce buffer limit // Enforce buffer limit
if self.state.vertex_buffers.object_counter as u64 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. // TODO: no panic, handle this better.
panic!("Sprite limit exceeded!") panic!("Sprite limit exceeded!")
@ -181,9 +180,7 @@ impl GPUState {
); );
// Enforce buffer limit // Enforce buffer limit
if self.state.vertex_buffers.object_counter as u64 if self.state.vertex_buffers.object_counter as u64 > OBJECT_SPRITE_INSTANCE_LIMIT {
> galactica_constants::OBJECT_SPRITE_INSTANCE_LIMIT
{
// TODO: no panic, handle this better. // TODO: no panic, handle this better.
panic!("Sprite limit exceeded!") panic!("Sprite limit exceeded!")
} }
@ -251,9 +248,7 @@ impl GPUState {
); );
// Enforce buffer limit // Enforce buffer limit
if self.state.vertex_buffers.object_counter as u64 if self.state.vertex_buffers.object_counter as u64 > OBJECT_SPRITE_INSTANCE_LIMIT {
> galactica_constants::OBJECT_SPRITE_INSTANCE_LIMIT
{
// TODO: no panic, handle this better. // TODO: no panic, handle this better.
panic!("Sprite limit exceeded!") panic!("Sprite limit exceeded!")
} }

View File

@ -1,5 +1,8 @@
use cgmath::{Point2, Point3, Vector2, Vector3}; 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 rand::{self, Rng};
use crate::vertexbuffer::types::StarfieldInstance; use crate::vertexbuffer::types::StarfieldInstance;
@ -34,20 +37,15 @@ impl Starfield {
pub fn regenerate(&mut self) { pub fn regenerate(&mut self) {
// TODO: save seed in system, regenerate on jump // TODO: save seed in system, regenerate on jump
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let sz = galactica_constants::STARFIELD_SIZE as f32 / 2.0; let sz = STARFIELD_SIZE as f32 / 2.0;
self.stars = (0..galactica_constants::STARFIELD_COUNT) self.stars = (0..STARFIELD_COUNT)
.map(|_| StarfieldStar { .map(|_| StarfieldStar {
pos: Point3 { pos: Point3 {
x: rng.gen_range(-sz..=sz), x: rng.gen_range(-sz..=sz),
y: rng.gen_range(-sz..=sz), y: rng.gen_range(-sz..=sz),
z: rng.gen_range( z: rng.gen_range(STARFIELD_Z_MIN..STARFIELD_Z_MAX),
galactica_constants::STARFIELD_Z_MIN..galactica_constants::STARFIELD_Z_MAX,
),
}, },
size: rng.gen_range( size: rng.gen_range(STARFIELD_SIZE_MIN..STARFIELD_SIZE_MAX),
galactica_constants::STARFIELD_SIZE_MIN
..galactica_constants::STARFIELD_SIZE_MAX,
),
tint: Vector2 { tint: Vector2 {
x: rng.gen_range(0.0..=1.0), x: rng.gen_range(0.0..=1.0),
y: 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<StarfieldInstance> { pub fn make_instances(&mut self, aspect: f32) -> Vec<StarfieldInstance> {
let sz = galactica_constants::STARFIELD_SIZE as f32; let sz = STARFIELD_SIZE as f32;
// Compute window size in starfield tiles // Compute window size in starfield tiles
let mut nw_tile: Point2<i32> = { let mut nw_tile: Point2<i32> = {
// Game coordinates (relative to camera) of nw corner of screen. // 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. // Parallax correction.
// Also, adjust v for mod to work properly // Also, adjust v for mod to work properly
// (v is centered at 0) // (v is centered at 0)
let v: Point2<f32> = clip_nw * galactica_constants::STARFIELD_Z_MIN; let v: Point2<f32> = clip_nw * STARFIELD_Z_MIN;
let v_adj: Point2<f32> = (v.x + (sz / 2.0), v.y + (sz / 2.0)).into(); let v_adj: Point2<f32> = (v.x + (sz / 2.0), v.y + (sz / 2.0)).into();
#[rustfmt::skip] #[rustfmt::skip]
@ -91,10 +89,8 @@ impl Starfield {
// Truncate tile grid to buffer size // Truncate tile grid to buffer size
// (The window won't be full of stars if our instance limit is too small) // (The window won't be full of stars if our instance limit is too small)
while ((nw_tile.x * 2 + 1) while ((nw_tile.x * 2 + 1) * (nw_tile.y * 2 + 1) * STARFIELD_COUNT as i32)
* (nw_tile.y * 2 + 1) > STARFIELD_SPRITE_INSTANCE_LIMIT as i32
* galactica_constants::STARFIELD_COUNT as i32)
> galactica_constants::STARFIELD_SPRITE_INSTANCE_LIMIT as i32
{ {
nw_tile -= Vector2::from((1, 1)); nw_tile -= Vector2::from((1, 1));
} }
@ -119,7 +115,7 @@ impl Starfield {
} }
// Enforce starfield limit // 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!") unreachable!("Starfield limit exceeded!")
} }
self.instance_count = instances.len() as u32; self.instance_count = instances.len() as u32;

View File

@ -1,9 +1,9 @@
use crate::globaluniform::{AtlasArray, AtlasImageLocation, SpriteData, SpriteDataArray}; use crate::globaluniform::{AtlasArray, AtlasImageLocation, SpriteData, SpriteDataArray};
use anyhow::Result; use anyhow::Result;
use bytemuck::Zeroable; use bytemuck::Zeroable;
use galactica_constants::ASSET_CACHE;
use galactica_content::Content; use galactica_content::Content;
use galactica_packer::SpriteAtlasImage; use galactica_packer::SpriteAtlasImage;
use galactica_util::constants::ASSET_CACHE;
use image::GenericImageView; use image::GenericImageView;
use std::{fs::File, io::Read, num::NonZeroU32, path::Path}; use std::{fs::File, io::Read, num::NonZeroU32, path::Path};
use wgpu::BindGroupLayout; use wgpu::BindGroupLayout;

View File

@ -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),
}
}
}

View File

@ -1,17 +1,21 @@
use glyphon::TextArea;
use crate::{datastructs::RenderState, RenderInput}; use crate::{datastructs::RenderState, RenderInput};
use super::{radar::Radar, status::Status, UiElement}; use super::{fpsindicator::FpsIndicator, radar::Radar, status::Status};
pub struct UiManager { pub struct UiManager {
radar: Radar, radar: Radar,
status: Status, status: Status,
fps: FpsIndicator,
} }
impl UiManager { impl UiManager {
pub fn new() -> Self { pub fn new(state: &mut RenderState) -> Self {
Self { Self {
radar: Radar::new(), radar: Radar::new(),
status: Status::new(), status: Status::new(),
fps: FpsIndicator::new(state),
} }
} }
@ -19,5 +23,10 @@ impl UiManager {
pub fn draw(&mut self, input: &RenderInput, state: &mut RenderState) { pub fn draw(&mut self, input: &RenderInput, state: &mut RenderState) {
self.radar.draw(input, state); self.radar.draw(input, state);
self.status.draw(input, state); self.status.draw(input, state);
self.fps.update(input, state);
}
pub fn get_textareas(&self) -> impl Iterator<Item = TextArea> {
(0..1).map(|_| self.fps.get_textarea())
} }
} }

View File

@ -1,11 +1,6 @@
use crate::{datastructs::RenderState, RenderInput}; mod fpsindicator;
mod manager; mod manager;
mod radar; mod radar;
mod status; mod status;
pub use manager::UiManager; pub use manager::UiManager;
trait UiElement {
fn draw(&mut self, input: &RenderInput, state: &mut RenderState);
}

View File

@ -1,13 +1,13 @@
use cgmath::{Deg, InnerSpace, Point2, Rad, Vector2}; use cgmath::{Deg, InnerSpace, Point2, Rad, Vector2};
use galactica_systemsim::util; use galactica_systemsim::util;
use galactica_util::constants::UI_SPRITE_INSTANCE_LIMIT;
use crate::{ use crate::{
datastructs::RenderState,
vertexbuffer::{types::UiInstance, BufferObject}, vertexbuffer::{types::UiInstance, BufferObject},
PositionAnchor, RenderInput, PositionAnchor, RenderInput,
}; };
use super::RenderState;
pub(super) struct Radar {} pub(super) struct Radar {}
impl Radar { impl Radar {
@ -16,8 +16,8 @@ impl Radar {
} }
} }
impl super::UiElement for Radar { impl Radar {
fn draw(&mut self, input: &RenderInput, state: &mut RenderState) { pub fn draw(&mut self, input: &RenderInput, state: &mut RenderState) {
let radar_range = 4000.0; let radar_range = 4000.0;
let radar_size = 300.0; let radar_size = 300.0;
let hide_range = 0.85; let hide_range = 0.85;
@ -37,7 +37,7 @@ impl super::UiElement for Radar {
let arrow_sprite = input.content.get_sprite_handle("ui::centerarrow"); let arrow_sprite = input.content.get_sprite_handle("ui::centerarrow");
// Enforce buffer limit // 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. // TODO: no panic, handle this better.
panic!("UI limit exceeded!") panic!("UI limit exceeded!")
} }
@ -77,9 +77,7 @@ impl super::UiElement for Radar {
} }
// Enforce buffer limit // Enforce buffer limit
if state.vertex_buffers.ui_counter as u64 if state.vertex_buffers.ui_counter as u64 > UI_SPRITE_INSTANCE_LIMIT {
> galactica_constants::UI_SPRITE_INSTANCE_LIMIT
{
// TODO: no panic, handle this better. // TODO: no panic, handle this better.
panic!("UI limit exceeded!") panic!("UI limit exceeded!")
} }
@ -138,9 +136,7 @@ impl super::UiElement for Radar {
// Enforce buffer limit // Enforce buffer limit
// TODO: cleaner solution. don't do this everywhere. // TODO: cleaner solution. don't do this everywhere.
if state.vertex_buffers.ui_counter as u64 if state.vertex_buffers.ui_counter as u64 > UI_SPRITE_INSTANCE_LIMIT {
> galactica_constants::UI_SPRITE_INSTANCE_LIMIT
{
// TODO: no panic, handle this better. // TODO: no panic, handle this better.
panic!("UI limit exceeded!") panic!("UI limit exceeded!")
} }
@ -175,9 +171,7 @@ impl super::UiElement for Radar {
let size = 7.0f32.min((0.8 - m) * 70.0); let size = 7.0f32.min((0.8 - m) * 70.0);
// Enforce buffer limit (this section adds four items) // Enforce buffer limit (this section adds four items)
if state.vertex_buffers.ui_counter as u64 + 4 if state.vertex_buffers.ui_counter as u64 + 4 > UI_SPRITE_INSTANCE_LIMIT {
> galactica_constants::UI_SPRITE_INSTANCE_LIMIT
{
// TODO: no panic, handle this better. // TODO: no panic, handle this better.
panic!("UI limit exceeded!") panic!("UI limit exceeded!")
} }
@ -266,9 +260,7 @@ impl super::UiElement for Radar {
y: radar_size / -2.0 - 10.0, y: radar_size / -2.0 - 10.0,
} + ((q.normalize() * 0.865) * (radar_size / 2.0)); } + ((q.normalize() * 0.865) * (radar_size / 2.0));
if state.vertex_buffers.ui_counter as u64 if state.vertex_buffers.ui_counter as u64 > UI_SPRITE_INSTANCE_LIMIT {
> galactica_constants::UI_SPRITE_INSTANCE_LIMIT
{
// TODO: no panic, handle this better. // TODO: no panic, handle this better.
panic!("UI limit exceeded!") panic!("UI limit exceeded!")
} }

View File

@ -1,5 +1,7 @@
use std::f32::consts::TAU; use std::f32::consts::TAU;
use galactica_util::constants::{RADIALBAR_SPRITE_INSTANCE_LIMIT, UI_SPRITE_INSTANCE_LIMIT};
use crate::{ use crate::{
datastructs::RenderState, datastructs::RenderState,
vertexbuffer::{ vertexbuffer::{
@ -9,8 +11,6 @@ use crate::{
PositionAnchor, RenderInput, PositionAnchor, RenderInput,
}; };
use super::UiElement;
pub(super) struct Status {} pub(super) struct Status {}
impl Status { impl Status {
pub fn new() -> Self { pub fn new() -> Self {
@ -18,9 +18,9 @@ impl Status {
} }
} }
impl UiElement for Status { impl Status {
fn draw(&mut self, input: &RenderInput, state: &mut RenderState) { pub fn draw(&mut self, input: &RenderInput, state: &mut RenderState) {
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. // TODO: no panic, handle this better.
panic!("UI limit exceeded!") panic!("UI limit exceeded!")
} }
@ -51,9 +51,7 @@ impl UiElement for Status {
state.vertex_buffers.ui_counter += 1; state.vertex_buffers.ui_counter += 1;
// We add two items here, so +2 // We add two items here, so +2
if state.vertex_buffers.radialbar_counter as u64 + 2 if state.vertex_buffers.radialbar_counter as u64 + 2 > RADIALBAR_SPRITE_INSTANCE_LIMIT {
> galactica_constants::RADIALBAR_SPRITE_INSTANCE_LIMIT
{
// TODO: no panic, handle this better. // TODO: no panic, handle this better.
panic!("Radialbar limit exceeded!") panic!("Radialbar limit exceeded!")
} }

View File

@ -1,5 +1,5 @@
[package] [package]
name = "galactica-constants" name = "galactica-util"
description = "Compile-time parameters for Galactica" description = "Compile-time parameters for Galactica"
categories = { workspace = true } categories = { workspace = true }
keywords = { workspace = true } keywords = { workspace = true }

View File

@ -1,6 +1,5 @@
#![warn(missing_docs)]
//! Compile-time parameters //! Compile-time parameters
// TODO: many of these should be moved to a config file or cli option // TODO: many of these should be moved to a config file or cli option
/// Minimum zoom level /// Minimum zoom level

6
crates/util/src/lib.rs Normal file
View File

@ -0,0 +1,6 @@
#![warn(missing_docs)]
//! Various utilities
pub mod constants;
pub mod timing;

44
crates/util/src/timing.rs Normal file
View File

@ -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<Instant>,
/// 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;
}
}