summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJon Santmyer <jon@jonsantmyer.com>2026-05-04 11:03:27 -0400
committerJon Santmyer <jon@jonsantmyer.com>2026-05-04 11:03:27 -0400
commitb35d6cf47ed154697fb45e10586206295148eb35 (patch)
treeb28f7de2152eff94f7e2d2f156f1390daff19106 /src
parentdd5de0107163bc3ea3898c07089d00f82feeec5e (diff)
downloadsystemic4x-b35d6cf47ed154697fb45e10586206295148eb35.tar.gz
systemic4x-b35d6cf47ed154697fb45e10586206295148eb35.tar.bz2
systemic4x-b35d6cf47ed154697fb45e10586206295148eb35.zip
add label rendering for planetary bodies
Diffstat (limited to 'src')
-rw-r--r--src/canvas.rs176
-rw-r--r--src/main.rs2
-rw-r--r--src/tacmap.rs95
-rw-r--r--src/tacmap/render.rs9
-rw-r--r--src/window.rs49
5 files changed, 84 insertions, 247 deletions
diff --git a/src/canvas.rs b/src/canvas.rs
deleted file mode 100644
index dbcac7f..0000000
--- a/src/canvas.rs
+++ /dev/null
@@ -1,176 +0,0 @@
-use wgpu::RenderPipeline;
-
-use crate::wgpuctx::WgpuCtx;
-use crate::texture::Texture;
-use crate::vertex::Vertex;
-use crate::wgpuctx::pipeline::RenderPipelineBuilder;
-
-struct CanvasTexture
-{
- pub texture: Texture,
- buffer: wgpu::Buffer
-}
-
-pub struct Canvas
-{
- pipeline: wgpu::RenderPipeline,
- vertex_buffer: wgpu::Buffer,
- texture: CanvasTexture,
-
- position: winit::dpi::LogicalPosition<f32>,
- size: winit::dpi::LogicalSize<f32>
-}
-
-impl Canvas
-{
- fn create_canvas_texture(
- wgpuctx: &WgpuCtx,
- canvas_size: winit::dpi::LogicalSize<f32>,
- window_size: winit::dpi::PhysicalSize<u32>)
- -> CanvasTexture
- {
- let canvas_physical_size = winit::dpi::PhysicalSize::<u32>::new(
- (window_size.width as f32 * canvas_size.width).floor() as u32,
- (window_size.height as f32 * canvas_size.height).floor() as u32
- );
-
- CanvasTexture::new(wgpuctx, canvas_physical_size)
- }
-
- pub fn new(
- wgpuctx: &WgpuCtx,
- window_size: winit::dpi::PhysicalSize<u32>,
- position: winit::dpi::LogicalPosition<f32>,
- size: winit::dpi::LogicalSize<f32>
- ) -> Result<Self, ()> {
-
- let pos_x = position.x * 2.0 - 1.0;
- let pos_y = position.y * 2.0 - 1.0;
- let size_x = size.width * 2.0;
- let size_y = size.height * 2.0;
-
- let vertices: &[Vertex] = &[
- Vertex { position: [ pos_x, pos_y, 0.0 ], uv: [ 0.0, 1.0 ] },
- Vertex { position: [ pos_x+size_x, pos_y, 0.0 ], uv: [ 1.0, 1.0 ] },
- Vertex { position: [ pos_x+size_x, pos_y+size_y, 0.0 ], uv: [ 1.0, 0.0 ] },
- Vertex { position: [ pos_x+size_x, pos_y+size_y, 0.0 ], uv: [ 1.0, 0.0 ] },
- Vertex { position: [ pos_x, pos_y+size_y, 0.0 ], uv: [ 0.0, 0.0 ] },
- Vertex { position: [ pos_x, pos_y, 0.0 ], uv: [ 0.0, 1.0 ] },
- ];
-
- let vertex_buffer = wgpuctx.create_buffer_init(
- &wgpu::util::BufferInitDescriptor {
- label: Some("Vertex Buffer"),
- contents: bytemuck::cast_slice(vertices),
- usage: wgpu::BufferUsages::VERTEX
- }
- );
-
- let shader = wgpuctx.create_shader(
- wgpu::include_wgsl!(concat!(
- env!("CARGO_MANIFEST_DIR"),
- "/assets/shaders/canvas.wgsl")
- ));
-
- let canvas_texture = Canvas::create_canvas_texture(wgpuctx, size, window_size);
-
- let render_pipeline = RenderPipelineBuilder::new(
- &shader)
- .add_bindgroup(&canvas_texture.texture.bindgrouplayout)
- .add_vertex_layout(Vertex::descr())
- .build(Some("Canvas render pipleine"), wgpuctx);
-
- Ok(Self {
- pipeline: render_pipeline,
- vertex_buffer: vertex_buffer,
- texture: canvas_texture,
- position: position,
- size: size
- })
- }
-
- pub fn resize(
- &mut self,
- wgpuctx: &WgpuCtx,
- width: u32,
- height: u32)
- {
- let window_size = winit::dpi::PhysicalSize::new(width, height);
- self.texture = Canvas::create_canvas_texture(wgpuctx, self.size, window_size);
- }
-
- pub fn present(
- &mut self,
- screen_pass: &mut wgpu::RenderPass
- )
- -> Result<(), wgpu::SurfaceError> {
-
- screen_pass.set_pipeline(&self.pipeline);
- self.texture.texture.use_on_pass(screen_pass, 0);
- screen_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
- screen_pass.draw(0..6,0..1);
- Ok(())
- }
-
- pub fn view(&self)
- -> &wgpu::TextureView
- {
- self.texture.texture.view()
- }
-} //impl Canvas
-
-impl CanvasTexture
-{
- pub fn new(
- wgpuctx: &WgpuCtx,
- size: winit::dpi::PhysicalSize<u32>)
- -> Self
- {
- let u32_size = std::mem::size_of::<u32>() as u32;
-
- let buffer_size = (u32_size * size.width * size.height) as wgpu::BufferAddress;
- let buffer_descr = wgpu::BufferDescriptor {
- size: buffer_size,
- usage: wgpu::BufferUsages::COPY_DST,
- label: None,
- mapped_at_creation: false
- };
-
- let texture = wgpuctx.new_render_texture(size);
- let buffer = wgpuctx.create_buffer(&buffer_descr);
-
- Self {
- texture: texture,
- buffer: buffer
- }
- }
-}
-
-impl WgpuCtx
-{
- pub fn new_render_texture(
- &self,
- size: winit::dpi::PhysicalSize<u32>)
- -> Texture
- {
- let descr = wgpu::TextureDescriptor {
- size: wgpu::Extent3d {
- width: size.width,
- height: size.height,
- depth_or_array_layers: 1
- },
- mip_level_count: 1,
- sample_count: 1,
- dimension: wgpu::TextureDimension::D2,
- format: wgpu::TextureFormat::Bgra8UnormSrgb,
- view_formats: &[
- wgpu::TextureFormat::Bgra8UnormSrgb
- ],
- usage: wgpu::TextureUsages::TEXTURE_BINDING |
- wgpu::TextureUsages::COPY_SRC |
- wgpu::TextureUsages::RENDER_ATTACHMENT,
- label: None
- };
- self.new_texture(descr)
- }
-}
diff --git a/src/main.rs b/src/main.rs
index 72cd3dd..4aeaa5e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -5,7 +5,6 @@ mod wgpuctx;
mod eguictx;
mod vertex;
mod texture;
-mod canvas;
mod solar_system;
mod known_stars;
mod timeman;
@@ -14,7 +13,6 @@ use std::cell::RefCell;
use std::thread;
use std::time::{Duration, Instant};
-use serde::de;
use winit::event::{KeyEvent, WindowEvent};
use winit::event_loop::{EventLoop, ActiveEventLoop, ControlFlow};
use winit::error::{EventLoopError};
diff --git a/src/tacmap.rs b/src/tacmap.rs
index de2ddcd..461d819 100644
--- a/src/tacmap.rs
+++ b/src/tacmap.rs
@@ -1,24 +1,16 @@
pub mod camera;
pub mod render;
-mod tacmap {
- pub use super::render;
- pub use super::camera;
-}
-
-use std::cell::RefCell;
use std::time::Duration;
+use cgmath::InnerSpace;
use winit::event::ElementState;
use winit::keyboard::KeyCode;
-use crate::GameState;
-use crate::canvas::Canvas;
use crate::solar_system::SolarSystem;
use crate::solar_system::SystemId;
use crate::timeman::TimeMan;
use crate::ui;
-use crate::wgpuctx::RenderPassBuilder;
use crate::wgpuctx::SceneCtx;
use crate::wgpuctx::WgpuCtx;
use render::*;
@@ -26,7 +18,6 @@ use camera::*;
pub struct TacticalMap
{
- canvas: Canvas,
camera: Camera,
pmatrix: Projection,
@@ -40,21 +31,12 @@ pub struct TacticalMap
impl TacticalMap
{
- pub fn new(
- wgpuctx: &WgpuCtx,
- position: winit::dpi::LogicalPosition<f32>,
- size: winit::dpi::LogicalSize<f32>)
+ pub fn new(wgpuctx: &WgpuCtx)
-> Self {
let surface_size = winit::dpi::PhysicalSize::new(
wgpuctx.surface_config().width,
wgpuctx.surface_config().height
);
-
- let canvas = Canvas::new(
- wgpuctx,
- surface_size,
- position,
- size).unwrap();
let camera = Camera::new(
wgpuctx,
@@ -69,7 +51,6 @@ impl TacticalMap
(0.01, 1000.0));
Self {
- canvas: canvas,
camera: camera,
pmatrix: projection,
camera_controller: CameraController::new(),
@@ -83,11 +64,9 @@ impl TacticalMap
pub fn resize(
&mut self,
- wgpuctx: &WgpuCtx,
width: u32,
height: u32)
{
- self.canvas.resize(wgpuctx, width, height);
self.pmatrix.resize(width, height);
}
@@ -142,29 +121,63 @@ impl TacticalMap
Err(e) => println!("Tactical map render update error: {}", e)
}
- let mut scene = SceneCtx::from_view_default(wgpuctx, self.canvas.view(), Some("Tactical map scene"));
- let pass_builder = RenderPassBuilder::new(Some("Tactical map render pass"), scene.view())
- .clear_color(wgpu::Color { r: 0.0, g: 0.0, b: 0.1, a: 1.0 });
+ Ok(())
+ }
+ pub fn prepare(
+ &self,
+ scene: &mut SceneCtx)
+ {
self.camera.stage_changes(scene.encoder_mut());
- {
- let mut pass = pass_builder.build_from_scene(&mut scene);
-
- self.grid_renderer.render(&mut pass, &self.camera);
- self.orbit_renderer.render(&mut pass, &self.camera);
- self.body_renderer.render(&mut pass, &self.camera);
- }
+ }
- scene.submit(wgpuctx);
- Ok(())
+ pub fn paint(
+ &self,
+ pass: &mut wgpu::RenderPass<'_>)
+ {
+ self.grid_renderer.render( pass, &self.camera);
+ self.orbit_renderer.render(pass, &self.camera);
+ self.body_renderer.render( pass, &self.camera);
}
- pub fn present(
- &mut self,
- screen_pass: &mut wgpu::RenderPass)
- -> Result<(), wgpu::SurfaceError>
+ pub fn paint_labels(
+ &self,
+ solar_system: &SolarSystem,
+ screen_size: egui::Vec2,
+ ui: &mut egui::Ui)
{
- self.canvas.present(screen_pass)?;
- Ok(())
+ let view_matrix = self.camera.view_matrix();
+ let proj_matrix = self.pmatrix.projection_matrix();
+ let pv_matrix = proj_matrix * view_matrix;
+
+ //Paint body labels
+ let bodies = solar_system.bodies();
+ bodies.iter().for_each(|body| {
+ let scaled_radius = (2.0 * body.radius() * self.camera.get_scale()).max(16.0);
+
+ let world_pos = solar_system.body_position(body);
+ let local_pos = world_pos - self.camera.get_abs_position();
+
+ let relative_pos = body.position() * self.camera.get_scale() as f64;
+ if relative_pos.magnitude() < 0.05 && relative_pos.magnitude() != 0.0
+ { return; }
+
+ let scaled_pos = local_pos * self.camera.get_scale() as f64;
+
+ let clip_pos = pv_matrix * scaled_pos.map(|v| { v as f32 }).extend(1.0);
+ let ndc_pos = clip_pos.truncate() / clip_pos.w;
+
+ let screen_pos = egui::pos2(
+ ((ndc_pos.x + 1.0) * 0.5) * screen_size.x,
+ (((-ndc_pos.y + 1.0) * 0.5) * screen_size.y) + scaled_radius);
+ if clip_pos.z < 0.0 { return; }
+
+ ui.put(
+ egui::Rect::from_pos(screen_pos).expand(64.0),
+ egui::Label::new(
+ egui::RichText::new(body.name())
+ .color(egui::Color32::WHITE)
+ ).selectable(false).sense(egui::Sense::empty()));
+ });
}
} // impl SystemViewport
diff --git a/src/tacmap/render.rs b/src/tacmap/render.rs
index 48823e2..e6944d0 100644
--- a/src/tacmap/render.rs
+++ b/src/tacmap/render.rs
@@ -1,14 +1,11 @@
-use std::{fmt::Display, num::NonZero};
+use std::{fmt::Display};
use std::error::Error;
-use cgmath::InnerSpace;
use wgpu::RenderPass;
-use crate::canvas::Canvas;
use crate::solar_system::Kilometers;
use crate::tacmap::camera::Camera;
-use crate::timeman::DAY;
-use crate::wgpuctx::{RenderPassBuilder, SceneCtx};
+use crate::timeman::{DAY, SYSTEM_TICK_INTERVAL};
use crate::{solar_system::{SolarSystem, SystemId}, timeman::Second, vertex::{self, Vertex}, wgpuctx::{WgpuCtx, pipeline::RenderPipelineBuilder}};
#[derive(Debug, Clone)]
@@ -370,7 +367,7 @@ impl OrbitRenderer
if !body.does_orbit() { return (0, None); }
let period = body.orbital_period();
- let num_points = ((period / (5 * DAY)) as usize).max(360);
+ let num_points = ((period / (SYSTEM_TICK_INTERVAL)) as usize).clamp(180, 360*4);
let period_interval = period as f64 / num_points as f64;
let mut points = vec![
diff --git a/src/window.rs b/src/window.rs
index c64d653..73034ef 100644
--- a/src/window.rs
+++ b/src/window.rs
@@ -38,10 +38,7 @@ impl GameWindow
let wgpuctx = pollster::block_on(WgpuCtx::new(instance, window.clone()));
let eguictx = EguiCtx::new(&window, &wgpuctx);
- let tacmap = TacticalMap::new(
- &wgpuctx,
- winit::dpi::LogicalPosition::new(0.0, 0.0),
- winit::dpi::LogicalSize::new(1.0, 1.0));
+ let tacmap = TacticalMap::new(&wgpuctx);
let ui_state = ui::State{
topbar_sate: ui::topbar::TopBarState {
@@ -100,7 +97,16 @@ impl GameWindow
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);
+
+ 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 current_system = &game_state.solar_systems()[self.ui_state.topbar_sate.current_system.unwrap()];
@@ -109,28 +115,27 @@ impl GameWindow
&self.wgpuctx,
current_system,
game_state.timeman())?;
- }
-
- let view = self.wgpuctx.prepare_surface(&wgpu::TextureViewDescriptor::default())?;
- let mut scene = SceneCtx::from_view_default(&self.wgpuctx, &view, Some("Systemic window scene"));
- {
+
+ 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.0, a: 1.0 })
+ .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.present(&mut pass)?;
- }
- {
- self.eguictx.prepare(&self.window);
- self.ui_state.render(game_state, &self.eguictx);
-
- self.eguictx.present(
- &self.window,
- &self.wgpuctx,
- scene.encoder_mut(),
- &view);
+ 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, screen_size, ui);
+ });
}
+ self.eguictx.present(
+ &self.window,
+ &self.wgpuctx,
+ scene.encoder_mut(),
+ &view);
scene.submit(&self.wgpuctx);
self.wgpuctx.present_surface();
@@ -155,7 +160,7 @@ impl GameWindow
) {
if width > 0 && height > 0 {
self.wgpuctx.resize(width, height);
- self.tactical_map.resize(&self.wgpuctx, width, height);
+ self.tactical_map.resize(width, height);
self.window.request_redraw();
}
}