use galactica_content::Content; use galactica_util::constants::{ OBJECT_SPRITE_INSTANCE_LIMIT, RADIALBAR_SPRITE_INSTANCE_LIMIT, UI_SPRITE_INSTANCE_LIMIT, }; use glyphon::{FontSystem, SwashCache, TextAtlas, TextRenderer}; use std::rc::Rc; use wgpu::BufferAddress; use winit::window::Window; use crate::{ globaluniform::GlobalUniform, vertexbuffer::{ consts::{SPRITE_INDICES, SPRITE_VERTICES}, types::{ObjectInstance, RadialBarInstance, StarfieldInstance, TexturedVertex, UiInstance}, BufferObject, VertexBuffer, }, }; /// Vertex buffers pub(crate) struct VertexBuffers { // Keeps track of length of each buffer // Most of these are reset on each frame. object_counter: BufferAddress, ui_counter: BufferAddress, radialbar_counter: BufferAddress, starfield_counter: BufferAddress, starfield_limit: BufferAddress, object: Rc, starfield: Rc, ui: Rc, radialbar: Rc, } impl<'a> VertexBuffers { pub fn new(device: &wgpu::Device, ct: &Content) -> Self { Self { object_counter: 0, ui_counter: 0, radialbar_counter: 0, starfield_counter: 0, starfield_limit: ct.get_config().starfield_instance_limit, object: Rc::new(VertexBuffer::new::( "object", &device, Some(SPRITE_VERTICES), Some(SPRITE_INDICES), OBJECT_SPRITE_INSTANCE_LIMIT, )), starfield: Rc::new(VertexBuffer::new::( "starfield", &device, Some(SPRITE_VERTICES), Some(SPRITE_INDICES), ct.get_config().starfield_instance_limit, )), ui: Rc::new(VertexBuffer::new::( "ui", &device, Some(SPRITE_VERTICES), Some(SPRITE_INDICES), UI_SPRITE_INSTANCE_LIMIT, )), radialbar: Rc::new(VertexBuffer::new::( "radial bar", &device, Some(SPRITE_VERTICES), Some(SPRITE_INDICES), 10, )), } } pub fn get_ui(&'a self) -> &'a Rc { &self.ui } pub fn get_object(&'a self) -> &'a Rc { &self.object } pub fn get_radialbar(&'a self) -> &'a Rc { &self.radialbar } pub fn get_starfield(&'a self) -> &'a Rc { &self.starfield } } /// Renderer state. A reference to this struct is often passed to helper functions. pub(crate) struct RenderState { pub window: Window, pub window_size: winit::dpi::PhysicalSize, pub window_aspect: f32, pub queue: wgpu::Queue, pub global_uniform: GlobalUniform, pub vertex_buffers: VertexBuffers, pub text_font_system: FontSystem, pub text_cache: SwashCache, pub text_atlas: TextAtlas, pub text_renderer: TextRenderer, } impl RenderState { /// Prepare this state for a new frame pub fn frame_reset(&mut self) { self.vertex_buffers.object_counter = 0; self.vertex_buffers.ui_counter = 0; self.vertex_buffers.radialbar_counter = 0 } pub fn push_ui_buffer(&mut self, instance: UiInstance) { // Enforce buffer limit if self.vertex_buffers.ui_counter as u64 > 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(&[instance]), ); self.vertex_buffers.ui_counter += 1; } pub fn get_ui_counter(&self) -> u32 { self.vertex_buffers.ui_counter as u32 } pub fn push_object_buffer(&mut self, instance: ObjectInstance) { // Enforce buffer limit if self.vertex_buffers.object_counter as u64 > OBJECT_SPRITE_INSTANCE_LIMIT { // TODO: no panic, handle this better. panic!("Object limit exceeded!") } self.queue.write_buffer( &self.vertex_buffers.object.instances, ObjectInstance::SIZE * self.vertex_buffers.object_counter, bytemuck::cast_slice(&[instance]), ); self.vertex_buffers.object_counter += 1; } pub fn get_object_counter(&self) -> u32 { self.vertex_buffers.object_counter as u32 } pub fn push_radialbar_buffer(&mut self, instance: RadialBarInstance) { // Enforce buffer limit if self.vertex_buffers.radialbar_counter as u64 > RADIALBAR_SPRITE_INSTANCE_LIMIT { // TODO: no panic, handle this better. panic!("Radialbar sprite limit exceeded!") } self.queue.write_buffer( &self.vertex_buffers.radialbar.instances, RadialBarInstance::SIZE * self.vertex_buffers.radialbar_counter, bytemuck::cast_slice(&[instance]), ); self.vertex_buffers.radialbar_counter += 1; } pub fn get_radialbar_counter(&self) -> u32 { self.vertex_buffers.radialbar_counter as u32 } pub fn reset_starfield_counter(&mut self) { self.vertex_buffers.starfield_counter = 0; } pub fn push_starfield_buffer(&mut self, instance: StarfieldInstance) { // Enforce buffer limit // This should never happen, since starfield generator checks array size if self.vertex_buffers.starfield_counter as u64 > self.vertex_buffers.starfield_limit { panic!("Starfield sprite limit exceeded!") } self.queue.write_buffer( &self.vertex_buffers.starfield.instances, StarfieldInstance::SIZE * self.vertex_buffers.starfield_counter, bytemuck::cast_slice(&[instance]), ); self.vertex_buffers.starfield_counter += 1; } pub fn get_starfield_counter(&self) -> u32 { self.vertex_buffers.starfield_counter as u32 } }