Add telemetry history graph
This commit is contained in:
parent
dc745ea8af
commit
57356366e6
13 changed files with 416 additions and 62 deletions
|
@ -20,3 +20,4 @@ cgmath = { version = "0.18.0", features = ["swizzle", "serde"] }
|
||||||
paste = "1.0.11"
|
paste = "1.0.11"
|
||||||
serde = "1.0.152"
|
serde = "1.0.152"
|
||||||
serde_json = "1.0.91"
|
serde_json = "1.0.91"
|
||||||
|
ringbuf = "0.3.2"
|
||||||
|
|
6
build.rs
6
build.rs
|
@ -10,8 +10,10 @@ const VK_HEADER: &[&str] = &[
|
||||||
const FN_PREFIX: &str = "PFN_";
|
const FN_PREFIX: &str = "PFN_";
|
||||||
|
|
||||||
const SHADER: &[&str] = &[
|
const SHADER: &[&str] = &[
|
||||||
"src/overlay/elements/pedals/single_color.vert",
|
"src/overlay/elements/radar/single_color.vert",
|
||||||
"src/overlay/elements/pedals/single_color.frag",
|
"src/overlay/elements/radar/single_color.frag",
|
||||||
|
"src/overlay/elements/pedals/history.vert",
|
||||||
|
"src/overlay/elements/pedals/history.frag",
|
||||||
];
|
];
|
||||||
|
|
||||||
fn query_vulkan_function_typedefs() {
|
fn query_vulkan_function_typedefs() {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?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 id="main_grid" x_dim="1" y_dim="25" x_offset="10" y_offset="70" width="350" height="875"
|
<grid id="main_grid" x_dim="1" y_dim="25" x_offset="10" y_offset="10" width="350" height="875"
|
||||||
vert_align="top" hori_align="left" margin="0" padding="0"> </grid>
|
vert_align="top" hori_align="left" margin="0" padding="0"> </grid>
|
||||||
</root>
|
</root>
|
|
@ -7,3 +7,42 @@ pub use leaderboard::*;
|
||||||
pub use pedals::*;
|
pub use pedals::*;
|
||||||
pub use radar::*;
|
pub use radar::*;
|
||||||
pub use watermark::*;
|
pub use watermark::*;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct PositionOnlyVertex {
|
||||||
|
pub position: cgmath::Vector4<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PositionOnlyVertex {
|
||||||
|
///
|
||||||
|
/// corners[0] - bottom left
|
||||||
|
/// corners[1] - top left
|
||||||
|
/// corners[2] - top right
|
||||||
|
/// corners[3] - bottom right
|
||||||
|
///
|
||||||
|
pub fn from_2d_corners(
|
||||||
|
ortho: cgmath::Matrix4<f32>,
|
||||||
|
corners: [cgmath::Vector2<f32>; 4],
|
||||||
|
) -> [Self; 6] {
|
||||||
|
[
|
||||||
|
Self {
|
||||||
|
position: ortho * corners[0].extend(0.0).extend(1.0),
|
||||||
|
},
|
||||||
|
Self {
|
||||||
|
position: ortho * corners[1].extend(0.0).extend(1.0),
|
||||||
|
},
|
||||||
|
Self {
|
||||||
|
position: ortho * corners[2].extend(0.0).extend(1.0),
|
||||||
|
},
|
||||||
|
Self {
|
||||||
|
position: ortho * corners[2].extend(0.0).extend(1.0),
|
||||||
|
},
|
||||||
|
Self {
|
||||||
|
position: ortho * corners[3].extend(0.0).extend(1.0),
|
||||||
|
},
|
||||||
|
Self {
|
||||||
|
position: ortho * corners[0].extend(0.0).extend(1.0),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
12
src/overlay/elements/pedals/history.frag
Normal file
12
src/overlay/elements/pedals/history.frag
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout (set = 0, binding = 0) uniform Color {
|
||||||
|
vec4 val;
|
||||||
|
} color;
|
||||||
|
|
||||||
|
layout (location = 0) out vec4 out_color;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
out_color = color.val;
|
||||||
|
}
|
8
src/overlay/elements/pedals/history.vert
Normal file
8
src/overlay/elements/pedals/history.vert
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout (location = 0) in vec4 position;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = position;
|
||||||
|
}
|
|
@ -1,45 +1,230 @@
|
||||||
use std::sync::Arc;
|
mod pipeline;
|
||||||
|
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use cgmath::{ortho, vec4, Matrix4};
|
||||||
use rfactor_sm_reader::{rF2VehicleTelemetry, VehicleScoringInfoV01};
|
use rfactor_sm_reader::{rF2VehicleTelemetry, VehicleScoringInfoV01};
|
||||||
|
use ringbuf::{HeapRb, Rb};
|
||||||
use ui::prelude::*;
|
use ui::prelude::*;
|
||||||
|
use vulkan_rs::prelude::*;
|
||||||
|
|
||||||
use crate::overlay::{
|
use crate::overlay::{
|
||||||
rfactor_data::{DataReceiver, GamePhase},
|
rfactor_data::{DataReceiver, GamePhase},
|
||||||
UiOverlay,
|
UiOverlay,
|
||||||
};
|
};
|
||||||
|
use crate::write_log;
|
||||||
|
|
||||||
|
use self::pipeline::HistoryPipeline;
|
||||||
|
|
||||||
|
use super::PositionOnlyVertex;
|
||||||
|
|
||||||
pub struct Pedals {
|
pub struct Pedals {
|
||||||
gui: Arc<GuiBuilder>,
|
gui: Arc<GuiBuilder>,
|
||||||
|
|
||||||
brake: Arc<ProgressBar>,
|
brake: Arc<ProgressBar>,
|
||||||
throttle: Arc<ProgressBar>,
|
throttle: Arc<ProgressBar>,
|
||||||
history: Arc<Icon>,
|
_history: Arc<Icon>,
|
||||||
|
|
||||||
throttle_samples: Vec<f32>,
|
throttle_samples: HeapRb<f32>,
|
||||||
brake_samples: Vec<f32>,
|
brake_samples: HeapRb<f32>,
|
||||||
|
|
||||||
|
ortho: Matrix4<f32>,
|
||||||
|
|
||||||
|
device: Arc<Device>,
|
||||||
|
queue: Arc<Mutex<Queue>>,
|
||||||
|
|
||||||
|
render_target: RenderTarget,
|
||||||
|
pipeline: HistoryPipeline,
|
||||||
|
|
||||||
|
brake_descriptor: Arc<DescriptorSet>,
|
||||||
|
brake_vertex_buffer: Arc<Buffer<PositionOnlyVertex>>,
|
||||||
|
throttle_descriptor: Arc<DescriptorSet>,
|
||||||
|
throttle_vertex_buffer: Arc<Buffer<PositionOnlyVertex>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pedals {
|
impl Pedals {
|
||||||
pub fn new(gui_handler: &Arc<GuiHandler>) -> Result<Self> {
|
pub fn new(
|
||||||
|
gui_handler: &Arc<GuiHandler>,
|
||||||
|
device: Arc<Device>,
|
||||||
|
queue: Arc<Mutex<Queue>>,
|
||||||
|
) -> Result<Self> {
|
||||||
const DESC: &str = include_str!("pedals.xml");
|
const DESC: &str = include_str!("pedals.xml");
|
||||||
|
|
||||||
let gui = GuiBuilder::from_str(gui_handler, DESC)?;
|
let gui = GuiBuilder::from_str(gui_handler, DESC)?;
|
||||||
|
|
||||||
let brake = gui.element("brake")?;
|
let brake = gui.element("brake")?;
|
||||||
let throttle = gui.element("throttle")?;
|
let throttle = gui.element("throttle")?;
|
||||||
let history = gui.element("history")?;
|
let history: Arc<Icon> = gui.element("history")?;
|
||||||
|
|
||||||
Ok(Self {
|
let (icon_width, icon_height) = history.extent();
|
||||||
|
let history_image = Image::empty(
|
||||||
|
icon_width as u32,
|
||||||
|
icon_height as u32,
|
||||||
|
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||||
|
VK_SAMPLE_COUNT_1_BIT,
|
||||||
|
)
|
||||||
|
.format(VK_FORMAT_R8G8B8A8_UNORM)
|
||||||
|
.attach_sampler(Sampler::nearest_sampler().build(&device)?)
|
||||||
|
.build(&device, &queue)?;
|
||||||
|
|
||||||
|
history_image.convert_layout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)?;
|
||||||
|
|
||||||
|
history.set_icon(&history_image)?;
|
||||||
|
|
||||||
|
let render_target = RenderTarget::builder()
|
||||||
|
.add_sub_pass(
|
||||||
|
SubPass::builder(history_image.width(), history_image.height())
|
||||||
|
.set_prepared_targets(&[history_image.clone()], 0, [0.3, 0.3, 0.3, 1.0], true)
|
||||||
|
.build(&device, &queue)?,
|
||||||
|
)
|
||||||
|
.build(&device)?;
|
||||||
|
|
||||||
|
let pipeline = HistoryPipeline::new(
|
||||||
|
device.clone(),
|
||||||
|
render_target.render_pass(),
|
||||||
|
history_image.width(),
|
||||||
|
history_image.height(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let ortho = ortho(0.0, history_image.width() as f32, 0.0, 1.0, -1.0, 1.0);
|
||||||
|
|
||||||
|
let descriptor_pool = DescriptorPool::builder()
|
||||||
|
.set_layout(pipeline.descriptor_layout().clone())
|
||||||
|
.set_descriptor_set_count(2)
|
||||||
|
.build(device.clone())?;
|
||||||
|
|
||||||
|
let brake_color_buffer: Arc<Buffer<f32>> = Buffer::builder()
|
||||||
|
.set_usage(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)
|
||||||
|
.set_memory_usage(MemoryUsage::CpuOnly)
|
||||||
|
.set_data(&[0.9, 0.0, 0.0, 1.0])
|
||||||
|
.build(device.clone())?;
|
||||||
|
|
||||||
|
write_log!("allocate brake descriptor");
|
||||||
|
|
||||||
|
let brake_descriptor = descriptor_pool.prepare_set().allocate()?;
|
||||||
|
brake_descriptor.update(&[DescriptorWrite::uniform_buffers(0, &[&brake_color_buffer])])?;
|
||||||
|
|
||||||
|
let throttle_color_buffer: Arc<Buffer<f32>> = Buffer::builder()
|
||||||
|
.set_usage(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)
|
||||||
|
.set_memory_usage(MemoryUsage::CpuOnly)
|
||||||
|
.set_data(&[0.0, 0.9, 0.0, 1.0])
|
||||||
|
.build(device.clone())?;
|
||||||
|
|
||||||
|
write_log!("allocate throttle descriptor");
|
||||||
|
|
||||||
|
let throttle_descriptor = descriptor_pool.prepare_set().allocate()?;
|
||||||
|
throttle_descriptor.update(&[DescriptorWrite::uniform_buffers(
|
||||||
|
0,
|
||||||
|
&[&throttle_color_buffer],
|
||||||
|
)])?;
|
||||||
|
|
||||||
|
let mut throttle_samples = HeapRb::new(icon_width as usize);
|
||||||
|
let mut brake_samples = HeapRb::new(icon_width as usize);
|
||||||
|
|
||||||
|
for _ in 0..icon_width {
|
||||||
|
throttle_samples.push_overwrite(0.0);
|
||||||
|
brake_samples.push_overwrite(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let brake_vertex_buffer = Self::create_vertex_buffer(&device, icon_width as VkDeviceSize)?;
|
||||||
|
let throttle_vertex_buffer =
|
||||||
|
Self::create_vertex_buffer(&device, icon_width as VkDeviceSize)?;
|
||||||
|
|
||||||
|
let me = Self {
|
||||||
gui,
|
gui,
|
||||||
|
|
||||||
brake,
|
brake,
|
||||||
throttle,
|
throttle,
|
||||||
history,
|
_history: history,
|
||||||
|
|
||||||
throttle_samples: Vec::new(),
|
throttle_samples,
|
||||||
brake_samples: Vec::new(),
|
brake_samples,
|
||||||
|
|
||||||
|
ortho,
|
||||||
|
|
||||||
|
device,
|
||||||
|
queue,
|
||||||
|
|
||||||
|
render_target,
|
||||||
|
pipeline,
|
||||||
|
|
||||||
|
brake_descriptor,
|
||||||
|
brake_vertex_buffer,
|
||||||
|
throttle_descriptor,
|
||||||
|
throttle_vertex_buffer,
|
||||||
|
};
|
||||||
|
|
||||||
|
me.update_vertex_buffers()?;
|
||||||
|
|
||||||
|
Ok(me)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_vertex_buffer(
|
||||||
|
device: &Arc<Device>,
|
||||||
|
size: VkDeviceSize,
|
||||||
|
) -> Result<Arc<Buffer<PositionOnlyVertex>>> {
|
||||||
|
Buffer::builder()
|
||||||
|
.set_usage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)
|
||||||
|
.set_memory_usage(MemoryUsage::CpuOnly)
|
||||||
|
.set_size(size)
|
||||||
|
.build(device.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_vertex_buffers(&self) -> Result<()> {
|
||||||
|
self.update_vertex_buffer(
|
||||||
|
&self.throttle_vertex_buffer,
|
||||||
|
self.throttle_samples.as_slices(),
|
||||||
|
)?;
|
||||||
|
self.update_vertex_buffer(&self.brake_vertex_buffer, self.brake_samples.as_slices())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_vertex_buffer(
|
||||||
|
&self,
|
||||||
|
buffer: &Arc<Buffer<PositionOnlyVertex>>,
|
||||||
|
(data1, data2): (&[f32], &[f32]),
|
||||||
|
) -> Result<()> {
|
||||||
|
let points = data1
|
||||||
|
.iter()
|
||||||
|
.chain(data2.iter())
|
||||||
|
.enumerate()
|
||||||
|
.map(|(x, &date)| PositionOnlyVertex {
|
||||||
|
position: self.ortho * vec4(x as f32, date, 0.0, 1.0),
|
||||||
})
|
})
|
||||||
|
.collect::<Vec<PositionOnlyVertex>>();
|
||||||
|
|
||||||
|
buffer.fill(&points)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&self) -> Result<Arc<CommandBuffer>> {
|
||||||
|
let command_buffer =
|
||||||
|
CommandBuffer::new_primary().build(self.device.clone(), self.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,
|
||||||
|
))?;
|
||||||
|
|
||||||
|
self.render_target
|
||||||
|
.begin(&recorder, VK_SUBPASS_CONTENTS_INLINE, 0);
|
||||||
|
|
||||||
|
recorder.bind_pipeline(self.pipeline.pipeline())?;
|
||||||
|
|
||||||
|
recorder.bind_descriptor_sets_minimal(&[&self.throttle_descriptor]);
|
||||||
|
recorder.bind_vertex_buffer(&self.throttle_vertex_buffer);
|
||||||
|
recorder.draw_complete_single_instance(self.throttle_vertex_buffer.size() as u32);
|
||||||
|
|
||||||
|
recorder.bind_descriptor_sets_minimal(&[&self.brake_descriptor]);
|
||||||
|
recorder.bind_vertex_buffer(&self.brake_vertex_buffer);
|
||||||
|
recorder.draw_complete_single_instance(self.brake_vertex_buffer.size() as u32);
|
||||||
|
|
||||||
|
self.render_target.end(&recorder);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(command_buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,8 +255,10 @@ impl DataReceiver for Pedals {
|
||||||
self.throttle.set_progress(throttle)?;
|
self.throttle.set_progress(throttle)?;
|
||||||
self.brake.set_progress(brake)?;
|
self.brake.set_progress(brake)?;
|
||||||
|
|
||||||
self.throttle_samples.push(throttle);
|
self.throttle_samples.push_overwrite(throttle);
|
||||||
self.brake_samples.push(brake);
|
self.brake_samples.push_overwrite(brake);
|
||||||
|
|
||||||
|
self.update_vertex_buffers()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
@ -82,3 +269,28 @@ impl DataReceiver for Pedals {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use ringbuf::{HeapRb, Rb};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rb_test() {
|
||||||
|
const CAP: usize = 10;
|
||||||
|
|
||||||
|
let mut buf = HeapRb::new(CAP);
|
||||||
|
|
||||||
|
for _ in 0..CAP {
|
||||||
|
buf.push_overwrite(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{:?}", buf.as_slices());
|
||||||
|
|
||||||
|
buf.push_overwrite(40);
|
||||||
|
buf.push_overwrite(40);
|
||||||
|
buf.push_overwrite(40);
|
||||||
|
buf.push_overwrite(40);
|
||||||
|
|
||||||
|
println!("{:?}", buf.as_slices());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?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="7" y_dim="2" x_offset="-750" y_offset="-250" width="150" height="200"
|
<grid x_dim="10" y_dim="2" x_offset="-850" y_offset="-190" width="200" height="160"
|
||||||
vert_align="bottom" hori_align="right" margin="3" padding="3" 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="#494949"
|
<progressbar id="brake" x_slot="0" y_slot="0" y_size="2" background="#494949"
|
||||||
direction="bottom_to_top" foreground="#e30000"></progressbar>
|
direction="bottom_to_top" foreground="#e30000"></progressbar>
|
||||||
|
@ -8,7 +8,7 @@
|
||||||
x_slot="1" y_slot="0" y_size="2" background="#494949" direction="bottom_to_top"
|
x_slot="1" y_slot="0" y_size="2" background="#494949" direction="bottom_to_top"
|
||||||
foreground="#00b900"></progressbar>
|
foreground="#00b900"></progressbar>
|
||||||
|
|
||||||
<icon id="history" x_slot="2" x_size="5" y_slot="0"
|
<icon id="history" x_slot="2" x_size="8" y_slot="0"
|
||||||
y_size="2"></icon>
|
y_size="2"></icon>
|
||||||
</grid>
|
</grid>
|
||||||
</root>
|
</root>
|
102
src/overlay/elements/pedals/pipeline.rs
Normal file
102
src/overlay/elements/pedals/pipeline.rs
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use vulkan_rs::prelude::*;
|
||||||
|
|
||||||
|
use std::{mem, sync::Arc};
|
||||||
|
|
||||||
|
use super::super::PositionOnlyVertex;
|
||||||
|
|
||||||
|
pub struct HistoryPipeline {
|
||||||
|
pipeline: Arc<Pipeline>,
|
||||||
|
descriptor_layout: Arc<DescriptorSetLayout>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HistoryPipeline {
|
||||||
|
pub fn new(
|
||||||
|
device: Arc<Device>,
|
||||||
|
renderpass: &Arc<RenderPass>,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
) -> Result<Self> {
|
||||||
|
let vertex_shader = ShaderModule::from_slice(
|
||||||
|
device.clone(),
|
||||||
|
include_bytes!("history.vert.spv"),
|
||||||
|
ShaderType::Vertex,
|
||||||
|
)?;
|
||||||
|
let fragment_shader = ShaderModule::from_slice(
|
||||||
|
device.clone(),
|
||||||
|
include_bytes!("history.frag.spv"),
|
||||||
|
ShaderType::Fragment,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let descriptor_layout = DescriptorSetLayout::builder()
|
||||||
|
.add_layout_binding(
|
||||||
|
0,
|
||||||
|
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||||
|
VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
.build(device.clone())?;
|
||||||
|
|
||||||
|
let pipeline_layout = PipelineLayout::builder()
|
||||||
|
.add_descriptor_set_layout(&descriptor_layout)
|
||||||
|
.build(device.clone())?;
|
||||||
|
|
||||||
|
let viewport = VkViewport {
|
||||||
|
x: 0.0,
|
||||||
|
y: 0.0,
|
||||||
|
width: width as f32,
|
||||||
|
height: height as f32,
|
||||||
|
minDepth: 0.0,
|
||||||
|
maxDepth: 1.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let scissor = VkRect2D {
|
||||||
|
offset: VkOffset2D { x: 0, y: 0 },
|
||||||
|
extent: VkExtent2D {
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let pipeline = Pipeline::new_graphics()
|
||||||
|
.set_vertex_shader(
|
||||||
|
vertex_shader.clone(),
|
||||||
|
vec![VkVertexInputBindingDescription {
|
||||||
|
binding: 0,
|
||||||
|
stride: mem::size_of::<PositionOnlyVertex>() as u32,
|
||||||
|
inputRate: VK_VERTEX_INPUT_RATE_VERTEX,
|
||||||
|
}],
|
||||||
|
vec![
|
||||||
|
// position
|
||||||
|
VkVertexInputAttributeDescription {
|
||||||
|
location: 0,
|
||||||
|
binding: 0,
|
||||||
|
format: VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.set_fragment_shader(fragment_shader.clone())
|
||||||
|
.input_assembly(VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, false)
|
||||||
|
.default_depth_stencil(false, false)
|
||||||
|
.default_color_blend(vec![VkPipelineColorBlendAttachmentState::default()])
|
||||||
|
.default_rasterization(VK_CULL_MODE_NONE, VK_FRONT_FACE_COUNTER_CLOCKWISE)
|
||||||
|
.default_multisample(VK_SAMPLE_COUNT_1_BIT)
|
||||||
|
.add_viewport(viewport)
|
||||||
|
.add_scissor(scissor)
|
||||||
|
.build(device, &pipeline_layout, &renderpass, 0)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
descriptor_layout,
|
||||||
|
pipeline,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pipeline(&self) -> &Arc<Pipeline> {
|
||||||
|
&self.pipeline
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn descriptor_layout(&self) -> &Arc<DescriptorSetLayout> {
|
||||||
|
&self.descriptor_layout
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
mod pipeline;
|
mod pipeline;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use cgmath::{ortho, vec2, vec3, vec4, Deg, InnerSpace, Matrix4, Rad, Vector2, Vector3, Vector4};
|
use cgmath::{ortho, vec2, vec3, vec4, Deg, InnerSpace, Matrix4, Rad, Vector2, Vector3};
|
||||||
use rfactor_sm_reader::*;
|
use rfactor_sm_reader::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use vulkan_rs::prelude::*;
|
use vulkan_rs::prelude::*;
|
||||||
|
@ -19,41 +19,7 @@ use crate::{
|
||||||
write_log,
|
write_log,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
use super::PositionOnlyVertex;
|
||||||
pub struct PositionOnlyVertex {
|
|
||||||
pub position: Vector4<f32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PositionOnlyVertex {
|
|
||||||
///
|
|
||||||
/// corners[0] - bottom left
|
|
||||||
/// corners[1] - top left
|
|
||||||
/// corners[2] - top right
|
|
||||||
/// corners[3] - bottom right
|
|
||||||
///
|
|
||||||
pub fn from_2d_corners(ortho: Matrix4<f32>, corners: [Vector2<f32>; 4]) -> [Self; 6] {
|
|
||||||
[
|
|
||||||
Self {
|
|
||||||
position: ortho * corners[0].extend(0.0).extend(1.0),
|
|
||||||
},
|
|
||||||
Self {
|
|
||||||
position: ortho * corners[1].extend(0.0).extend(1.0),
|
|
||||||
},
|
|
||||||
Self {
|
|
||||||
position: ortho * corners[2].extend(0.0).extend(1.0),
|
|
||||||
},
|
|
||||||
Self {
|
|
||||||
position: ortho * corners[2].extend(0.0).extend(1.0),
|
|
||||||
},
|
|
||||||
Self {
|
|
||||||
position: ortho * corners[3].extend(0.0).extend(1.0),
|
|
||||||
},
|
|
||||||
Self {
|
|
||||||
position: ortho * corners[0].extend(0.0).extend(1.0),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn convert_vec(v: rF2Vec3) -> Vector3<f32> {
|
fn convert_vec(v: rF2Vec3) -> Vector3<f32> {
|
||||||
vec3(v.x as f32, v.y as f32, v.z as f32)
|
vec3(v.x as f32, v.y as f32, v.z as f32)
|
||||||
|
|
|
@ -10,7 +10,7 @@ use crate::overlay::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Watermark {
|
pub struct Watermark {
|
||||||
_gui: Arc<GuiBuilder>,
|
gui: Arc<GuiBuilder>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Watermark {
|
impl Watermark {
|
||||||
|
@ -19,9 +19,7 @@ impl Watermark {
|
||||||
|
|
||||||
let gui = GuiBuilder::from_str(gui_handler, DESC)?;
|
let gui = GuiBuilder::from_str(gui_handler, DESC)?;
|
||||||
|
|
||||||
gui.enable()?;
|
Ok(Self { gui })
|
||||||
|
|
||||||
Ok(Self { _gui: gui })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,9 +28,14 @@ impl UiOverlay for Watermark {}
|
||||||
impl DataReceiver for Watermark {
|
impl DataReceiver for Watermark {
|
||||||
fn scoring_update(
|
fn scoring_update(
|
||||||
&mut self,
|
&mut self,
|
||||||
_phase: GamePhase,
|
phase: GamePhase,
|
||||||
_vehicle_scoring: &[VehicleScoringInfoV01],
|
_vehicle_scoring: &[VehicleScoringInfoV01],
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
match phase {
|
||||||
|
GamePhase::TestDay => self.gui.enable()?,
|
||||||
|
_ => self.gui.disable()?,
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -142,7 +142,7 @@ 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("/usr/share/vulkan_rf2_layer/font.png");
|
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
|
// required to not crash
|
||||||
|
@ -196,8 +196,15 @@ impl Overlay {
|
||||||
|
|
||||||
// create pedals
|
// create pedals
|
||||||
if self.config.ui_config.enable_pedals {
|
if self.config.ui_config.enable_pedals {
|
||||||
let pedals = Rc::new(RefCell::new(Pedals::new(&gui_handler)?));
|
let pedals = Rc::new(RefCell::new(Pedals::new(
|
||||||
self.ui_elements.push(pedals);
|
&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");
|
write_log!("Pedals successfully created");
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,6 +109,8 @@ impl RFactorData {
|
||||||
|
|
||||||
let phase = GamePhase::try_from(scoring_info.mSession)?;
|
let phase = GamePhase::try_from(scoring_info.mSession)?;
|
||||||
|
|
||||||
|
write_log!(format!("GamePhase: {:?}", phase));
|
||||||
|
|
||||||
for receiver in self.receivers.iter() {
|
for receiver in self.receivers.iter() {
|
||||||
receiver
|
receiver
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
|
|
Loading…
Reference in a new issue