diff options
| author | Jon Santmyer <jon@jonsantmyer.com> | 2026-05-04 11:03:27 -0400 |
|---|---|---|
| committer | Jon Santmyer <jon@jonsantmyer.com> | 2026-05-04 11:03:27 -0400 |
| commit | b35d6cf47ed154697fb45e10586206295148eb35 (patch) | |
| tree | b28f7de2152eff94f7e2d2f156f1390daff19106 | |
| parent | dd5de0107163bc3ea3898c07089d00f82feeec5e (diff) | |
| download | systemic4x-b35d6cf47ed154697fb45e10586206295148eb35.tar.gz systemic4x-b35d6cf47ed154697fb45e10586206295148eb35.tar.bz2 systemic4x-b35d6cf47ed154697fb45e10586206295148eb35.zip | |
add label rendering for planetary bodies
| -rw-r--r-- | src/canvas.rs | 176 | ||||
| -rw-r--r-- | src/main.rs | 2 | ||||
| -rw-r--r-- | src/tacmap.rs | 95 | ||||
| -rw-r--r-- | src/tacmap/render.rs | 9 | ||||
| -rw-r--r-- | src/window.rs | 49 |
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(); } } |
