Add support to create colored images

This commit is contained in:
hodasemi 2023-01-20 17:01:21 +01:00
parent 5248070a0f
commit 267c9aecad
5 changed files with 128 additions and 34 deletions

View file

@ -16,14 +16,15 @@ impl BackgroundGenerator {
pub fn generate<const N: usize>( pub fn generate<const N: usize>(
device: &Arc<Device>, device: &Arc<Device>,
queue: &Arc<Mutex<Queue>>, queue: &Arc<Mutex<Queue>>,
color: [f32; 4],
image_infos: [(u32, u32); N], image_infos: [(u32, u32); N],
) -> Result<[Arc<Image>; N]> { ) -> Result<[Arc<Image>; N]> {
Ok(image_infos Ok(image_infos
.iter() .iter()
.map(|(width, height)| { .map(|(width, height)| {
let image = Image::empty( let image = Image::empty(
*width as u32, *width,
*height as u32, *height,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_1_BIT,
) )
@ -36,7 +37,7 @@ impl BackgroundGenerator {
let render_target = RenderTarget::builder() let render_target = RenderTarget::builder()
.add_sub_pass( .add_sub_pass(
SubPass::builder(image.width(), image.height()) SubPass::builder(image.width(), image.height())
.set_prepared_targets(&[image.clone()], 0, [0.0, 0.0, 0.0, 1.0], true) .set_prepared_targets(&[image.clone()], 0, [0.0, 0.0, 0.0, 0.0], true)
.build(&device, &queue)?, .build(&device, &queue)?,
) )
.build(&device)?; .build(&device)?;
@ -69,6 +70,15 @@ impl BackgroundGenerator {
}, },
}; };
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 = Pipeline::new_graphics() let pipeline = Pipeline::new_graphics()
.set_vertex_shader( .set_vertex_shader(
vertex_shader.clone(), vertex_shader.clone(),
@ -97,11 +107,26 @@ impl BackgroundGenerator {
.add_scissor(scissor) .add_scissor(scissor)
.build( .build(
device.clone(), device.clone(),
&PipelineLayout::builder().build(device.clone())?, &PipelineLayout::builder()
.add_descriptor_set_layout(&descriptor_layout)
.build(device.clone())?,
render_target.render_pass(), render_target.render_pass(),
0, 0,
)?; )?;
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 desc_pool = DescriptorPool::builder()
.set_layout(descriptor_layout)
.build(device.clone())?;
let descriptor_set = desc_pool.prepare_set().allocate()?;
descriptor_set.update(&[DescriptorWrite::uniform_buffers(0, &[&color_buffer])])?;
let ortho = ortho( let ortho = ortho(
0.0, 0.0,
image.width() as f32, image.width() as f32,
@ -142,6 +167,7 @@ impl BackgroundGenerator {
recorder.bind_pipeline(&pipeline)?; recorder.bind_pipeline(&pipeline)?;
recorder.bind_descriptor_sets_minimal(&[&descriptor_set]);
recorder.bind_vertex_buffer(&vertex_buffer); recorder.bind_vertex_buffer(&vertex_buffer);
recorder.draw_complete_single_instance(vertex_buffer.size() as u32); recorder.draw_complete_single_instance(vertex_buffer.size() as u32);
@ -207,7 +233,9 @@ mod test {
fn generate_image_test() { fn generate_image_test() {
let (device, queue) = create_vk_handles().unwrap(); let (device, queue) = create_vk_handles().unwrap();
let images = BackgroundGenerator::generate(&device, &queue, [(120, 40)]).unwrap(); let images =
BackgroundGenerator::generate(&device, &queue, [1.0, 0.0, 0.0, 1.0], [(120, 40)])
.unwrap();
for (index, image) in images.iter().enumerate() { for (index, image) in images.iter().enumerate() {
image image

View file

@ -1,8 +1,12 @@
#version 450 #version 450
layout (set = 0, binding = 0) uniform Color {
vec4 val;
} color;
layout (location = 0) out vec4 out_color; layout (location = 0) out vec4 out_color;
void main() void main()
{ {
out_color = vec4(1.0, 1.0, 1.0, 1.0); out_color = color.val;
} }

View file

@ -3,7 +3,7 @@ use std::sync::Arc;
use anyhow::Result; use anyhow::Result;
use ui::prelude::*; use ui::prelude::*;
use utilities::prelude::Color; use vulkan_rs::prelude::*;
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub enum BehindLeader { pub enum BehindLeader {
@ -22,9 +22,9 @@ pub struct LeaderBoardEntry {
snippet: Arc<GuiSnippet>, snippet: Arc<GuiSnippet>,
name_label: Arc<Label>, name_label: Arc<Icon>,
place_label: Arc<Label>, place_label: Arc<Icon>,
time_label: Arc<Label>, time_label: Arc<Icon>,
place_updated: bool, place_updated: bool,
} }
@ -32,6 +32,10 @@ pub struct LeaderBoardEntry {
impl LeaderBoardEntry { impl LeaderBoardEntry {
const ENTRY: &str = include_str!("leaderboard_entry.xml"); const ENTRY: &str = include_str!("leaderboard_entry.xml");
pub fn create_snippet(gui_handler: &Arc<GuiHandler>) -> Result<Arc<GuiSnippet>> {
GuiSnippet::from_str(gui_handler, Self::ENTRY)
}
pub fn empty(gui_handler: &Arc<GuiHandler>) -> Result<Self> { pub fn empty(gui_handler: &Arc<GuiHandler>) -> Result<Self> {
Self::new( Self::new(
gui_handler, gui_handler,
@ -53,11 +57,11 @@ impl LeaderBoardEntry {
time_behind_next: f64, time_behind_next: f64,
best_lap: f64, best_lap: f64,
) -> Result<Self> { ) -> Result<Self> {
let snippet = GuiSnippet::from_str(gui_handler, Self::ENTRY)?; let snippet = Self::create_snippet(gui_handler)?;
let name_label: Arc<Label> = snippet.element("name")?; let name_label: Arc<Icon> = snippet.element("name")?;
let place_label: Arc<Label> = snippet.element("place")?; let place_label: Arc<Icon> = snippet.element("place")?;
let time_label: Arc<Label> = snippet.element("time")?; let time_label: Arc<Icon> = snippet.element("time")?;
name_label.set_text(&name)?; name_label.set_text(&name)?;
place_label.set_text(place)?; place_label.set_text(place)?;
@ -108,10 +112,13 @@ impl LeaderBoardEntry {
self.snippet.clone() self.snippet.clone()
} }
pub fn change_background_color(&self, color: Color) -> Result<()> { pub fn change_background_color(
self.time_label.set_background(color)?; &self,
self.name_label.set_background(color)?; (place_image, name_image, time_image): &(Arc<Image>, Arc<Image>, Arc<Image>),
self.place_label.set_background(color)?; ) -> Result<()> {
self.time_label.set_icon(&time_image)?;
self.name_label.set_icon(&name_image)?;
self.place_label.set_icon(&place_image)?;
Ok(()) Ok(())
} }

View file

@ -1,12 +1,10 @@
<?xml-model href="../gui.xsd" type="application/xml" schematypes="http://www.w3.org/2001/XMLSchema"?> <?xml-model href="../gui.xsd" type="application/xml" schematypes="http://www.w3.org/2001/XMLSchema"?>
<root> <root>
<grid x_dim="11" y_dim="1" padding="2" margin="2"> <grid x_dim="11" y_dim="1" padding="2" margin="2">
<label id="place" x_slot="0" y_slot="0" text_color="black" text_alignment="right"></label> <icon id="place" x_slot="0" y_slot="0" text_color="black"></icon>
<label <icon id="name" x_slot="1"
id="name" y_slot="0" x_size="7" text_color="black"></icon>
x_slot="1" y_slot="0" x_size="7" text_color="black"></label> <icon id="time" x_slot="8" y_slot="0"
<label x_size="3" text_color="black"></icon>
id="time"
x_slot="8" y_slot="0" x_size="3" text_color="black" text_alignment="right"></label>
</grid> </grid>
</root> </root>

View file

@ -12,6 +12,7 @@ use anyhow::Result;
use rfactor_sm_reader::{rF2VehicleTelemetry, VehicleScoringInfoV01}; use rfactor_sm_reader::{rF2VehicleTelemetry, VehicleScoringInfoV01};
use ui::prelude::*; use ui::prelude::*;
use utilities::prelude::Color; use utilities::prelude::Color;
use vulkan_rs::prelude::*;
use crate::overlay::{ use crate::overlay::{
rfactor_data::{DataReceiver, GamePhase}, rfactor_data::{DataReceiver, GamePhase},
@ -19,6 +20,8 @@ use crate::overlay::{
}; };
use crate::write_log; use crate::write_log;
use self::bg_generator::BackgroundGenerator;
pub struct LeaderBoard { pub struct LeaderBoard {
gui_handler: Arc<GuiHandler>, gui_handler: Arc<GuiHandler>,
leaderboard: Arc<GuiBuilder>, leaderboard: Arc<GuiBuilder>,
@ -33,8 +36,8 @@ pub struct LeaderBoard {
leaderboard_redraw: bool, leaderboard_redraw: bool,
last_player_id: i32, last_player_id: i32,
entry_backgrounds: [Color; 2], entry_backgrounds: [(Arc<Image>, Arc<Image>, Arc<Image>); 2],
player_background: Color, player_background: (Arc<Image>, Arc<Image>, Arc<Image>),
} }
impl LeaderBoard { impl LeaderBoard {
@ -45,13 +48,63 @@ impl LeaderBoard {
let leaderboard = GuiBuilder::from_str(gui_handler, Self::LEADERBOARD)?; let leaderboard = GuiBuilder::from_str(gui_handler, Self::LEADERBOARD)?;
let deltaboard = GuiBuilder::from_str(gui_handler, Self::DELTABOARD)?; let deltaboard = GuiBuilder::from_str(gui_handler, Self::DELTABOARD)?;
let leaderboard_grid = leaderboard.element("main_grid")?; let leaderboard_grid: Arc<Grid> = leaderboard.element("main_grid")?;
let deltaboard_grid = deltaboard.element("main_grid")?; let deltaboard_grid = deltaboard.element("main_grid")?;
let images = {
// attach snippet to leader board to let it resize its child element correctly
// then use these sizes to create actual UI element background
let dummy_snippet = LeaderBoardEntry::create_snippet(gui_handler)?;
let place: Arc<Icon> = dummy_snippet.element("place")?;
let name: Arc<Icon> = dummy_snippet.element("name")?;
let time: Arc<Icon> = dummy_snippet.element("time")?;
leaderboard_grid.attach(dummy_snippet, 0, 0, 1, 1)?;
let colors = [
{
let a: [f32; 3] = Color::try_from("#545454")?.into();
[a[0], a[1], a[2], 1.0]
},
{
let a: [f32; 3] = Color::try_from("#838383")?.into();
[a[0], a[1], a[2], 1.0]
},
{
let a: [f32; 3] = Color::try_from("#b4bf26")?.into();
[a[0], a[1], a[2], 1.0]
},
];
let images = colors
.iter()
.map(|color| {
let images = BackgroundGenerator::generate(
gui_handler.device(),
gui_handler.queue(),
*color,
[
Self::extent_i_to_u(place.extent()),
Self::extent_i_to_u(name.extent()),
Self::extent_i_to_u(time.extent()),
],
)?;
Ok((images[0].clone(), images[1].clone(), images[2].clone()))
})
.collect::<Result<Vec<(Arc<Image>, Arc<Image>, Arc<Image>)>>>()?;
leaderboard_grid.detach(0, 0)?;
images
};
Ok(Self { Ok(Self {
gui_handler: gui_handler.clone(), gui_handler: gui_handler.clone(),
leaderboard, leaderboard,
deltaboard, deltaboard,
leaderboard_grid, leaderboard_grid,
deltaboard_grid, deltaboard_grid,
@ -67,11 +120,15 @@ impl LeaderBoard {
leaderboard_redraw: false, leaderboard_redraw: false,
last_player_id: -1, last_player_id: -1,
entry_backgrounds: [Color::try_from("#838383")?, Color::try_from("#545454")?], entry_backgrounds: [images[0].clone(), images[1].clone()],
player_background: Color::try_from("#b4bf26")?, player_background: images[2].clone(),
}) })
} }
fn extent_i_to_u((x, y): (i32, i32)) -> (u32, u32) {
(x as u32, y as u32)
}
fn c_char_to_string(c: [c_char; 32usize]) -> String { fn c_char_to_string(c: [c_char; 32usize]) -> String {
unsafe { CStr::from_ptr(&c as *const c_char) } unsafe { CStr::from_ptr(&c as *const c_char) }
.to_str() .to_str()
@ -184,7 +241,7 @@ impl LeaderBoard {
// don't break here, just skip adding to grid // don't break here, just skip adding to grid
// because resorting_finished should be called for every entry // because resorting_finished should be called for every entry
if i < self.leaderboard_grid.dimensions().1 { if i < self.leaderboard_grid.dimensions().1 {
entry.change_background_color(self.entry_backgrounds[i % 2])?; entry.change_background_color(&self.entry_backgrounds[i % 2])?;
self.leaderboard_grid.attach(entry.snippet(), 0, i, 1, 1)?; self.leaderboard_grid.attach(entry.snippet(), 0, i, 1, 1)?;
} }
@ -249,9 +306,9 @@ impl LeaderBoard {
entry.update_place(leaderboard_entry.place())?; entry.update_place(leaderboard_entry.place())?;
if entry.id() == self.last_player_id { if entry.id() == self.last_player_id {
entry.change_background_color(self.player_background)?; entry.change_background_color(&self.player_background)?;
} else { } else {
entry.change_background_color(self.entry_backgrounds[i % 2])?; entry.change_background_color(&self.entry_backgrounds[i % 2])?;
} }
if entry.name() != leaderboard_entry.name() { if entry.name() != leaderboard_entry.name() {
@ -388,7 +445,7 @@ impl DataReceiver for LeaderBoard {
"Update player entry background color: {:?}", "Update player entry background color: {:?}",
self.player_background self.player_background
)); ));
entry.change_background_color(self.player_background)?; entry.change_background_color(&self.player_background)?;
} }
} }
} }