use super::Labelifier;
use crate::data::Data;
use crate::window::Window;
use crate::{error::textures::*, utils::u16tou8vec};
use image::{load_from_memory_with_format, DynamicImage, ImageFormat};
use parking_lot::Mutex;
use std::sync::Arc;
use vulkano::buffer::BufferContents;
use vulkano::descriptor_set::persistent::PersistentDescriptorSet;
use vulkano::descriptor_set::WriteDescriptorSet;
use vulkano::pipeline::cache::PipelineCache;
mod loader;
pub mod vulkan;
pub(crate) use loader::Loader;
use vulkan::Vulkan;
pub mod textures;
use textures::*;
pub mod data;
pub mod materials;
pub mod model;
pub use model::Model;
mod macros;
pub use macros::*;
const NOT_INITIALIZED_MSG: &str = "Resources are not initialized to a game.";
#[derive(Clone)]
pub struct Resources {
pub(crate) vulkan: Option<Vulkan>,
pub(crate) loader: Option<Arc<Mutex<Loader>>>,
pub(crate) labelifier: Option<Arc<Mutex<Labelifier>>>,
}
impl Resources {
pub fn new() -> Self {
Self {
vulkan: None,
loader: None,
labelifier: None,
}
}
pub(crate) fn init(&mut self, vulkan: Vulkan) {
let mut loader = Loader::init(&vulkan);
let labelifier = Some(Arc::new(Mutex::new(Labelifier::new(&vulkan, &mut loader))));
*self = Self {
vulkan: Some(vulkan),
loader: Some(Arc::new(Mutex::new(loader))),
labelifier,
}
}
pub(crate) fn vulkan(&self) -> &Vulkan {
self.vulkan.as_ref().expect(NOT_INITIALIZED_MSG)
}
pub(crate) fn loader(&self) -> &Arc<Mutex<Loader>> {
self.loader.as_ref().expect(NOT_INITIALIZED_MSG)
}
pub(crate) fn labelifier(&self) -> &Arc<Mutex<Labelifier>> {
self.labelifier.as_ref().expect(NOT_INITIALIZED_MSG)
}
pub(crate) fn update(&self) {
let mut loader = self.loader.as_ref().unwrap().lock();
let mut labelifier = self.labelifier.as_ref().unwrap().lock();
labelifier.update(self.vulkan(), &mut loader);
}
pub unsafe fn load_pipeline_cache(&self, data: &[u8]) {
let cache = PipelineCache::with_data(self.vulkan().device.clone(), data).unwrap();
self.loader()
.lock()
.pipeline_cache
.merge([&cache].iter())
.unwrap();
}
pub fn get_pipeline_binary(&self) -> Vec<u8> {
self.loader().lock().pipeline_cache.get_data().unwrap()
}
pub fn load_model(&self, data: Data) -> Model {
let mut loader = self.loader().lock();
Model::new(data, &mut loader)
}
pub fn load_font(&self, data: &[u8]) -> Font {
let mut labelifier = self.labelifier().lock();
labelifier.load_font(data)
}
pub fn load_texture_from_raw(
&self,
data: &[u8],
dimensions: (u32, u32),
format: Format,
layers: u32,
settings: TextureSettings,
) -> Texture {
let loader = self.loader().lock();
Texture {
data: Arc::from(data.to_vec().into_boxed_slice()),
dimensions,
layers,
set: loader.load_texture(self.vulkan(), data, dimensions, layers, format, settings),
}
}
pub fn load_texture(
&self,
data: &[u8],
image_format: ImageFormat,
layers: u32,
settings: TextureSettings,
) -> Result<Texture, InvalidFormatError> {
let image = match load_from_memory_with_format(data, image_format) {
Err(_) => return Err(InvalidFormatError),
Ok(v) => v,
};
let mut dimensions: (u32, u32);
let mut format = Format::RGBA8;
let image: Vec<u8> = match image {
DynamicImage::ImageLuma8(image) => {
format = Format::R8;
dimensions = image.dimensions();
image.into_vec()
}
DynamicImage::ImageLumaA8(_) => {
let image = image.to_rgba8();
dimensions = image.dimensions();
image.into_vec()
}
DynamicImage::ImageLuma16(_) => {
let image = image.to_luma8();
dimensions = image.dimensions();
format = Format::R8;
image.into_vec()
}
DynamicImage::ImageLumaA16(_) => {
let image = image.to_rgba16();
dimensions = image.dimensions();
format = Format::RGBA16;
u16tou8vec(image.into_vec())
}
DynamicImage::ImageRgb8(_) => {
let image = image.to_rgba8();
dimensions = image.dimensions();
image.into_vec()
}
DynamicImage::ImageRgba8(image) => {
dimensions = image.dimensions();
image.into_vec()
}
DynamicImage::ImageRgb16(_) => {
let image = image.to_rgba16();
dimensions = image.dimensions();
format = Format::RGBA16;
u16tou8vec(image.into_vec())
}
DynamicImage::ImageRgba16(image) => {
format = Format::RGBA16;
dimensions = image.dimensions();
u16tou8vec(image.into_vec())
}
DynamicImage::ImageRgb32F(_) => {
let image = image.to_rgba16();
dimensions = image.dimensions();
format = Format::RGBA16;
u16tou8vec(image.into_vec())
}
DynamicImage::ImageRgba32F(_) => {
let image = image.to_rgba16();
dimensions = image.dimensions();
format = Format::RGBA16;
u16tou8vec(image.into_vec())
}
_ => {
let image = image.to_rgba8();
dimensions = image.dimensions();
image.into_vec()
}
};
dimensions.1 /= layers;
Ok(Self::load_texture_from_raw(
self, &image, dimensions, format, layers, settings,
))
}
pub unsafe fn new_shader_from_raw(
&self,
vertex_data: &[u8],
fragment_data: &[u8],
) -> materials::Shaders {
unsafe { materials::Shaders::from_bytes(vertex_data, fragment_data, self.vulkan()) }
}
pub fn new_descriptor_write<T: BufferContents>(&self, buf: T, set: u32) -> WriteDescriptorSet {
let loader = self.loader().lock();
loader.write_descriptor(buf, set)
}
pub fn new_material_with_shaders(
&self,
settings: materials::MaterialSettings,
shaders: &materials::Shaders,
descriptor_bindings: Vec<WriteDescriptorSet>,
) -> materials::Material {
let loader = self.loader().lock();
loader.load_material(self.vulkan(), shaders, settings, descriptor_bindings)
}
pub fn new_material(&self, settings: materials::MaterialSettings) -> materials::Material {
let loader = self.loader().lock();
let shaders = self.vulkan().default_shaders.clone();
loader.load_material(self.vulkan(), &shaders, settings, vec![])
}
pub fn new_material_from_texture(
&self,
texture: &[u8],
format: ImageFormat,
layers: u32,
settings: TextureSettings,
) -> Result<materials::Material, InvalidFormatError> {
let texture = Self::load_texture(self, texture, format, layers, settings)?;
Ok(Self::default_textured_material(self, &texture))
}
pub fn new_material_from_raw_texture(
&self,
texture: &[u8],
format: Format,
dimensions: (u32, u32),
layers: u32,
settings: TextureSettings,
) -> materials::Material {
let texture =
Self::load_texture_from_raw(self, texture, dimensions, format, layers, settings);
Self::default_textured_material(self, &texture)
}
pub fn default_textured_material(&self, texture: &Texture) -> materials::Material {
let default = if texture.layers == 1 {
self.vulkan().textured_material.clone()
} else {
self.vulkan().texture_array_material.clone()
};
materials::Material {
texture: Some(texture.clone()),
..default
}
}
pub fn get_window(&self) -> Window {
self.vulkan().window.clone()
}
}
impl Default for Resources {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone)]
pub struct Texture {
pub data: Arc<[u8]>,
pub dimensions: (u32, u32),
pub layers: u32,
pub set: Arc<PersistentDescriptorSet>,
}
#[derive(Clone)]
pub struct Font {
pub font: Arc<rusttype::Font<'static>>,
pub fontid: usize,
}
pub struct Sound {
pub data: Arc<[u8]>,
}
#[allow(dead_code)]
pub fn load_sound(sound: &[u8]) -> Sound {
Sound {
data: Arc::from(sound.to_vec().into_boxed_slice()),
}
}
impl PartialEq for Texture {
fn eq(&self, other: &Self) -> bool {
self.data == other.data
&& self.dimensions == other.dimensions
&& Arc::ptr_eq(&self.set, &other.set)
}
}
impl std::fmt::Debug for Texture {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Texture")
.field("size", &self.data.len())
.field("dimensions", &self.dimensions)
.field("frames", &self.layers)
.finish()
}
}