//! `Displayable` is a property to display a background texture use crate::prelude::*; use anyhow::Result; use assetpath::AssetPath; use utilities::prelude::*; use vulkan_rs::prelude::*; use cgmath::{vec2, vec4}; use super::texturedvertex::TexturedVertex; use std::sync::{ atomic::{AtomicI32, Ordering::SeqCst}, {Arc, RwLock}, }; #[derive(Debug, Clone)] pub enum DisplayableType { Path(AssetPath), Descriptor(ElementDescriptor), } impl From for DisplayableType { fn from(value: AssetPath) -> Self { Self::Path(value) } } impl From for DisplayableType { fn from(value: ElementDescriptor) -> Self { Self::Descriptor(value) } } /// `Displayable` gives the ability to display a texture as background image for an item pub struct Displayable { framable: Arc, descriptor_set: Arc, buffer: Arc>, displayable_type: RwLock, ui_layer: AtomicI32, left_factor: RwLock, right_factor: RwLock, bottom_factor: RwLock, top_factor: RwLock, left_uv_factor: RwLock, right_uv_factor: RwLock, bottom_uv_factor: RwLock, top_uv_factor: RwLock, } impl Displayable { /// Factory method for `Displayable`, returns `Arc` /// /// # Arguments /// /// * `framable` is a `Arc` instance /// * `name` is the name for a png pub fn new( framable: Arc, displayable_type: impl Into, ) -> Result> { let descriptor_set = framable.gui_handler().image_descriptor_set()?; let displayable_type = displayable_type.into(); if let DisplayableType::Path(path) = &displayable_type { let texture = framable .gui_handler() .displayable_image_from_path(path.clone())?; descriptor_set.update(&[DescriptorWrite::combined_samplers(0, &[&texture])])?; } 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, buffer, displayable_type: RwLock::new(displayable_type), 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` instance that is going to be added pub fn add(self: &Arc) -> 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` instance that is going to be deleted pub fn delete(self: &Arc) -> Result<()> { self.framable .gui_handler() .delete_displayable(self.ui_layer.load(SeqCst), self) } pub fn inner_type(&self) -> DisplayableType { self.displayable_type.read().unwrap().clone() } pub fn set_ui_layer(&self, ui_layer: i32) { self.ui_layer.store(ui_layer, SeqCst); } pub fn clear_callback(self: &Arc) { 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, displayable_type: impl Into) -> Result<()> { let displayable_type = displayable_type.into(); let texture = match displayable_type.clone() { DisplayableType::Path(path) => Some( self.framable .gui_handler() .displayable_image_from_path(path)?, ), DisplayableType::Descriptor(descriptor) => { let width = (self.framable.right() - self.framable.left()) as u32; let height = (self.framable.bottom() - self.framable.top()) as u32; if width > 0 && height > 0 { Some( self.framable .gui_handler() .displayable_image_from_descriptor(width, height, descriptor)?, ) } else { None } } }; if let Some(texture) = texture { self.descriptor_set .update(&[DescriptorWrite::combined_samplers(0, &[&texture])])?; } *self.displayable_type.write().unwrap() = displayable_type; Ok(()) } /// Returns the internal vulkan buffer pub fn buffer(&self) -> &Arc> { &self.buffer } /// Returns the internal vulkan descriptor set pub fn descriptor_set(&self) -> Arc { self.descriptor_set.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; if let DisplayableType::Descriptor(descriptor) = &*self.displayable_type.read().unwrap() { if width > 0.0 && height > 0.0 { let texture = self .framable .gui_handler() .displayable_image_from_descriptor( width as u32, height as u32, descriptor.clone(), )?; self.descriptor_set .update(&[DescriptorWrite::combined_samplers(0, &[&texture])])?; } } 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(()) } }