Minor cleanup

master
Mark 2024-01-08 19:11:46 -08:00
parent 744533c05c
commit 861c1ce8e6
Signed by: Mark
GPG Key ID: C6D63995FE72FD80
4 changed files with 282 additions and 157 deletions

View File

@ -51,6 +51,10 @@ pub const OBJECT_SPRITE_INSTANCE_LIMIT: u64 = 500;
/// We can draw at most this many ui sprites on the screen.
pub const UI_SPRITE_INSTANCE_LIMIT: u64 = 100;
/// We can draw at most this many radual bars on the screen.
/// This is fairly small, since we know exactly how many of these we'll draw (for now)
pub const RADIALBAR_SPRITE_INSTANCE_LIMIT: u64 = 10;
/// The size of our circular particle buffer. When we create particles, the oldest ones are replaced.
pub const PARTICLE_SPRITE_INSTANCE_LIMIT: u64 = 1000;

View File

@ -12,7 +12,7 @@ use crate::{
};
impl GPUState {
pub(super) fn hud_add_radar(&mut self, state: &RenderState, instances: &mut Vec<UiInstance>) {
pub(super) fn hud_add_radar(&mut self, state: &RenderState) {
let radar_range = 4000.0;
let radar_size = 300.0;
let hide_range = 0.85;
@ -26,14 +26,26 @@ impl GPUState {
let ship_sprite = state.content.get_sprite_handle("ui::shipblip");
let arrow_sprite = state.content.get_sprite_handle("ui::centerarrow");
instances.push(UiInstance {
anchor: PositionAnchor::NwNw.to_int(),
position: [10.0, -10.0],
angle: 0.0,
size: radar_size,
color: [1.0, 1.0, 1.0, 1.0],
sprite_index: state.content.get_sprite_handle("ui::radar").get_index(),
});
// Enforce buffer limit
if self.vertex_buffers.ui_counter as u64 > galactica_constants::UI_SPRITE_INSTANCE_LIMIT {
// TODO: no panic, handle this better.
panic!("UI limit exceeded!")
}
// Push this object's instance
self.queue.write_buffer(
&self.vertex_buffers.ui.instances,
UiInstance::SIZE * self.vertex_buffers.ui_counter,
bytemuck::cast_slice(&[UiInstance {
anchor: PositionAnchor::NwNw.to_int(),
position: [10.0, -10.0],
angle: 0.0,
size: radar_size,
color: [1.0, 1.0, 1.0, 1.0],
sprite_index: state.content.get_sprite_handle("ui::radar").get_index(),
}]),
);
self.vertex_buffers.ui_counter += 1;
/*
// Draw system objects
@ -95,14 +107,28 @@ impl GPUState {
y: radar_size / -2.0 - 10.0,
} + (d * (radar_size / 2.0));
instances.push(UiInstance {
anchor: PositionAnchor::NwC.to_int(),
position: position.into(),
angle: -Rad::from(angle).0, // TODO: consistent angles
size,
color: f.into(),
sprite_index: ship_sprite.get_index(),
});
// Enforce buffer limit
if self.vertex_buffers.ui_counter as u64
> galactica_constants::UI_SPRITE_INSTANCE_LIMIT
{
// TODO: no panic, handle this better.
panic!("UI limit exceeded!")
}
// Push this object's instance
self.queue.write_buffer(
&self.vertex_buffers.ui.instances,
UiInstance::SIZE * self.vertex_buffers.ui_counter,
bytemuck::cast_slice(&[UiInstance {
anchor: PositionAnchor::NwC.to_int(),
position: position.into(),
angle: -Rad::from(angle).0, // TODO: consistent angles
size,
color: f.into(),
sprite_index: ship_sprite.get_index(),
}]),
);
self.vertex_buffers.ui_counter += 1;
}
}
@ -118,57 +144,85 @@ impl GPUState {
let sprite = state.content.get_sprite_handle("ui::radarframe");
let size = 7.0f32.min((0.8 - m) * 70.0);
instances.push(UiInstance {
anchor: PositionAnchor::NwNw.to_int(),
position: Point2 {
x: (radar_size / 2.0 + 10.0) - d.x,
y: (radar_size / -2.0 - 10.0) + d.y,
}
.into(),
angle: 0.0,
size,
color,
sprite_index: sprite.get_index(),
});
// Enforce buffer limit (this section adds four items)
if self.vertex_buffers.ui_counter as u64 + 4
> galactica_constants::UI_SPRITE_INSTANCE_LIMIT
{
// TODO: no panic, handle this better.
panic!("UI limit exceeded!")
}
instances.push(UiInstance {
anchor: PositionAnchor::NwSw.to_int(),
position: Point2 {
x: (radar_size / 2.0 + 10.0) - d.x,
y: (radar_size / -2.0 - 10.0) - d.y,
}
.into(),
angle: Rad::from(Deg(90.0)).0,
size,
color,
sprite_index: sprite.get_index(),
});
self.queue.write_buffer(
&self.vertex_buffers.ui.instances,
UiInstance::SIZE * self.vertex_buffers.ui_counter,
bytemuck::cast_slice(&[UiInstance {
anchor: PositionAnchor::NwNw.to_int(),
position: Point2 {
x: (radar_size / 2.0 + 10.0) - d.x,
y: (radar_size / -2.0 - 10.0) + d.y,
}
.into(),
angle: 0.0,
size,
color,
sprite_index: sprite.get_index(),
}]),
);
self.vertex_buffers.ui_counter += 1;
instances.push(UiInstance {
anchor: PositionAnchor::NwSe.to_int(),
position: Point2 {
x: (radar_size / 2.0 + 10.0) + d.x,
y: (radar_size / -2.0 - 10.0) - d.y,
}
.into(),
angle: Rad::from(Deg(180.0)).0,
size,
color,
sprite_index: sprite.get_index(),
});
self.queue.write_buffer(
&self.vertex_buffers.ui.instances,
UiInstance::SIZE * self.vertex_buffers.ui_counter,
bytemuck::cast_slice(&[UiInstance {
anchor: PositionAnchor::NwSw.to_int(),
position: Point2 {
x: (radar_size / 2.0 + 10.0) - d.x,
y: (radar_size / -2.0 - 10.0) - d.y,
}
.into(),
angle: Rad::from(Deg(90.0)).0,
size,
color,
sprite_index: sprite.get_index(),
}]),
);
self.vertex_buffers.ui_counter += 1;
instances.push(UiInstance {
anchor: PositionAnchor::NwNe.to_int(),
position: Point2 {
x: (radar_size / 2.0 + 10.0) + d.x,
y: (radar_size / -2.0 - 10.0) + d.y,
}
.into(),
angle: Rad::from(Deg(270.0)).0,
size,
color,
sprite_index: sprite.get_index(),
});
self.queue.write_buffer(
&self.vertex_buffers.ui.instances,
UiInstance::SIZE * self.vertex_buffers.ui_counter,
bytemuck::cast_slice(&[UiInstance {
anchor: PositionAnchor::NwSe.to_int(),
position: Point2 {
x: (radar_size / 2.0 + 10.0) + d.x,
y: (radar_size / -2.0 - 10.0) - d.y,
}
.into(),
angle: Rad::from(Deg(180.0)).0,
size,
color,
sprite_index: sprite.get_index(),
}]),
);
self.vertex_buffers.ui_counter += 1;
self.queue.write_buffer(
&self.vertex_buffers.ui.instances,
UiInstance::SIZE * self.vertex_buffers.ui_counter,
bytemuck::cast_slice(&[UiInstance {
anchor: PositionAnchor::NwNe.to_int(),
position: Point2 {
x: (radar_size / 2.0 + 10.0) + d.x,
y: (radar_size / -2.0 - 10.0) + d.y,
}
.into(),
angle: Rad::from(Deg(270.0)).0,
size,
color,
sprite_index: sprite.get_index(),
}]),
);
self.vertex_buffers.ui_counter += 1;
}
// Arrow to center of system
@ -182,31 +236,60 @@ impl GPUState {
y: radar_size / -2.0 - 10.0,
} + ((q.normalize() * 0.865) * (radar_size / 2.0));
instances.push(UiInstance {
anchor: PositionAnchor::NwC.to_int(),
position: position.into(),
angle: -player_angle.0,
size: 10.0,
color: [1.0, 1.0, 1.0, 1f32.min((m - 200.0) / 400.0)],
sprite_index: arrow_sprite.get_index(),
});
if self.vertex_buffers.ui_counter as u64 > galactica_constants::UI_SPRITE_INSTANCE_LIMIT
{
// TODO: no panic, handle this better.
panic!("UI limit exceeded!")
}
self.queue.write_buffer(
&self.vertex_buffers.ui.instances,
UiInstance::SIZE * self.vertex_buffers.ui_counter,
bytemuck::cast_slice(&[UiInstance {
anchor: PositionAnchor::NwC.to_int(),
position: position.into(),
angle: -player_angle.0,
size: 10.0,
color: [1.0, 1.0, 1.0, 1f32.min((m - 200.0) / 400.0)],
sprite_index: arrow_sprite.get_index(),
}]),
);
self.vertex_buffers.ui_counter += 1;
}
}
pub(super) fn hud_add_status(&mut self, state: &RenderState, instances: &mut Vec<UiInstance>) {
instances.push(UiInstance {
anchor: PositionAnchor::NeNe.to_int(),
position: [-10.0, -10.0],
angle: 0.0,
size: 200.0,
color: [1.0, 1.0, 1.0, 1.0],
sprite_index: state.content.get_sprite_handle("ui::status").get_index(),
});
pub(super) fn hud_add_status(&mut self, state: &RenderState) {
if self.vertex_buffers.ui_counter as u64 > galactica_constants::UI_SPRITE_INSTANCE_LIMIT {
// TODO: no panic, handle this better.
panic!("UI limit exceeded!")
}
self.queue.write_buffer(
&self.vertex_buffers.ui.instances,
UiInstance::SIZE * self.vertex_buffers.ui_counter,
bytemuck::cast_slice(&[UiInstance {
anchor: PositionAnchor::NeNe.to_int(),
position: [-10.0, -10.0],
angle: 0.0,
size: 200.0,
color: [1.0, 1.0, 1.0, 1.0],
sprite_index: state.content.get_sprite_handle("ui::status").get_index(),
}]),
);
self.vertex_buffers.ui_counter += 1;
// We add two items here, so +2
if self.vertex_buffers.radialbar_counter as u64 + 2
> galactica_constants::RADIALBAR_SPRITE_INSTANCE_LIMIT
{
// TODO: no panic, handle this better.
panic!("Radialbar limit exceeded!")
}
// TODO: counters for each buffer, remove arrays
self.queue.write_buffer(
&self.vertex_buffers.radialbar.instances,
RadialBarInstance::SIZE * 0,
RadialBarInstance::SIZE * self.vertex_buffers.radialbar_counter,
bytemuck::cast_slice(&[RadialBarInstance {
position: [-19.0, -19.0],
anchor: PositionAnchor::NeNe.to_int(),
@ -216,10 +299,11 @@ impl GPUState {
angle: -state.current_time / 2.0,
}]),
);
self.vertex_buffers.radialbar_counter += 1;
self.queue.write_buffer(
&self.vertex_buffers.radialbar.instances,
RadialBarInstance::SIZE * 1,
RadialBarInstance::SIZE * self.vertex_buffers.radialbar_counter,
bytemuck::cast_slice(&[RadialBarInstance {
position: [-27.0, -27.0],
anchor: PositionAnchor::NeNe.to_int(),
@ -229,5 +313,6 @@ impl GPUState {
angle: state.current_time / 5.0,
}]),
);
self.vertex_buffers.radialbar_counter += 1;
}
}

View File

@ -5,7 +5,7 @@ use galactica_constants;
use rand::seq::SliceRandom;
use std::{iter, rc::Rc};
use wgpu;
use wgpu::{self, BufferAddress};
use winit::{self, window::Window};
use crate::{
@ -58,16 +58,17 @@ pub struct GPUState {
}
struct VertexBuffers {
// Keeps track of length of each buffer
pub object_counter: BufferAddress,
pub ui_counter: BufferAddress,
pub particle_counter: BufferAddress,
pub radialbar_counter: BufferAddress,
object: Rc<VertexBuffer>,
starfield: Rc<VertexBuffer>,
ui: Rc<VertexBuffer>,
/// The index of the next particle slot we'll write to.
/// This must cycle to 0 whenever it exceeds the size
/// of the particle instance array.
particle_array_head: u64,
particle: Rc<VertexBuffer>,
radialbar: Rc<VertexBuffer>,
}
@ -171,6 +172,11 @@ impl GPUState {
}
let vertex_buffers = VertexBuffers {
object_counter: 0,
ui_counter: 0,
particle_counter: 0,
radialbar_counter: 0,
object: Rc::new(VertexBuffer::new::<TexturedVertex, ObjectInstance>(
"object",
&device,
@ -195,7 +201,6 @@ impl GPUState {
galactica_constants::UI_SPRITE_INSTANCE_LIMIT,
)),
particle_array_head: 0,
particle: Rc::new(VertexBuffer::new::<TexturedVertex, ParticleInstance>(
"particle",
&device,
@ -345,55 +350,30 @@ impl GPUState {
self.update_starfield_buffer()
}
/// Make an instance for all the game's sprites
/// (Objects and UI)
/// This will Will panic if any X_SPRITE_INSTANCE_LIMIT is exceeded.
fn update_sprite_instances(&mut self, state: &RenderState) -> (usize, usize) {
let mut object_instances: Vec<ObjectInstance> = Vec::new();
/// Entrypoint for all vertex buffer builders
pub(super) fn update_all_buffers(&mut self, state: &RenderState) {
// Game coordinates (relative to camera) of ne and sw corners of screen.
// Used to skip off-screen sprites.
let clip_ne = Point2::from((-self.window_aspect, 1.0)) * state.camera_zoom;
let clip_sw = Point2::from((self.window_aspect, -1.0)) * state.camera_zoom;
// TODO:sort. Order matters.
// TODO: sorting. We don't need to sort ships, but we do need to sort system objects by z-level
// (which we don't yet draw)
// that should probably be done in iter_system().
// Order matters, it determines what is drawn on top.
// The order inside ships and projectiles doesn't matter,
// but ships should always be under projectiles.
for s in state.world.iter_ships() {
self.world_push_ship(state, (clip_ne, clip_sw), &s, &mut object_instances);
self.world_push_ship(state, (clip_ne, clip_sw), &s);
}
for p in state.world.iter_projectiles() {
self.world_push_projectile(state, (clip_ne, clip_sw), &p, &mut object_instances);
self.world_push_projectile(state, (clip_ne, clip_sw), &p);
}
// Enforce sprite limit
if object_instances.len() as u64 > galactica_constants::OBJECT_SPRITE_INSTANCE_LIMIT {
// TODO: no panic, handle this better.
panic!("Sprite limit exceeded!")
}
self.queue.write_buffer(
&self.vertex_buffers.object.instances,
0,
bytemuck::cast_slice(&object_instances),
);
// TODO: we don't need an array, just use a counter
let mut ui_instances: Vec<UiInstance> = Vec::new();
self.hud_add_radar(state, &mut ui_instances);
self.hud_add_status(state, &mut ui_instances);
if ui_instances.len() as u64 > galactica_constants::UI_SPRITE_INSTANCE_LIMIT {
panic!("Ui sprite limit exceeded!")
}
self.queue.write_buffer(
&self.vertex_buffers.ui.instances,
0,
bytemuck::cast_slice(&ui_instances),
);
return (object_instances.len(), ui_instances.len());
self.hud_add_radar(state);
self.hud_add_status(state);
}
/// Make a StarfieldInstance for each star that needs to be drawn.
@ -457,6 +437,11 @@ impl GPUState {
timestamp_writes: None,
});
self.vertex_buffers.object_counter = 0;
self.vertex_buffers.ui_counter = 0;
self.vertex_buffers.radialbar_counter = 0;
// Don't reset particle counter, it's special
let s = state.content.get_starfield_handle();
// Update global values
@ -488,7 +473,7 @@ impl GPUState {
for i in state.particles.iter() {
self.queue.write_buffer(
&self.vertex_buffers.particle.instances,
ParticleInstance::SIZE * self.vertex_buffers.particle_array_head,
ParticleInstance::SIZE * self.vertex_buffers.particle_counter,
bytemuck::cast_slice(&[ParticleInstance {
position: [i.pos.x, i.pos.y],
velocity: i.velocity.into(),
@ -501,17 +486,17 @@ impl GPUState {
fade: i.fade,
}]),
);
self.vertex_buffers.particle_array_head += 1;
if self.vertex_buffers.particle_array_head
self.vertex_buffers.particle_counter += 1;
if self.vertex_buffers.particle_counter
== galactica_constants::PARTICLE_SPRITE_INSTANCE_LIMIT
{
self.vertex_buffers.particle_array_head = 0;
self.vertex_buffers.particle_counter = 0;
}
}
state.particles.clear();
// Create sprite instances
let (n_object, n_ui) = self.update_sprite_instances(&state);
self.update_all_buffers(&state);
// These should match the indices in each shader,
// and should each have a corresponding bind group layout.
@ -530,7 +515,11 @@ impl GPUState {
// Sprite pipeline
self.vertex_buffers.object.set_in_pass(&mut render_pass);
render_pass.set_pipeline(&self.object_pipeline);
render_pass.draw_indexed(0..SPRITE_INDICES.len() as u32, 0, 0..n_object as _);
render_pass.draw_indexed(
0..SPRITE_INDICES.len() as u32,
0,
0..self.vertex_buffers.object_counter as _,
);
// Particle pipeline
self.vertex_buffers.particle.set_in_pass(&mut render_pass);
@ -544,13 +533,21 @@ impl GPUState {
// Ui pipeline
self.vertex_buffers.ui.set_in_pass(&mut render_pass);
render_pass.set_pipeline(&self.ui_pipeline);
render_pass.draw_indexed(0..SPRITE_INDICES.len() as u32, 0, 0..n_ui as _);
render_pass.draw_indexed(
0..SPRITE_INDICES.len() as u32,
0,
0..self.vertex_buffers.ui_counter as _,
);
// Radial progress bars
// TODO: do we need to do this every time?
self.vertex_buffers.radialbar.set_in_pass(&mut render_pass);
render_pass.set_pipeline(&self.radialbar_pipeline);
render_pass.draw_indexed(0..SPRITE_INDICES.len() as u32, 0, 0..2);
render_pass.draw_indexed(
0..SPRITE_INDICES.len() as u32,
0,
0..self.vertex_buffers.radialbar_counter as _,
);
// begin_render_pass borrows encoder mutably, so we can't call finish()
// without dropping this variable.

View File

@ -8,17 +8,18 @@ use galactica_world::{
};
use crate::{
globaluniform::ObjectData, vertexbuffer::types::ObjectInstance, GPUState, RenderState,
globaluniform::ObjectData,
vertexbuffer::{types::ObjectInstance, BufferObject},
GPUState, RenderState,
};
impl GPUState {
pub(super) fn world_push_ship(
&self,
&mut self,
state: &RenderState,
// NE and SW corners of screen
screen_clip: (Point2<f32>, Point2<f32>),
s: &ShipWorldObject,
instances: &mut Vec<ObjectInstance>,
) {
let (_, r) = state.world.get_ship_body(s.physics_handle).unwrap();
let ship_pos = util::rigidbody_position(&r);
@ -47,7 +48,7 @@ impl GPUState {
return;
}
let idx = instances.len();
let idx = self.vertex_buffers.object_counter;
// Write this object's location data
self.queue.write_buffer(
&self.global_uniform.object_buffer,
@ -64,11 +65,24 @@ impl GPUState {
}]),
);
// Enforce buffer limit
if self.vertex_buffers.object_counter as u64
> galactica_constants::OBJECT_SPRITE_INSTANCE_LIMIT
{
// TODO: no panic, handle this better.
panic!("Sprite limit exceeded!")
}
// Push this object's instance
instances.push(ObjectInstance {
sprite_index: ship_cnt.sprite.get_index(),
object_index: idx as u32,
});
self.queue.write_buffer(
&self.vertex_buffers.object.instances,
ObjectInstance::SIZE * self.vertex_buffers.object_counter,
bytemuck::cast_slice(&[ObjectInstance {
sprite_index: ship_cnt.sprite.get_index(),
object_index: idx as u32,
}]),
);
self.vertex_buffers.object_counter += 1;
// Draw engine flares if necessary
if s.controls.thrust {
@ -80,7 +94,7 @@ impl GPUState {
self.queue.write_buffer(
&self.global_uniform.object_buffer,
ObjectData::SIZE * instances.len() as u64,
ObjectData::SIZE * self.vertex_buffers.object_counter as u64,
bytemuck::cast_slice(&[ObjectData {
xpos: f.pos.x,
ypos: f.pos.y - f.size / 2.0,
@ -93,21 +107,33 @@ impl GPUState {
}]),
);
instances.push(ObjectInstance {
sprite_index: flare.get_index(),
object_index: instances.len() as u32,
});
// Enforce buffer limit
if self.vertex_buffers.object_counter as u64
> galactica_constants::OBJECT_SPRITE_INSTANCE_LIMIT
{
// TODO: no panic, handle this better.
panic!("Sprite limit exceeded!")
}
self.queue.write_buffer(
&self.vertex_buffers.object.instances,
ObjectInstance::SIZE * self.vertex_buffers.object_counter,
bytemuck::cast_slice(&[ObjectInstance {
sprite_index: flare.get_index(),
object_index: self.vertex_buffers.object_counter as u32,
}]),
);
self.vertex_buffers.object_counter += 1;
}
}
}
pub(super) fn world_push_projectile(
&self,
&mut self,
state: &RenderState,
// NE and SW corners of screen
screen_clip: (Point2<f32>, Point2<f32>),
p: &ProjectileWorldObject,
instances: &mut Vec<ObjectInstance>,
) {
let r = state.world.get_rigid_body(p.rigid_body).unwrap();
let proj_pos = util::rigidbody_position(&r);
@ -136,7 +162,7 @@ impl GPUState {
return;
}
let idx = instances.len();
let idx = self.vertex_buffers.object_counter;
// Write this object's location data
self.queue.write_buffer(
&self.global_uniform.object_buffer,
@ -153,10 +179,23 @@ impl GPUState {
}]),
);
// Enforce buffer limit
if self.vertex_buffers.object_counter as u64
> galactica_constants::OBJECT_SPRITE_INSTANCE_LIMIT
{
// TODO: no panic, handle this better.
panic!("Sprite limit exceeded!")
}
// Push this object's instance
instances.push(ObjectInstance {
sprite_index: proj_cnt.sprite.get_index(),
object_index: idx as u32,
});
self.queue.write_buffer(
&self.vertex_buffers.object.instances,
ObjectInstance::SIZE * self.vertex_buffers.object_counter,
bytemuck::cast_slice(&[ObjectInstance {
sprite_index: proj_cnt.sprite.get_index(),
object_index: idx as u32,
}]),
);
self.vertex_buffers.object_counter += 1;
}
}