summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJon Santmyer <jon@jonsantmyer.com>2026-04-22 15:40:32 -0400
committerJon Santmyer <jon@jonsantmyer.com>2026-04-22 15:40:32 -0400
commit25255a8b9147d27aa40b28d6aadb62c0ab275d32 (patch)
tree2d2ec324de7c0c16c098d85746ab060edb536f76 /src
parent3d3864171785c589872bf23faaaa3a421f56ee4e (diff)
downloadsystemic4x-25255a8b9147d27aa40b28d6aadb62c0ab275d32.tar.gz
systemic4x-25255a8b9147d27aa40b28d6aadb62c0ab275d32.tar.bz2
systemic4x-25255a8b9147d27aa40b28d6aadb62c0ab275d32.zip
simplify rendering pipeline. add gridlines to tacmap
Diffstat (limited to 'src')
-rw-r--r--src/tacmap.rs31
-rw-r--r--src/tacmap/camera.rs6
-rw-r--r--src/tacmap/render.rs70
-rw-r--r--src/wgpuctx/mod.rs71
-rw-r--r--src/wgpuctx/pipeline.rs17
-rw-r--r--src/window.rs16
6 files changed, 155 insertions, 56 deletions
diff --git a/src/tacmap.rs b/src/tacmap.rs
index e4cb76a..abae50e 100644
--- a/src/tacmap.rs
+++ b/src/tacmap.rs
@@ -17,6 +17,8 @@ use crate::canvas::Canvas;
use crate::solar_system::SolarSystem;
use crate::solar_system::SystemId;
use crate::ui;
+use crate::wgpuctx::RenderPassBuilder;
+use crate::wgpuctx::SceneCtx;
use crate::wgpuctx::WgpuCtx;
use render::*;
use camera::*;
@@ -28,7 +30,8 @@ pub struct TacticalMap
pmatrix: Projection,
camera_controller: CameraController,
- renderstate: Option<(SystemId, BodyRenderer)>
+ body_renderer: Option<(SystemId, BodyRenderer)>,
+ grid_renderer: GridRenderer
}
impl TacticalMap
@@ -66,7 +69,8 @@ impl TacticalMap
camera: camera,
pmatrix: projection,
camera_controller: CameraController::new(),
- renderstate: None,
+ body_renderer: None,
+ grid_renderer: GridRenderer::new(wgpuctx)
}
}
@@ -121,7 +125,7 @@ impl TacticalMap
self.camera.update_buffer(wgpuctx, &self.pmatrix);
- let tacrender = match &mut self.renderstate {
+ let body_renderer = match &mut self.body_renderer {
Some((id, render)) => {
if *id != current_system_id {
*id = current_system_id;
@@ -131,14 +135,14 @@ impl TacticalMap
},
None => {
let tmp = render::BodyRenderer::new(wgpuctx);
- self.renderstate = Some((current_system_id, tmp));
- &mut self.renderstate.as_mut().unwrap().1
+ self.body_renderer = Some((current_system_id, tmp));
+ &mut self.body_renderer.as_mut().unwrap().1
}
};
//Update buffers for the current system and time.
- tacrender.rebuild(wgpuctx, current_system);
- match tacrender.update(
+ body_renderer.rebuild(wgpuctx, current_system);
+ match body_renderer.update(
wgpuctx, current_system, &self.camera,
game_state.timeman().seconds())
{
@@ -146,8 +150,19 @@ impl TacticalMap
Err(e) => println!("Tactical map render update error: {}", e)
}
- tacrender.render(wgpuctx, &self.canvas, &self.camera);
+ 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 });
+ self.camera.stage_changes(scene.encoder_mut());
+ {
+ let mut pass = pass_builder.build_from_scene(&mut scene);
+
+ self.grid_renderer.render(wgpuctx, &mut pass, &self.camera);
+ body_renderer.render(wgpuctx, &mut pass, &self.camera);
+ }
+
+ scene.submit(wgpuctx);
Ok(())
}
diff --git a/src/tacmap/camera.rs b/src/tacmap/camera.rs
index c573cfb..895fa1e 100644
--- a/src/tacmap/camera.rs
+++ b/src/tacmap/camera.rs
@@ -253,7 +253,7 @@ impl CameraController
&mut self,
camera: &mut Camera,
target: Vector3<Kilometers>,
- min_radius: f32,
+ target_radius: f32,
dt: Duration)
{
camera.abs_position = target;
@@ -278,7 +278,7 @@ impl CameraController
let (az_sin, az_cos) = camera.yaw.0.sin_cos();
let (p_sin, p_cos) = camera.pitch.0.sin_cos();
- let radius = f32::max(min_radius * camera.scale, current_radius + dist_diff);
+ let radius = f32::max(target_radius * camera.scale, current_radius + dist_diff).max(0.1);
camera.rel_position = Vector3::new(
radius * p_cos * az_cos,
radius * p_sin,
@@ -333,7 +333,7 @@ impl CameraController
self.update_orbit(
camera,
current_system.body_position(body).cast().unwrap(),
- body.radius() * 2.0,
+ (body.radius() * 2.0).max(1.0),
dt);
}
None => self.update_pan(camera, dt)
diff --git a/src/tacmap/render.rs b/src/tacmap/render.rs
index 26d6977..c1256ff 100644
--- a/src/tacmap/render.rs
+++ b/src/tacmap/render.rs
@@ -1,10 +1,12 @@
use std::{fmt::Display, num::NonZero};
use std::error::Error;
+use wgpu::RenderPass;
+
use crate::canvas::Canvas;
use crate::solar_system::Kilometers;
use crate::tacmap::camera::Camera;
-use crate::wgpuctx::RenderPassBuilder;
+use crate::wgpuctx::{RenderPassBuilder, SceneCtx};
use crate::{solar_system::{SolarSystem, SystemId}, timeman::Second, vertex::{self, Vertex}, wgpuctx::{WgpuCtx, pipeline::RenderPipelineBuilder}};
struct BodyInstance
@@ -161,7 +163,7 @@ impl BodyRenderer
pub fn render(
&self,
wgpuctx: &WgpuCtx,
- canvas: &Canvas,
+ pass: &mut RenderPass,
camera: &Camera)
{
let (num_bodies, bodies_buffer) = match &self.body_instance_buffer {
@@ -169,27 +171,13 @@ impl BodyRenderer
None => return
};
- let mut encoder = wgpuctx.create_default_encoder("Tactical map renderer encoder");
- let view = canvas.view();
-
- {
- camera.stage_changes(&mut encoder);
- }
- {
- let mut pass = RenderPassBuilder::new("Tactiacal map render pass", view)
- .clear_color(wgpu::Color { r: 0.0, g: 0.0, b: 0.1, a: 1.0 })
- .build(&mut encoder);
-
- pass.set_pipeline(&self.pipeline);
- pass.set_bind_group(0, camera.bindgroup(), &[]);
+ pass.set_pipeline(&self.pipeline);
+ pass.set_bind_group(0, camera.bindgroup(), &[]);
- pass.set_vertex_buffer(0, self.body_vertex_buffer.slice(..));
- pass.set_vertex_buffer(1, bodies_buffer.slice(..));
+ pass.set_vertex_buffer(0, self.body_vertex_buffer.slice(..));
+ pass.set_vertex_buffer(1, bodies_buffer.slice(..));
- pass.draw(0..6, 0..num_bodies.clone() as _);
- }
-
- wgpuctx.submit_encoder(encoder);
+ pass.draw(0..6, 0..num_bodies.clone() as _);
}
} // impl RenderState
@@ -229,3 +217,43 @@ impl BodyInstanceRaw
}
}
}
+
+pub struct GridRenderer
+{
+ pipeline: wgpu::RenderPipeline,
+}
+
+impl GridRenderer
+{
+ pub fn new(wgpuctx: &WgpuCtx)
+ -> Self
+ {
+ let shader = wgpuctx.create_shader(
+ wgpu::include_wgsl!(concat!(
+ env!("CARGO_MANIFEST_DIR"),
+ "/assets/shaders/tacmap/grid.wgsl")
+ ));
+
+ let render_pipeline = RenderPipelineBuilder::new(&shader)
+ .add_bindgroup(&Camera::bindgroup_layout(wgpuctx))
+ .cull_mode(None)
+ .build(Some("Tactical map grid pipeline"), wgpuctx);
+
+ Self {
+ pipeline: render_pipeline
+ }
+ }
+
+ pub fn render(
+ &self,
+ wgpuctx: &WgpuCtx,
+ pass: &mut RenderPass,
+ camera: &Camera
+ )
+ {
+ pass.set_pipeline(&self.pipeline);
+ pass.set_bind_group(0, camera.bindgroup(), &[]);
+
+ pass.draw(0..6, 0..1);
+ }
+}
diff --git a/src/wgpuctx/mod.rs b/src/wgpuctx/mod.rs
index f8aa3ec..5f26a99 100644
--- a/src/wgpuctx/mod.rs
+++ b/src/wgpuctx/mod.rs
@@ -19,11 +19,10 @@ pub struct WgpuCtx
queue: wgpu::Queue,
}
-pub struct RenderPassBuilder<'encoder>
+pub struct SceneCtx<'view>
{
- label: &'static str,
- view: &'encoder wgpu::TextureView,
- clear_color: wgpu::Color
+ view: &'view wgpu::TextureView,
+ encoder: wgpu::CommandEncoder
}
impl WgpuCtx
@@ -127,11 +126,11 @@ impl WgpuCtx
pub fn create_default_encoder(
&self,
- label: &'static str)
+ label: Option<&'static str>)
-> wgpu::CommandEncoder {
self.create_encoder(
&wgpu::CommandEncoderDescriptor {
- label: Some(label)
+ label: label
}
)
}
@@ -198,16 +197,53 @@ impl WgpuCtx
} //impl WgpuCtx
+impl<'view> SceneCtx<'view>
+{
+ pub fn from_view_default(
+ wgpuctx: &WgpuCtx,
+ view: &'view wgpu::TextureView,
+ label: Option<&'static str>)
+ -> Self {
+ Self {
+ view: view,
+ encoder: wgpuctx.create_default_encoder(label)
+ }
+ }
+
+ pub fn view(&self) -> &'view wgpu::TextureView
+ { self.view }
+
+ pub fn encoder(&self) -> &wgpu::CommandEncoder
+ { &self.encoder }
+
+ pub fn encoder_mut(&mut self) -> &mut wgpu::CommandEncoder
+ { &mut self.encoder }
+
+ pub fn submit(
+ self,
+ wgpuctx: &WgpuCtx)
+ {
+ wgpuctx.submit_encoder(self.encoder);
+ }
+}
+
+pub struct RenderPassBuilder<'encoder>
+{
+ label: Option<&'static str>,
+ view: &'encoder wgpu::TextureView,
+ clear_color: Option<wgpu::Color>
+}
+
impl<'encoder> RenderPassBuilder<'encoder>
{
pub fn new(
- label: &'static str,
+ label: Option<&'static str>,
view: &'encoder wgpu::TextureView)
-> Self {
Self {
label: label,
view: view,
- clear_color: wgpu::Color { r: 0.0, g: 0.0, b: 0.0, a: 1.0 }
+ clear_color: None
}
}
@@ -215,24 +251,27 @@ impl<'encoder> RenderPassBuilder<'encoder>
mut self,
color: wgpu::Color)
-> Self {
- self.clear_color = color;
+ self.clear_color = Some(color);
self
}
- pub fn build(
+ pub fn build_from_encoder(
self,
encoder: &'encoder mut wgpu::CommandEncoder)
-> wgpu::RenderPass<'encoder>
{
encoder.begin_render_pass(
&wgpu::RenderPassDescriptor {
- label: Some(self.label),
+ label: self.label,
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: self.view,
resolve_target: None,
depth_slice: None,
ops: wgpu::Operations {
- load: wgpu::LoadOp::Clear(self.clear_color),
+ load: match self.clear_color {
+ Some(color) => wgpu::LoadOp::Clear(color),
+ None => wgpu::LoadOp::Load
+ },
store: wgpu::StoreOp::Store
}
})],
@@ -242,4 +281,10 @@ impl<'encoder> RenderPassBuilder<'encoder>
}
)
}
-}
+
+ pub fn build_from_scene(
+ self,
+ scene: &'encoder mut SceneCtx)
+ -> wgpu::RenderPass<'encoder>
+ { self.build_from_encoder(scene.encoder_mut()) }
+}// impl RenderPassBuilder
diff --git a/src/wgpuctx/pipeline.rs b/src/wgpuctx/pipeline.rs
index 7606203..0811800 100644
--- a/src/wgpuctx/pipeline.rs
+++ b/src/wgpuctx/pipeline.rs
@@ -12,7 +12,9 @@ pub struct RenderPipelineBuilder<'a>
vertex_comp_options: Option<wgpu::PipelineCompilationOptions<'a>>,
fragment_comp_options: Option<wgpu::PipelineCompilationOptions<'a>>,
- vertex_buffer_layouts: Vec<wgpu::VertexBufferLayout<'a>>
+ vertex_buffer_layouts: Vec<wgpu::VertexBufferLayout<'a>>,
+
+ cull_mode: Option<wgpu::Face>
}
impl<'a> RenderPipelineBuilder<'a>
@@ -30,7 +32,9 @@ impl<'a> RenderPipelineBuilder<'a>
vertex_comp_options: None,
fragment_comp_options: None,
- vertex_buffer_layouts: Vec::new()
+ vertex_buffer_layouts: Vec::new(),
+
+ cull_mode: Some(wgpu::Face::Back)
}
}
@@ -50,6 +54,13 @@ impl<'a> RenderPipelineBuilder<'a>
self
}
+ pub fn cull_mode(
+ mut self,
+ mode: Option<wgpu::Face>
+ ) -> Self {
+ self.cull_mode = mode; self
+ }
+
pub fn build(
self,
label: Option<&'static str>,
@@ -101,7 +112,7 @@ impl<'a> RenderPipelineBuilder<'a>
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
- cull_mode: Some(wgpu::Face::Back),
+ cull_mode: self.cull_mode,
polygon_mode: wgpu::PolygonMode::Fill,
unclipped_depth: false,
conservative: false
diff --git a/src/window.rs b/src/window.rs
index 28c69f8..3b090ff 100644
--- a/src/window.rs
+++ b/src/window.rs
@@ -8,7 +8,7 @@ use winit::keyboard::KeyCode;
use crate::tacmap::TacticalMap;
use crate::{GameState, SystemicApp, ui};
use crate::solar_system::{SolarSystem, SystemId};
-use crate::wgpuctx::{RenderPassBuilder, WgpuCtx};
+use crate::wgpuctx::{RenderPassBuilder, SceneCtx, WgpuCtx};
use crate::eguictx::EguiCtx;
pub struct GameWindow
@@ -58,7 +58,7 @@ impl GameWindow
eguictx: eguictx,
tactical_map: tacmap,
- ui_state: Default::default()
+ ui_state: ui_state
})
}
@@ -100,12 +100,12 @@ impl GameWindow
game_state,
self.ui_state.current_system)?;
- let mut encoder = self.wgpuctx.create_default_encoder("Systemic window command encoder");
let view = self.wgpuctx.prepare_surface(&wgpu::TextureViewDescriptor::default())?;
+ let mut scene = SceneCtx::from_view_default(&self.wgpuctx, &view, Some("Systemic window scene"));
{
- let mut pass = RenderPassBuilder::new("Systemic window render pass", &view)
- .clear_color(wgpu::Color { r: 1.0, g: 1.0, b: 1.0, a: 1.0 })
- .build(&mut encoder);
+ 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 })
+ .build_from_scene(&mut scene);
//Draw the tactical map canvas.
self.tactical_map.present(&mut pass)?;
@@ -117,11 +117,11 @@ impl GameWindow
self.eguictx.present(
&self.window,
&self.wgpuctx,
- &mut encoder,
+ scene.encoder_mut(),
&view);
}
- self.wgpuctx.submit_encoder(encoder);
+ scene.submit(&self.wgpuctx);
self.wgpuctx.present_surface();
self.window.request_redraw();