summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJon Santmyer <jon@jonsantmyer.com>2026-05-12 19:01:27 -0400
committerJon Santmyer <jon@jonsantmyer.com>2026-05-12 19:01:27 -0400
commita0a3b3974cab754c10a1517d82762b99482970ce (patch)
tree8aeb0ca1e007bacecc8e12a263bd5aa321b8f69a /src
parent7f63ec5c10eb7e8dd4edaabd1a6a437328911d39 (diff)
downloadsystemic4x-a0a3b3974cab754c10a1517d82762b99482970ce.tar.gz
systemic4x-a0a3b3974cab754c10a1517d82762b99482970ce.tar.bz2
systemic4x-a0a3b3974cab754c10a1517d82762b99482970ce.zip
update packages to latest versionsHEADmain
Diffstat (limited to 'src')
-rw-r--r--src/eguictx.rs3
-rw-r--r--src/fleet.rs31
-rw-r--r--src/main.rs17
-rw-r--r--src/solar_system.rs27
-rw-r--r--src/solar_system/body.rs8
-rw-r--r--src/solar_system/orbit.rs12
-rw-r--r--src/tacmap.rs27
-rw-r--r--src/tacmap/orbit_render.rs81
-rw-r--r--src/texture.rs2
-rw-r--r--src/ui.rs14
-rw-r--r--src/ui/bodies_window.rs114
-rw-r--r--src/ui/fleet_window.rs190
-rw-r--r--src/ui/topbar.rs9
-rw-r--r--src/wgpuctx/mod.rs19
-rw-r--r--src/wgpuctx/pipeline.rs10
-rw-r--r--src/window.rs98
16 files changed, 382 insertions, 280 deletions
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<Second> = 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<OrbitalBody>,
+ heirarchy: NTreeNode<BodyId>
}
impl SolarSystem
{
+ fn rebuild_system_heirarchy(
+ bodies: &[OrbitalBody],
+ root: &mut NTreeNode<BodyId>)
+ {
+ 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<BodyId>
+ { &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<Second>,
+ last_time: Option<Second>,
pipeline: wgpu::RenderPipeline,
- orbit_vertex_buffers: Option<Vec<(BodyId, wgpu::Buffer)>>,
+ body_orbit_vertex_buffers: Option<Vec<(BodyId, wgpu::Buffer)>>,
+ fleet_orbit_vertex_buffers: Option<Vec<(FleetId, wgpu::Buffer)>>,
+
origin_buffer: Option<wgpu::Buffer>,
+
origin_bind_group: Option<wgpu::BindGroup>,
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::<Vec<_>>());
}
@@ -179,16 +190,29 @@ impl OrbitRenderer
pub fn update(
&mut self,
wgpuctx: &WgpuCtx,
+ fleets_man: &FleetsManager,
solar_system: &SolarSystem,
time: Second)
-> Result<(), Box<dyn Error>>
{
- 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::<Vec<_>>());
- 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::<Vec<_>>());*/
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<GameState>,
- 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<SystemId>,
- system_heirarchy: NTree<SystemId>,
selected_body: Option<BodyId>
}
@@ -24,64 +19,19 @@ pub struct BodiesWindowAction
impl BodiesWindowState
{
- fn build_system_heirarchy_rec(
- bodies: &[OrbitalBody],
- node: &mut NTreeNode<BodyId>)
- {
- 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::<BodyId>::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<SystemId>,
+ pub selected_fleet: Option<FleetId>,
+ pub menu_panel: FleetMenuPanelSel,
pub new_fleet_window: Option<NewFleetWindowState>
}
@@ -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<SystemId>,
focused_body: &Option<BodyId>)
-> 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<BodyId>)
- -> 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::<f32>::from(heading.x),
+ cgmath::Deg::<f32>::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<NewFleet>
{
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<wgpu::TextureView, wgpu::SurfaceError>
+ -> Result<wgpu::TextureView, CurrentSurfaceTexture>
{
- 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<Option<&'a wgpu::BindGroupLayout>>,
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<winit::window::Window>,
wgpuctx: WgpuCtx,
eguictx: EguiCtx,
+ window: Arc<winit::window::Window>,
+
tactical_map: TacticalMap,
ui_state: ui::State
@@ -92,52 +93,66 @@ impl GameWindow
pub fn render(
&mut self,
- game_state: &RefCell<GameState>)
- -> Result<(), wgpu::SurfaceError> {
+ game_state: &RefCell<GameState>,
+ 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(