summaryrefslogtreecommitdiffstats
path: root/src/tacmap/fleet_render.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tacmap/fleet_render.rs')
-rw-r--r--src/tacmap/fleet_render.rs177
1 files changed, 177 insertions, 0 deletions
diff --git a/src/tacmap/fleet_render.rs b/src/tacmap/fleet_render.rs
new file mode 100644
index 0000000..ba21318
--- /dev/null
+++ b/src/tacmap/fleet_render.rs
@@ -0,0 +1,177 @@
+use std::error::Error;
+
+use crate::fleet::FleetsManager;
+use crate::solar_system::orbit::StaticOrbiter;
+use crate::solar_system::{Kilometers};
+use crate::timeman::{Second};
+use crate::wgpuctx::{WgpuCtx, pipeline::RenderPipelineBuilder};
+
+use super::*;
+
+pub struct FleetRenderer
+{
+ last_time: Option<Second>,
+
+ pipeline: wgpu::RenderPipeline,
+
+ fleet_instance_buffer: Option<(usize, wgpu::Buffer)>
+}
+
+struct FleetInstance
+{
+ offset: cgmath::Vector3<Kilometers>,
+ origin: cgmath::Vector3<Kilometers>,
+ heading: cgmath::Vector2<cgmath::Rad<f32>>
+}
+
+#[repr(C)]
+#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
+struct FleetInstanceRaw
+{
+ rotmat: [[f32;3];3],
+ origin: [f32;3],
+ offset: [f32;3],
+}
+
+impl FleetRenderer
+{
+ pub fn new(
+ wgpuctx: &WgpuCtx)
+ -> Self {
+ let shader = wgpuctx.create_shader(
+ wgpu::include_wgsl!(concat!(
+ env!("CARGO_MANIFEST_DIR"),
+ "/assets/shaders/tacmap/fleet.wgsl")
+ ));
+
+ let render_pipeline = RenderPipelineBuilder::new(&shader)
+ .add_bindgroup(&Camera::bindgroup_layout(wgpuctx))
+ .add_vertex_layout(FleetInstanceRaw::descr())
+ .cull_mode(None)
+ .build(Some("Tactical map fleet render pipeline"), wgpuctx);
+
+ Self {
+ last_time: None,
+ pipeline: render_pipeline,
+ fleet_instance_buffer: None
+ }
+ }
+
+ pub fn update(
+ &mut self,
+ wgpuctx: &WgpuCtx,
+ fleets_manager: &FleetsManager,
+ 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);
+
+ if let Some((_, buffer)) = &self.fleet_instance_buffer {
+ buffer.destroy();
+ self.fleet_instance_buffer = None;
+ }
+
+ let fleets = solar_system.fleets(fleets_manager);
+ let fleets_instances = fleets.iter().filter_map(|id| {
+ let fleet = match fleets_manager.entry(*id) {
+ Some(fleet) => fleet,
+ None => { return None; }
+ };
+ let heading = fleet.heading();
+ let offset = fleet.offset_position();
+ let origin = match fleet.orbit() {
+ Some(orbit) => {
+ let origin_body = solar_system.body(orbit.parent());
+ origin_body.absolute_position(solar_system, time)
+ },
+ None => cgmath::vec3(0.0, 0.0, 0.0)
+ };
+ Some(
+ FleetInstance {
+ heading: *heading,
+ offset: *offset,
+ origin: origin
+ }.raw()
+ )
+ }).collect::<Vec<_>>();
+ let fleets_buffer = wgpuctx.create_buffer_init(
+ &wgpu::util::BufferInitDescriptor {
+ label: None,
+ contents: bytemuck::cast_slice(fleets_instances.as_slice()),
+ usage: wgpu::BufferUsages::VERTEX
+ });
+
+ self.fleet_instance_buffer = Some((fleets.len(), fleets_buffer));
+
+ Ok(())
+ }
+
+ pub fn render(
+ &self,
+ pass: &mut wgpu::RenderPass,
+ camera: &Camera)
+ {
+ let (num_fleets, fleets_buffer) = match &self.fleet_instance_buffer {
+ Some(tuple) => tuple,
+ None => return
+ };
+ if *num_fleets == 0 { return; }
+
+ pass.set_pipeline(&self.pipeline);
+ pass.set_bind_group(0, camera.bindgroup(), &[]);
+
+ pass.set_vertex_buffer(0, fleets_buffer.slice(..));
+
+ pass.draw(0..6, 0..*num_fleets as _);
+ }
+} // impl RenderState
+
+impl FleetInstance
+{
+ fn raw(&self) -> FleetInstanceRaw
+ {
+ FleetInstanceRaw {
+ rotmat: (cgmath::Matrix3::from_angle_x(self.heading.x) *
+ cgmath::Matrix3::from_angle_y(self.heading.y))
+ .into(),
+ origin: [
+ self.origin.x as f32,
+ self.origin.y as f32,
+ self.origin.z as f32
+ ],
+ offset: [
+ self.offset.x as f32,
+ self.offset.y as f32,
+ self.offset.z as f32
+ ]
+ }
+ }
+} // impl BodyInstance
+
+impl FleetInstanceRaw
+{
+ const ATTRIBS: [wgpu::VertexAttribute;5] =
+ wgpu::vertex_attr_array![
+ 0 => Float32x3, 1 => Float32x3, 2 => Float32x3,
+ 3 => Float32x3,
+ 4 => 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::Instance,
+ attributes: &Self::ATTRIBS
+ }
+ }
+}