//! Marathon Shapes format handling. use crate::{durandal::{bin::*, err::*, fixed::*, image::*, text::*}, marathon::xfer::TransferMode}; use bitflags::bitflags; use serde::Serialize; fn color(b: &[u8], clut: &mut [ColorShp]) -> ResultS<()> { read_data! { 8, BE in b => l = u8[0]; i = u8[1]; r = u16[2]; g = u16[4]; b = u16[6]; } let l = match l { 128 => Ok(true), 0 => Ok(false), _ => Err(err_msg("invalid flag in color")), }?; let cr = ColorShp::Opaque{r, g, b, l}; clut[i as usize] = cr; Ok(()) } fn color_tables(b: &[u8], tab_ofs: usize, tab_num: usize, clr_num: usize) -> ResultS>> { let end = tab_num * clr_num * 8; let b = &b[tab_ofs..tab_ofs + end]; let mut v = vec![vec![ColorShp::Translucent; clr_num]; tab_num]; let mut p = 0; for clut in v.iter_mut().take(tab_num) { for _ in 0..clr_num { color(&b[p..p + 8], clut)?; p += 8; } } Ok(v) } fn bitmap(b: &[u8]) -> ResultS { read_data! { 26, BE in b => width = u16[0] as usize; height = u16[2] as usize; compr = u16[4]; flags = u16[6]; depth = u16[8]; } let compr = compr == u16::max_value(); let flags = flag_ok!(BmpFlags, flags)?; let alpha = flags.contains(BmpFlags::Transparent); let cmajr = flags.contains(BmpFlags::ColumnMajor); if depth != 8 { bail!("invalid bit depth (should always be 8)"); } let mut bmp = Bitmap::new(width, height, alpha, cmajr); let mut p = 30 + if cmajr {4 * width} else {4 * height}; let scanlines = if cmajr {width} else {height}; let pitch = if cmajr {height} else {width}; if compr { // compressed scanlines (transparency RLE) for _ in 0..scanlines { read_data! { p + 4, BE in b => fst = u16[p] as usize; lst = u16[p + 2] as usize; } let end = lst - fst; p += 4; if lst < fst || fst > pitch || lst > pitch || b.len() < p + end { bail!("invalid compressed scanline"); } for _ in 0..fst { bmp.cr.push(0); } bmp.cr.extend_from_slice(&b[p..p + end]); for _ in lst..pitch { bmp.cr.push(0); } p += end; } } else { // simple copy if b.len() < p + width * height { bail!("invalid scanline"); } bmp.cr.extend_from_slice(&b[p..p + width * height]); } Ok(bmp) } fn frame(b: &[u8]) -> ResultS { read_data! { 36, BE in b => flags = u16[0]; min_lt = Fixed[2]; bmp_ind = u16[6] as usize; wrl_l = Unit[16]; wrl_r = Unit[18]; wrl_t = Unit[20]; wrl_b = Unit[22]; wrl_x = Unit[24]; wrl_y = Unit[26]; } let flags = flag_ok!(FrameFlags, flags)?; Ok(Frame{flags, min_lt, bmp_ind, wrl_l, wrl_r, wrl_t, wrl_b, wrl_x, wrl_y}) } fn sequence(b: &[u8]) -> ResultS { read_data! { 88, BE in b => name = u8[4..38] array; v_type = u16[38]; frames = u16[40]; ticks = u16[42]; key = u16[44]; xfer = u16[46]; xfer_pd = u16[48]; snd_beg = OptU16[50]; snd_key = OptU16[52]; snd_end = OptU16[54]; loop_f = u16[58]; } let name = mac_roman_conv(ok!(pascal_str(name), "bad string")?); let xfer = TransferMode::from_repr(xfer)?; let v_type = ViewType::from_repr(v_type)?; Ok(Sequence{name, v_type, frames, ticks, key, xfer, xfer_pd, snd_beg, snd_key, snd_end, loop_f}) } fn collection(b: &[u8]) -> ResultS { read_data! { 544, BE in b => version = u16[0]; cl_type = u16[2]; clr_num = u16[6] as usize; tab_num = u16[8] as usize; tab_ofs = u32[10] as usize; seq_num = u16[14] as usize; seq_ofs = u32[16] as usize; frm_num = u16[20] as usize; frm_ofs = u32[22] as usize; bmp_num = u16[26] as usize; bmp_ofs = u32[28] as usize; } let cl_type = CollectionType::from_repr(cl_type)?; if version != 3 { bail!("invalid collection definition"); } let tabs = color_tables(b, tab_ofs, tab_num, clr_num)?; let bmps = rd_ofstable(b, bmp_ofs, bmp_num, bitmap)?; let frms = rd_ofstable(b, frm_ofs, frm_num, frame)?; let seqs = rd_ofstable(b, seq_ofs, seq_num, sequence)?; Ok(Collection{ctyp: cl_type, tabs, bmps, frms, seqs}) } pub fn read_shapes(b: &[u8]) -> ResultS> { let mut cl = Vec::with_capacity(32); let mut p = 0; for _ in 0..32 { read_data! { p + 32, BE in b => lo_ofs = u32[p + 4] as usize; lo_len = u32[p + 8] as usize; hi_ofs = u32[p + 12] as usize; hi_len = u32[p + 16] as usize; } let c_lo = if lo_ofs == u32::max_value() as usize { None } else { Some(collection(&b[lo_ofs..lo_ofs + lo_len])?) }; let c_hi = if hi_ofs == u32::max_value() as usize { None } else { Some(collection(&b[hi_ofs..hi_ofs + hi_len])?) }; cl.push((c_lo, c_hi)); p += 32; } Ok(cl) } impl Bitmap { fn new(w: usize, h: usize, alpha: bool, cmajr: bool) -> Self { Self{w, h, alpha, cmajr, cr: Vec::with_capacity(w * h)} } } impl<'a, 'b> ImageShp<'a, 'b> { pub fn new(bmp: &'a Bitmap, clut: &'b [ColorShp]) -> Self { Self{bmp, clut} } } impl Image for ImageShp<'_, '_> { type Output = ColorShp; fn w(&self) -> usize {self.bmp.w} fn h(&self) -> usize {self.bmp.h} fn index(&self, x: usize, y: usize) -> &Self::Output { static TRANSLUCENT_COLOR: ColorShp = ColorShp::Translucent; let cr = if self.bmp.cmajr { self.bmp.cr[y + x * self.bmp.h] as usize } else { self.bmp.cr[x + y * self.bmp.w] as usize }; if self.bmp.alpha && cr == 0 { &TRANSLUCENT_COLOR } else { self.clut.get(cr).unwrap_or(&TRANSLUCENT_COLOR) } } } impl Color for ColorShp { fn r(&self) -> u16 { match *self { ColorShp::Translucent => 0, ColorShp::Opaque{r, ..} => r, } } fn g(&self) -> u16 { match *self { ColorShp::Translucent => 0, ColorShp::Opaque{g, ..} => g, } } fn b(&self) -> u16 { match *self { ColorShp::Translucent => 0, ColorShp::Opaque{b, ..} => b, } } fn a(&self) -> u16 { match *self { ColorShp::Translucent => 0, ColorShp::Opaque{..} => u16::max_value(), } } } #[derive(Clone, Debug, Serialize)] pub enum ColorShp { Translucent, Opaque { r: u16, g: u16, b: u16, l: bool, }, } #[derive(Debug)] pub struct Bitmap { w: usize, h: usize, cr: Vec, alpha: bool, cmajr: bool, } pub struct ImageShp<'a, 'b> { bmp: &'a Bitmap, clut: &'b [ColorShp], } #[derive(Debug, Serialize)] pub struct Frame { flags: FrameFlags, min_lt: Fixed, bmp_ind: usize, wrl_l: Unit, wrl_r: Unit, wrl_t: Unit, wrl_b: Unit, wrl_x: Unit, wrl_y: Unit, } #[derive(Debug, Serialize)] pub struct Sequence { name: String, v_type: ViewType, frames: u16, ticks: u16, key: u16, xfer: TransferMode, xfer_pd: u16, snd_beg: OptU16, snd_key: OptU16, snd_end: OptU16, loop_f: u16, } #[derive(Debug)] pub struct Collection { pub ctyp: CollectionType, pub tabs: Vec>, pub bmps: Vec, pub frms: Vec, pub seqs: Vec, } pub type CollectionDef = (Option, Option); bitflags! { struct BmpFlags: u16 { const Transparent = 1 << 14; const ColumnMajor = 1 << 15; } } bitflags! { #[derive(Serialize)] pub struct FrameFlags: u16 { const Obscure = 1 << 13; const FlipY = 1 << 14; const FlipX = 1 << 15; } } c_enum! { #[derive(Debug, Serialize)] pub enum CollectionType: u16 { 0 => Unused, 1 => Wall, 2 => Object, 3 => Interface, 4 => Scenery, } } c_enum! { #[derive(Debug, Serialize)] pub enum ViewType: u16 { 1 => Anim, 3 => Anim4from3, 4 => Anim4, 9 => Anim5from3, 11 => Anim5, 2 => Anim8from2, 5 => Anim8from5, 8 => Anim8, 10 => Still, } } // EOF