Add support to create colored images
This commit is contained in:
parent
5248070a0f
commit
267c9aecad
5 changed files with 128 additions and 34 deletions
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
|
@ -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)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue