diff --git a/crates/render/shaders/include/animate.wgsl b/crates/render/shaders/include/animate.wgsl deleted file mode 100644 index 73317ff..0000000 --- a/crates/render/shaders/include/animate.wgsl +++ /dev/null @@ -1,41 +0,0 @@ -// Pick a frame of a sprite animation from an instance. -fn animate(sprite_index: u32, age: f32, offset: f32) -> f32 { - - let len = global_sprites[sprite_index].frame_count; - let rep = global_sprites[sprite_index].repeatmode; - let frame_duration = global_sprites[sprite_index].frame_duration; - var frame: f32 = 0.0; - - // Once - if rep == u32(1) { - - frame = min( - age / frame_duration + offset, - f32(len) - 1.0 - ); - - // Reverse - } else if rep == u32(2) { - let x = age / frame_duration + offset; - let m = f32(len) * 2.0 - 1.0; - // x fmod m - frame = x - floor(x / m) * m; - - if frame >= f32(len) { - frame = ( - f32(len) + f32(len) - 1.0 - // Split integer and fractional part so tweening works properly - - floor(frame) - + fract(frame) - ); - } - - // Repeat (default) - } else { - let x = age / frame_duration + offset; - let m = f32(len); - frame = x - floor(x / m) * m; - } - - return frame + f32(global_sprites[sprite_index].first_frame); -} \ No newline at end of file diff --git a/crates/render/shaders/object.wgsl b/crates/render/shaders/object.wgsl index a694ebc..2969b76 100644 --- a/crates/render/shaders/object.wgsl +++ b/crates/render/shaders/object.wgsl @@ -1,8 +1,9 @@ // INCLUDE: global uniform header struct InstanceInput { - @location(2) sprite_index: u32, - @location(3) object_index: u32, + @location(2) texture_index: vec2, + @location(3) texture_fade: f32, + @location(4) object_index: u32, }; struct VertexInput { @@ -25,20 +26,19 @@ var texture_array: binding_array>; @group(0) @binding(1) var sampler_array: binding_array; - -// INCLUDE: animate.wgsl - -fn transform_vertex(obj: ObjectData, vertex_position: vec2, sprite_index: u32) -> vec4 { +fn transform_vertex(obj: ObjectData, vertex_position: vec2, texture_index: u32) -> vec4 { // Object scale var scale: f32 = obj.size / (global_data.camera_zoom.x * obj.zpos); if obj.is_child == 1u { scale /= objects[obj.parent].zpos; } + let texture = global_atlas[texture_index]; + // Apply scale and sprite aspect // Note that our mesh starts centered at (0, 0). This is important! var pos: vec2 = vec2( - vertex_position.x * scale * global_sprites[sprite_index].aspect, + vertex_position.x * scale * (texture.width / texture.height), vertex_position.y * scale ); @@ -113,18 +113,18 @@ fn vertex_main( ) -> VertexOutput { var out: VertexOutput; - - - out.position = transform_vertex(objects[instance.object_index], vertex.position.xy, instance.sprite_index); + out.position = transform_vertex( + objects[instance.object_index], + vertex.position.xy, + instance.texture_index.x + ); // Compute texture coordinates - let age = global_data.current_time.x; - let frame = animate(instance.sprite_index, age, 0.0); - out.tween = fract(frame); + out.tween = instance.texture_fade; - let t = global_atlas[u32(floor(frame))]; + let t = global_atlas[instance.texture_index.x]; out.texture_index_a = u32(t.atlas_texture); out.texture_coords_a = vec2(t.xpos, t.ypos); if vertex.texture_coords.x == 1.0 { @@ -134,7 +134,7 @@ fn vertex_main( out.texture_coords_a = out.texture_coords_a + vec2(0.0, t.height); } - let b = global_atlas[u32(floor(animate(instance.sprite_index, age, 1.0)))]; + let b = global_atlas[instance.texture_index.y]; out.texture_index_b = u32(b.atlas_texture); out.texture_coords_b = vec2(b.xpos, b.ypos); if vertex.texture_coords.x == 1.0 { diff --git a/crates/render/shaders/particle.wgsl b/crates/render/shaders/particle.wgsl index 681f1c0..ef1c84a 100644 --- a/crates/render/shaders/particle.wgsl +++ b/crates/render/shaders/particle.wgsl @@ -9,7 +9,8 @@ struct InstanceInput { @location(7) created: f32, @location(8) expires: f32, @location(9) fade: f32, - @location(10) sprite_index: u32, + @location(10) texture_index: vec2, + @location(11) texture_fade: f32, }; struct VertexInput { @@ -33,9 +34,6 @@ var texture_array: binding_array>; @group(0) @binding(1) var sampler_array: binding_array; - -// INCLUDE: animate.wgsl - @vertex fn vertex_main( vertex: VertexInput, @@ -96,9 +94,9 @@ fn vertex_main( // Compute texture coordinates let frame = animate(instance.sprite_index, age, 0.0); - out.tween = fract(frame); + out.tween = instance.texture_fade; - let t = global_atlas[u32(floor(frame))]; + let t = global_atlas[instance.texture_index.x]; out.texture_index_a = u32(t.atlas_texture); out.texture_coords_a = vec2(t.xpos, t.ypos); if vertex.texture_coords.x == 1.0 { @@ -108,7 +106,7 @@ fn vertex_main( out.texture_coords_a = out.texture_coords_a + vec2(0.0, t.height); } - let b = global_atlas[u32(floor(animate(instance.sprite_index, age, 1.0)))]; + let b = global_atlas[instance.texture_index.y]; out.texture_index_b = u32(b.atlas_texture); out.texture_coords_b = vec2(b.xpos, b.ypos); if vertex.texture_coords.x == 1.0 { @@ -118,7 +116,6 @@ fn vertex_main( out.texture_coords_b = out.texture_coords_b + vec2(0.0, b.height); } - return out; } diff --git a/crates/render/shaders/starfield.wgsl b/crates/render/shaders/starfield.wgsl index 6875389..e24b84f 100644 --- a/crates/render/shaders/starfield.wgsl +++ b/crates/render/shaders/starfield.wgsl @@ -109,8 +109,7 @@ fn vertex_main( // Starfield sprites may not be animated - let i = global_sprites[global_data.starfield_sprite.x].first_frame; - let t = global_atlas[i]; + let t = global_atlas[global_data.starfield_sprite.x]; out.texture_index = u32(t.atlas_texture); out.texture_coords = vec2(t.xpos, t.ypos); if vertex.texture_coords.x == 1.0 { diff --git a/crates/render/shaders/ui.wgsl b/crates/render/shaders/ui.wgsl index 7a71cf5..898f0aa 100644 --- a/crates/render/shaders/ui.wgsl +++ b/crates/render/shaders/ui.wgsl @@ -6,8 +6,9 @@ struct InstanceInput { @location(4) angle: f32, @location(5) size: f32, @location(6) color_transform: vec4, - @location(7) sprite_index: u32, - @location(8) mask_index: vec2, + @location(7) texture_index: vec2, + @location(8) texture_fade: f32, + @location(9) mask_index: vec2, }; struct VertexInput { @@ -30,7 +31,6 @@ var texture_array: binding_array>; var sampler_array: binding_array; -// INCLUDE: animate.wgsl // INCLUDE: anchor.wgsl @vertex @@ -42,12 +42,15 @@ fn vertex_main( let window_dim = global_data.window_size / global_data.window_scale.x; let scale = instance.size / window_dim.y; - let sprite_aspect = global_sprites[instance.sprite_index].aspect; + let aspect = ( + global_atlas[instance.texture_index.x].width / + global_atlas[instance.texture_index.x].height + ); // Apply scale and sprite aspect // Note that our mesh starts centered at (0, 0). This is important! var pos: vec2 = vec2( - vertex.position.x * scale * sprite_aspect, + vertex.position.x * scale * aspect, vertex.position.y * scale ); @@ -66,7 +69,7 @@ fn vertex_main( pos = pos + anchor( instance.anchor, instance.position, - vec2(instance.size * sprite_aspect, instance.size) + vec2(instance.size * aspect, instance.size) ); var out: VertexOutput; @@ -77,7 +80,7 @@ fn vertex_main( // TODO: function to get texture from sprite // Pick texture frame - let t = global_atlas[u32(animate(instance.sprite_index, global_data.current_time.x, 0.0))]; + let t = global_atlas[instance.texture_index.x]; out.texture_index = u32(t.atlas_texture); out.texture_coords = vec2(t.xpos, t.ypos); if vertex.texture_coords.x == 1.0 { @@ -91,8 +94,7 @@ fn vertex_main( // x coordinate of mask index is either 0 or 1, telling us whether or not to use a mask. // y coordinate is mask sprite index if instance.mask_index.x == 1u { - let ms = global_sprites[instance.mask_index.y].first_frame; - let m = global_atlas[ms]; + let m = global_atlas[instance.mask_index.y]; out.mask_index = vec2(1u, u32(m.atlas_texture)); out.mask_coords = vec2(m.xpos, m.ypos); if vertex.texture_coords.x == 1.0 { diff --git a/crates/render/src/globaluniform/globaluniform.rs b/crates/render/src/globaluniform/globaluniform.rs index dc6122e..eaedf76 100644 --- a/crates/render/src/globaluniform/globaluniform.rs +++ b/crates/render/src/globaluniform/globaluniform.rs @@ -1,12 +1,11 @@ -use galactica_util::constants::{IMAGE_LIMIT, OBJECT_SPRITE_INSTANCE_LIMIT, SPRITE_LIMIT}; +use galactica_util::constants::{IMAGE_LIMIT, OBJECT_SPRITE_INSTANCE_LIMIT}; use wgpu; -use super::{object::ObjectLocationArray, AtlasArray, GlobalDataContent, SpriteDataArray}; +use super::{object::ObjectLocationArray, AtlasArray, GlobalDataContent}; pub struct GlobalUniform { pub data_buffer: wgpu::Buffer, pub atlas_buffer: wgpu::Buffer, - pub sprite_buffer: wgpu::Buffer, pub object_buffer: wgpu::Buffer, pub bind_group: wgpu::BindGroup, pub bind_group_layout: wgpu::BindGroupLayout, @@ -70,35 +69,10 @@ impl GlobalUniform { // `Buffer is bound with size 3456 where the shader expects 5184 in group[1] compact index 2` // More notes are in datacontent - // Sprite data - out.push_str(&format!( - r#" - @group({group}) @binding(2) - var global_sprites: array; - "# - )); - out.push_str("\n"); - out.push_str( - r#" - struct SpriteData { - frame_count: u32, - repeatmode: u32, - aspect: f32, - frame_duration: f32, - first_frame: u32, - - padding_a: f32, - padding_b: f32, - padding_c: f32, - }; - "#, - ); - out.push_str("\n"); - // Object location data out.push_str(&format!( r#" - @group({group}) @binding(3) + @group({group}) @binding(2) var objects: array; "# )); @@ -138,13 +112,6 @@ impl GlobalUniform { mapped_at_creation: false, }); - let sprite_buffer = device.create_buffer(&wgpu::BufferDescriptor { - label: Some("global uniform sprite buffer"), - size: SpriteDataArray::SIZE, - usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - }); - let object_buffer = device.create_buffer(&wgpu::BufferDescriptor { label: Some("global uniform object buffer"), size: ObjectLocationArray::SIZE, @@ -184,16 +151,6 @@ impl GlobalUniform { }, count: None, }, - wgpu::BindGroupLayoutEntry { - binding: 3, - 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"), }); @@ -211,10 +168,6 @@ impl GlobalUniform { }, wgpu::BindGroupEntry { binding: 2, - resource: sprite_buffer.as_entire_binding(), - }, - wgpu::BindGroupEntry { - binding: 3, resource: object_buffer.as_entire_binding(), }, ], @@ -224,7 +177,6 @@ impl GlobalUniform { return Self { data_buffer, atlas_buffer, - sprite_buffer, object_buffer, bind_group, bind_group_layout, diff --git a/crates/render/src/globaluniform/mod.rs b/crates/render/src/globaluniform/mod.rs index 1235b6f..29ba7ef 100644 --- a/crates/render/src/globaluniform/mod.rs +++ b/crates/render/src/globaluniform/mod.rs @@ -2,10 +2,8 @@ mod atlas; mod data; mod globaluniform; mod object; -mod sprite; pub use atlas::{AtlasArray, AtlasImageLocation}; pub use data::GlobalDataContent; pub use globaluniform::GlobalUniform; pub use object::ObjectData; -pub use sprite::{SpriteData, SpriteDataArray}; diff --git a/crates/render/src/globaluniform/sprite.rs b/crates/render/src/globaluniform/sprite.rs deleted file mode 100644 index 7e04aed..0000000 --- a/crates/render/src/globaluniform/sprite.rs +++ /dev/null @@ -1,43 +0,0 @@ -use bytemuck::{Pod, Zeroable}; -use galactica_util::constants::SPRITE_LIMIT; -use std::mem; -use wgpu; - -#[repr(C)] -#[derive(Debug, Copy, Clone, Pod, Zeroable, Default)] -pub struct SpriteData { - // Animation parameters - pub frame_count: u32, - pub repeatmode: u32, - pub aspect: f32, - pub frame_duration: f32, - - // Index of first frame in ImageLocationArray - pub first_frame: u32, - // stride must be a multiple of 16 - pub _padding: [f32; 3], -} - -#[derive(Debug, Copy, Clone)] -pub struct SpriteDataArray { - pub data: [SpriteData; SPRITE_LIMIT as usize], -} - -unsafe impl Pod for SpriteDataArray {} -unsafe impl Zeroable for SpriteDataArray { - fn zeroed() -> Self { - Self { - data: [SpriteData::zeroed(); SPRITE_LIMIT as usize], - } - } -} - -impl Default for SpriteDataArray { - fn default() -> Self { - Self::zeroed() - } -} - -impl SpriteDataArray { - pub const SIZE: u64 = mem::size_of::() as wgpu::BufferAddress; -} diff --git a/crates/render/src/gpustate/mod.rs b/crates/render/src/gpustate/mod.rs index 7284b2a..deecf5d 100644 --- a/crates/render/src/gpustate/mod.rs +++ b/crates/render/src/gpustate/mod.rs @@ -20,7 +20,7 @@ pub struct GPUState { object_pipeline: wgpu::RenderPipeline, starfield_pipeline: wgpu::RenderPipeline, - particle_pipeline: wgpu::RenderPipeline, + //particle_pipeline: wgpu::RenderPipeline, ui_pipeline: wgpu::RenderPipeline, radialbar_pipeline: wgpu::RenderPipeline, @@ -57,12 +57,7 @@ impl GPUState { self.state.queue.write_buffer( &self.state.global_uniform.atlas_buffer, 0, - bytemuck::cast_slice(&[self.texture_array.image_locations]), - ); - self.state.queue.write_buffer( - &self.state.global_uniform.sprite_buffer, - 0, - bytemuck::cast_slice(&[self.texture_array.sprite_data]), + bytemuck::cast_slice(&[self.texture_array.texture_atlas]), ); self.starfield.update_buffer(ct, &mut self.state); diff --git a/crates/render/src/gpustate/new.rs b/crates/render/src/gpustate/new.rs index 4351594..c7284f4 100644 --- a/crates/render/src/gpustate/new.rs +++ b/crates/render/src/gpustate/new.rs @@ -167,6 +167,7 @@ impl GPUState { .set_bind_group_layouts(bind_group_layouts) .build(); + /* let particle_pipeline = PipelineBuilder::new("particle", &device) .set_shader(&preprocess_shader( &include_str!(concat!( @@ -181,7 +182,7 @@ impl GPUState { .set_triangle(true) .set_vertex_buffer(vertex_buffers.get_particle()) .set_bind_group_layouts(bind_group_layouts) - .build(); + .build();*/ let radialbar_pipeline = PipelineBuilder::new("radialbar", &device) .set_shader(&preprocess_shader( @@ -228,7 +229,7 @@ impl GPUState { object_pipeline, starfield_pipeline, ui_pipeline, - particle_pipeline, + //particle_pipeline, radialbar_pipeline, state, diff --git a/crates/render/src/gpustate/phys.rs b/crates/render/src/gpustate/phys.rs index dd9b3af..ccb3844 100644 --- a/crates/render/src/gpustate/phys.rs +++ b/crates/render/src/gpustate/phys.rs @@ -22,7 +22,7 @@ impl GPUState { let ship_pos; let ship_ang; let ship_cnt; - match ship.data.get_state() { + match ship.get_data().get_state() { ShipState::Dead | ShipState::Landed { .. } => continue, ShipState::Collapsing { .. } | ShipState::Flying { .. } => { @@ -31,7 +31,7 @@ impl GPUState { ship_pos = Point3::new(pos.x, pos.y, 1.0); let ship_rot = r.rotation(); ship_ang = ship_rot.angle(); - ship_cnt = state.ct.get_ship(ship.data.get_content()); + ship_cnt = state.ct.get_ship(ship.get_data().get_content()); } ShipState::UnLanding { current_z, .. } | ShipState::Landing { current_z, .. } => { @@ -40,7 +40,7 @@ impl GPUState { ship_pos = Point3::new(pos.x, pos.y, *current_z); let ship_rot = r.rotation(); ship_ang = ship_rot.angle(); - ship_cnt = state.ct.get_ship(ship.data.get_content()); + ship_cnt = state.ct.get_ship(ship.get_data().get_content()); } } @@ -84,22 +84,23 @@ impl GPUState { ); // Push this object's instance + let anim_state = ship.get_anim_state(); self.state.push_object_buffer(ObjectInstance { - sprite_index: ship_cnt.sprite.get_index(), + texture_index: anim_state.texture_index(), + texture_fade: anim_state.fade, object_index: idx as u32, }); - let flare = ship.data.get_outfits().get_flare_sprite(state.ct); if { - let is_flying = match ship.data.get_state() { + let is_flying = match ship.get_data().get_state() { ShipState::Flying { .. } | ShipState::UnLanding { .. } | ShipState::Landing { .. } => true, _ => false, }; - ship.get_controls().thrust && flare.is_some() && is_flying + ship.get_controls().thrust && is_flying } { - for engine_point in &ship_cnt.engines { + for (engine_point, anim) in ship.iter_engine_anim() { self.state.queue.write_buffer( &self.state.global_uniform.object_buffer, ObjectData::SIZE * self.state.get_object_counter() as u64, @@ -122,8 +123,10 @@ impl GPUState { }]), ); + let anim_state = anim.get_texture_idx(); self.state.push_object_buffer(ObjectInstance { - sprite_index: flare.unwrap().get_index(), + texture_index: anim_state.texture_index(), + texture_fade: anim_state.fade, object_index: self.state.get_object_counter() as u32, }); } @@ -182,9 +185,10 @@ impl GPUState { }]), ); - // Push this object's instance + let anim_state = p.get_anim_state(); self.state.push_object_buffer(ObjectInstance { - sprite_index: proj_cnt.sprite.get_index(), + texture_index: anim_state.texture_index(), + texture_fade: anim_state.fade, object_index: idx as u32, }); } @@ -235,9 +239,13 @@ impl GPUState { }]), ); + let sprite = state.ct.get_sprite(o.sprite); + let texture_a = sprite.get_section(sprite.default_section).frames[0]; // ANIMATE + // Push this object's instance self.state.push_object_buffer(ObjectInstance { - sprite_index: o.sprite.get_index(), + texture_index: [texture_a, texture_a], + texture_fade: 1.0, object_index: idx as u32, }); } diff --git a/crates/render/src/gpustate/render.rs b/crates/render/src/gpustate/render.rs index e34b1b5..40f7edc 100644 --- a/crates/render/src/gpustate/render.rs +++ b/crates/render/src/gpustate/render.rs @@ -1,5 +1,6 @@ use anyhow::Result; use bytemuck; +use galactica_system::{data::ShipState, phys::PhysSimShipHandle}; use galactica_util::constants::PARTICLE_SPRITE_INSTANCE_LIMIT; use glyphon::Resolution; use nalgebra::Point2; @@ -12,9 +13,9 @@ use crate::{ RenderInput, }; -impl super::GPUState { - /// Main render function. Draws sprites on a window. - pub fn render(&mut self, input: RenderInput) -> Result<(), wgpu::SurfaceError> { +impl<'a> super::GPUState { + /// Render routines while player is flying + fn render_flying(&'a mut self, input: &RenderInput) -> Result<()> { let output = self.surface.get_current_texture()?; let view = output.texture.create_view(&Default::default()); @@ -45,45 +46,19 @@ impl super::GPUState { timestamp_writes: None, }); - self.state.frame_reset(); - let s = input.ct.get_starfield_handle(); - - // Update global values - self.state.queue.write_buffer( - &self.state.global_uniform.data_buffer, - 0, - bytemuck::cast_slice(&[GlobalDataContent { - camera_position: input.camera_pos.into(), - camera_zoom: [input.camera_zoom, 0.0], - camera_zoom_limits: [ - input.ct.get_config().zoom_min, - input.ct.get_config().zoom_max, - ], - window_size: [ - self.state.window_size.width as f32, - self.state.window_size.height as f32, - ], - 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: [input.ct.get_config().starfield_size, 0.0], - starfield_size_limits: [ - input.ct.get_config().starfield_min_size, - input.ct.get_config().starfield_max_size, - ], - current_time: [input.current_time, 0.0], - }]), - ); - // Write all new particles to GPU buffer for i in input.particles.iter() { + let sprite = input.ct.get_sprite(i.sprite); + let texture_a = sprite.get_section(sprite.default_section).frames[0]; // ANIMATE + self.state.push_particle_buffer(ParticleInstance { position: [i.pos.x, i.pos.y], velocity: i.velocity.into(), angle: i.angle, angvel: i.angvel, size: i.size, - sprite_index: i.sprite.get_index(), + texture_index: [texture_a, texture_a], + texture_fade: 1.0, created: input.current_time, expires: input.current_time + i.lifetime, fade: i.fade, @@ -134,6 +109,7 @@ impl super::GPUState { 0..self.state.get_object_counter(), ); + /* // Particle pipeline self.state .vertex_buffers @@ -144,7 +120,7 @@ impl super::GPUState { 0..SPRITE_INDICES.len() as u32, 0, 0..PARTICLE_SPRITE_INSTANCE_LIMIT as _, - ); + ); */ // Ui pipeline self.state @@ -171,7 +147,7 @@ impl super::GPUState { 0..self.state.get_radialbar_counter(), ); - let textareas = self.ui.get_textareas(&input, &self.state); + let textareas = self.ui.get_textareas_flying(input, &self.state); self.state .text_renderer .prepare( @@ -193,13 +169,175 @@ impl super::GPUState { .render(&self.state.text_atlas, &mut render_pass) .unwrap(); - // begin_render_pass borrows encoder mutably, so we can't call finish() - // without dropping this variable. + // begin_render_pass borrows encoder mutably, + // so we need to drop it before calling finish. drop(render_pass); self.state.queue.submit(iter::once(encoder.finish())); output.present(); - Ok(()) + return Ok(()); + } + + /// Render routines while player is landed + fn render_landed(&'a mut self, input: &RenderInput) -> Result<()> { + let output = self.surface.get_current_texture()?; + let view = output.texture.create_view(&Default::default()); + + let mut encoder = self + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("render encoder"), + }); + + let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("render pass"), + + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: 1.0, + }), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + occlusion_query_set: None, + timestamp_writes: None, + }); + + // Create sprite instances + self.ui.draw(&input, &mut self.state); + + // These should match the indices in each shader, + // and should each have a corresponding bind group layout. + render_pass.set_bind_group(0, &self.texture_array.bind_group, &[]); + render_pass.set_bind_group(1, &self.state.global_uniform.bind_group, &[]); + + // Starfield pipeline + self.state + .vertex_buffers + .get_starfield() + .set_in_pass(&mut render_pass); + render_pass.set_pipeline(&self.starfield_pipeline); + render_pass.draw_indexed( + 0..SPRITE_INDICES.len() as u32, + 0, + 0..self.state.get_starfield_counter(), + ); + + // Ui pipeline + self.state + .vertex_buffers + .get_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..self.state.get_ui_counter(), + ); + + // Radial progress bars + self.state + .vertex_buffers + .get_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..self.state.get_radialbar_counter(), + ); + + let textareas = self.ui.get_textareas_landed(input, &self.state); + self.state + .text_renderer + .prepare( + &self.device, + &self.state.queue, + &mut self.state.text_font_system, + &mut self.state.text_atlas, + Resolution { + width: self.state.window_size.width, + height: self.state.window_size.height, + }, + textareas, + &mut self.state.text_cache, + ) + .unwrap(); + + self.state + .text_renderer + .render(&self.state.text_atlas, &mut render_pass) + .unwrap(); + + // begin_render_pass borrows encoder mutably, + // so we need to drop it before calling finish. + drop(render_pass); + + self.state.queue.submit(iter::once(encoder.finish())); + output.present(); + + return Ok(()); + } + + /// Main render function. Draws sprites on a window. + pub fn render(&mut self, input: RenderInput) -> Result<(), wgpu::SurfaceError> { + // Update global values + self.state.queue.write_buffer( + &self.state.global_uniform.data_buffer, + 0, + bytemuck::cast_slice(&[GlobalDataContent { + camera_position: input.camera_pos.into(), + camera_zoom: [input.camera_zoom, 0.0], + camera_zoom_limits: [ + input.ct.get_config().zoom_min, + input.ct.get_config().zoom_max, + ], + window_size: [ + self.state.window_size.width as f32, + self.state.window_size.height as f32, + ], + window_scale: [self.state.window.scale_factor() as f32, 0.0], + window_aspect: [self.state.window_aspect, 0.0], + starfield_sprite: [input.ct.get_starfield_texture(), 0], + starfield_tile_size: [input.ct.get_config().starfield_size, 0.0], + starfield_size_limits: [ + input.ct.get_config().starfield_min_size, + input.ct.get_config().starfield_max_size, + ], + current_time: [input.current_time, 0.0], + }]), + ); + + self.state.frame_reset(); + + match input + .systemsim + .get_ship(&PhysSimShipHandle(input.player.ship.unwrap())) + .unwrap() + .get_data() + .get_state() + { + ShipState::Collapsing + | ShipState::Dead + | ShipState::Landing { .. } + | ShipState::UnLanding { .. } + | ShipState::Flying { .. } => { + self.render_flying(&input).unwrap(); + } + + ShipState::Landed { .. } => { + self.render_landed(&input).unwrap(); + } + } + + return Ok(()); } } diff --git a/crates/render/src/shaderprocessor.rs b/crates/render/src/shaderprocessor.rs index 5889a7a..23b81f1 100644 --- a/crates/render/src/shaderprocessor.rs +++ b/crates/render/src/shaderprocessor.rs @@ -13,15 +13,6 @@ pub(crate) fn preprocess_shader( ); // Insert common functions - let shader = shader.replace( - "// INCLUDE: animate.wgsl", - &include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/shaders/include/", - "animate.wgsl" - )), - ); - let shader = shader.replace( "// INCLUDE: anchor.wgsl", &include_str!(concat!( diff --git a/crates/render/src/texturearray.rs b/crates/render/src/texturearray.rs index 4c8bfba..a5d09dc 100644 --- a/crates/render/src/texturearray.rs +++ b/crates/render/src/texturearray.rs @@ -1,4 +1,4 @@ -use crate::globaluniform::{AtlasArray, AtlasImageLocation, SpriteData, SpriteDataArray}; +use crate::globaluniform::{AtlasArray, AtlasImageLocation}; use anyhow::Result; use bytemuck::Zeroable; use galactica_content::Content; @@ -84,8 +84,7 @@ pub struct Texture { pub struct TextureArray { pub bind_group: wgpu::BindGroup, pub bind_group_layout: BindGroupLayout, - pub image_locations: AtlasArray, - pub sprite_data: SpriteDataArray, + pub texture_atlas: AtlasArray, } impl TextureArray { @@ -93,49 +92,36 @@ impl TextureArray { // Load all textures let mut texture_data = Vec::new(); - for a in ct.atlas_files() { - println!("opening {a}"); + for file in ct.atlas_files() { + println!("opening {file}"); let p = Path::new(ASSET_CACHE); - let mut f = File::open(p.join(a))?; + let mut f = File::open(p.join(file))?; let mut bytes = Vec::new(); f.read_to_end(&mut bytes)?; texture_data.push(RawTexture::from_bytes( &device, &queue, &bytes, - &format!("Atlas `{a}`"), + &format!("Atlas `{file}`"), )?); } let mut image_locations = AtlasArray::zeroed(); - let mut sprite_data = SpriteDataArray::zeroed(); println!("sending to gpu"); - let mut image_counter = 0; - let mut sprite_counter = 0; - for t in &ct.sprites { - sprite_data.data[sprite_counter] = SpriteData { - frame_count: t.frames.len() as u32, - repeatmode: t.repeat.as_int(), - aspect: t.aspect, - frame_duration: t.frame_duration, - first_frame: image_counter, - _padding: Default::default(), - }; - sprite_counter += 1; - - // Insert texture location data - for path in &t.frames { - let image = ct.get_image(&path); - image_locations.data[image_counter as usize] = AtlasImageLocation { - xpos: image.x, - ypos: image.y, - width: image.w, - height: image.h, - atlas_texture: image.atlas, - _padding: Default::default(), - }; - image_counter += 1; + for sprite in &ct.sprites { + for section in sprite.iter_sections() { + for idx in §ion.frames { + let image = ct.get_image(*idx); + image_locations.data[*idx as usize] = AtlasImageLocation { + xpos: image.x, + ypos: image.y, + width: image.w, + height: image.h, + atlas_texture: image.atlas, + _padding: Default::default(), + }; + } } } @@ -192,8 +178,7 @@ impl TextureArray { return Ok(Self { bind_group, bind_group_layout, - image_locations, - sprite_data, + texture_atlas: image_locations, }); } } diff --git a/crates/render/src/ui/manager.rs b/crates/render/src/ui/manager.rs index 6ee49b5..233af29 100644 --- a/crates/render/src/ui/manager.rs +++ b/crates/render/src/ui/manager.rs @@ -32,7 +32,7 @@ impl UiManager { self.fps.update(input, state); - match ship.data.get_state() { + match ship.get_data().get_state() { ShipState::Collapsing | ShipState::Dead | ShipState::Flying { .. } @@ -48,23 +48,22 @@ impl UiManager { } } - pub fn get_textareas(&self, input: &RenderInput, state: &RenderState) -> Vec