static EGA_PALETTE: [[u8; 4]; 16] = [[0x00, 0x00, 0x00, 0x00], [0x00, 0x00, 0xAA, 0x00], [0x00, 0xAA, 0x00, 0x00], [0x00, 0xAA, 0xAA, 0x00], [0xAA, 0x00, 0x00, 0x00], [0xAA, 0x00, 0xAA, 0x00], [0xAA, 0x55, 0x00, 0x00], [0xAA, 0xAA, 0xAA, 0x00], [0x55, 0x55, 0x55, 0x00], [0x55, 0x55, 0xFF, 0x00], [0x55, 0xFF, 0x55, 0x00], [0x55, 0xFF, 0xFF, 0x00], [0xFF, 0x55, 0x55, 0x00], [0xFF, 0x55, 0xFF, 0x00], [0xFF, 0xFF, 0x55, 0x00], [0xFF, 0xFF, 0xFF, 0x00]]; pub enum Compression { UNCOMPRESSED, RLE, LZW } pub enum Tiling { UNTILED, TILED(u16) } pub struct EgaPage { pub data: Vec, pub dim: usize, } impl EgaPage { pub fn iter<'a>(&'a self) -> impl Iterator { self.data.chunks(4 * self.dim * self.dim) } pub fn mipmap(&self, scale_levels: u8) -> Mipmap { let scale = 1 << scale_levels; let scaled: Vec> = self.iter().map(|tile| { let mut tilevec = Vec::new(); for row in tile.chunks(4 * self.dim) { for _ in 0..scale { for px in row.chunks(4) { for subpx in px.iter().cycle().take(4 * scale) { tilevec.push(*subpx); } } } } tilevec }).collect(); // dummy buffers just to provide proper sizing on texture for mips let dim = self.dim << scale_levels; let mut dummies = Vec::new(); let mut level = 1; loop { let mipdim = dim >> level; if mipdim == 0 { break; } dummies.push(vec![0; 4 * mipdim * mipdim]); level += 1; } Mipmap { len: self.data.len() / (4 * self.dim * self.dim), dim: dim, backing: scaled, dummies: dummies, } } } pub struct Mipmap { pub len: usize, pub dim: usize, backing: Vec>, dummies: Vec>, } impl Mipmap { pub fn slices(&self) -> Vec<&[u8]> { let mut slices: Vec<&[u8]> = Vec::with_capacity((1 + self.dummies.len()) * self.len); for tile in self.backing.iter() { slices.push(tile); for dummy in self.dummies.iter() { slices.push(&dummy); } } slices } } pub fn decode<'a>(buf: &[u8], compression: Compression, tiling: Tiling) -> EgaPage { let out: Vec; out = match compression { Compression::UNCOMPRESSED => buf.iter() .flat_map(|tile_byte| { EGA_PALETTE[(tile_byte >> 4u8 & 0xF) as usize] .into_iter() .chain(EGA_PALETTE[(tile_byte & 0xF) as usize] .into_iter()) }) .map(|x| *x) .collect(), _ => unimplemented!() }; let dim = match tiling { Tiling::TILED(tiledim) => tiledim as usize, Tiling::UNTILED => out.len() }; EgaPage { data: out, dim: dim} }