summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--assets/shaders/canvas.wgsl32
-rw-r--r--src/solar_system.rs95
-rw-r--r--src/solar_system/orbit.rs29
-rw-r--r--src/solar_system/ship.rs4
-rw-r--r--src/tacmap.rs4
-rw-r--r--src/tacmap/body_render.rs193
-rw-r--r--src/tacmap/orbit_render.rs240
-rw-r--r--src/tacmap/render.rs420
-rw-r--r--src/window.rs3
9 files changed, 541 insertions, 479 deletions
diff --git a/assets/shaders/canvas.wgsl b/assets/shaders/canvas.wgsl
deleted file mode 100644
index 3be1a77..0000000
--- a/assets/shaders/canvas.wgsl
+++ /dev/null
@@ -1,32 +0,0 @@
-struct VertexInput {
- @location(0) position: vec3<f32>,
- @location(1) uv: vec2<f32>
-};
-
-struct VertexOutput {
- @builtin(position) clip_position: vec4<f32>,
- @location(0) uv: vec2<f32>
-};
-
-@vertex
-fn vs_main(
- model: VertexInput,
-) -> VertexOutput {
- var out: VertexOutput;
-
- out.clip_position = vec4<f32>(model.position, 1.0);
- out.uv = model.uv;
-
- return out;
-}
-
-@group(0) @binding(0)
-var canvas_texture: texture_2d<f32>;
-@group(0) @binding(1)
-var canvas_sampler: sampler;
-
-@fragment
-fn fs_main(in: VertexOutput
-) -> @location(0) vec4<f32> {
- return textureSample(canvas_texture, canvas_sampler, in.uv);
-}
diff --git a/src/solar_system.rs b/src/solar_system.rs
index f4ca9ae..c53f045 100644
--- a/src/solar_system.rs
+++ b/src/solar_system.rs
@@ -1,5 +1,8 @@
+pub mod orbit;
+pub mod ship;
+
use serde::{Deserialize};
-use crate::{known_stars::*, timeman::Second};
+use crate::{known_stars::*, solar_system::orbit::StaticOrbit, timeman::Second};
use std::error::Error;
const GRAVITATIONAL_CONSTANT: f64 = 6.67408e-20;
@@ -13,7 +16,7 @@ pub type BodyId = usize;
pub type SystemId = usize;
#[derive(Debug, Deserialize)]
-pub struct SerialOrbitalBody
+pub struct CSVOrbitalBody
{
name: String,
orbits: Option<BodyId>,
@@ -32,7 +35,12 @@ pub struct SerialOrbitalBody
pub struct OrbitalBody
{
- body: SerialOrbitalBody,
+ name: String,
+ mass: Kilograms,
+ radius: Kilometers,
+ sgp: f64,
+
+ orbit: Option<StaticOrbit>,
position: Option<cgmath::Vector3<Kilometers>>
}
@@ -64,12 +72,12 @@ impl SolarSystem
let mut bodies = Vec::<OrbitalBody>::new();
for result in body_reader.deserialize() {
- let mut record: SerialOrbitalBody = result?;
+ let mut record: CSVOrbitalBody = result?;
match record.orbits {
Some(orbits) => {
if record.sgp == 0.0 {
- record.sgp = (bodies[orbits].body.mass + record.mass) * GRAVITATIONAL_CONSTANT;
+ record.sgp = (bodies[orbits].mass + record.mass) * GRAVITATIONAL_CONSTANT;
}
}
None => {}
@@ -78,7 +86,19 @@ impl SolarSystem
println!("New body: {:?}", record);
bodies.push(OrbitalBody {
- body: record,
+ name: record.name,
+ mass: record.mass,
+ radius: record.radius,
+ sgp: record.sgp,
+ orbit: Some(StaticOrbit {
+ parent: record.orbits,
+ eccentricity: record.eccentricity,
+ inclination: record.inclination,
+ long_asc_node: record.long_asc_node,
+ long_periapsis: record.long_periapsis,
+ mean_long: record.mean_long,
+ semi_major_axis: record.semi_major_axis
+ }),
position: None
});
}
@@ -116,11 +136,16 @@ impl SolarSystem
body: &OrbitalBody)
-> cgmath::Vector3<Kilometers>
{
- match body.body.orbits {
- Some(parent) => {
- let body_pos = body.position();
- let parent_pos = self.bodies[parent].position();
- body_pos + parent_pos
+ match &body.orbit {
+ Some(orbit) => {
+ match orbit.parent {
+ Some(parent) => {
+ let this_pos = body.position();
+ let parent_pos = self.bodies[parent].position();
+ this_pos + parent_pos
+ },
+ None => body.position()
+ }
},
None => body.position()
}
@@ -138,33 +163,53 @@ impl SolarSystem
impl OrbitalBody
{
- pub fn name(&self) -> &String { &self.body.name }
- pub fn radius(&self) -> f32 { self.body.radius as f32 }
+ pub fn name(&self) -> &String { &self.name }
+ pub fn radius(&self) -> f32 { self.radius as f32 }
pub fn position(&self) -> cgmath::Vector3<f64> { self.position.unwrap() }
- pub fn does_orbit(&self) -> bool { self.body.orbits.is_some() }
- pub fn get_orbits(&self) -> Option<BodyId> { self.body.orbits }
+ pub fn does_orbit(&self) -> bool {
+ match &self.orbit {
+ Some(orbit) => orbit.parent.is_some(),
+ None => false
+ }
+ }
+ pub fn get_orbits(&self) -> Option<BodyId> {
+ match &self.orbit {
+ Some(orbit) => orbit.parent(),
+ None => None
+ }
+ }
pub fn orbital_period(&self) -> Second
- { ((self.body.semi_major_axis.powf(3.0) / self.body.sgp).sqrt() * std::f64::consts::TAU) as u64 }
+ {
+ match &self.orbit {
+ Some(v) => v.period(self),
+ None => return 0
+ }
+ }
pub fn calculate_orbit_at(
&self,
time: Second)
-> cgmath::Vector3<f64>
{
- if self.body.orbits.is_none() {
+ let orbit = match &self.orbit {
+ Some(v) => v,
+ None => return cgmath::vec3(0.0, 0.0, 0.0)
+ };
+
+ if orbit.parent.is_none() {
return cgmath::Vector3::<f64>::new(0.0, 0.0, 0.0);
}
- let eccentricity = self.body.eccentricity;
+ let eccentricity = orbit.eccentricity;
- let long_asc_node = self.body.long_asc_node;
- let arg_periaps = self.body.long_periapsis - long_asc_node;
+ let long_asc_node = orbit.long_asc_node;
+ let arg_periaps = orbit.long_periapsis - long_asc_node;
- let sma_cubed = self.body.semi_major_axis.powf(3.0);
- let mean_motion = (self.body.sgp / sma_cubed).sqrt();
+ let sma_cubed = orbit.semi_major_axis.powf(3.0);
+ let mean_motion = (self.sgp / sma_cubed).sqrt();
- let mean_anomaly_epoch = self.body.mean_long - self.body.long_periapsis;
+ let mean_anomaly_epoch = orbit.mean_long - orbit.long_periapsis;
let mean_anomaly = mean_anomaly_epoch + (mean_motion * time as f64);
//Find the eccentric anomaly via newton's method
@@ -192,9 +237,9 @@ impl OrbitalBody
let vw = true_anomaly + arg_periaps;
let (vw_sin, vw_cos) = vw.sin_cos();
let (omega_sin, omega_cos) = long_asc_node.sin_cos();
- let (i_sin, i_cos) = self.body.inclination.sin_cos();
+ let (i_sin, i_cos) = orbit.inclination.sin_cos();
- let r = self.body.semi_major_axis * (1.0 - eccentricity * eccentric_anomaly.cos());
+ let r = orbit.semi_major_axis * (1.0 - eccentricity * eccentric_anomaly.cos());
let x = r * (omega_cos * vw_cos - omega_sin * vw_sin * i_cos);
let y = r * i_sin * vw_sin;
let z = r * (omega_sin * vw_cos + omega_cos * vw_sin * i_cos);
diff --git a/src/solar_system/orbit.rs b/src/solar_system/orbit.rs
new file mode 100644
index 0000000..fe55e4f
--- /dev/null
+++ b/src/solar_system/orbit.rs
@@ -0,0 +1,29 @@
+use crate::solar_system::{Angle, BodyId, Kilometers, OrbitalBody, Percentage};
+use crate::timeman::{Second};
+
+pub struct StaticOrbit
+{
+ pub parent: Option<BodyId>,
+ pub eccentricity: Percentage,
+ pub inclination: Angle,
+ pub long_asc_node: Angle,
+ pub long_periapsis: Angle,
+ pub mean_long: Angle,
+
+ pub semi_major_axis: Kilometers,
+}
+
+impl StaticOrbit
+{
+ pub fn period(
+ &self,
+ this_body: &OrbitalBody)
+ -> Second
+ {
+ ((self.semi_major_axis.powf(3.0) / this_body.sgp).sqrt() * std::f64::consts::TAU) as u64
+ }
+
+ pub fn parent(&self) -> Option<BodyId> {
+ self.parent
+ }
+}
diff --git a/src/solar_system/ship.rs b/src/solar_system/ship.rs
new file mode 100644
index 0000000..eb4cdf3
--- /dev/null
+++ b/src/solar_system/ship.rs
@@ -0,0 +1,4 @@
+pub struct Ship
+{
+
+}
diff --git a/src/tacmap.rs b/src/tacmap.rs
index 461d819..222363f 100644
--- a/src/tacmap.rs
+++ b/src/tacmap.rs
@@ -1,5 +1,7 @@
pub mod camera;
pub mod render;
+mod body_render;
+mod orbit_render;
use std::time::Duration;
@@ -14,6 +16,8 @@ use crate::ui;
use crate::wgpuctx::SceneCtx;
use crate::wgpuctx::WgpuCtx;
use render::*;
+use body_render::*;
+use orbit_render::*;
use camera::*;
pub struct TacticalMap
diff --git a/src/tacmap/body_render.rs b/src/tacmap/body_render.rs
new file mode 100644
index 0000000..8b32532
--- /dev/null
+++ b/src/tacmap/body_render.rs
@@ -0,0 +1,193 @@
+use std::error::Error;
+
+use crate::solar_system::Kilometers;
+use crate::timeman::Second;
+use crate::wgpuctx::{WgpuCtx, pipeline::RenderPipelineBuilder};
+
+use super::*;
+
+pub struct BodyRenderer
+{
+ needs_rebuild: bool,
+ last_time: Option<Second>,
+
+ pipeline: wgpu::RenderPipeline,
+
+ body_instance_buffer: Option<(usize, wgpu::Buffer)>
+}
+
+impl BodyRenderer
+{
+ pub fn new(
+ wgpuctx: &WgpuCtx)
+ -> Self {
+ let shader = wgpuctx.create_shader(
+ wgpu::include_wgsl!(concat!(
+ env!("CARGO_MANIFEST_DIR"),
+ "/assets/shaders/tacmap/body.wgsl")
+ ));
+
+ let render_pipeline = RenderPipelineBuilder::new(&shader)
+ .add_bindgroup(&Camera::bindgroup_layout(wgpuctx))
+ .add_vertex_layout(BodyInstanceRaw::descr())
+ .cull_mode(None)
+ .build(Some("Tactical map render pipeline"), wgpuctx);
+
+ Self {
+ needs_rebuild: true,
+ last_time: None,
+ pipeline: render_pipeline,
+ body_instance_buffer: None
+ }
+ }
+
+ pub fn mark_to_rebuild(&mut self)
+ { self.needs_rebuild = true; }
+
+ pub fn rebuild(
+ &mut self,
+ wgpuctx: &WgpuCtx,
+ solar_system: &SolarSystem)
+ {
+ if self.body_instance_buffer.is_some() && !self.needs_rebuild {
+ return;
+ }
+ self.needs_rebuild = false;
+
+ match self.body_instance_buffer.as_mut() {
+ Some(buffer) => {
+ buffer.1.destroy();
+ self.body_instance_buffer = None;
+ }
+ None => {}
+ }
+
+ let bodies = solar_system.bodies();
+ let buffer_len = bodies.len() * size_of::<BodyInstanceRaw>();
+
+ let buffer = wgpuctx.create_buffer(
+ &wgpu::BufferDescriptor {
+ label: Some("Tactical map bodies instance buffer"),
+ size: buffer_len as u64,
+ usage: wgpu::BufferUsages::COPY_DST |
+ wgpu::BufferUsages::VERTEX,
+ mapped_at_creation: false
+ }
+ );
+
+ self.last_time = None;
+ self.body_instance_buffer = Some((bodies.len(), buffer));
+ }
+
+ pub fn update(
+ &mut self,
+ wgpuctx: &WgpuCtx,
+ solar_system: &SolarSystem,
+ time: Second)
+ -> Result<(), Box<dyn Error>>
+ {
+ //If the last updated time is the same, we don't need to update
+ //the positions of all the bodies.
+ if self.last_time.is_some_and(|last_time| { last_time == time }) {
+ return Ok(());
+ }
+
+ self.last_time = Some(time);
+
+ let (_, bodies_buffer) = match &self.body_instance_buffer {
+ Some(tuple) => tuple,
+ None => return Err(Box::new(NeedsRebuildError))
+ };
+
+ let bodies = solar_system.bodies();
+ let body_instances = bodies.iter().map(|body| {
+ let position = body.position();
+ let origin = match body.get_orbits() {
+ Some(origin_id) => {
+ let origin_body = &bodies[origin_id];
+ origin_body.position()
+ },
+ None => cgmath::Vector3::new(0.0, 0.0, 0.0)
+ };
+ BodyInstance {
+ position: position,
+ origin: origin,
+ radius: body.radius()
+ }.raw()
+ }).collect::<Vec<_>>();
+
+ wgpuctx.queue().write_buffer(bodies_buffer, 0, bytemuck::cast_slice(&body_instances));
+
+ Ok(())
+ }
+
+ pub fn render(
+ &self,
+ pass: &mut wgpu::RenderPass,
+ camera: &Camera)
+ {
+ let (num_bodies, bodies_buffer) = match &self.body_instance_buffer {
+ Some(tuple) => tuple,
+ None => return
+ };
+
+ pass.set_pipeline(&self.pipeline);
+ pass.set_bind_group(0, camera.bindgroup(), &[]);
+
+ pass.set_vertex_buffer(0, bodies_buffer.slice(..));
+
+ pass.draw(0..6, 0..num_bodies.clone() as _);
+ }
+} // impl RenderState
+
+struct BodyInstance
+{
+ position: cgmath::Vector3<Kilometers>,
+ origin: cgmath::Vector3<Kilometers>,
+ radius: f32
+}
+
+#[repr(C)]
+#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
+struct BodyInstanceRaw
+{
+ position: [f32;3],
+ origin: [f32;3],
+ radius: f32
+}
+
+impl BodyInstance
+{
+ fn raw(&self) -> BodyInstanceRaw
+ {
+ BodyInstanceRaw {
+ position: [
+ self.position.x as f32,
+ self.position.y as f32,
+ self.position.z as f32 ],
+ origin: [
+ self.origin.x as f32,
+ self.origin.y as f32,
+ self.origin.z as f32 ],
+ radius: self.radius
+ }
+ }
+} // impl BodyInstance
+
+impl BodyInstanceRaw
+{
+ const ATTRIBS: [wgpu::VertexAttribute;3] =
+ wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x3, 2 => Float32];
+
+ pub fn descr()
+ -> wgpu::VertexBufferLayout<'static> {
+ use std::mem;
+
+ wgpu::VertexBufferLayout {
+ array_stride: mem::size_of::<Self>() as wgpu::BufferAddress,
+ step_mode: wgpu::VertexStepMode::Instance,
+ attributes: &Self::ATTRIBS
+ }
+ }
+}
+
diff --git a/src/tacmap/orbit_render.rs b/src/tacmap/orbit_render.rs
new file mode 100644
index 0000000..d79294e
--- /dev/null
+++ b/src/tacmap/orbit_render.rs
@@ -0,0 +1,240 @@
+use super::*;
+
+use crate::solar_system::BodyId;
+use crate::timeman::{SYSTEM_TICK_INTERVAL, Second};
+use crate::wgpuctx::{WgpuCtx, pipeline::RenderPipelineBuilder};
+
+pub struct OrbitRenderer
+{
+ needs_rebuild: bool,
+ last_time: Option<Second>,
+
+ pipeline: wgpu::RenderPipeline,
+
+ orbit_vertex_buffers: Option<Vec<(BodyId, Option<wgpu::Buffer>)>>,
+ origin_buffer: Option<wgpu::Buffer>,
+ origin_bind_group: Option<wgpu::BindGroup>,
+ origin_bind_group_layout: wgpu::BindGroupLayout
+}
+
+impl OrbitRenderer
+{
+ pub fn new(
+ wgpuctx: &WgpuCtx)
+ -> Self {
+ let shader = wgpuctx.create_shader(
+ wgpu::include_wgsl!(concat!(
+ env!("CARGO_MANIFEST_DIR"),
+ "/assets/shaders/tacmap/orbit.wgsl")
+ ));
+
+ let origin_bind_group_layout = wgpuctx.device().create_bind_group_layout(
+ &wgpu::BindGroupLayoutDescriptor {
+ label: None,
+ entries: &[
+ wgpu::BindGroupLayoutEntry {
+ binding: 0,
+ visibility: wgpu::ShaderStages::VERTEX,
+ ty: wgpu::BindingType::Buffer {
+ ty: wgpu::BufferBindingType::Storage { read_only: true },
+ has_dynamic_offset: false,
+ min_binding_size: None
+ },
+ count: None
+ }
+ ]
+ }
+ );
+
+ let render_pipeline = RenderPipelineBuilder::new(&shader)
+ .add_bindgroup(&Camera::bindgroup_layout(wgpuctx))
+ .add_bindgroup(&origin_bind_group_layout)
+ .add_vertex_layout(OrbitVertex::descr())
+ .primitive_topology(wgpu::PrimitiveTopology::TriangleStrip)
+ .cull_mode(None)
+ .build(Some("Tactical map orbit render pipeline"), wgpuctx);
+
+ Self {
+ needs_rebuild: true,
+ last_time: None,
+ pipeline: render_pipeline,
+ orbit_vertex_buffers: None,
+ origin_buffer: None,
+ origin_bind_group: None,
+ origin_bind_group_layout: origin_bind_group_layout
+ }
+ }
+
+ pub fn mark_to_rebuild(&mut self)
+ { self.needs_rebuild = true; }
+
+ pub fn rebuild(
+ &mut self,
+ wgpuctx: &WgpuCtx,
+ solar_system: &SolarSystem)
+ {
+ if self.orbit_vertex_buffers.is_some() && !self.needs_rebuild {
+ return;
+ }
+ self.needs_rebuild = false;
+
+ match &self.orbit_vertex_buffers {
+ Some(buffers) => {
+ for buffer in buffers {
+ match &buffer.1 {
+ Some(v) => v.destroy(),
+ None => {}
+ }
+ }
+ self.orbit_vertex_buffers = None;
+ },
+ None => {}
+ };
+
+ //From the solar system's bodies, calculate the orbits.
+ let bodies = solar_system.bodies();
+
+ match &self.origin_buffer {
+ Some(buffer) => {
+ buffer.destroy();
+ }
+ None => {}
+ };
+ let origin_buffer = wgpuctx.create_buffer(
+ &wgpu::BufferDescriptor {
+ label: None,
+ size: (std::mem::size_of::<[f32;3]>() * bodies.len()) as _,
+ usage: wgpu::BufferUsages::COPY_DST
+ | wgpu::BufferUsages::STORAGE,
+ mapped_at_creation: false
+ }
+ );
+
+ self.origin_bind_group = Some(wgpuctx.device().create_bind_group(
+ &wgpu::BindGroupDescriptor {
+ label: None,
+ layout: &self.origin_bind_group_layout,
+ entries: &[
+ wgpu::BindGroupEntry {
+ binding: 0,
+ resource: origin_buffer.as_entire_binding()
+ }
+ ]
+ }
+ ));
+ self.origin_buffer = Some(origin_buffer);
+
+ self.orbit_vertex_buffers = Some(bodies.iter().map(|body| {
+ if !body.does_orbit() { return (0, None); }
+
+ let period = body.orbital_period();
+ 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![
+ OrbitVertex::default();(num_points+1)*2];
+ for i in 0..num_points {
+ let position = body.calculate_orbit_at(
+ (i as f64 * period_interval) as u64);
+
+ points[i*2].origin_id = body.get_orbits().unwrap() as _;
+ points[i*2].position = [
+ position.x as f32,
+ position.y as f32,
+ position.z as f32
+ ];
+
+ points[(i*2)+1] = points[i*2].clone();
+ }
+ points[num_points*2] = points[0].clone();
+ points[num_points*2+1] = points[1].clone();
+
+ let buffer = wgpuctx.create_buffer_init(
+ &wgpu::util::BufferInitDescriptor {
+ label: None,
+ usage: wgpu::BufferUsages::VERTEX,
+ contents: bytemuck::cast_slice(&points)
+ }
+ );
+ ((num_points+1)*2, Some(buffer))
+ }).collect::<Vec<_>>());
+ }
+
+ pub fn update(
+ &mut self,
+ wgpuctx: &WgpuCtx,
+ solar_system: &SolarSystem,
+ time: Second)
+ {
+ if self.last_time.is_some_and(|t| { t == time }) {
+ return;
+ }
+
+ self.last_time = Some(time);
+ let positions = solar_system.bodies().iter().map(|body| {
+ let pos = solar_system.body_position(body);
+ [ pos.x as f32, pos.y as f32, pos.z as f32 ]
+ }).collect::<Vec<_>>();
+
+ match &self.origin_buffer {
+ Some(buffer) => {
+ wgpuctx.queue().write_buffer(buffer, 0, bytemuck::cast_slice(&positions));
+ },
+ None => { return; }
+ };
+ }
+
+ pub fn render(
+ &self,
+ 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(), &[]);
+
+ match &self.origin_bind_group {
+ Some(bind_group) => { pass.set_bind_group(1, bind_group, &[]); },
+ None => { return; }
+ }
+
+ for (num_points, buffer) in buffers {
+ match &buffer {
+ Some(buffer) => {
+ pass.set_vertex_buffer(0, buffer.slice(..));
+ pass.draw(0..(*num_points as u32), 0..1);
+ },
+ None => {}
+ }
+ }
+ }
+}
+
+#[repr(C)]
+#[derive(Copy, Clone, Default, Debug, bytemuck::Pod, bytemuck::Zeroable)]
+pub struct OrbitVertex
+{
+ pub origin_id: u32,
+ pub position: [f32;3]
+}
+
+impl OrbitVertex
+{
+ const ATTRIBS: [wgpu::VertexAttribute;2] =
+ wgpu::vertex_attr_array![0 => Uint32, 1 => Float32x3];
+
+ pub fn descr()
+ -> wgpu::VertexBufferLayout<'static> {
+ use std::mem;
+
+ wgpu::VertexBufferLayout {
+ array_stride: mem::size_of::<Self>() as wgpu::BufferAddress,
+ step_mode: wgpu::VertexStepMode::Vertex,
+ attributes: &Self::ATTRIBS
+ }
+ }
+}
diff --git a/src/tacmap/render.rs b/src/tacmap/render.rs
index e6944d0..fd93941 100644
--- a/src/tacmap/render.rs
+++ b/src/tacmap/render.rs
@@ -19,191 +19,6 @@ impl Display for NeedsRebuildError {
impl Error for NeedsRebuildError {}
-pub struct BodyRenderer
-{
- needs_rebuild: bool,
- last_time: Option<Second>,
-
- pipeline: wgpu::RenderPipeline,
-
- body_instance_buffer: Option<(usize, wgpu::Buffer)>
-}
-
-impl BodyRenderer
-{
- pub fn new(
- wgpuctx: &WgpuCtx)
- -> Self {
- let shader = wgpuctx.create_shader(
- wgpu::include_wgsl!(concat!(
- env!("CARGO_MANIFEST_DIR"),
- "/assets/shaders/tacmap/body.wgsl")
- ));
-
- let render_pipeline = RenderPipelineBuilder::new(&shader)
- .add_bindgroup(&Camera::bindgroup_layout(wgpuctx))
- .add_vertex_layout(BodyInstanceRaw::descr())
- .cull_mode(None)
- .build(Some("Tactical map render pipeline"), wgpuctx);
-
- Self {
- needs_rebuild: true,
- last_time: None,
- pipeline: render_pipeline,
- body_instance_buffer: None
- }
- }
-
- pub fn mark_to_rebuild(&mut self)
- { self.needs_rebuild = true; }
-
- pub fn rebuild(
- &mut self,
- wgpuctx: &WgpuCtx,
- solar_system: &SolarSystem)
- {
- if self.body_instance_buffer.is_some() && !self.needs_rebuild {
- return;
- }
- self.needs_rebuild = false;
-
- match self.body_instance_buffer.as_mut() {
- Some(buffer) => {
- buffer.1.destroy();
- self.body_instance_buffer = None;
- }
- None => {}
- }
-
- let bodies = solar_system.bodies();
- let buffer_len = bodies.len() * size_of::<BodyInstanceRaw>();
-
- let buffer = wgpuctx.create_buffer(
- &wgpu::BufferDescriptor {
- label: Some("Tactical map bodies instance buffer"),
- size: buffer_len as u64,
- usage: wgpu::BufferUsages::COPY_DST |
- wgpu::BufferUsages::VERTEX,
- mapped_at_creation: false
- }
- );
-
- self.last_time = None;
- self.body_instance_buffer = Some((bodies.len(), buffer));
- }
-
- pub fn update(
- &mut self,
- wgpuctx: &WgpuCtx,
- solar_system: &SolarSystem,
- time: Second)
- -> Result<(), Box<dyn Error>>
- {
- //If the last updated time is the same, we don't need to update
- //the positions of all the bodies.
- if self.last_time.is_some_and(|last_time| { last_time == time }) {
- return Ok(());
- }
-
- self.last_time = Some(time);
-
- let (_, bodies_buffer) = match &self.body_instance_buffer {
- Some(tuple) => tuple,
- None => return Err(Box::new(NeedsRebuildError))
- };
-
- let bodies = solar_system.bodies();
- let body_instances = bodies.iter().map(|body| {
- let position = body.position();
- let origin = match body.get_orbits() {
- Some(origin_id) => {
- let origin_body = &bodies[origin_id];
- origin_body.position()
- },
- None => cgmath::Vector3::new(0.0, 0.0, 0.0)
- };
- BodyInstance {
- position: position,
- origin: origin,
- radius: body.radius()
- }.raw()
- }).collect::<Vec<_>>();
-
- wgpuctx.queue().write_buffer(bodies_buffer, 0, bytemuck::cast_slice(&body_instances));
-
- Ok(())
- }
-
- pub fn render(
- &self,
- pass: &mut RenderPass,
- camera: &Camera)
- {
- let (num_bodies, bodies_buffer) = match &self.body_instance_buffer {
- Some(tuple) => tuple,
- None => return
- };
-
- pass.set_pipeline(&self.pipeline);
- pass.set_bind_group(0, camera.bindgroup(), &[]);
-
- pass.set_vertex_buffer(0, bodies_buffer.slice(..));
-
- pass.draw(0..6, 0..num_bodies.clone() as _);
- }
-} // impl RenderState
-
-struct BodyInstance
-{
- position: cgmath::Vector3<Kilometers>,
- origin: cgmath::Vector3<Kilometers>,
- radius: f32
-}
-
-#[repr(C)]
-#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
-struct BodyInstanceRaw
-{
- position: [f32;3],
- origin: [f32;3],
- radius: f32
-}
-
-impl BodyInstance
-{
- fn raw(&self) -> BodyInstanceRaw
- {
- BodyInstanceRaw {
- position: [
- self.position.x as f32,
- self.position.y as f32,
- self.position.z as f32 ],
- origin: [
- self.origin.x as f32,
- self.origin.y as f32,
- self.origin.z as f32 ],
- radius: self.radius
- }
- }
-} // impl BodyInstance
-
-impl BodyInstanceRaw
-{
- const ATTRIBS: [wgpu::VertexAttribute;3] =
- wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x3, 2 => Float32];
-
- pub fn descr()
- -> wgpu::VertexBufferLayout<'static> {
- use std::mem;
-
- wgpu::VertexBufferLayout {
- array_stride: mem::size_of::<Self>() as wgpu::BufferAddress,
- step_mode: wgpu::VertexStepMode::Instance,
- attributes: &Self::ATTRIBS
- }
- }
-}
-
pub struct GridRenderer
{
pipeline: wgpu::RenderPipeline,
@@ -242,238 +57,3 @@ impl GridRenderer
pass.draw(0..6, 0..1);
}
} //impl GridRenderer
-
-pub struct OrbitRenderer
-{
- needs_rebuild: bool,
- last_time: Option<Second>,
-
- pipeline: wgpu::RenderPipeline,
-
- orbit_vertex_buffers: Option<Vec<(usize, Option<wgpu::Buffer>)>>,
- origin_buffer: Option<wgpu::Buffer>,
- origin_bind_group: Option<wgpu::BindGroup>,
- origin_bind_group_layout: wgpu::BindGroupLayout
-}
-
-impl OrbitRenderer
-{
- pub fn new(
- wgpuctx: &WgpuCtx)
- -> Self {
- let shader = wgpuctx.create_shader(
- wgpu::include_wgsl!(concat!(
- env!("CARGO_MANIFEST_DIR"),
- "/assets/shaders/tacmap/orbit.wgsl")
- ));
-
- let origin_bind_group_layout = wgpuctx.device().create_bind_group_layout(
- &wgpu::BindGroupLayoutDescriptor {
- label: None,
- entries: &[
- wgpu::BindGroupLayoutEntry {
- binding: 0,
- visibility: wgpu::ShaderStages::VERTEX,
- ty: wgpu::BindingType::Buffer {
- ty: wgpu::BufferBindingType::Storage { read_only: true },
- has_dynamic_offset: false,
- min_binding_size: None
- },
- count: None
- }
- ]
- }
- );
-
- let render_pipeline = RenderPipelineBuilder::new(&shader)
- .add_bindgroup(&Camera::bindgroup_layout(wgpuctx))
- .add_bindgroup(&origin_bind_group_layout)
- .add_vertex_layout(OrbitVertex::descr())
- .primitive_topology(wgpu::PrimitiveTopology::TriangleStrip)
- .cull_mode(None)
- .build(Some("Tactical map orbit render pipeline"), wgpuctx);
-
- Self {
- needs_rebuild: true,
- last_time: None,
- pipeline: render_pipeline,
- orbit_vertex_buffers: None,
- origin_buffer: None,
- origin_bind_group: None,
- origin_bind_group_layout: origin_bind_group_layout
- }
- }
-
- pub fn mark_to_rebuild(&mut self)
- { self.needs_rebuild = true; }
-
- pub fn rebuild(
- &mut self,
- wgpuctx: &WgpuCtx,
- solar_system: &SolarSystem)
- {
- if self.orbit_vertex_buffers.is_some() && !self.needs_rebuild {
- return;
- }
- self.needs_rebuild = false;
-
- match &self.orbit_vertex_buffers {
- Some(buffers) => {
- for buffer in buffers {
- match &buffer.1 {
- Some(v) => v.destroy(),
- None => {}
- }
- }
- self.orbit_vertex_buffers = None;
- },
- None => {}
- };
-
- //From the solar system's bodies, calculate the orbits.
- let bodies = solar_system.bodies();
-
- match &self.origin_buffer {
- Some(buffer) => {
- buffer.destroy();
- }
- None => {}
- };
- let origin_buffer = wgpuctx.create_buffer(
- &wgpu::BufferDescriptor {
- label: None,
- size: (std::mem::size_of::<[f32;3]>() * bodies.len()) as _,
- usage: wgpu::BufferUsages::COPY_DST
- | wgpu::BufferUsages::STORAGE,
- mapped_at_creation: false
- }
- );
-
- self.origin_bind_group = Some(wgpuctx.device().create_bind_group(
- &wgpu::BindGroupDescriptor {
- label: None,
- layout: &self.origin_bind_group_layout,
- entries: &[
- wgpu::BindGroupEntry {
- binding: 0,
- resource: origin_buffer.as_entire_binding()
- }
- ]
- }
- ));
- self.origin_buffer = Some(origin_buffer);
-
- self.orbit_vertex_buffers = Some(bodies.iter().map(|body| {
- if !body.does_orbit() { return (0, None); }
-
- let period = body.orbital_period();
- 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![
- OrbitVertex::default();(num_points+1)*2];
- for i in 0..num_points {
- let position = body.calculate_orbit_at(
- (i as f64 * period_interval) as u64);
-
- points[i*2].origin_id = body.get_orbits().unwrap() as _;
- points[i*2].position = [
- position.x as f32,
- position.y as f32,
- position.z as f32
- ];
-
- points[(i*2)+1] = points[i*2].clone();
- }
- points[num_points*2] = points[0].clone();
- points[num_points*2+1] = points[1].clone();
-
- let buffer = wgpuctx.create_buffer_init(
- &wgpu::util::BufferInitDescriptor {
- label: None,
- usage: wgpu::BufferUsages::VERTEX,
- contents: bytemuck::cast_slice(&points)
- }
- );
- ((num_points+1)*2, Some(buffer))
- }).collect::<Vec<_>>());
- }
-
- pub fn update(
- &mut self,
- wgpuctx: &WgpuCtx,
- solar_system: &SolarSystem,
- time: Second)
- {
- if self.last_time.is_some_and(|t| { t == time }) {
- return;
- }
-
- self.last_time = Some(time);
- let positions = solar_system.bodies().iter().map(|body| {
- let pos = solar_system.body_position(body);
- [ pos.x as f32, pos.y as f32, pos.z as f32 ]
- }).collect::<Vec<_>>();
-
- match &self.origin_buffer {
- Some(buffer) => {
- wgpuctx.queue().write_buffer(buffer, 0, bytemuck::cast_slice(&positions));
- },
- None => { return; }
- };
- }
-
- pub fn render(
- &self,
- pass: &mut 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(), &[]);
-
- match &self.origin_bind_group {
- Some(bind_group) => { pass.set_bind_group(1, bind_group, &[]); },
- None => { return; }
- }
-
- for (num_points, buffer) in buffers {
- match &buffer {
- Some(buffer) => {
- pass.set_vertex_buffer(0, buffer.slice(..));
- pass.draw(0..(*num_points as u32), 0..1);
- },
- None => {}
- }
- }
- }
-}
-
-#[repr(C)]
-#[derive(Copy, Clone, Default, Debug, bytemuck::Pod, bytemuck::Zeroable)]
-pub struct OrbitVertex
-{
- pub origin_id: u32,
- pub position: [f32;3]
-}
-
-impl OrbitVertex
-{
- const ATTRIBS: [wgpu::VertexAttribute;2] =
- wgpu::vertex_attr_array![0 => Uint32, 1 => Float32x3];
-
- pub fn descr()
- -> wgpu::VertexBufferLayout<'static> {
- use std::mem;
-
- wgpu::VertexBufferLayout {
- array_stride: mem::size_of::<Self>() as wgpu::BufferAddress,
- step_mode: wgpu::VertexStepMode::Vertex,
- attributes: &Self::ATTRIBS
- }
- }
-}
diff --git a/src/window.rs b/src/window.rs
index 73034ef..3461a53 100644
--- a/src/window.rs
+++ b/src/window.rs
@@ -6,8 +6,7 @@ use winit::event::{ElementState, WindowEvent};
use winit::keyboard::KeyCode;
use crate::tacmap::TacticalMap;
-use crate::{GameState, SystemicApp, ui};
-use crate::solar_system::{SolarSystem, SystemId};
+use crate::{GameState, ui};
use crate::wgpuctx::{RenderPassBuilder, SceneCtx, WgpuCtx};
use crate::eguictx::EguiCtx;