Add watermark

This commit is contained in:
hodasemi 2023-01-17 15:44:11 +01:00
parent dd3d9fd2f2
commit b449e74ca0
11 changed files with 191 additions and 75 deletions

5
.vscode/tasks.json vendored
View file

@ -4,11 +4,14 @@
{ {
"type": "cargo", "type": "cargo",
"command": "build", "command": "build",
"args": [
"--release"
],
"problemMatcher": [ "problemMatcher": [
"$rustc" "$rustc"
], ],
"group": "build", "group": "build",
"label": "rust: cargo build --release" "label": "rust: cargo build"
}, },
{ {
"type": "shell", "type": "shell",

BIN
font.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View file

@ -1,6 +1,8 @@
mod pedals; mod pedals;
mod pipeline; mod pipeline;
mod radar; mod radar;
mod watermark;
pub use pedals::*; pub use pedals::*;
pub use radar::*; pub use radar::*;
pub use watermark::*;

View file

@ -11,6 +11,8 @@ pub struct Pedals {
brake: Arc<ProgressBar>, brake: Arc<ProgressBar>,
throttle: Arc<ProgressBar>, throttle: Arc<ProgressBar>,
fuel: Arc<Label>,
gear: Arc<Label>,
} }
impl Pedals { impl Pedals {
@ -21,11 +23,15 @@ impl Pedals {
let brake = gui.element("brake")?; let brake = gui.element("brake")?;
let throttle = gui.element("throttle")?; let throttle = gui.element("throttle")?;
let fuel = gui.element("fuel")?;
let gear = gui.element("gear")?;
Ok(Self { Ok(Self {
gui, gui,
brake, brake,
throttle, throttle,
fuel,
gear,
}) })
} }
} }
@ -36,11 +42,7 @@ impl Drop for Pedals {
} }
} }
impl UiOverlay for Pedals { impl UiOverlay for Pedals {}
fn enable_ui(&mut self) -> Result<()> {
self.gui.enable()
}
}
impl DataReceiver for Pedals { impl DataReceiver for Pedals {
fn scoring_update(&mut self, _vehicle_scoring: &[VehicleScoringInfoV01]) -> Result<()> { fn scoring_update(&mut self, _vehicle_scoring: &[VehicleScoringInfoV01]) -> Result<()> {
@ -52,12 +54,22 @@ impl DataReceiver for Pedals {
player_id: Option<i32>, player_id: Option<i32>,
telemetries: &[rF2VehicleTelemetry], telemetries: &[rF2VehicleTelemetry],
) -> Result<()> { ) -> Result<()> {
if let Some(id) = player_id { match player_id {
Some(id) => {
self.gui.enable()?;
if let Some(telemetry) = telemetries.iter().find(|telemetry| telemetry.id == id) { if let Some(telemetry) = telemetries.iter().find(|telemetry| telemetry.id == id) {
self.brake self.brake
.set_progress(telemetry.unfiltered_throttle as f32)?; .set_progress(telemetry.unfiltered_throttle as f32)?;
self.throttle self.throttle
.set_progress(telemetry.unfiltered_throttle as f32)?; .set_progress(telemetry.unfiltered_throttle as f32)?;
self.gear.set_text(telemetry.gear)?;
let fuel = telemetry.fuel;
self.fuel.set_text(format!("{:.2}", fuel))?;
}
}
None => {
self.gui.disable()?;
} }
} }

View file

@ -92,9 +92,6 @@ pub struct Radar {
// buffer car objects, to prevent recreating them every update // buffer car objects, to prevent recreating them every update
car_handles: Vec<RadarObject>, car_handles: Vec<RadarObject>,
// game info
player_id: Option<i32>,
// math objects // math objects
radar_center: Vector2<f32>, radar_center: Vector2<f32>,
ortho: Matrix4<f32>, ortho: Matrix4<f32>,
@ -109,8 +106,6 @@ pub struct Radar {
pipeline: SingleColorPipeline, pipeline: SingleColorPipeline,
render_target: RenderTarget, render_target: RenderTarget,
enabled: bool,
} }
impl Radar { impl Radar {
@ -120,8 +115,6 @@ impl Radar {
queue: Arc<Mutex<Queue>>, queue: Arc<Mutex<Queue>>,
rendering: &Rendering, rendering: &Rendering,
) -> Result<Self> { ) -> Result<Self> {
write_log!(" =================== create RFactorData ===================");
let radar_extent = rendering.swapchain().width() as f32 * 0.075 * config.radar_scale; let radar_extent = rendering.swapchain().width() as f32 * 0.075 * config.radar_scale;
let car_height = radar_extent * config.height_scale; let car_height = radar_extent * config.height_scale;
let car_width = car_height * config.width_scale; let car_width = car_height * config.width_scale;
@ -198,8 +191,6 @@ impl Radar {
cars: Vec::new(), cars: Vec::new(),
car_handles: Vec::new(), car_handles: Vec::new(),
player_id: None,
radar_center, radar_center,
ortho, ortho,
_window_width: rendering.swapchain().width(), _window_width: rendering.swapchain().width(),
@ -213,8 +204,6 @@ impl Radar {
render_target, render_target,
pipeline, pipeline,
enabled: false,
}) })
} }
@ -285,8 +274,6 @@ impl Radar {
let mut objects = Vec::new(); let mut objects = Vec::new();
// only draw radar when player is loaded into a map
if let Some(_player_id) = &self.player_id {
// only draw radar when any car is near enough // only draw radar when any car is near enough
if !self.cars.is_empty() { if !self.cars.is_empty() {
if let Some(background) = &self.background { if let Some(background) = &self.background {
@ -299,19 +286,14 @@ impl Radar {
objects.push(&self.player_car); objects.push(&self.player_car);
} }
}
write_log!(format!("obj count {}", objects.len()));
objects objects
} }
} }
impl UiOverlay for Radar { impl UiOverlay for Radar {}
fn enable_ui(&mut self) -> Result<()> {
self.enabled = true;
Ok(())
}
}
impl DataReceiver for Radar { impl DataReceiver for Radar {
fn scoring_update(&mut self, _vehicle_scoring: &[VehicleScoringInfoV01]) -> Result<()> { fn scoring_update(&mut self, _vehicle_scoring: &[VehicleScoringInfoV01]) -> Result<()> {
@ -323,11 +305,10 @@ impl DataReceiver for Radar {
player_id: Option<i32>, player_id: Option<i32>,
telemetries: &[rF2VehicleTelemetry], telemetries: &[rF2VehicleTelemetry],
) -> Result<()> { ) -> Result<()> {
self.cars.clear(); write_log!(" ============================ Radar telemetry udpate ======================");
write_log!(format!("player id {:?}", player_id));
if !self.enabled { self.cars.clear();
return Ok(());
}
if let Some(player_id) = player_id { if let Some(player_id) = player_id {
// make sure there are enough cars in buffer // make sure there are enough cars in buffer
@ -389,6 +370,8 @@ impl DataReceiver for Radar {
} }
} }
write_log!(format!("other cars: {:?}", self.cars.len()));
Ok(()) Ok(())
} }
} }

View file

@ -61,6 +61,14 @@
</xs:restriction> </xs:restriction>
</xs:simpleType> </xs:simpleType>
</xs:attribute> </xs:attribute>
<xs:attribute name="direction">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="left_to_right"></xs:enumeration>
<xs:enumeration value="bottom_to_top"></xs:enumeration>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="background" type="xs:string"></xs:attribute> <xs:attribute name="background" type="xs:string"></xs:attribute>
<xs:attribute name="foreground" type="xs:string"></xs:attribute> <xs:attribute name="foreground" type="xs:string"></xs:attribute>
<xs:attribute name="button_normal" type="xs:string"></xs:attribute> <xs:attribute name="button_normal" type="xs:string"></xs:attribute>
@ -200,6 +208,7 @@
<xs:attribute ref="text_alignment"></xs:attribute> <xs:attribute ref="text_alignment"></xs:attribute>
<xs:attribute ref="background"></xs:attribute> <xs:attribute ref="background"></xs:attribute>
<xs:attribute ref="foreground"></xs:attribute> <xs:attribute ref="foreground"></xs:attribute>
<xs:attribute ref="direction"></xs:attribute>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>

View file

@ -1,11 +1,16 @@
<?xml-model href="gui.xsd" type="application/xml" schematypens="http://www.w3.org/2001/XMLSchema"?> <?xml-model href="gui.xsd" type="application/xml" schematypens="http://www.w3.org/2001/XMLSchema"?>
<root reference_width="2560" reference_height="1440"> <root reference_width="2560" reference_height="1440">
<grid x_dim="5" y_dim="2" x_offset="-600" y_offset="-350" width="250" height="300" <grid x_dim="7" y_dim="2" x_offset="-750" y_offset="-250" width="150" height="200"
vert_align="bottom" hori_align="right" margin="10" padding="10" background="#686868"> vert_align="bottom" hori_align="right" margin="3" padding="3" background="#686868">
<progressbar id="brake" x_slot="0" y_slot="0" y_size="2" background="#f44444" <progressbar id="brake" x_slot="0" y_slot="0" y_size="2" background="#f44444"
foreground="#e30000"></progressbar> direction="bottom_to_top" foreground="#e30000"></progressbar>
<progressbar id="throttle" x_slot="1" y_slot="0" <progressbar id="throttle"
y_size="2" background="#51fd51" x_slot="1" y_slot="0" y_size="2" background="#51fd51" direction="bottom_to_top"
foreground="#00b900"></progressbar> foreground="#00b900"></progressbar>
<label id="fuel" x_slot="2"
x_size="5" y_slot="0"
text_color="black"></label>
<label id="gear" x_slot="2" x_size="5" y_slot="1"
text_color="black"></label>
</grid> </grid>
</root> </root>

View file

@ -0,0 +1,8 @@
<?xml-model href="gui.xsd" type="application/xml" schematypens="http://www.w3.org/2001/XMLSchema"?>
<root reference_width="2560" reference_height="1440">
<grid x_dim="1" y_dim="1" x_offset="10" y_offset="10" width="300" height="50"
vert_align="top" hori_align="left" margin="2" padding="2" background="#c9c9c9">
<label x_slot="0" y_slot="0" text_color="#c9c9c9" text_ratio="1.0"
background="black">Vulkan Overlay Enabled</label>
</grid>
</root>

View file

@ -0,0 +1,45 @@
use std::sync::Arc;
use anyhow::Result;
use rfactor_sm_reader::{rF2VehicleTelemetry, VehicleScoringInfoV01};
use ui::prelude::*;
use crate::overlay::{rfactor_data::DataReceiver, UiOverlay};
pub struct Watermark {
gui: Arc<GuiBuilder>,
}
impl Watermark {
pub fn new(gui_handler: &Arc<GuiHandler>) -> Result<Self> {
const DESC: &str = include_str!("ui_files/watermark.xml");
let gui = GuiBuilder::from_str(gui_handler, DESC)?;
gui.enable()?;
Ok(Self { gui })
}
}
impl Drop for Watermark {
fn drop(&mut self) {
self.gui.disable().unwrap()
}
}
impl UiOverlay for Watermark {}
impl DataReceiver for Watermark {
fn scoring_update(&mut self, _vehicle_scoring: &[VehicleScoringInfoV01]) -> Result<()> {
Ok(())
}
fn telemetry_update(
&mut self,
_player_id: Option<i32>,
_telemetries: &[rF2VehicleTelemetry],
) -> Result<()> {
Ok(())
}
}

View file

@ -23,12 +23,30 @@ use elements::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub trait UiOverlay: DataReceiver { pub trait UiOverlay: DataReceiver {}
fn enable_ui(&mut self) -> Result<()>;
#[derive(Deserialize, Serialize)]
pub struct UiSelectorConfig {
pub enable_watermark: bool,
pub enable_radar: bool,
pub enable_pedals: bool,
}
impl UiSelectorConfig {
pub const fn new() -> Self {
Self {
enable_watermark: true,
enable_radar: true,
enable_pedals: true,
}
}
} }
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct OverlayConfig { pub struct OverlayConfig {
pub ui_config: UiSelectorConfig,
pub radar_config: RadarConfig, pub radar_config: RadarConfig,
pub font_path: String, pub font_path: String,
} }
@ -36,6 +54,7 @@ pub struct OverlayConfig {
impl OverlayConfig { impl OverlayConfig {
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self {
ui_config: UiSelectorConfig::new(),
radar_config: RadarConfig::new(), radar_config: RadarConfig::new(),
font_path: String::new(), font_path: String::new(),
} }
@ -74,6 +93,8 @@ impl Overlay {
pub fn set_config(&mut self, config: OverlayConfig) { pub fn set_config(&mut self, config: OverlayConfig) {
self.config = config; self.config = config;
self.config.font_path = "/opt/sata_ssd/Workspace/vk_layer_rs/font.png".to_string();
} }
pub fn set_instance(&mut self, instance: Arc<Instance>) { pub fn set_instance(&mut self, instance: Arc<Instance>) {
@ -123,8 +144,12 @@ impl Overlay {
// only font is used // only font is used
let mut create_info = GuiHandlerCreateInfo::default(); let mut create_info = GuiHandlerCreateInfo::default();
create_info.font_path = AssetPath::from(self.config.font_path.clone()); // create_info.font_path = AssetPath::from(self.config.font_path.clone());
create_info.font_path = AssetPath::from("/opt/sata_ssd/Workspace/vk_layer_rs/font.png");
create_info.font_path.assume_prefix_free(); create_info.font_path.assume_prefix_free();
// required to not crash
create_info.resource_directory = AssetPath::from("");
create_info.resource_directory.assume_prefix_free();
// provide trait required by GuiHandler // provide trait required by GuiHandler
let ctx = Arc::new(ContextImpl::new( let ctx = Arc::new(ContextImpl::new(
@ -135,11 +160,24 @@ impl Overlay {
)); ));
// create GuiHandler // create GuiHandler
write_log!(format!("Create Info: \n{:#?}", create_info));
let gui_handler = GuiHandler::new(create_info, &(ctx as Arc<dyn ContextInterface>))?; let gui_handler = GuiHandler::new(create_info, &(ctx as Arc<dyn ContextInterface>))?;
write_log!("GuiHandler successfully created");
// create ui elements // 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 // create radar
if self.config.ui_config.enable_radar {
let radar = Rc::new(RefCell::new(Radar::new( let radar = Rc::new(RefCell::new(Radar::new(
self.config.radar_config, self.config.radar_config,
self.device(), self.device(),
@ -147,16 +185,26 @@ impl Overlay {
&rendering, &rendering,
)?)); )?));
// create pedals
let pedals = Rc::new(RefCell::new(Pedals::new(&gui_handler)?));
// add rendering callbacks
rendering.add_render_callback({ rendering.add_render_callback({
let radar = radar.clone(); let radar = radar.clone();
move |index| radar.borrow().render(index) 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.ui_elements.push(pedals);
write_log!("Pedals successfully created");
}
// add rendering callbacks
rendering.add_render_callback({ rendering.add_render_callback({
let gui_handler = gui_handler.clone(); let gui_handler = gui_handler.clone();
let device = self.device(); let device = self.device();
@ -179,15 +227,13 @@ impl Overlay {
} }
}); });
// add ui elements to local list write_log!("render callbacks added");
self.ui_elements.push(radar);
self.ui_elements.push(pedals);
write_log!("-> create rendering: end");
self.rendering = Some(rendering); self.rendering = Some(rendering);
self.gui_handler = Some(gui_handler); self.gui_handler = Some(gui_handler);
write_log!("-> create rendering: end");
Ok(()) Ok(())
} }
@ -199,13 +245,11 @@ impl Overlay {
write_log!("created RFactorData"); write_log!("created RFactorData");
for receiver in self.ui_elements.iter() { for receiver in self.ui_elements.iter() {
receiver.borrow_mut().enable_ui()?;
data.add_receiver(receiver.clone()); data.add_receiver(receiver.clone());
} }
} }
} }
// check twice for rfactor data, because of borrowing rules
if let Some(rfactor) = &mut self.rfactor_data { if let Some(rfactor) = &mut self.rfactor_data {
rfactor.update()?; rfactor.update()?;
} }

View file

@ -72,6 +72,11 @@ impl Rendering {
.map(|c| c(image_index)) .map(|c| c(image_index))
.collect::<Result<Vec<Arc<CommandBuffer>>>>()?; .collect::<Result<Vec<Arc<CommandBuffer>>>>()?;
write_log!(format!(
"submitting {} commandbuffer(s)",
command_buffers.len()
));
let queue = self.queue.lock().unwrap(); let queue = self.queue.lock().unwrap();
queue.minimal_submit(Duration::from_secs(10), &command_buffers)?; queue.minimal_submit(Duration::from_secs(10), &command_buffers)?;