use crate::header::*;
use byteorder::{BigEndian, ByteOrder, LittleEndian};
use core::{fmt, ops::Deref};
#[derive(Clone, Copy)]
pub struct Ktx<D> {
header: KtxHeader,
ktx_data: D,
texture_start: u32,
}
impl<D> AsRef<KtxHeader> for Ktx<D> {
#[inline]
fn as_ref(&self) -> &KtxHeader {
&self.header
}
}
impl<D> fmt::Debug for Ktx<D> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Ktx")
.field("header", &self.header)
.finish()
}
}
impl<D> Ktx<D>
where
D: Deref<Target = [u8]>,
{
#[inline]
pub fn new(ktx_data: D) -> Self {
let header = KtxHeader::new(&ktx_data);
let texture_start = 64 + header.bytes_of_key_value_data();
Self {
header,
ktx_data,
texture_start,
}
}
#[inline]
pub fn texture_level(&self, level: u32) -> &[u8] {
self.textures().nth(level as _).expect("invalid level")
}
#[inline]
pub fn textures(&self) -> Textures<'_, D> {
Textures {
parent: self,
next_level: 0,
level_end: self.texture_start as _,
}
}
}
impl<D> From<D> for Ktx<D>
where
D: Deref<Target = [u8]>,
{
#[inline]
fn from(d: D) -> Self {
Ktx::new(d)
}
}
#[derive(Debug)]
pub struct Textures<'a, D> {
parent: &'a Ktx<D>,
next_level: u32,
level_end: usize,
}
impl<'a, D> Iterator for Textures<'a, D>
where
D: Deref<Target = [u8]>,
{
type Item = &'a [u8];
fn next(&mut self) -> Option<Self::Item> {
if self.next_level >= self.parent.mipmap_levels() {
None
} else {
self.next_level += 1;
let l_end = self.level_end;
let mut next_lvl_len = if self.parent.big_endian() {
BigEndian::read_u32(&self.parent.ktx_data[l_end..l_end + 4])
} else {
LittleEndian::read_u32(&self.parent.ktx_data[l_end..l_end + 4])
};
if self.parent.array_elements() == 0 && self.parent.faces() == 6 {
next_lvl_len *= 6;
}
self.level_end = l_end + 4 + next_lvl_len as usize;
Some(&self.parent.ktx_data[l_end + 4..self.level_end])
}
}
}
impl<D> core::iter::FusedIterator for Textures<'_, D> where D: Deref<Target = [u8]> {}
#[macro_export]
macro_rules! include_ktx {
($path:tt) => {
$crate::Ktx::new(include_bytes!($path) as &[u8])
};
}