engine/asset/src/imageformatchecker.rs

171 lines
5.7 KiB
Rust
Raw Normal View History

2024-08-23 11:22:09 +00:00
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<Device>, queue: &Arc<Mutex<Queue>>) -> Result<Arc<Image>> {
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)
2025-02-28 14:13:19 +00:00
.max_mip_map_levels()
.attach_pretty_sampler(device)?;
2024-08-23 11:22:09 +00:00
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
2025-02-28 14:13:19 +00:00
)));
2024-08-23 11:22:09 +00:00
}
};
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<VkFormat> {
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<u8>,
source_format: VkFormat,
destination_format: VkFormat,
) -> Vec<u8> {
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!"),
}
}
}