use anyhow::Result; use gltf_loader::prelude::*; use vulkan_rs::prelude::*; use std::sync::{Arc, Mutex}; pub struct ImageFormatChecker { image_data: GltfImageData, } impl ImageFormatChecker { pub fn new(image_data: GltfImageData) -> ImageFormatChecker { ImageFormatChecker { image_data } } pub fn build(self, device: &Arc, queue: &Arc>) -> Result> { let initial_format = Self::convert_format(self.image_data.format); let mut image_builder = Image::from_raw( self.image_data.pixels.clone(), self.image_data.width, self.image_data.height, ) .format(initial_format) .attach_sampler(Sampler::pretty_sampler().build(device)?); let mut format = initial_format; loop { if image_builder.check_configuration(device) { break; } else { format = match Self::backup_format(format) { Some(format) => format, None => { return Err(anyhow::Error::msg(format!( "Image format {:?} for asset does not work", format ))) } }; image_builder = image_builder.format(format); } } if initial_format != format { image_builder = image_builder.update_data(Self::convert_data( self.image_data.pixels, initial_format, format, )); } image_builder.build(device, queue) } fn convert_format(gltf_format: GltfImageFormat) -> VkFormat { match gltf_format { GltfImageFormat::R8 => VK_FORMAT_R8_UNORM, GltfImageFormat::R8G8 => VK_FORMAT_R8G8_UNORM, GltfImageFormat::R8G8B8 => VK_FORMAT_R8G8B8_UNORM, GltfImageFormat::R8G8B8A8 => VK_FORMAT_R8G8B8A8_UNORM, GltfImageFormat::R16 => VK_FORMAT_R16_UNORM, GltfImageFormat::R16G16 => VK_FORMAT_R16G16_UNORM, GltfImageFormat::R16G16B16 => VK_FORMAT_R16G16B16_UNORM, GltfImageFormat::R16G16B16A16 => VK_FORMAT_R16G16B16A16_UNORM, GltfImageFormat::R32G32B32FLOAT => VK_FORMAT_R32G32B32_SFLOAT, GltfImageFormat::R32G32B32A32FLOAT => VK_FORMAT_R32G32B32A32_SFLOAT, } } fn backup_format(format: VkFormat) -> Option { match format { VK_FORMAT_R8_UNORM => Some(VK_FORMAT_R8G8_UNORM), VK_FORMAT_R8G8_UNORM => Some(VK_FORMAT_R8G8B8_UNORM), VK_FORMAT_R8G8B8_UNORM => Some(VK_FORMAT_R8G8B8A8_UNORM), VK_FORMAT_R8G8B8A8_UNORM => None, VK_FORMAT_B8G8R8_UNORM => Some(VK_FORMAT_B8G8R8A8_UNORM), VK_FORMAT_B8G8R8A8_UNORM => None, _ => None, } } fn convert_data( data: Vec, source_format: VkFormat, destination_format: VkFormat, ) -> Vec { let source_step_size = Self::format_size(source_format); let destination_step_size = Self::format_size(destination_format); let final_size = (data.len() / source_step_size) * destination_step_size; let mut dst_buffer = Vec::with_capacity(final_size); if source_step_size == 1 { if destination_step_size == 2 { for d in data { dst_buffer.push(d); dst_buffer.push(0); } } else if destination_step_size == 3 { for d in data { dst_buffer.push(d); dst_buffer.push(0); dst_buffer.push(0); } } else if destination_step_size == 4 { for d in data { dst_buffer.push(d); dst_buffer.push(0); dst_buffer.push(0); dst_buffer.push(255); } } else { panic!("not possible !?"); } } else if source_step_size == 2 { if destination_step_size == 3 { for i in (0..data.len()).step_by(source_step_size) { dst_buffer.push(data[i]); dst_buffer.push(data[i + 1]); dst_buffer.push(0); } } else if destination_step_size == 4 { for i in (0..data.len()).step_by(source_step_size) { dst_buffer.push(data[i]); dst_buffer.push(data[i + 1]); dst_buffer.push(0); dst_buffer.push(255); } } else { panic!("not possible !?"); } } else if source_step_size == 3 { if destination_step_size == 4 { for i in (0..data.len()).step_by(source_step_size) { dst_buffer.push(data[i]); dst_buffer.push(data[i + 1]); dst_buffer.push(data[i + 2]); dst_buffer.push(255); } } else { panic!("not possible !?"); } } else { panic!("not possible !?"); }; if dst_buffer.len() != final_size { panic!("something went wrong"); } dst_buffer } fn format_size(format: VkFormat) -> usize { match format { VK_FORMAT_R8_UNORM => 1, VK_FORMAT_R8G8_UNORM => 2, VK_FORMAT_R8G8B8_UNORM => 3, VK_FORMAT_R8G8B8A8_UNORM => 4, VK_FORMAT_B8G8R8_UNORM => 3, VK_FORMAT_B8G8R8A8_UNORM => 4, _ => panic!("actually should never panic!"), } } }