rFactor2_vk_hud/src/overlay/rfactor_data.rs

406 lines
13 KiB
Rust
Raw Normal View History

2023-01-12 16:45:06 +00:00
use anyhow::Result;
use cgmath::{ortho, vec2, vec3, Deg, InnerSpace, Matrix4, Rad, Vector2, Vector3};
use rfactor_sm_reader::*;
use vulkan_rs::prelude::*;
2023-01-15 05:58:23 +00:00
use std::{sync::Arc, time::Instant};
use super::rendering::PositionOnlyVertex;
2023-01-15 05:58:23 +00:00
use crate::write_log;
2023-01-14 19:15:43 +00:00
fn convert_vec(v: rF2Vec3) -> Vector3<f32> {
vec3(v.x as f32, v.y as f32, v.z as f32)
}
pub trait RenderObject {
fn descriptor(&self) -> &Arc<DescriptorSet>;
fn buffer(&self) -> &Arc<Buffer<PositionOnlyVertex>>;
}
2023-01-12 16:45:06 +00:00
2023-01-14 19:15:43 +00:00
pub struct DataConfig {
pub radar_scale: f32,
pub radar_car_distance: f32,
pub safe_color: Vector3<f32>,
pub danger_color: Vector3<f32>,
}
2023-01-12 16:45:06 +00:00
pub struct RFactorData {
2023-01-14 19:15:43 +00:00
// config
config: DataConfig,
// rf2 memory mapped data
2023-01-14 19:15:43 +00:00
telemetry_reader: TelemetryReader,
scoring_reader: ScoringReader,
// radar objects
background: RadarObject,
player_car: RadarObject,
cars: Vec<RadarObject>,
2023-01-14 19:15:43 +00:00
// buffer car objects, to prevent recreating them every update
car_handles: Vec<RadarObject>,
2023-01-14 19:15:43 +00:00
// game info
player_id: Option<i32>,
// math objects
radar_center: Vector2<f32>,
ortho: Matrix4<f32>,
_window_width: u32,
_window_height: u32,
2023-01-15 05:58:23 +00:00
radar_extent: f32,
2023-01-14 19:15:43 +00:00
car_width: f32,
car_height: f32,
2023-01-15 05:58:23 +00:00
start_time: Instant,
2023-01-14 19:15:43 +00:00
device: Arc<Device>,
descriptor_layout: Arc<DescriptorSetLayout>,
2023-01-12 16:45:06 +00:00
}
impl RFactorData {
2023-01-14 19:15:43 +00:00
pub fn new(
config: DataConfig,
device: Arc<Device>,
descriptor_layout: &Arc<DescriptorSetLayout>,
width: u32,
height: u32,
) -> Result<Self> {
2023-01-15 05:58:23 +00:00
write_log!(" =================== create RFactorData ===================");
2023-01-14 19:15:43 +00:00
let radar_extent = width as f32 * 0.075 * config.radar_scale;
let car_height = radar_extent * 0.2;
let car_width = car_height * 0.5;
let radar_center = vec2(
width as f32 / 2.0,
height as f32 / 2.0 + height as f32 * 0.25,
);
let ortho = ortho(0.0, width as f32, 0.0, height as f32, -1.0, 1.0);
2023-01-15 05:58:23 +00:00
let start_time = Instant::now();
Ok(Self {
2023-01-14 19:15:43 +00:00
config,
2023-01-15 05:58:23 +00:00
telemetry_reader: TelemetryReader::new(start_time.elapsed().as_secs_f32())?,
scoring_reader: ScoringReader::new(start_time.elapsed().as_secs_f32())?,
2023-01-14 19:15:43 +00:00
background: RadarObject::new(
device.clone(),
descriptor_layout,
2023-01-14 19:15:43 +00:00
PositionOnlyVertex::from_2d_corners(
ortho,
[
vec2(radar_center.x - radar_extent, radar_center.y - radar_extent),
vec2(radar_center.x - radar_extent, radar_center.y + radar_extent),
vec2(radar_center.x + radar_extent, radar_center.y + radar_extent),
vec2(radar_center.x + radar_extent, radar_center.y - radar_extent),
],
),
[0.5, 0.5, 0.5, 0.5],
)?,
player_car: RadarObject::new(
device.clone(),
descriptor_layout,
2023-01-14 19:15:43 +00:00
PositionOnlyVertex::from_2d_corners(
ortho,
[
vec2(radar_center.x - car_width, radar_center.y - car_height),
vec2(radar_center.x - car_width, radar_center.y + car_height),
vec2(radar_center.x + car_width, radar_center.y + car_height),
vec2(radar_center.x + car_width, radar_center.y - car_height),
],
),
[0.0, 0.9, 0.0, 0.9],
)?,
cars: Vec::new(),
car_handles: Vec::new(),
2023-01-14 19:15:43 +00:00
player_id: None,
radar_center,
ortho,
_window_width: width,
_window_height: height,
2023-01-15 05:58:23 +00:00
radar_extent,
2023-01-14 19:15:43 +00:00
car_width,
car_height,
2023-01-15 05:58:23 +00:00
start_time,
2023-01-14 19:15:43 +00:00
device,
descriptor_layout: descriptor_layout.clone(),
})
2023-01-12 16:45:06 +00:00
}
2023-01-14 19:15:43 +00:00
fn create_car_object(&self, offset: Vector2<f32>, color: [f32; 4]) -> Result<RadarObject> {
2023-01-15 05:58:23 +00:00
write_log!(" =================== create car object ===================");
2023-01-14 19:15:43 +00:00
RadarObject::new(
self.device.clone(),
&self.descriptor_layout,
Self::create_car_vertices(
2023-01-14 19:15:43 +00:00
self.ortho,
self.radar_center,
self.car_width,
self.car_height,
offset,
2023-01-14 19:15:43 +00:00
),
color,
)
}
fn create_car_vertices(
mvp: Matrix4<f32>,
radar_center: Vector2<f32>,
car_width: f32,
car_height: f32,
offset: Vector2<f32>,
) -> [PositionOnlyVertex; 6] {
PositionOnlyVertex::from_2d_corners(
mvp,
[
vec2(
radar_center.x - car_width + offset.x,
radar_center.y - car_height + offset.y,
),
vec2(
radar_center.x - car_width + offset.x,
radar_center.y + car_height + offset.y,
),
vec2(
radar_center.x + car_width + offset.x,
radar_center.y + car_height + offset.y,
),
vec2(
radar_center.x + car_width + offset.x,
radar_center.y - car_height + offset.y,
),
],
)
}
2023-01-15 05:58:23 +00:00
fn now(&self) -> f32 {
self.start_time.elapsed().as_secs_f32()
}
2023-01-12 16:45:06 +00:00
pub fn update(&mut self) -> Result<()> {
2023-01-15 05:58:23 +00:00
write_log!(" =================== update RFactorData ===================");
2023-01-14 19:15:43 +00:00
// get scoring info
2023-01-15 05:58:23 +00:00
if let Some((scoring_info, vehicle_scorings)) =
self.scoring_reader.vehicle_scoring(self.now())
{
write_log!(format!(
"new scoring info: vehicles: {}",
scoring_info.mNumVehicles
));
// check for player id
if scoring_info.mNumVehicles == 0 {
self.player_id = None;
} else if self.player_id.is_none() {
for vehicle_scoring in vehicle_scorings.iter() {
if vehicle_scoring.mIsPlayer != 0 {
write_log!(format!("player found: {}", vehicle_scoring.mID));
self.player_id = Some(vehicle_scoring.mID);
break;
}
2023-01-14 19:15:43 +00:00
}
}
}
// if player id is set (a map is loaded), check telemetry data
if let Some(player_id) = &self.player_id {
2023-01-15 05:58:23 +00:00
write_log!("before telemetry update");
if let Some(telemetries) = self.telemetry_reader.query_telemetry(self.now()) {
write_log!("new telemetry update");
// make sure there are enough cars in buffer
if self.car_handles.len() < telemetries.len() {
let size_diff = telemetries.len() - self.car_handles.len();
for _ in 0..size_diff {
self.car_handles
.push(self.create_car_object(vec2(0.0, 0.0), [0.0, 0.0, 0.0, 0.0])?);
}
}
2023-01-15 05:58:23 +00:00
let mut player_position = CarPosition::default();
let mut other_positions = Vec::new();
for telemetry in telemetries {
if telemetry.id == *player_id {
player_position.position = convert_vec(telemetry.position);
player_position.orientation = [
convert_vec(telemetry.orientation[0]),
convert_vec(telemetry.orientation[1]),
convert_vec(telemetry.orientation[2]),
];
2023-01-15 05:58:23 +00:00
} else {
other_positions.push(CarPosition {
position: convert_vec(telemetry.position),
orientation: [
convert_vec(telemetry.orientation[0]),
convert_vec(telemetry.orientation[1]),
convert_vec(telemetry.orientation[2]),
],
2023-01-15 05:58:23 +00:00
});
}
2023-01-14 19:15:43 +00:00
}
2023-01-15 05:58:23 +00:00
// update radar objects
self.cars.clear();
let mut buffer_car_index = 0;
2023-01-14 19:15:43 +00:00
2023-01-15 05:58:23 +00:00
for other_position in other_positions {
let diff = player_position.position - other_position.position;
let distance = diff.magnitude();
2023-01-14 19:15:43 +00:00
2023-01-15 05:58:23 +00:00
// check if car is close enough the players car
if distance < self.config.radar_car_distance {
let offset =
diff.xz() * (self.radar_extent / self.config.radar_car_distance);
let buffered_car = self.car_handles[buffer_car_index].clone();
buffer_car_index += 1;
buffered_car.update(
self.ortho,
offset,
Self::car_orientation(&other_position),
self.radar_center,
self.car_width,
self.car_height,
[0.9, 0.9, 0.0, 0.9],
)?;
self.cars.push(buffered_car);
2023-01-15 05:58:23 +00:00
}
2023-01-14 19:15:43 +00:00
}
}
}
2023-01-12 16:45:06 +00:00
Ok(())
}
pub fn objects(&self) -> Vec<&dyn RenderObject> {
2023-01-15 05:58:23 +00:00
write_log!(" =================== get objects of RFactorData ===================");
let mut objects: Vec<&dyn RenderObject> = Vec::new();
2023-01-14 19:15:43 +00:00
// only draw radar when player is loaded into a map
if let Some(_player_id) = &self.player_id {
2023-01-14 19:15:43 +00:00
// only draw radar when any car is near enough
if !self.cars.is_empty() {
objects.push(&self.background);
2023-01-14 19:15:43 +00:00
for other_player_cars in &self.cars {
objects.push(other_player_cars);
}
2023-01-14 19:15:43 +00:00
objects.push(&self.player_car);
}
}
objects
}
fn car_orientation(car: &CarPosition) -> Rad<f32> {
const DEGREES_IN_RADIAN: f32 = 57.2957795;
let xz_val = car.orientation[2].xz();
Rad(xz_val.x.atan2(xz_val.y) * DEGREES_IN_RADIAN)
}
}
#[derive(Clone)]
struct RadarObject {
descriptor_set: Arc<DescriptorSet>,
// uniform buffer
color_buffer: Arc<Buffer<f32>>,
// vertex buffer
position_buffer: Arc<Buffer<PositionOnlyVertex>>,
}
impl RadarObject {
fn new(
device: Arc<Device>,
descriptor_layout: &Arc<DescriptorSetLayout>,
positions: [PositionOnlyVertex; 6],
color: [f32; 4],
) -> Result<Self> {
let color_buffer = Buffer::builder()
.set_usage(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)
.set_memory_usage(MemoryUsage::CpuOnly)
.set_data(&color)
.build(device.clone())?;
let position_buffer = Buffer::builder()
.set_usage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)
.set_memory_usage(MemoryUsage::CpuOnly)
.set_data(&positions)
.build(device.clone())?;
let descriptor_pool = DescriptorPool::builder()
.set_layout(descriptor_layout.clone())
.build(device.clone())?;
let descriptor_set = descriptor_pool.prepare_set().allocate()?;
descriptor_set.update(&[DescriptorWrite::uniform_buffers(0, &[&color_buffer])])?;
Ok(Self {
descriptor_set,
color_buffer,
position_buffer,
})
}
pub fn update(
&self,
ortho: Matrix4<f32>,
offset: Vector2<f32>,
rotation: impl Into<Deg<f32>>,
radar_center: Vector2<f32>,
car_width: f32,
car_height: f32,
color: [f32; 4],
) -> Result<()> {
self.position_buffer
.fill(&RFactorData::create_car_vertices(
ortho * Matrix4::from_angle_z(rotation.into()),
radar_center,
car_width,
car_height,
offset,
))?;
self.color_buffer.fill(&color)
}
}
impl RenderObject for RadarObject {
fn descriptor(&self) -> &Arc<DescriptorSet> {
&self.descriptor_set
}
fn buffer(&self) -> &Arc<Buffer<PositionOnlyVertex>> {
&self.position_buffer
}
2023-01-12 16:45:06 +00:00
}
2023-01-14 19:15:43 +00:00
struct CarPosition {
pub position: Vector3<f32>,
pub orientation: [Vector3<f32>; 3],
2023-01-14 19:15:43 +00:00
}
impl Default for CarPosition {
fn default() -> Self {
Self {
position: vec3(0.0, 0.0, 0.0),
orientation: [vec3(0.0, 0.0, 0.0); 3],
2023-01-14 19:15:43 +00:00
}
}
}