use crate::write_log; use self::{ rendering::Rendering, rfactor_data::{DataReceiver, RFactorData}, }; mod elements; mod rendering; mod rfactor_data; use anyhow::Result; use assetpath::AssetPath; use std::{ cell::RefCell, rc::Rc, sync::{Arc, Mutex}, }; use ui::{guihandler::guihandler::Font, prelude::*}; use vulkan_rs::prelude::*; use elements::*; use serde::{Deserialize, Serialize}; pub trait UiOverlay: DataReceiver {} #[derive(Deserialize, Serialize)] pub struct UiSelectorConfig { pub enable_watermark: bool, pub enable_radar: bool, pub enable_pedals: bool, pub enable_leaderboard: bool, } impl UiSelectorConfig { pub const fn new() -> Self { Self { enable_watermark: true, enable_radar: true, enable_pedals: true, enable_leaderboard: true, } } } #[derive(Deserialize, Serialize)] pub struct OverlayConfig { pub ui_config: UiSelectorConfig, pub radar_config: RadarConfig, } impl OverlayConfig { pub const fn new() -> Self { Self { ui_config: UiSelectorConfig::new(), radar_config: RadarConfig::new(), } } } pub struct Overlay { config: OverlayConfig, instance: Option>, device: Option>, queue: Option>>, rendering: Option, gui_handler: Option>, ui_elements: Vec>>, rfactor_data: Option, } impl Overlay { pub const fn new() -> Self { Self { config: OverlayConfig::new(), instance: None, device: None, queue: None, rendering: None, gui_handler: None, ui_elements: Vec::new(), rfactor_data: None, } } pub fn set_config(&mut self, config: OverlayConfig) { self.config = config; } pub fn set_instance(&mut self, instance: Arc) { self.instance = Some(instance); } pub fn instance(&self) -> Arc { self.instance.as_ref().unwrap().clone() } pub fn set_device(&mut self, device: Arc) { self.device = Some(device); } pub fn device(&self) -> Arc { self.device.as_ref().unwrap().clone() } pub fn set_queue(&mut self, queue: Arc>) { self.queue = Some(queue); } pub fn queue(&self) -> Arc> { self.queue.as_ref().unwrap().clone() } pub fn swapchain(&self, swapchain: VkSwapchainKHR) -> Option<&Arc> { let sc = self.rendering.as_ref().unwrap().swapchain(); if sc.vk_handle() == swapchain { Some(sc) } else { None } } pub fn create_rendering(&mut self, swapchain: Arc) -> Result<()> { write_log!("-> create rendering: start"); self.rendering = None; write_log!("-> create rendering: old cleared"); let mut rendering = Rendering::new(self.queue(), swapchain.clone())?; write_log!("-> create rendering: new created"); // only font is used let mut create_info = GuiHandlerCreateInfo::default(); create_info.font = Font::Bytes(include_bytes!("../../font.png")); // required to not crash create_info.resource_directory = AssetPath::from(""); create_info.resource_directory.assume_prefix_free(); // provide trait required by GuiHandler let ctx = Arc::new(ContextImpl::new( self.device(), self.queue(), swapchain, rendering.images().clone(), )); // create GuiHandler let gui_handler = GuiHandler::new(create_info, &(ctx as Arc))?; write_log!("GuiHandler successfully created"); // create ui elements // create watermark if self.config.ui_config.enable_watermark { let watermark = Rc::new(RefCell::new(Watermark::new(&gui_handler)?)); self.ui_elements.push(watermark); write_log!("Watermark successfully created"); } // create radar if self.config.ui_config.enable_radar { let radar = Rc::new(RefCell::new(Radar::new( self.config.radar_config, self.device(), self.queue(), &rendering, )?)); rendering.add_render_callback({ let radar = radar.clone(); move |index| radar.borrow().render(index) }); self.ui_elements.push(radar); write_log!("Radar successfully created"); } // create pedals if self.config.ui_config.enable_pedals { let pedals = Rc::new(RefCell::new(Pedals::new( &gui_handler, self.device(), self.queue(), )?)); self.ui_elements.push(pedals.clone()); rendering.add_render_callback(move |_| pedals.borrow().render()); write_log!("Pedals successfully created"); } // create leaderboard if self.config.ui_config.enable_leaderboard { let leaderboard = Rc::new(RefCell::new(LeaderBoard::new(&gui_handler)?)); self.ui_elements.push(leaderboard); write_log!("Leader Board successfully created"); } // add rendering callbacks rendering.add_render_callback({ let gui_handler = gui_handler.clone(); let device = self.device(); let queue = self.queue(); move |index| { let command_buffer = CommandBuffer::new_primary().build(device.clone(), 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, ))?; gui_handler.process(&mut recorder, &TargetMode::Mono(index as usize))?; } Ok(command_buffer) } }); write_log!("render callbacks added"); self.rendering = Some(rendering); self.gui_handler = Some(gui_handler); write_log!("-> create rendering: end"); Ok(()) } pub fn render(&mut self) -> Result<()> { if self.rfactor_data.is_none() { self.rfactor_data = RFactorData::new().ok(); if let Some(data) = &mut self.rfactor_data { write_log!("created RFactorData"); for receiver in self.ui_elements.iter() { data.add_receiver(receiver.clone()); } } } if let Some(rfactor) = &mut self.rfactor_data { rfactor.update()?; } self.rendering.as_ref().unwrap().render() } } struct ContextImpl { device: Arc, queue: Arc>, swapchain: Arc, images: Vec>, } impl ContextImpl { fn new( device: Arc, queue: Arc>, swapchain: Arc, images: Vec>, ) -> Self { Self { device, queue, swapchain, images, } } } impl ContextInterface for ContextImpl { fn device(&self) -> &Arc { &self.device } fn queue(&self) -> &Arc> { &self.queue } fn format(&self) -> VkFormat { self.swapchain.format() } fn image_layout(&self) -> VkImageLayout { VK_IMAGE_LAYOUT_PRESENT_SRC_KHR } fn image_count(&self) -> usize { self.images.len() } fn images(&self) -> TargetMode>> { TargetMode::Mono(self.images.clone()) } fn width(&self) -> u32 { self.swapchain.width() } fn height(&self) -> u32 { self.swapchain.height() } }