170 lines
5.7 KiB
Rust
170 lines
5.7 KiB
Rust
|
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)
|
||
|
.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<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!"),
|
||
|
}
|
||
|
}
|
||
|
}
|