ui/src/guihandler/gui/displayable.rs

218 lines
6.8 KiB
Rust
Raw Normal View History

2023-01-16 09:53:52 +00:00
//! `Displayable` is a property to display a background texture
use crate::prelude::*;
use anyhow::Result;
use assetpath::AssetPath;
use cgmath::{vec2, vec4};
use super::texturedvertex::TexturedVertex;
use std::sync::{
atomic::{AtomicI32, Ordering::SeqCst},
{Arc, RwLock},
};
/// `Displayable` gives the ability to display a texture as background image for an item
pub struct Displayable {
framable: Arc<Framable>,
descriptor_set: RwLock<Arc<DescriptorSet>>,
buffer: Arc<Buffer<TexturedVertex>>,
ui_layer: AtomicI32,
left_factor: RwLock<f32>,
right_factor: RwLock<f32>,
bottom_factor: RwLock<f32>,
top_factor: RwLock<f32>,
left_uv_factor: RwLock<f32>,
right_uv_factor: RwLock<f32>,
bottom_uv_factor: RwLock<f32>,
top_uv_factor: RwLock<f32>,
}
impl Displayable {
/// Factory method for `Displayable`, returns `Arc<Displayable>`
///
/// # Arguments
///
/// * `framable` is a `Arc<Framable>` instance
/// * `name` is the name for a png
pub fn new(framable: Arc<Framable>, name: AssetPath) -> Result<Arc<Self>> {
let descriptor_set = framable.gui_handler().image_descriptor(name)?;
let buffer = Buffer::builder()
.set_usage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)
.set_memory_usage(MemoryUsage::CpuOnly)
.set_size(6)
.build(framable.gui_handler().device().clone())?;
let displayable = Arc::new(Displayable {
framable,
descriptor_set: RwLock::new(descriptor_set),
buffer,
ui_layer: AtomicI32::new(0),
left_factor: RwLock::new(0.0),
right_factor: RwLock::new(1.0),
bottom_factor: RwLock::new(1.0),
top_factor: RwLock::new(0.0),
left_uv_factor: RwLock::new(0.0),
right_uv_factor: RwLock::new(1.0),
bottom_uv_factor: RwLock::new(1.0),
top_uv_factor: RwLock::new(0.0),
});
let displayable_clone = displayable.clone();
let weak_displayable = Arc::downgrade(&displayable);
displayable.framable.add_callback(
weak_displayable,
Box::new(move || displayable_clone.update_frame()),
);
Ok(displayable)
}
/// Add method
///
/// # Arguments
///
/// * `displayable` is a `&Arc<Displayable>` instance that is going to be added
pub fn add(self: &Arc<Self>) -> Result<()> {
self.framable
.gui_handler()
.add_displayable(self.ui_layer.load(SeqCst), self.clone())
}
/// Delete method, has to be explicitly called, otherwise it will remain in memory
///
/// # Arguments
///
/// * `displayable` is a `&Arc<Displayable>` instance that is going to be deleted
pub fn delete(self: &Arc<Self>) -> Result<()> {
self.framable
.gui_handler()
.delete_displayable(self.ui_layer.load(SeqCst), self)
}
pub fn set_ui_layer(&self, ui_layer: i32) {
self.ui_layer.store(ui_layer, SeqCst);
}
pub fn clear_callback(self: &Arc<Self>) {
let weak_displayable = Arc::downgrade(self);
self.framable.remove_callback(weak_displayable);
}
/// Replaces the current background image
///
/// # Arguments
///
/// * `name` is the name of the texture in `gui/` without `.png` suffix
pub fn set_image(&self, name: AssetPath) -> Result<()> {
let descriptor_set = self.framable.gui_handler().image_descriptor(name)?;
*self.descriptor_set.write().unwrap() = descriptor_set;
Ok(())
}
/// Returns the internal vulkan buffer
pub fn buffer(&self) -> &Arc<Buffer<TexturedVertex>> {
&self.buffer
}
/// Returns the internal vulkan descriptor set
pub fn descriptor_set(&self) -> Arc<DescriptorSet> {
self.descriptor_set.read().unwrap().clone()
}
pub fn set_left_factor(&self, factor: f32) {
*self.left_factor.write().unwrap() = factor;
}
pub fn set_right_factor(&self, factor: f32) {
*self.right_factor.write().unwrap() = factor;
}
pub fn set_top_factor(&self, factor: f32) {
*self.top_factor.write().unwrap() = factor;
}
pub fn set_bottom_factor(&self, factor: f32) {
*self.bottom_factor.write().unwrap() = factor;
}
pub fn set_left_uv_factor(&self, factor: f32) {
*self.left_uv_factor.write().unwrap() = factor;
}
pub fn set_right_uv_factor(&self, factor: f32) {
*self.right_uv_factor.write().unwrap() = factor;
}
pub fn set_top_uv_factor(&self, factor: f32) {
*self.top_uv_factor.write().unwrap() = factor;
}
pub fn set_bottom_uv_factor(&self, factor: f32) {
*self.bottom_uv_factor.write().unwrap() = factor;
}
/// Update frame method if the original frame is invalidated
pub fn update_frame(&self) -> Result<()> {
let mut frame = self.buffer.map_complete()?;
let x_start = self.framable.left() as f32;
let y_start = self.framable.top() as f32;
let width = (self.framable.right() - self.framable.left()) as f32;
let height = (self.framable.bottom() - self.framable.top()) as f32;
let left = x_start + width * *self.left_factor.read().unwrap();
let right = x_start + width * *self.right_factor.read().unwrap();
let top = y_start + height * *self.top_factor.read().unwrap();
let bottom = y_start + height * *self.bottom_factor.read().unwrap();
frame[0].position = self.framable.ortho() * vec4(left, bottom, 0.0, 1.0);
frame[1].position = self.framable.ortho() * vec4(right, bottom, 0.0, 1.0);
frame[2].position = self.framable.ortho() * vec4(right, top, 0.0, 1.0);
frame[3].position = self.framable.ortho() * vec4(right, top, 0.0, 1.0);
frame[4].position = self.framable.ortho() * vec4(left, top, 0.0, 1.0);
frame[5].position = self.framable.ortho() * vec4(left, bottom, 0.0, 1.0);
frame[0].texture_coordinates = vec2(
*self.left_uv_factor.read().unwrap(),
*self.bottom_uv_factor.read().unwrap(),
);
frame[1].texture_coordinates = vec2(
*self.right_uv_factor.read().unwrap(),
*self.bottom_uv_factor.read().unwrap(),
);
frame[2].texture_coordinates = vec2(
*self.right_uv_factor.read().unwrap(),
*self.top_uv_factor.read().unwrap(),
);
frame[3].texture_coordinates = vec2(
*self.right_uv_factor.read().unwrap(),
*self.top_uv_factor.read().unwrap(),
);
frame[4].texture_coordinates = vec2(
*self.left_uv_factor.read().unwrap(),
*self.top_uv_factor.read().unwrap(),
);
frame[5].texture_coordinates = vec2(
*self.left_uv_factor.read().unwrap(),
*self.bottom_uv_factor.read().unwrap(),
);
Ok(())
}
}