use galactica_constants::{IMAGE_LIMIT, SPRITE_LIMIT}; use wgpu; use super::{AtlasContent, DataContent, SpriteContent}; pub struct GlobalUniform { pub data_buffer: wgpu::Buffer, pub atlas_buffer: wgpu::Buffer, pub sprite_buffer: wgpu::Buffer, pub bind_group: wgpu::BindGroup, pub bind_group_layout: wgpu::BindGroupLayout, pub content: DataContent, } impl GlobalUniform { pub fn shader_header(&self, group: u32) -> String { let mut out = String::new(); out.push_str(&format!("@group({group}) @binding(0)\n")); out.push_str( r#" var global: GlobalUniform; struct GlobalUniform { camera_position: vec2, camera_zoom: vec2, camera_zoom_limits: vec2, window_size: vec2, window_aspect: vec2, starfield_sprite: vec2, starfield_tile_size: vec2, starfield_size_limits: vec2, current_time: vec2, }; "#, ); out.push_str("\n"); out.push_str(&format!("@group({group}) @binding(1)\n")); out.push_str( r#" var atlas: AtlasUniform; struct ImageLocation { xpos: f32, ypos: f32, width: f32, height: f32, atlas_texture: u32, padding_a: f32, padding_b: f32, padding_c: f32, }; "#, ); out.push_str(&format!( r#" struct AtlasUniform {{ data: array, }}; "#, IMAGE_LIMIT, )); out.push_str("\n"); // TODO: document // wgpu uniforms require constant item sizes. // if you get an error like the following,check! // `Buffer is bound with size 3456 where the shader expects 5184 in group[1] compact index 2` // More notes are in datacontent out.push_str(&format!("@group({group}) @binding(2)\n")); out.push_str( r#" var sprites: SpriteUniform; struct SpriteData { frame_count: u32, repeatmode: u32, aspect: f32, fps: f32, first_frame: u32, padding_a: f32, padding_b: f32, padding_c: f32, }; "#, ); out.push_str(&format!( r#" struct SpriteUniform {{ data: array, }}; "#, SPRITE_LIMIT, )); out.push_str("\n"); return out; } pub fn new(device: &wgpu::Device) -> Self { let data_buffer = device.create_buffer(&wgpu::BufferDescriptor { label: Some("global uniform data buffer"), size: DataContent::SIZE, usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, mapped_at_creation: false, }); let atlas_buffer = device.create_buffer(&wgpu::BufferDescriptor { label: Some("global uniform atlas buffer"), size: AtlasContent::SIZE, usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, mapped_at_creation: false, }); let sprite_buffer = device.create_buffer(&wgpu::BufferDescriptor { label: Some("global uniform sprite buffer"), size: SpriteContent::SIZE, usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, mapped_at_creation: false, }); let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { entries: &[ wgpu::BindGroupLayoutEntry { binding: 0, visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, ty: wgpu::BindingType::Buffer { ty: wgpu::BufferBindingType::Uniform, has_dynamic_offset: false, min_binding_size: None, }, count: None, }, wgpu::BindGroupLayoutEntry { binding: 1, visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, ty: wgpu::BindingType::Buffer { ty: wgpu::BufferBindingType::Uniform, has_dynamic_offset: false, min_binding_size: None, }, count: None, }, wgpu::BindGroupLayoutEntry { binding: 2, visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, ty: wgpu::BindingType::Buffer { ty: wgpu::BufferBindingType::Uniform, has_dynamic_offset: false, min_binding_size: None, }, count: None, }, ], label: Some("global uniform bind group layout"), }); let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { layout: &bind_group_layout, entries: &[ wgpu::BindGroupEntry { binding: 0, resource: data_buffer.as_entire_binding(), }, wgpu::BindGroupEntry { binding: 1, resource: atlas_buffer.as_entire_binding(), }, wgpu::BindGroupEntry { binding: 2, resource: sprite_buffer.as_entire_binding(), }, ], label: Some("global uniform bind group"), }); return Self { data_buffer, atlas_buffer, sprite_buffer, bind_group, bind_group_layout, content: DataContent::default(), }; } }