diff --git a/Cargo.toml b/Cargo.toml index 557798d..9e877bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,5 +13,7 @@ vulkan-rs = { git = "https://gavania.de/hodasemi/vulkan_lib.git" } rfactor_sm_reader = { git = "https://gavania.de/hodasemi/rfactor_sm_reader.git" } anyhow = { version = "1.0.68", features = ["backtrace"] } -cgmath = { version = "0.18.0", features = ["swizzle"] } +cgmath = { version = "0.18.0", features = ["swizzle", "serde"] } paste = "1.0.11" +serde = "1.0.152" +serde_json = "1.0.91" diff --git a/src/lib.rs b/src/lib.rs index 2700f58..dda6b8e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,15 +6,16 @@ mod vk_handles; use std::{ ffi::c_void, - fs::{File, OpenOptions}, + fs::{self, File, OpenOptions}, io::Write, mem, os::raw::c_char, + path::Path, ptr, }; use enums::*; -use overlay::Overlay; +use overlay::{Overlay, OverlayConfig}; use structs::*; use vk_handles::*; use vulkan_rs::prelude::*; @@ -55,8 +56,9 @@ pub(crate) extern "C" fn vkNegotiateLoaderLayerInterfaceVersion( unsafe { LOG_ENABLED = log_enabled }; + let home = std::env::var("HOME").unwrap(); + if logging() { - let home = std::env::var("HOME").unwrap(); unsafe { LOG_FILE = format!("{}/rf2_vk_hud.log", home); } @@ -68,6 +70,50 @@ pub(crate) extern "C" fn vkNegotiateLoaderLayerInterfaceVersion( write_log!(" =================================================================="); } + let config_path = Path::new(&home).join(".config/rFactorHUD/config.json"); + + let config = if config_path.exists() { + fs::read_to_string(&config_path) + .map(|s| { + serde_json::from_str(&s).unwrap_or({ + write_log!("failed to deserialize config file"); + OverlayConfig::new() + }) + }) + .unwrap_or({ + write_log!(format!("failed to open config file: {:?}", config_path)); + OverlayConfig::new() + }) + } else { + if let Err(err) = std::fs::create_dir_all(config_path.parent().unwrap()) { + write_log!(format!("failed to create dirs for config file: {:?}", err)); + } + + let config = OverlayConfig::new(); + + match File::create(config_path) { + Ok(mut file) => match serde_json::to_string(&config) { + Ok(conf_str) => { + if let Err(err) = file.write_all(conf_str.as_bytes()) { + write_log!(format!("failed to write to config file: {:?}", err)); + } + } + Err(err) => { + write_log!(format!("failed to serialize config: {:?}", err)); + } + }, + Err(err) => { + write_log!(format!("failed to create config file: {:?}", err)); + } + } + + config + }; + + unsafe { + OVERLAY.set_config(config); + } + unsafe { *pVersionStruct = VkNegotiateLayerInterface { sType: enums::VkNegotiateLayerStructType::LAYER_NEGOTIATE_INTERFACE_STRUCT, diff --git a/src/overlay/mod.rs b/src/overlay/mod.rs index 4a74310..ab05a89 100644 --- a/src/overlay/mod.rs +++ b/src/overlay/mod.rs @@ -10,11 +10,27 @@ mod rendering; mod rfactor_data; use anyhow::Result; -use cgmath::vec3; use std::sync::{Arc, Mutex}; use vulkan_rs::prelude::*; +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize)] +pub struct OverlayConfig { + pub data_config: DataConfig, +} + +impl OverlayConfig { + pub const fn new() -> Self { + Self { + data_config: DataConfig::new(), + } + } +} + pub struct Overlay { + config: OverlayConfig, + instance: Option>, device: Option>, queue: Option>>, @@ -26,6 +42,8 @@ pub struct Overlay { impl Overlay { pub const fn new() -> Self { Self { + config: OverlayConfig::new(), + instance: None, device: None, queue: None, @@ -35,6 +53,10 @@ impl Overlay { } } + pub fn set_config(&mut self, config: OverlayConfig) { + self.config = config; + } + pub fn set_instance(&mut self, instance: Arc) { self.instance = Some(instance); } @@ -79,7 +101,6 @@ impl Overlay { self.rendering = Some(Rendering::new(self.device(), self.queue(), swapchain)?); write_log!("-> create rendering: new created"); - write_log!("-> create rendering: end"); Ok(()) @@ -90,12 +111,7 @@ impl Overlay { if self.rfactor_data.is_none() { self.rfactor_data = RFactorData::new( - DataConfig { - radar_scale: 1.0, - radar_car_distance: 20.0, - safe_color: vec3(0.0, 0.75, 0.0), - danger_color: vec3(0.75, 0.0, 0.0), - }, + self.config.data_config, self.device(), self.rendering .as_mut() diff --git a/src/overlay/rfactor_data.rs b/src/overlay/rfactor_data.rs index 16c61ee..4f0891f 100644 --- a/src/overlay/rfactor_data.rs +++ b/src/overlay/rfactor_data.rs @@ -3,6 +3,8 @@ use cgmath::{ortho, vec2, vec3, vec4, Deg, InnerSpace, Matrix4, Rad, Vector2, Ve use rfactor_sm_reader::*; use vulkan_rs::prelude::*; +use serde::{Deserialize, Serialize}; + use std::{sync::Arc, time::Instant}; use super::rendering::PositionOnlyVertex; @@ -17,13 +19,33 @@ pub trait RenderObject { fn buffer(&self) -> &Arc>; } +#[derive(Deserialize, Serialize, Clone, Copy, Debug)] pub struct DataConfig { pub radar_scale: f32, + pub radar_center_factor: f32, + pub radar_transparency: f32, + pub height_scale: f32, + pub width_scale: f32, pub radar_car_distance: f32, pub safe_color: Vector3, pub danger_color: Vector3, } +impl DataConfig { + pub const fn new() -> Self { + Self { + radar_scale: 1.0, + radar_center_factor: 0.25, + radar_transparency: 0.5, + height_scale: 0.15, + width_scale: 0.4, + radar_car_distance: 20.0, + safe_color: vec3(0.0, 0.75, 0.0), + danger_color: vec3(0.75, 0.0, 0.0), + } + } +} + pub struct RFactorData { // config config: DataConfig, @@ -69,11 +91,11 @@ impl RFactorData { write_log!(" =================== create RFactorData ==================="); let radar_extent = width as f32 * 0.075 * config.radar_scale; - let car_height = radar_extent * 0.15; - let car_width = car_height / 2.5; + let car_height = radar_extent * config.height_scale; + let car_width = car_height * config.width_scale; let radar_center = vec2( width as f32 / 2.0, - height as f32 / 2.0 - height as f32 * 0.25, + height as f32 / 2.0 - height as f32 * config.radar_center_factor, ); let flip_y = matrix4_from_diagonal(vec3(1.0, -1.0, 1.0)); @@ -98,7 +120,7 @@ impl RFactorData { vec2(radar_extent, -radar_extent), ], ), - [0.5, 0.5, 0.5, 0.5], + [0.5, 0.5, 0.5, config.radar_transparency], )?, player_car: RadarObject::new( device.clone(),