From a0a3b3974cab754c10a1517d82762b99482970ce Mon Sep 17 00:00:00 2001 From: Jon Santmyer Date: Tue, 12 May 2026 19:01:27 -0400 Subject: update packages to latest versions --- src/eguictx.rs | 3 +- src/fleet.rs | 31 +------- src/main.rs | 17 ++-- src/solar_system.rs | 27 ++++++- src/solar_system/body.rs | 8 +- src/solar_system/orbit.rs | 12 ++- src/tacmap.rs | 27 ++++--- src/tacmap/orbit_render.rs | 81 ++++++++++++------- src/texture.rs | 2 +- src/ui.rs | 14 ++-- src/ui/bodies_window.rs | 114 ++++++++++----------------- src/ui/fleet_window.rs | 190 ++++++++++++++++++++++++++++++++------------- src/ui/topbar.rs | 9 +-- src/wgpuctx/mod.rs | 19 +++-- src/wgpuctx/pipeline.rs | 10 +-- src/window.rs | 98 +++++++++++++---------- 16 files changed, 382 insertions(+), 280 deletions(-) (limited to 'src') diff --git a/src/eguictx.rs b/src/eguictx.rs index 3bc2841..39f0ba2 100644 --- a/src/eguictx.rs +++ b/src/eguictx.rs @@ -126,7 +126,8 @@ impl EguiCtx })], depth_stencil_attachment: None, timestamp_writes: None, - occlusion_query_set: None + occlusion_query_set: None, + multiview_mask: None }); self.renderer.render( diff --git a/src/fleet.rs b/src/fleet.rs index 39558cd..344aef3 100644 --- a/src/fleet.rs +++ b/src/fleet.rs @@ -15,8 +15,6 @@ use crate::ui::fleet_window::NewFleet; pub type FleetId = usize; -pub const FLEET_TICK_DURATION: Second = timeman::HOUR; - pub struct Fleet { id: FleetId, @@ -56,8 +54,6 @@ impl StaticOrbiter for Fleet { impl Fleet { - pub const TICK_DURATION: Second = FLEET_TICK_DURATION; - pub fn new( id: FleetId, name: String) @@ -191,32 +187,7 @@ impl FleetsManager time_now: Second) -> Result<(), Second> { - let tick_interval = Fleet::TICK_DURATION; - - let time_then_offset = time_then % tick_interval; - let time_now_offset = time_now % tick_interval; - - let tick_start = time_then + tick_interval - time_then_offset; - let tick_end = time_now - time_now_offset; - - let num_ticks = (tick_end - tick_start) / tick_interval; - let mut tick_interrupt: Option = None; - - for tick_i in 0..num_ticks+1 { - let tick_time = tick_start + tick_i * tick_interval; - if self.subtick_fleet(star_systems, tick_time).is_err() { - tick_interrupt = Some(tick_time); - } - } - - let final_tick = match tick_interrupt { - Some(v) => v, - None => tick_end - }; - - if final_tick != tick_end { - self.subtick_fleet(star_systems, final_tick); - } + self.subtick_fleet(star_systems, time_now); Ok(()) } diff --git a/src/main.rs b/src/main.rs index a50eec1..68ecd55 100644 --- a/src/main.rs +++ b/src/main.rs @@ -139,7 +139,7 @@ impl ApplicationHandler for SystemicApp None => return }; - window.on_event(&event); + let event_resp = window.on_event(&event); match event { WindowEvent::CloseRequested => { @@ -156,14 +156,17 @@ impl ApplicationHandler for SystemicApp game_state.borrow_mut().update(delta_time); window.update(game_state, delta_time); - match window.render(game_state) { + match window.render(game_state, event_resp) { Ok(_) => {} - Err(wgpu::SurfaceError::Outdated | wgpu::SurfaceError::Lost) => { + Err(wgpu::CurrentSurfaceTexture::Suboptimal(_) | + wgpu::CurrentSurfaceTexture::Outdated | + wgpu::CurrentSurfaceTexture::Lost + ) => { let size = window.size(); window.resize(size.width, size.height); }, - Err(e) => { - log::error!("Unable to render: {}", e); + Err(_) => { + log::error!("Uncaught error while trying to render!"); } } if delta_time < TARGET_DT { @@ -178,7 +181,9 @@ impl ApplicationHandler for SystemicApp }, .. } => { - window.keyboard_input(key_code, key_state); + if !event_resp.consumed { + window.keyboard_input(key_code, key_state); + } } _ => {} } diff --git a/src/solar_system.rs b/src/solar_system.rs index 94508fd..7799a59 100644 --- a/src/solar_system.rs +++ b/src/solar_system.rs @@ -6,6 +6,8 @@ use self::orbit::*; use serde::{Deserialize}; use crate::known_stars::*; +use crate::ntree::NTree; +use crate::ntree::NTreeNode; use crate::timeman::Second; use std::error::Error; @@ -42,10 +44,26 @@ pub struct SolarSystem name: String, bodies: Vec, + heirarchy: NTreeNode } impl SolarSystem { + fn rebuild_system_heirarchy( + bodies: &[OrbitalBody], + root: &mut NTreeNode) + { + for body in bodies { + if let Some(orbit) = body.orbit() { + if orbit.parent() == *root.value() { + let mut subtree = NTreeNode::new(body.id()); + SolarSystem::rebuild_system_heirarchy(bodies, &mut subtree); + root.insert_node(subtree); + } + } + } + } + pub fn new_from_csv( id: SystemId, data: &'static str) @@ -69,13 +87,17 @@ impl SolarSystem //if record.radius == 0.0 { continue; } println!("New body: {:?}", record); - bodies.push(OrbitalBody::new_from_record(bodies.len(), record)); + bodies.push(OrbitalBody::new_from_record(bodies.len(), id, record)); } + let mut heirarchy_root = NTreeNode::new(0); + SolarSystem::rebuild_system_heirarchy(&bodies, &mut heirarchy_root); + Ok(Self { id: id, name: bodies[0].name().clone(), bodies: bodies, + heirarchy: heirarchy_root }) } @@ -102,6 +124,9 @@ impl SolarSystem pub fn body(&self, id: BodyId) -> &OrbitalBody { &self.bodies[id] } + pub fn heirarchy(&self) -> &NTreeNode + { &self.heirarchy } + pub fn body_position( &self, body: &OrbitalBody, diff --git a/src/solar_system/body.rs b/src/solar_system/body.rs index 3e61486..f3aef8c 100644 --- a/src/solar_system/body.rs +++ b/src/solar_system/body.rs @@ -9,6 +9,8 @@ pub const BODY_TICK_DURATION: Second = timeman::DAY; pub struct OrbitalBody { id: BodyId, + system: SystemId, + name: String, mass: Kilograms, radius: Kilometers, @@ -34,10 +36,12 @@ impl OrbitalBody pub fn new_from_record( id: BodyId, + system: SystemId, record: CSVOrbitalBody) -> Self { Self { - id: id, + id, + system, name: record.name, mass: record.mass, radius: record.radius, @@ -45,6 +49,7 @@ impl OrbitalBody orbit: match record.orbits { Some(parent) => Some(StaticOrbit::new( parent, + system, record.eccentricity, record.inclination, record.long_asc_node, @@ -59,6 +64,7 @@ impl OrbitalBody } pub fn id(&self) -> BodyId { self.id } + pub fn system(&self) -> SystemId { self.system } pub fn name(&self) -> &String { &self.name } pub fn radius(&self) -> f32 { self.radius as f32 } pub fn mass(&self) -> Kilograms { self.mass } diff --git a/src/solar_system/orbit.rs b/src/solar_system/orbit.rs index f5a564c..b29e2c2 100644 --- a/src/solar_system/orbit.rs +++ b/src/solar_system/orbit.rs @@ -1,9 +1,11 @@ -use crate::solar_system::{Angle, BodyId, Kilometers, OrbitalBody, Percentage}; +use crate::solar_system::{Angle, BodyId, Kilometers, OrbitalBody, Percentage, SystemId}; use crate::timeman::{Second}; pub struct StaticOrbit { parent: BodyId, + system: SystemId, + eccentricity: Percentage, inclination: Angle, long_asc_node: Angle, @@ -23,6 +25,7 @@ impl StaticOrbit { pub fn new( parent: BodyId, + system: SystemId, eccentricity: Percentage, inclination: Angle, long_asc_node: Angle, @@ -32,6 +35,7 @@ impl StaticOrbit -> Self { Self { parent, + system, eccentricity, inclination, long_asc_node, @@ -48,6 +52,7 @@ impl StaticOrbit { Self { parent: parent.id(), + system: parent.system(), eccentricity: 1e-6, inclination: 0.0, long_asc_node: 0.0, @@ -65,9 +70,8 @@ impl StaticOrbit ((self.semi_major_axis.powf(3.0) / this_body.sgp()).sqrt() * std::f64::consts::TAU) as Second } - pub fn parent(&self) -> BodyId { - self.parent - } + pub fn parent(&self) -> BodyId { self.parent } + pub fn system(&self) -> SystemId { self.system } pub fn sma(&self) -> Kilometers { self.semi_major_axis } diff --git a/src/tacmap.rs b/src/tacmap.rs index 9ff69f6..05747d4 100644 --- a/src/tacmap.rs +++ b/src/tacmap.rs @@ -101,16 +101,18 @@ impl TacticalMap self.camera_controller.keyboard_input(key_code, key_state); } - pub fn draw( + pub fn prepare( &mut self, + scene: &mut SceneCtx, wgpuctx: &WgpuCtx, - fleets_manager: &FleetsManager, + fleets_man: &FleetsManager, solar_system: &SolarSystem, timeman: &TimeMan, - ) -> Result<(), wgpu::SurfaceError> + ) -> Result<(), ()> { self.camera.update_buffer(wgpuctx, &self.pmatrix); - + self.camera.stage_changes(scene.encoder_mut()); + if self.system_for_render.is_none() || self.system_for_render.unwrap() != solar_system.id() { @@ -123,8 +125,12 @@ impl TacticalMap self.body_renderer.rebuild(wgpuctx, solar_system); self.orbit_renderer.rebuild(wgpuctx, solar_system); - match self.orbit_renderer.update(wgpuctx, solar_system, timeman.seconds()) - { + match self.orbit_renderer.update( + wgpuctx, + fleets_man, + solar_system, + timeman.seconds() + ){ Ok(()) => {}, Err(e) => println!("Tactical map orbit render update error: {}", e) } @@ -137,7 +143,7 @@ impl TacticalMap match self.fleet_renderer.update( wgpuctx, - fleets_manager, + fleets_man, solar_system, timeman.seconds()) { @@ -148,13 +154,6 @@ impl TacticalMap Ok(()) } - pub fn prepare( - &self, - scene: &mut SceneCtx) - { - self.camera.stage_changes(scene.encoder_mut()); - } - pub fn paint( &self, pass: &mut wgpu::RenderPass<'_>) diff --git a/src/tacmap/orbit_render.rs b/src/tacmap/orbit_render.rs index 7c0a089..32c0abb 100644 --- a/src/tacmap/orbit_render.rs +++ b/src/tacmap/orbit_render.rs @@ -2,6 +2,7 @@ use std::error::Error; use super::*; +use crate::fleet::FleetId; use crate::solar_system::body::{BodyId, OrbitalBody}; use crate::solar_system::orbit::StaticOrbiter; use crate::timeman::{self, Second}; @@ -10,12 +11,15 @@ use crate::wgpuctx::{WgpuCtx, pipeline::RenderPipelineBuilder}; pub struct OrbitRenderer { needs_rebuild: bool, - last_tick: Option, + last_time: Option, pipeline: wgpu::RenderPipeline, - orbit_vertex_buffers: Option>, + body_orbit_vertex_buffers: Option>, + fleet_orbit_vertex_buffers: Option>, + origin_buffer: Option, + origin_bind_group: Option, origin_bind_group_layout: wgpu::BindGroupLayout } @@ -59,9 +63,12 @@ impl OrbitRenderer Self { needs_rebuild: true, - last_tick: None, + last_time: None, pipeline: render_pipeline, - orbit_vertex_buffers: None, + + body_orbit_vertex_buffers: None, + fleet_orbit_vertex_buffers: None, + origin_buffer: None, origin_bind_group: None, origin_bind_group_layout: origin_bind_group_layout @@ -123,19 +130,23 @@ impl OrbitRenderer wgpuctx: &WgpuCtx, solar_system: &SolarSystem) { - if self.orbit_vertex_buffers.is_some() && !self.needs_rebuild { + if self.body_orbit_vertex_buffers.is_some() && !self.needs_rebuild { return; } self.needs_rebuild = false; - match &self.orbit_vertex_buffers { - Some(buffers) => { - for buffer in buffers { - buffer.1.destroy(); - } - self.orbit_vertex_buffers = None; - }, - None => {} + if let Some(buffers) = &self.body_orbit_vertex_buffers { + for buffer in buffers { + buffer.1.destroy(); + } + self.body_orbit_vertex_buffers = None; + }; + + if let Some(buffers) = &self.fleet_orbit_vertex_buffers { + for buffer in buffers { + buffer.1.destroy(); + } + self.fleet_orbit_vertex_buffers = None; }; //From the solar system's bodies, calculate the orbits. @@ -171,7 +182,7 @@ impl OrbitRenderer )); self.origin_buffer = Some(origin_buffer); - self.orbit_vertex_buffers = Some(bodies.iter().filter_map(|body| { + self.body_orbit_vertex_buffers = Some(bodies.iter().filter_map(|body| { self.create_orbit_buffer(wgpuctx, body, 0) }).collect::>()); } @@ -179,16 +190,29 @@ impl OrbitRenderer pub fn update( &mut self, wgpuctx: &WgpuCtx, + fleets_man: &FleetsManager, solar_system: &SolarSystem, time: Second) -> Result<(), Box> { - let tick = time / OrbitalBody::TICK_DURATION; - if self.last_tick.is_some_and(|t| { t == tick }) { + if self.last_time.is_some_and(|t| { t == time }) { return Ok(()); } + + self.fleet_orbit_vertex_buffers = + Some(fleets_man.all_in_system(solar_system.id()).iter().filter_map(|id| { + let fleet = fleets_man.entry(*id).unwrap(); + self.create_orbit_buffer(wgpuctx, fleet, time) + }).collect::>()); - self.last_tick = Some(time); + let body_tick = time / OrbitalBody::TICK_DURATION; + let last_body_tick = self.last_time.unwrap_or(i64::MAX) / OrbitalBody::TICK_DURATION; + self.last_time = Some(time); + + if body_tick == last_body_tick { + return Ok(()); + } + let positions = solar_system.bodies().iter().map(|body| { let pos = solar_system.body_position(body, time); [ pos.x as f32, pos.y as f32, pos.z as f32 ] @@ -201,10 +225,6 @@ impl OrbitRenderer None => { return Err(Box::new(NeedsRebuildError)); } }; - //let bodies = solar_system.bodies(); - /*self.orbit_vertex_buffers = Some(bodies.iter().map(|body| { - self.create_orbit_buffer_for_body(wgpuctx, body, tick_time) - }).collect::>());*/ Ok(()) } @@ -213,11 +233,6 @@ impl OrbitRenderer pass: &mut wgpu::RenderPass, camera: &Camera) { - let buffers = match &self.orbit_vertex_buffers { - Some(v) => v, - None => return - }; - pass.set_pipeline(&self.pipeline); pass.set_bind_group(0, camera.bindgroup(), &[]); @@ -226,9 +241,17 @@ impl OrbitRenderer None => { return; } } - for (num_points, buffer) in buffers { - pass.set_vertex_buffer(0, buffer.slice(..)); - pass.draw(0..(*num_points as u32), 0..1); + if let Some(body_buffers) = &self.body_orbit_vertex_buffers { + for (num_points, buffer) in body_buffers { + pass.set_vertex_buffer(0, buffer.slice(..)); + pass.draw(0..(*num_points as u32), 0..1); + } + } + if let Some(fleet_buffers) = &self.fleet_orbit_vertex_buffers { + for (num_points, buffer) in fleet_buffers { + pass.set_vertex_buffer(0, buffer.slice(..)); + pass.draw(0..(*num_points as u32), 0..1); + } } } } diff --git a/src/texture.rs b/src/texture.rs index f5165a7..cef96d6 100644 --- a/src/texture.rs +++ b/src/texture.rs @@ -24,7 +24,7 @@ impl Texture address_mode_w: wgpu::AddressMode::ClampToEdge, mag_filter: wgpu::FilterMode::Linear, min_filter: wgpu::FilterMode::Nearest, - mipmap_filter: wgpu::FilterMode::Nearest, + mipmap_filter: wgpu::MipmapFilterMode::Nearest, ..Default::default() } ); diff --git a/src/ui.rs b/src/ui.rs index c2c4b05..73389a8 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -23,15 +23,15 @@ pub struct State impl State { - pub fn render( + pub fn paint( &mut self, game_state: &RefCell, - eguictx: &EguiCtx) + ui: &mut egui::Ui) { let mut game_state = game_state.borrow_mut(); let topbar_action = self.topbar_sate.paint( - eguictx, + ui, &game_state, &self.bodies_window, &self.fleet_window); @@ -48,13 +48,17 @@ impl State }; let bodies_window_action = - self.bodies_window.render(current_system, eguictx); + self.bodies_window.paint(ui, current_system); if bodies_window_action.focus_body.is_some() { self.camera_target = bodies_window_action.focus_body; } let fleet_window_action = - self.fleet_window.paint(game_state.borrow(), eguictx, &self.camera_target); + self.fleet_window.paint( + ui, + game_state.borrow(), + &self.topbar_sate.current_system, + &self.camera_target); if let Some(new_fleet) = fleet_window_action.new_fleet { game_state.new_fleet_from_ui(new_fleet); diff --git a/src/ui/bodies_window.rs b/src/ui/bodies_window.rs index 21a2060..7e24948 100644 --- a/src/ui/bodies_window.rs +++ b/src/ui/bodies_window.rs @@ -1,6 +1,3 @@ -use egui::Sense; - -use crate::eguictx::EguiCtx; use crate::ntree::{NTree, NTreeNode}; use crate::solar_system::body::{BodyId, OrbitalBody}; use crate::solar_system::{SolarSystem, SystemId}; @@ -11,8 +8,6 @@ use crate::timeman::TimeMan; pub struct BodiesWindowState { pub open: bool, - last_system: Option, - system_heirarchy: NTree, selected_body: Option } @@ -24,64 +19,19 @@ pub struct BodiesWindowAction impl BodiesWindowState { - fn build_system_heirarchy_rec( - bodies: &[OrbitalBody], - node: &mut NTreeNode) - { - for body in bodies { - let orbit = body.get_orbit(); - match orbit { - Some(orbit) => { - if orbit.parent() != *node.value() { - continue; - } - }, - None => { - continue; - } - } - let mut subnode = NTreeNode::new(body.id()); - BodiesWindowState::build_system_heirarchy_rec(bodies, &mut subnode); - node.insert_node(subnode); - } - } - - fn rebuild_system_heirarchy( + pub fn paint( &mut self, - star_system: &SolarSystem) - { - let mut root_node = NTreeNode::::new(0); - - let bodies = star_system.bodies(); - BodiesWindowState::build_system_heirarchy_rec(bodies, &mut root_node); - self.system_heirarchy.set_root(root_node); - } - - pub fn render( - &mut self, - current_system: &SolarSystem, - eguictx: &EguiCtx) + ui: &mut egui::Ui, + current_system: &SolarSystem) -> BodiesWindowAction { - match self.last_system { - Some(last_system) => { - if last_system != current_system.id() { - self.rebuild_system_heirarchy(current_system); - } - }, - None => { - self.rebuild_system_heirarchy(current_system); - } - } - self.last_system = Some(current_system.id()); - let mut action = BodiesWindowAction::default(); let mut bodies_window_open = self.open; egui::Window::new("Bodies") .open(&mut &mut bodies_window_open) .resizable(true) - .show(eguictx.context(), |ui| { + .show(ui.ctx(), |ui| { ui.horizontal(|ui| { self.paint_bodies_list(current_system, ui); @@ -142,8 +92,8 @@ impl BodiesWindowState .min_scrolled_height(200.0) .show(ui, |ui| { ui.vertical(|ui| { - let root = self.system_heirarchy.root(); - let new_sel = self.paint_bodies_node_rec(star_system, root.as_ref().unwrap(), ui); + let root = star_system.heirarchy(); + let new_sel = self.paint_bodies_node_rec(star_system, root, ui); if new_sel.is_some() { self.selected_body = new_sel; } @@ -176,26 +126,40 @@ impl BodiesWindowState }); ui.vertical(|ui| { - ui.vertical_centered(|ui| { - ui.label("Physical Properties"); - }); - ui.label(format!("Mass: {:.4E} kg", selected_body.mass())); - ui.label(format!("Radius: {} km", selected_body.radius())); - - if let Some(orbit) = selected_body.get_orbit() { - ui.vertical_centered(|ui| { - ui.label("Orbital Properties"); + ui.style_mut().interaction.selectable_labels = false; + egui_extras::TableBuilder::new(ui) + .column(egui_extras::Column::auto()) + .column(egui_extras::Column::remainder()) + .body(|mut body| { + body.row(16.0, |mut row| { + row.col(|col| { col.label("Mass"); }); + row.col(|col| { col.label(format!("{:.4E}", selected_body.mass())); }); }); - ui.label(format!("Orbiting {}", - star_system.body(orbit.parent()).name() - )); - ui.label(format!("Period: {}", - TimeMan::format_duration(orbit.period(selected_body)) - )); - ui.label(format!("Semi-major Axis: {:.4E} km", - orbit.sma() - )); - } + body.row(16.0, |mut row| { + row.col(|col| { col.label("Radius"); }); + row.col(|col| { col.label(format!("{:.4E}", selected_body.radius())); }); + }); + + if let Some(orbit) = selected_body.get_orbit() { + let parent = star_system.body(orbit.parent()); + body.row(16.0, |mut row| { + row.col(|col| { col.label("Orbiting"); }); + row.col(|col| { col.label(parent.name()); }); + }); + body.row(16.0, |mut row| { + row.col(|col| { col.label("Period"); }); + row.col(|col| { + col.label(format!("{}", + TimeMan::format_duration(orbit.period(selected_body)) + )); + }); + }); + body.row(16.0, |mut row| { + row.col(|col| { col.label("Semi-major Axis"); }); + row.col(|col| { col.label(format!("{:.4E} km", orbit.sma())); }); + }); + } + }); }); }); diff --git a/src/ui/fleet_window.rs b/src/ui/fleet_window.rs index eb8ccde..55e3d59 100644 --- a/src/ui/fleet_window.rs +++ b/src/ui/fleet_window.rs @@ -1,17 +1,22 @@ -use std::cell::RefCell; - use crate::GameState; -use crate::eguictx::EguiCtx; -use crate::fleet::{Fleet, FleetsManager}; +use crate::fleet::{Fleet, FleetId, FleetsManager}; +use crate::solar_system::orbit::StaticOrbiter; use crate::solar_system::{Kilometers, SolarSystem, SystemId}; use crate::solar_system::body::BodyId; +#[derive(Default, Clone, PartialEq)] +enum FleetMenuPanelSel { + #[default] + Info, + Schedule +} #[derive(Default, Clone)] pub struct FleetWindowState { pub open: bool, - pub selected_system: Option, + pub selected_fleet: Option, + pub menu_panel: FleetMenuPanelSel, pub new_fleet_window: Option } @@ -33,7 +38,7 @@ pub struct NewFleetWindowState pub fleet_sma: Kilometers } -#[derive(Default, Clone)] +#[derive(Clone)] pub struct NewFleet { pub system: SystemId, @@ -46,8 +51,9 @@ impl FleetWindowState { pub fn paint( &mut self, + ui: &mut egui::Ui, game_state: &GameState, - eguictx: &EguiCtx, + focused_system: &Option, focused_body: &Option) -> FleetWindowAction { @@ -59,22 +65,30 @@ impl FleetWindowState let mut mgr_open = self.open; egui::Window::new("Fleet Manager") .open(&mut mgr_open) - .show(eguictx.context(), |ui| { + .show(ui.ctx(), |ui| { - ui.horizontal(|ui| { - self.paint_systems_list( - &mut action, - ui, - fleets_manager, - star_systems, - focused_body - ); + ui.vertical(|ui| { + ui.horizontal(|ui| { + self.paint_fleet_list(fleets_manager, ui); + self.paint_fleet_menu(star_systems, fleets_manager, ui); + }); + + if focused_system.is_some() { + if ui.button("New Fleet").clicked() { + if self.new_fleet_window.is_none() { + self.new_fleet_window = Some(NewFleetWindowState::new( + focused_system.unwrap(), + focused_body.unwrap_or(0) + )); + } + } + } }); }); match &mut self.new_fleet_window { Some(new_fleet_window) => { - action.new_fleet = new_fleet_window.paint(game_state, eguictx); + action.new_fleet = new_fleet_window.paint(ui, game_state); if action.new_fleet.is_some() || !new_fleet_window.open { self.new_fleet_window = None; } @@ -86,53 +100,106 @@ impl FleetWindowState action } - fn paint_systems_list( + fn paint_fleet_menu( &mut self, - action: &mut FleetWindowAction, - ui: &mut egui::Ui, - fleets_manager: &FleetsManager, star_systems: &[SolarSystem], - focused_body: &Option) - -> egui::InnerResponse<()> + fleets_man: &FleetsManager, + ui: &mut egui::Ui) { - ui.vertical(|ui| { - for system in star_systems { - self.paint_fleet_list(fleets_manager, &system, ui); + let fleet = match self.selected_fleet { + Some(id) => { fleets_man.entry(id) }, + None => { return; } + }; + let fleet = match fleet { + Some(entry) => entry, + None => { + self.selected_fleet = None; + return; } + }; - if self.selected_system.is_none() { return; } - if ui.button("New Fleet").clicked() { - if self.new_fleet_window.is_none() { - self.new_fleet_window = Some(NewFleetWindowState::new( - self.selected_system.unwrap(), - focused_body.unwrap_or(0) - )); + ui.separator(); + ui.vertical(|ui| { + ui.horizontal(|ui| { + if ui.button("Info").clicked() { + self.menu_panel = FleetMenuPanelSel::Info; } + if ui.button("Schedule").clicked() { + self.menu_panel = FleetMenuPanelSel::Schedule; + } + }); + self.paint_fleet_menu_info(star_systems, fleets_man, fleet, ui); + }); + } + + fn paint_fleet_menu_info( + &mut self, + star_systems: &[SolarSystem], + fleets_man: &FleetsManager, + fleet: &Fleet, + ui: &mut egui::Ui) + { + if self.menu_panel != FleetMenuPanelSel::Info { + return; + } + egui::Frame::canvas(ui.style()).show(ui, |ui| { + ui.set_min_width(200.0); + ui.style_mut().interaction.selectable_labels = false; + + if let Some(orbit) = fleet.orbit() { + let star_system = &star_systems[orbit.system()]; + let parent = star_system.body(orbit.parent()); + + ui.push_id("orbital_info_table", |ui| { + egui_extras::TableBuilder::new(ui) + .column(egui_extras::Column::auto()) + .column(egui_extras::Column::remainder()) + .body(|mut body| { + body.row(16.0, |mut row| { + row.col(|col| { col.label("System"); }); + row.col(|col| { col.label(star_system.name()); }); + }); + body.row(16.0, |mut row| { + row.col(|col| { col.label("Orbiting"); }); + row.col(|col| { col.label(parent.name()); }); + }); + body.row(16.0, |mut row| { + row.col(|col| { col.label("Radius"); }); + row.col(|col| { col.label(format!("{:.1}", orbit.sma())); }); + }); + }); + }); + + ui.separator(); } - }) + + let heading = fleet.heading(); + egui_extras::TableBuilder::new(ui) + .column(egui_extras::Column::auto()) + .column(egui_extras::Column::remainder()) + .body(|mut body| { + body.row(16.0, |mut row| { + row.col(|col| { col.label("Heading"); }); + row.col(|col| { + col.label(format!("{:?} by {:?}", + cgmath::Deg::::from(heading.x), + cgmath::Deg::::from(heading.y) + )); + }); + }); + }); + }); } fn paint_fleet_list( &mut self, - fleets_manager: &FleetsManager, - star_system: &SolarSystem, + fleets_man: &FleetsManager, ui: &mut egui::Ui) { - let fleet_ids = star_system.fleets(fleets_manager); - egui::collapsing_header::CollapsingState::load_with_default_open( - ui.ctx(), - ui.make_persistent_id(format!("fleet_window_star_{}", star_system.id())), - true - ) - .show_header(ui, |ui| { - let selected = self.selected_system.is_some_and(|id| { id == star_system.id() }); - if ui.selectable_label(selected, star_system.name()).clicked() { - self.selected_system = if !selected { Some(star_system.id()) } else { None }; - } - }) - .body(|ui| { + let fleet_ids = fleets_man.all(); + ui.vertical(|ui| { for id in fleet_ids { - if let Some(fleet) = fleets_manager.entry(id) { + if let Some(fleet) = fleets_man.entry(id) { self.paint_fleet_entry(fleet, ui); } } @@ -144,7 +211,10 @@ impl FleetWindowState fleet: &Fleet, ui: &mut egui::Ui) { - ui.label(fleet.name()); + let selected = self.selected_fleet.is_some_and(|id| { id == fleet.id() }); + if ui.selectable_label(selected, fleet.name()).clicked() { + self.selected_fleet = if selected { None } else { Some(fleet.id()) }; + } } } // FleetWindowAction @@ -164,8 +234,8 @@ impl NewFleetWindowState pub fn paint( &mut self, - game_state: &GameState, - eguictx: &EguiCtx) + ui: &mut egui::Ui, + game_state: &GameState,) -> Option { let solar_system = &game_state.solar_systems()[self.parent_system]; @@ -174,7 +244,7 @@ impl NewFleetWindowState match egui::Window::new("New Fleet") .collapsible(false) .open(&mut self.open) - .show(eguictx.context(), |ui| { + .show(ui.ctx(), |ui| { ui.vertical(|ui| { ui.horizontal(|ui| { ui.label("Name: "); @@ -205,4 +275,16 @@ impl NewFleetWindowState None => None } } +} // impl FleetWindowState + +impl Default for NewFleet +{ + fn default() -> Self { + Self { + system: Default::default(), + orbiting: Default::default(), + name: "New Fleet".to_string(), + sma: Default::default() + } + } } diff --git a/src/ui/topbar.rs b/src/ui/topbar.rs index ba26d7c..511c67e 100644 --- a/src/ui/topbar.rs +++ b/src/ui/topbar.rs @@ -22,7 +22,7 @@ impl TopBarState { pub fn paint( &mut self, - eguictx: &EguiCtx, + ui: &mut egui::Ui, game_state: &GameState, bodies_window_state: &BodiesWindowState, fleets_window_state: &FleetWindowState) @@ -33,8 +33,8 @@ impl TopBarState let solar_systems = game_state.solar_systems(); let timeman = game_state.timeman(); - egui::TopBottomPanel::top("topbar").show( - eguictx.context(), + egui::Panel::top("topbar").show_inside( + ui, |ui| { ui.horizontal(|ui| { @@ -62,7 +62,7 @@ impl TopBarState }); }); - self.paint_tick_buttons(&mut action, timeman, ui); + self.paint_tick_buttons(&mut action, ui); }); ui.vertical_centered_justified(|ui| { @@ -95,7 +95,6 @@ impl TopBarState pub fn paint_tick_buttons( &mut self, action: &mut TopBarAction, - timeman: &TimeMan, ui: &mut egui::Ui) { let button_seconds = [ diff --git a/src/wgpuctx/mod.rs b/src/wgpuctx/mod.rs index 5f8e381..ef2abfc 100644 --- a/src/wgpuctx/mod.rs +++ b/src/wgpuctx/mod.rs @@ -1,5 +1,5 @@ use std::sync::Arc; -use wgpu::util::DeviceExt; +use wgpu::{CurrentSurfaceTexture, util::DeviceExt}; use winit::window::{Window}; use crate::texture::Texture; @@ -106,13 +106,17 @@ impl WgpuCtx pub fn prepare_surface( &mut self, view_descr: &wgpu::TextureViewDescriptor) - -> Result + -> Result { - let texture = self.surface.get_current_texture()?; - let view = texture.texture.create_view(view_descr); - - self.surface_texture = Some(texture); - Ok(view) + let surface_texture = self.surface.get_current_texture(); + match surface_texture { + CurrentSurfaceTexture::Success(texture) => { + let view = texture.texture.create_view(view_descr); + self.surface_texture = Some(texture); + Ok(view) + }, + _ => Err(surface_texture) + } } pub fn create_encoder( @@ -277,6 +281,7 @@ impl<'encoder> RenderPassBuilder<'encoder> depth_stencil_attachment: None, occlusion_query_set: None, timestamp_writes: None, + multiview_mask: None, } ) } diff --git a/src/wgpuctx/pipeline.rs b/src/wgpuctx/pipeline.rs index d698ac4..460b71d 100644 --- a/src/wgpuctx/pipeline.rs +++ b/src/wgpuctx/pipeline.rs @@ -3,7 +3,7 @@ use crate::wgpuctx::WgpuCtx; pub struct RenderPipelineBuilder<'a> { - bind_groups: Vec<&'a wgpu::BindGroupLayout>, + bind_groups: Vec>, shader: &'a wgpu::ShaderModule, vertex_entry_point: Option<&'static str>, @@ -44,7 +44,7 @@ impl<'a> RenderPipelineBuilder<'a> mut self, bindgroup: &'a wgpu::BindGroupLayout) -> Self { - self.bind_groups.push(bindgroup); + self.bind_groups.push(Some(bindgroup)); self } @@ -79,7 +79,7 @@ impl<'a> RenderPipelineBuilder<'a> let layout_descr = wgpu::PipelineLayoutDescriptor { label: label, bind_group_layouts: self.bind_groups.as_slice(), - push_constant_ranges: &[] + immediate_size: 0, }; let layout = wgpuctx.create_pipeline_layout(&layout_descr); @@ -134,8 +134,8 @@ impl<'a> RenderPipelineBuilder<'a> mask: !0, alpha_to_coverage_enabled: false }, - multiview: None, - cache: None + cache: None, + multiview_mask: None, } ) diff --git a/src/window.rs b/src/window.rs index 29c347f..3c395d5 100644 --- a/src/window.rs +++ b/src/window.rs @@ -12,10 +12,11 @@ use crate::eguictx::EguiCtx; pub struct GameWindow { - window: Arc, wgpuctx: WgpuCtx, eguictx: EguiCtx, + window: Arc, + tactical_map: TacticalMap, ui_state: ui::State @@ -92,52 +93,66 @@ impl GameWindow pub fn render( &mut self, - game_state: &RefCell) - -> Result<(), wgpu::SurfaceError> { + game_state: &RefCell, + egui_event_resp: egui_winit::EventResponse) + -> Result<(), wgpu::CurrentSurfaceTexture> { if !self.wgpuctx.is_ready() { return Ok(()); } - - let view = self.wgpuctx.prepare_surface(&wgpu::TextureViewDescriptor::default())?; - let mut scene = SceneCtx::from_view_default(&self.wgpuctx, &view, Some("Systemic window scene")); - self.eguictx.prepare(&self.window); let screen_size = egui::vec2( self.wgpuctx.surface_config().width as f32, self.wgpuctx.surface_config().height as f32); + + let view = self.wgpuctx.prepare_surface(&wgpu::TextureViewDescriptor::default())?; + let mut scene = SceneCtx::from_view_default(&self.wgpuctx, &view, Some("Systemic window scene")); - self.ui_state.render(game_state, &self.eguictx); - if self.ui_state.topbar_sate.current_system.is_some() { - let game_state = game_state.borrow(); - let fleets_manager = game_state.fleets(); - let current_system = &game_state.solar_systems()[self.ui_state.topbar_sate.current_system.unwrap()]; - - self.tactical_map.draw( - &self.wgpuctx, - fleets_manager, - current_system, - game_state.timeman())?; - - self.tactical_map.prepare(&mut scene); - - let mut pass = RenderPassBuilder::new(Some("Systemic window render pass"), &view) - .clear_color(wgpu::Color { r: 0.0, g: 0.0, b: 0.1, a: 1.0 }) - .build_from_scene(&mut scene); - - //Draw the tactical map canvas. - self.tactical_map.paint(&mut pass); - - egui::CentralPanel::default() - .frame(egui::Frame::new()) - .show(self.eguictx.context(), |ui| { - self.tactical_map.paint_labels( - current_system, - game_state.timeman().seconds(), - screen_size, - ui - ); - }); - } + self.eguictx.prepare(&self.window); + + egui::Window::new("Systemic 4X") + .fixed_rect(egui::Rect::from_min_size(egui::pos2(0.0, 0.0), screen_size)) + .resizable(false) + .collapsible(false) + .title_bar(false) + .interactable(false) + .frame(egui::Frame::NONE) + .show(self.eguictx.context(), |ui| { + self.ui_state.paint(game_state, ui); + + if self.ui_state.topbar_sate.current_system.is_some() { + let game_state = game_state.borrow(); + let fleets_manager = game_state.fleets(); + let current_system = &game_state.solar_systems()[self.ui_state.topbar_sate.current_system.unwrap()]; + + match self.tactical_map.prepare( + &mut scene, + &self.wgpuctx, + fleets_manager, + current_system, + game_state.timeman()) + { + Ok(_) => {}, + Err(_) => { + println!("Error in tactical map prepare"); + panic!(); + } + } + + let mut pass = RenderPassBuilder::new(Some("Systemic window render pass"), &view) + .clear_color(wgpu::Color { r: 0.0, g: 0.0, b: 0.1, a: 1.0 }) + .build_from_scene(&mut scene); + + //Draw the tactical map canvas. + self.tactical_map.paint(&mut pass); + + self.tactical_map.paint_labels( + current_system, + game_state.timeman().seconds(), + screen_size, + ui + ); + } + }); self.eguictx.present( &self.window, &self.wgpuctx, @@ -154,10 +169,9 @@ impl GameWindow pub fn on_event( &mut self, event: &WindowEvent) + -> egui_winit::EventResponse { - if self.eguictx.window_event(&self.window, event).consumed { - return; - } + self.eguictx.window_event(&self.window, event) } pub fn resize( -- cgit v1.2.3