mod pipeline; use std::sync::{Arc, Mutex}; use anyhow::Result; use cgmath::{ortho, vec4, Matrix4}; use rfactor_sm_reader::{rF2VehicleTelemetry, VehicleScoringInfoV01}; use ringbuf::{HeapRb, Rb}; use ui::prelude::*; use vulkan_rs::prelude::*; use crate::overlay::{ rfactor_data::{DataReceiver, GamePhase}, UiOverlay, }; use crate::write_log; use self::pipeline::HistoryPipeline; use super::PositionOnlyVertex; pub struct Pedals { gui: Arc, brake: Arc, throttle: Arc, _history: Arc, throttle_samples: HeapRb, brake_samples: HeapRb, ortho: Matrix4, device: Arc, queue: Arc>, render_target: RenderTarget, pipeline: HistoryPipeline, brake_descriptor: Arc, brake_vertex_buffer: Arc>, throttle_descriptor: Arc, throttle_vertex_buffer: Arc>, } impl Pedals { pub fn new( gui_handler: &Arc, device: Arc, queue: Arc>, ) -> Result { const DESC: &str = include_str!("pedals.xml"); let gui = GuiBuilder::from_str(gui_handler, DESC)?; let brake = gui.element("brake")?; let throttle = gui.element("throttle")?; let history: Arc = gui.element("history")?; let (icon_width, icon_height) = history.extent(); let history_image = Image::empty( icon_width as u32, icon_height as u32, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_SAMPLE_COUNT_1_BIT, ) .format(VK_FORMAT_R8G8B8A8_UNORM) .attach_sampler(Sampler::nearest_sampler().build(&device)?) .build(&device, &queue)?; history_image.convert_layout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)?; history.set_icon(&history_image)?; let render_target = RenderTarget::builder() .add_sub_pass( SubPass::builder(history_image.width(), history_image.height()) .set_prepared_targets(&[history_image.clone()], 0, [0.3, 0.3, 0.3, 1.0], true) .build(&device, &queue)?, ) .build(&device)?; let pipeline = HistoryPipeline::new( device.clone(), render_target.render_pass(), history_image.width(), history_image.height(), )?; let ortho = ortho(0.0, history_image.width() as f32, 0.0, 1.0, -1.0, 1.0); let descriptor_pool = DescriptorPool::builder() .set_layout(pipeline.descriptor_layout().clone()) .set_descriptor_set_count(2) .build(device.clone())?; let brake_color_buffer: Arc> = Buffer::builder() .set_usage(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) .set_memory_usage(MemoryUsage::CpuOnly) .set_data(&[0.9, 0.0, 0.0, 1.0]) .build(device.clone())?; write_log!("allocate brake descriptor"); let brake_descriptor = descriptor_pool.prepare_set().allocate()?; brake_descriptor.update(&[DescriptorWrite::uniform_buffers(0, &[&brake_color_buffer])])?; let throttle_color_buffer: Arc> = Buffer::builder() .set_usage(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) .set_memory_usage(MemoryUsage::CpuOnly) .set_data(&[0.0, 0.9, 0.0, 1.0]) .build(device.clone())?; write_log!("allocate throttle descriptor"); let throttle_descriptor = descriptor_pool.prepare_set().allocate()?; throttle_descriptor.update(&[DescriptorWrite::uniform_buffers( 0, &[&throttle_color_buffer], )])?; let mut throttle_samples = HeapRb::new(icon_width as usize); let mut brake_samples = HeapRb::new(icon_width as usize); for _ in 0..icon_width { throttle_samples.push_overwrite(0.0); brake_samples.push_overwrite(0.0); } let brake_vertex_buffer = Self::create_vertex_buffer(&device, icon_width as VkDeviceSize)?; let throttle_vertex_buffer = Self::create_vertex_buffer(&device, icon_width as VkDeviceSize)?; let me = Self { gui, brake, throttle, _history: history, throttle_samples, brake_samples, ortho, device, queue, render_target, pipeline, brake_descriptor, brake_vertex_buffer, throttle_descriptor, throttle_vertex_buffer, }; me.update_vertex_buffers()?; Ok(me) } fn create_vertex_buffer( device: &Arc, size: VkDeviceSize, ) -> Result>> { Buffer::builder() .set_usage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) .set_memory_usage(MemoryUsage::CpuOnly) .set_size(size) .build(device.clone()) } fn update_vertex_buffers(&self) -> Result<()> { self.update_vertex_buffer( &self.throttle_vertex_buffer, self.throttle_samples.as_slices(), )?; self.update_vertex_buffer(&self.brake_vertex_buffer, self.brake_samples.as_slices())?; Ok(()) } fn update_vertex_buffer( &self, buffer: &Arc>, (data1, data2): (&[f32], &[f32]), ) -> Result<()> { let points = data1 .iter() .chain(data2.iter()) .enumerate() .map(|(x, &date)| PositionOnlyVertex { position: self.ortho * vec4(x as f32, date, 0.0, 1.0), }) .collect::>(); buffer.fill(&points) } pub fn render(&self) -> Result> { let command_buffer = CommandBuffer::new_primary().build(self.device.clone(), self.queue.clone())?; { let mut recorder = command_buffer.begin(VkCommandBufferBeginInfo::new( VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, ))?; self.render_target .begin(&recorder, VK_SUBPASS_CONTENTS_INLINE, 0); recorder.bind_pipeline(self.pipeline.pipeline())?; recorder.bind_descriptor_sets_minimal(&[&self.throttle_descriptor]); recorder.bind_vertex_buffer(&self.throttle_vertex_buffer); recorder.draw_complete_single_instance(self.throttle_vertex_buffer.size() as u32); recorder.bind_descriptor_sets_minimal(&[&self.brake_descriptor]); recorder.bind_vertex_buffer(&self.brake_vertex_buffer); recorder.draw_complete_single_instance(self.brake_vertex_buffer.size() as u32); self.render_target.end(&recorder); } Ok(command_buffer) } } impl UiOverlay for Pedals {} impl DataReceiver for Pedals { fn scoring_update( &mut self, _phase: GamePhase, _vehicle_scoring: &[VehicleScoringInfoV01], ) -> Result<()> { Ok(()) } fn telemetry_update( &mut self, player_id: Option, telemetries: &[rF2VehicleTelemetry], ) -> Result<()> { match player_id { Some(id) => { self.gui.enable()?; if let Some(telemetry) = telemetries.iter().find(|telemetry| telemetry.id == id) { let brake = 1.0 - telemetry.unfiltered_brake as f32; let throttle = 1.0 - telemetry.unfiltered_throttle as f32; self.throttle.set_progress(throttle)?; self.brake.set_progress(brake)?; self.throttle_samples.push_overwrite(throttle); self.brake_samples.push_overwrite(brake); self.update_vertex_buffers()?; } } None => { self.gui.disable()?; } } Ok(()) } } #[cfg(test)] mod test { use ringbuf::{HeapRb, Rb}; #[test] fn rb_test() { const CAP: usize = 10; let mut buf = HeapRb::new(CAP); for _ in 0..CAP { buf.push_overwrite(20); } println!("{:?}", buf.as_slices()); buf.push_overwrite(40); buf.push_overwrite(40); buf.push_overwrite(40); buf.push_overwrite(40); println!("{:?}", buf.as_slices()); } }