use binrw::{binread, BinRead, BinReaderExt};
use pict::{
drawing_context::decode_pixmap,
shared::{self, ColorTable},
};
use resource_fork::Resource;
#[derive(BinRead, Debug)]
#[br(big)]
pub struct Pat([u8; Self::DATA_LEN]);
impl Pat {
pub const DATA_LEN: usize = Self::HEIGHT * Self::WIDTH / 8;
pub const HEIGHT: usize = 8;
pub const WIDTH: usize = 8;
pub fn at(&self, x: usize, y: usize) -> bool {
let bytes_per_row = self.width() / 8;
let chosen_byte = y * bytes_per_row + x / 8;
let bit = 7 - (x % 8);
(self.0[chosen_byte] & (1 << bit)) != 0
}
pub fn into_data(self) -> [u8; Self::DATA_LEN] {
self.0
}
pub const fn width(&self) -> usize {
Self::WIDTH
}
pub const fn height(&self) -> usize {
Self::HEIGHT
}
}
#[binread]
#[derive(Debug, Resource)]
#[resource(code = "PAT#")]
#[br(big)]
pub struct Pattern {
#[br(temp)]
count: u16,
#[br(count(count))]
pub patterns: Vec<Pat>,
}
#[derive(Debug, Resource)]
#[resource(code = "ppat")]
pub struct PixelPattern {
pub image: image::ImageBuffer<image::Rgba<u8>, Vec<u8>>,
}
impl BinRead for PixelPattern {
type Args<'a> = ();
fn read_options<R: std::io::Read + std::io::Seek>(
reader: &mut R,
_endian: binrw::Endian,
_args: Self::Args<'_>,
) -> binrw::BinResult<Self> {
let offset = reader.stream_position().unwrap();
let header: PixelPatternHeader = reader.read_be()?;
match header.pattern_type {
PatternType::Monochrome => {
todo!()
}
PatternType::Indexed => {
reader.seek(std::io::SeekFrom::Start(
offset + header.pixel_map_offset as u64 + 4,
))?;
let high_byte_and_row_flags: u8 = reader.read_be()?;
let pix_map = reader.read_be_args::<shared::PixMap>((high_byte_and_row_flags,))?;
reader.seek(std::io::SeekFrom::Start(offset + pix_map.pm_table as u64))?;
let color_table = reader.read_be();
let color_table: ColorTable = color_table?;
reader.seek(std::io::SeekFrom::Start(
offset + header.pixel_data_offset as u64,
))?;
let mut pixels =
vec![0u8; pix_map.bytes_per_row() as usize * pix_map.bounds.height() as usize];
reader.read_exact(&mut pixels)?;
let buffer = decode_pixmap(&pix_map, &color_table, &pixels);
Ok(Self { image: buffer })
}
PatternType::Rgb => todo!(),
}
}
}
#[derive(Debug, BinRead)]
#[br(big, repr=u16)]
pub enum PatternType {
Monochrome = 0,
Indexed = 1,
Rgb = 2,
}
#[derive(Debug, BinRead)]
#[br(big)]
pub struct PixelPatternHeader {
pub pattern_type: PatternType,
pub pixel_map_offset: u32,
pub pixel_data_offset: u32,
pub unused1: u32,
pub unused2: u16,
pub reserved: u32,
}