2023-01-12 16:45:06 +00:00
|
|
|
use anyhow::Result;
|
2023-01-16 06:32:32 +00:00
|
|
|
use cgmath::{ortho, vec2, vec3, vec4, Deg, InnerSpace, Matrix4, Rad, Vector2, Vector3};
|
2023-01-13 07:11:53 +00:00
|
|
|
use rfactor_sm_reader::*;
|
|
|
|
use vulkan_rs::prelude::*;
|
|
|
|
|
2023-01-15 05:58:23 +00:00
|
|
|
use std::{sync::Arc, time::Instant};
|
2023-01-13 07:11:53 +00:00
|
|
|
|
|
|
|
use super::rendering::PositionOnlyVertex;
|
2023-01-15 05:58:23 +00:00
|
|
|
use crate::write_log;
|
2023-01-13 07:11:53 +00:00
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2023-01-13 07:11:53 +00:00
|
|
|
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,
|
|
|
|
|
2023-01-13 07:11:53 +00:00
|
|
|
// rf2 memory mapped data
|
2023-01-14 19:15:43 +00:00
|
|
|
telemetry_reader: TelemetryReader,
|
|
|
|
scoring_reader: ScoringReader,
|
2023-01-13 07:11:53 +00:00
|
|
|
|
|
|
|
// radar objects
|
|
|
|
background: RadarObject,
|
|
|
|
player_car: RadarObject,
|
|
|
|
cars: Vec<RadarObject>,
|
2023-01-14 19:15:43 +00:00
|
|
|
|
2023-01-15 09:46:22 +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>,
|
2023-01-15 09:46:22 +00:00
|
|
|
_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;
|
2023-01-16 06:32:32 +00:00
|
|
|
let car_height = radar_extent * 0.15;
|
|
|
|
let car_width = car_height / 2.5;
|
2023-01-14 19:15:43 +00:00
|
|
|
let radar_center = vec2(
|
|
|
|
width as f32 / 2.0,
|
2023-01-16 06:32:32 +00:00
|
|
|
height as f32 / 2.0 - height as f32 * 0.25,
|
2023-01-14 19:15:43 +00:00
|
|
|
);
|
|
|
|
|
2023-01-16 06:32:32 +00:00
|
|
|
let flip_y = matrix4_from_diagonal(vec3(1.0, -1.0, 1.0));
|
|
|
|
let ortho = flip_y * 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();
|
2023-01-13 07:11:53 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
2023-01-13 07:11:53 +00:00
|
|
|
background: RadarObject::new(
|
|
|
|
device.clone(),
|
|
|
|
descriptor_layout,
|
2023-01-14 19:15:43 +00:00
|
|
|
PositionOnlyVertex::from_2d_corners(
|
2023-01-15 18:58:23 +00:00
|
|
|
ortho * Matrix4::from_translation(radar_center.extend(0.0)),
|
2023-01-14 19:15:43 +00:00
|
|
|
[
|
2023-01-15 18:58:23 +00:00
|
|
|
vec2(-radar_extent, -radar_extent),
|
|
|
|
vec2(-radar_extent, radar_extent),
|
|
|
|
vec2(radar_extent, radar_extent),
|
|
|
|
vec2(radar_extent, -radar_extent),
|
2023-01-14 19:15:43 +00:00
|
|
|
],
|
|
|
|
),
|
2023-01-13 07:11:53 +00:00
|
|
|
[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(
|
2023-01-15 18:58:23 +00:00
|
|
|
ortho * Matrix4::from_translation(radar_center.extend(0.0)),
|
2023-01-14 19:15:43 +00:00
|
|
|
[
|
2023-01-15 18:58:23 +00:00
|
|
|
vec2(-car_width, -car_height),
|
|
|
|
vec2(-car_width, car_height),
|
|
|
|
vec2(car_width, car_height),
|
|
|
|
vec2(car_width, -car_height),
|
2023-01-14 19:15:43 +00:00
|
|
|
],
|
|
|
|
),
|
2023-01-15 09:46:22 +00:00
|
|
|
[0.0, 0.9, 0.0, 0.9],
|
2023-01-13 07:11:53 +00:00
|
|
|
)?,
|
|
|
|
cars: Vec::new(),
|
2023-01-15 09:46:22 +00:00
|
|
|
car_handles: Vec::new(),
|
2023-01-14 19:15:43 +00:00
|
|
|
|
|
|
|
player_id: None,
|
|
|
|
|
|
|
|
radar_center,
|
|
|
|
ortho,
|
2023-01-15 09:46:22 +00:00
|
|
|
_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-13 07:11:53 +00:00
|
|
|
})
|
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,
|
2023-01-15 09:46:22 +00:00
|
|
|
Self::create_car_vertices(
|
2023-01-15 18:58:23 +00:00
|
|
|
self.ortho
|
|
|
|
* Matrix4::from_translation(self.radar_center.extend(0.0))
|
|
|
|
* Matrix4::from_translation(offset.extend(0.0)),
|
2023-01-15 09:46:22 +00:00
|
|
|
self.car_width,
|
|
|
|
self.car_height,
|
2023-01-14 19:15:43 +00:00
|
|
|
),
|
|
|
|
color,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2023-01-15 09:46:22 +00:00
|
|
|
fn create_car_vertices(
|
|
|
|
mvp: Matrix4<f32>,
|
|
|
|
car_width: f32,
|
|
|
|
car_height: f32,
|
|
|
|
) -> [PositionOnlyVertex; 6] {
|
|
|
|
PositionOnlyVertex::from_2d_corners(
|
|
|
|
mvp,
|
|
|
|
[
|
2023-01-15 18:58:23 +00:00
|
|
|
vec2(-car_width, -car_height),
|
|
|
|
vec2(-car_width, car_height),
|
|
|
|
vec2(car_width, car_height),
|
|
|
|
vec2(car_width, -car_height),
|
2023-01-15 09:46:22 +00:00
|
|
|
],
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
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");
|
|
|
|
|
2023-01-15 09:46:22 +00:00
|
|
|
// 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 {
|
2023-01-15 18:58:23 +00:00
|
|
|
let car = CarPosition::new(
|
|
|
|
convert_vec(telemetry.position),
|
|
|
|
[
|
2023-01-15 09:46:22 +00:00
|
|
|
convert_vec(telemetry.orientation[0]),
|
|
|
|
convert_vec(telemetry.orientation[1]),
|
|
|
|
convert_vec(telemetry.orientation[2]),
|
2023-01-15 18:58:23 +00:00
|
|
|
],
|
|
|
|
);
|
|
|
|
|
|
|
|
if telemetry.id == *player_id {
|
|
|
|
player_position = car
|
2023-01-15 05:58:23 +00:00
|
|
|
} else {
|
2023-01-15 18:58:23 +00:00
|
|
|
other_positions.push(car);
|
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();
|
2023-01-15 09:46:22 +00:00
|
|
|
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 18:58:23 +00:00
|
|
|
// check if car is close enough to the players car
|
2023-01-15 05:58:23 +00:00
|
|
|
if distance < self.config.radar_car_distance {
|
|
|
|
let offset =
|
2023-01-15 09:46:22 +00:00
|
|
|
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,
|
2023-01-16 02:56:10 +00:00
|
|
|
player_position.rotation,
|
|
|
|
other_position.rotation,
|
2023-01-15 09:46:22 +00:00
|
|
|
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(())
|
|
|
|
}
|
2023-01-13 07:11:53 +00:00
|
|
|
|
|
|
|
pub fn objects(&self) -> Vec<&dyn RenderObject> {
|
2023-01-15 05:58:23 +00:00
|
|
|
write_log!(" =================== get objects of RFactorData ===================");
|
|
|
|
|
2023-01-13 07:11:53 +00:00
|
|
|
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
|
2023-01-15 09:46:22 +00:00
|
|
|
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-13 07:11:53 +00:00
|
|
|
|
2023-01-14 19:15:43 +00:00
|
|
|
for other_player_cars in &self.cars {
|
|
|
|
objects.push(other_player_cars);
|
|
|
|
}
|
2023-01-13 07:11:53 +00:00
|
|
|
|
2023-01-14 19:15:43 +00:00
|
|
|
objects.push(&self.player_car);
|
|
|
|
}
|
|
|
|
}
|
2023-01-13 07:11:53 +00:00
|
|
|
|
|
|
|
objects
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-15 09:46:22 +00:00
|
|
|
#[derive(Clone)]
|
2023-01-13 07:11:53 +00:00
|
|
|
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,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-01-15 09:46:22 +00:00
|
|
|
pub fn update(
|
|
|
|
&self,
|
2023-01-16 02:56:10 +00:00
|
|
|
|
2023-01-15 09:46:22 +00:00
|
|
|
ortho: Matrix4<f32>,
|
|
|
|
offset: Vector2<f32>,
|
2023-01-16 02:56:10 +00:00
|
|
|
player_rotation: impl Into<Deg<f32>>,
|
2023-01-15 09:46:22 +00:00
|
|
|
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(
|
2023-01-15 18:58:23 +00:00
|
|
|
ortho
|
|
|
|
* Matrix4::from_translation(radar_center.extend(0.0))
|
2023-01-16 02:56:10 +00:00
|
|
|
* Matrix4::from_angle_z(-player_rotation.into())
|
2023-01-15 18:58:23 +00:00
|
|
|
* Matrix4::from_translation(offset.extend(0.0))
|
|
|
|
* Matrix4::from_angle_z(rotation.into()),
|
2023-01-15 09:46:22 +00:00
|
|
|
car_width,
|
|
|
|
car_height,
|
|
|
|
))?;
|
2023-01-13 07:11:53 +00:00
|
|
|
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>,
|
2023-01-15 18:58:23 +00:00
|
|
|
pub rotation: Rad<f32>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CarPosition {
|
|
|
|
fn new(position: Vector3<f32>, orientation: [Vector3<f32>; 3]) -> Self {
|
|
|
|
Self {
|
|
|
|
position,
|
2023-01-16 06:32:32 +00:00
|
|
|
rotation: Rad(orientation[2].x.atan2(orientation[2].z)),
|
2023-01-15 18:58:23 +00:00
|
|
|
}
|
|
|
|
}
|
2023-01-14 19:15:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for CarPosition {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
position: vec3(0.0, 0.0, 0.0),
|
2023-01-15 18:58:23 +00:00
|
|
|
rotation: Rad(0.0),
|
2023-01-14 19:15:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-01-16 06:32:32 +00:00
|
|
|
|
|
|
|
const fn matrix4_from_diagonal(diagonal: Vector3<f32>) -> Matrix4<f32> {
|
|
|
|
Matrix4::from_cols(
|
|
|
|
vec4(diagonal.x, 0.0, 0.0, 0.0),
|
|
|
|
vec4(0.0, diagonal.y, 0.0, 0.0),
|
|
|
|
vec4(0.0, 0.0, diagonal.z, 0.0),
|
|
|
|
vec4(0.0, 0.0, 0.0, 1.0),
|
|
|
|
)
|
|
|
|
}
|