use super::{Decoder, create_rgba_image, validate_dimensions};
use crate::error::{BinaryError, Result};
use crate::texture::formats::TextureFormat;
use crate::texture::types::Texture2D;
use image::RgbaImage;
pub struct CompressedDecoder;
impl CompressedDecoder {
pub fn new() -> Self {
Self
}
#[cfg(feature = "texture-advanced")]
fn decode_dxt1(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
validate_dimensions(width, height)?;
let mut output = vec![0u32; (width * height) as usize];
match texture2ddecoder::decode_bc1(data, width as usize, height as usize, &mut output) {
Ok(_) => {
let rgba_data: Vec<u8> = output
.iter()
.flat_map(|&pixel| {
[
(pixel & 0xFF) as u8, ((pixel >> 8) & 0xFF) as u8, ((pixel >> 16) & 0xFF) as u8, ((pixel >> 24) & 0xFF) as u8, ]
})
.collect();
create_rgba_image(rgba_data, width, height)
}
Err(e) => Err(BinaryError::generic(format!("DXT1 decoding failed: {}", e))),
}
}
#[cfg(feature = "texture-advanced")]
fn decode_dxt5(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
validate_dimensions(width, height)?;
let mut output = vec![0u32; (width * height) as usize];
match texture2ddecoder::decode_bc3(data, width as usize, height as usize, &mut output) {
Ok(_) => {
let rgba_data: Vec<u8> = output
.iter()
.flat_map(|&pixel| {
[
(pixel & 0xFF) as u8, ((pixel >> 8) & 0xFF) as u8, ((pixel >> 16) & 0xFF) as u8, ((pixel >> 24) & 0xFF) as u8, ]
})
.collect();
create_rgba_image(rgba_data, width, height)
}
Err(e) => Err(BinaryError::generic(format!("DXT5 decoding failed: {}", e))),
}
}
#[cfg(feature = "texture-advanced")]
fn decode_bc7(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
validate_dimensions(width, height)?;
let mut output = vec![0u32; (width * height) as usize];
match texture2ddecoder::decode_bc7(data, width as usize, height as usize, &mut output) {
Ok(_) => {
let rgba_data: Vec<u8> = output
.iter()
.flat_map(|&pixel| {
[
(pixel & 0xFF) as u8, ((pixel >> 8) & 0xFF) as u8, ((pixel >> 16) & 0xFF) as u8, ((pixel >> 24) & 0xFF) as u8, ]
})
.collect();
create_rgba_image(rgba_data, width, height)
}
Err(e) => Err(BinaryError::generic(format!("BC7 decoding failed: {}", e))),
}
}
#[cfg(feature = "texture-advanced")]
fn decode_bc4(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
validate_dimensions(width, height)?;
let mut output = vec![0u32; (width * height) as usize];
match texture2ddecoder::decode_bc4(data, width as usize, height as usize, &mut output) {
Ok(_) => {
let rgba_data: Vec<u8> = output
.iter()
.flat_map(|&pixel| {
let value = (pixel & 0xFF) as u8;
[value, value, value, 255] })
.collect();
create_rgba_image(rgba_data, width, height)
}
Err(e) => Err(BinaryError::generic(format!("BC4 decoding failed: {}", e))),
}
}
#[cfg(feature = "texture-advanced")]
fn decode_bc5(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
validate_dimensions(width, height)?;
let mut output = vec![0u32; (width * height) as usize];
match texture2ddecoder::decode_bc5(data, width as usize, height as usize, &mut output) {
Ok(_) => {
let rgba_data: Vec<u8> = output
.iter()
.flat_map(|&pixel| {
[
(pixel & 0xFF) as u8, ((pixel >> 8) & 0xFF) as u8, 0, 255, ]
})
.collect();
create_rgba_image(rgba_data, width, height)
}
Err(e) => Err(BinaryError::generic(format!("BC5 decoding failed: {}", e))),
}
}
#[cfg(not(feature = "texture-advanced"))]
fn decode_unsupported(&self, format: TextureFormat) -> Result<RgbaImage> {
Err(BinaryError::unsupported(format!(
"Compressed format {:?} requires texture-advanced feature",
format
)))
}
}
impl Decoder for CompressedDecoder {
fn decode(&self, texture: &Texture2D) -> Result<RgbaImage> {
let width = texture.width as u32;
let height = texture.height as u32;
let data = &texture.image_data;
match texture.format {
#[cfg(feature = "texture-advanced")]
TextureFormat::DXT1 => self.decode_dxt1(data, width, height),
#[cfg(feature = "texture-advanced")]
TextureFormat::DXT5 => self.decode_dxt5(data, width, height),
#[cfg(feature = "texture-advanced")]
TextureFormat::BC7 => self.decode_bc7(data, width, height),
#[cfg(feature = "texture-advanced")]
TextureFormat::BC4 => self.decode_bc4(data, width, height),
#[cfg(feature = "texture-advanced")]
TextureFormat::BC5 => self.decode_bc5(data, width, height),
#[cfg(not(feature = "texture-advanced"))]
format if format.is_compressed_format() => self.decode_unsupported(format),
_ => Err(BinaryError::unsupported(format!(
"Format {:?} is not a compressed format",
texture.format
))),
}
}
fn can_decode(&self, format: TextureFormat) -> bool {
#[cfg(feature = "texture-advanced")]
{
matches!(
format,
TextureFormat::DXT1
| TextureFormat::DXT5
| TextureFormat::BC4
| TextureFormat::BC5
| TextureFormat::BC7
)
}
#[cfg(not(feature = "texture-advanced"))]
{
false
}
}
fn supported_formats(&self) -> Vec<TextureFormat> {
#[cfg(feature = "texture-advanced")]
{
vec![
TextureFormat::DXT1,
TextureFormat::DXT5,
TextureFormat::BC4,
TextureFormat::BC5,
TextureFormat::BC7,
]
}
#[cfg(not(feature = "texture-advanced"))]
{
vec![]
}
}
}
impl Default for CompressedDecoder {
fn default() -> Self {
Self::new()
}
}