mod bcn;
mod uncompressed;
pub mod reference;
use crate::content::{slice_payload_bytes, DecodeContent, ImageRgba8};
use crate::error::Error;
use crate::surface::SubresourceId;
use crate::Dds;
impl Dds {
pub fn decode_rgba8(&self, id: SubresourceId) -> Result<ImageRgba8, Error> {
let surf = self.surface(id)?;
let kind = self.decode_content()?;
let pixels = decode_surface_pixels(kind, surf.data, surf.width, surf.height, surf.depth)?;
Ok(ImageRgba8 {
width: surf.width,
height: surf.height,
depth: surf.depth,
pixels,
})
}
}
pub(crate) fn decode_surface_pixels(
kind: DecodeContent,
data: &[u8],
width: u32,
height: u32,
depth: u32,
) -> Result<Vec<u8>, Error> {
if depth == 0 {
return Err(Error::InvalidField("zero depth".into()));
}
if depth == 1 {
return decode_slice(kind, data, width, height);
}
let slice_bytes = slice_payload_bytes(kind, width, height)?;
let need = slice_bytes
.checked_mul(depth as usize)
.ok_or(Error::OutOfBounds)?;
if data.len() < need {
return Err(Error::TruncatedData);
}
let mut out = Vec::with_capacity(
(width as usize)
.saturating_mul(height as usize)
.saturating_mul(depth as usize)
.saturating_mul(4),
);
for z in 0..depth as usize {
let start = z * slice_bytes;
out.extend(decode_slice(
kind,
&data[start..start + slice_bytes],
width,
height,
)?);
}
Ok(out)
}
fn decode_slice(
kind: DecodeContent,
data: &[u8],
width: u32,
height: u32,
) -> Result<Vec<u8>, Error> {
match kind {
DecodeContent::Bc1 => bcn::decode_bc1(data, width, height),
DecodeContent::Bc2 => bcn::decode_bc2(data, width, height),
DecodeContent::Bc3 => bcn::decode_bc3(data, width, height),
DecodeContent::Bc4UNorm => bcn::decode_bc4(data, width, height, false),
DecodeContent::Bc4SNorm => bcn::decode_bc4(data, width, height, true),
DecodeContent::Bc5UNorm => bcn::decode_bc5(data, width, height, false),
DecodeContent::Bc5SNorm => bcn::decode_bc5(data, width, height, true),
DecodeContent::Bc7 => bcn::decode_bc7(data, width, height),
DecodeContent::Rgba8 => uncompressed::decode_rgba8(data, width, height),
DecodeContent::Bgra8 => uncompressed::decode_bgra8(data, width, height),
}
}