diff --git a/MarathonData.md b/MarathonData.md index b8ee503..1bc0fd6 100644 --- a/MarathonData.md +++ b/MarathonData.md @@ -883,7 +883,7 @@ if matte: ### Collection Header ### -32 bytes +Collection Header is 32 bytes. | Type | Description | Name | | ---- | ----------- | ---- | @@ -896,13 +896,25 @@ if matte: ### Collection Definition ### -544 bytes (no, I'm not kidding) +Collection Definition is 544 bytes (no, I'm not kidding, there are actually 506 +unused bytes.) | Type | Description | Name | | ---- | ----------- | ---- | | u16 | Version, not checked by engine (current is 3) | Version | | u16 | Collection Type | Type | | 2 bytes | Unused | | +| u16 | Colors per CLUT | Colors | +| u16 | Number of CLUTs | CLUNum | +| u32 | Offset to CLUTs | CLUOfs | +| u16 | Number of sequences | SeqNum | +| u32 | Offset to sequences | SeqOfs | +| u16 | Number of frames | FrmNum | +| u32 | Offset to frames | FrmOfs | +| u16 | Number of bitmaps | BmpNum | +| u32 | Offset to bitmaps | BmpOfs | +| 2 bytes | Unused | | +| u32 | Size of entire collection | | # ENUMERATIONS ################################################################ diff --git a/src/durandal/text.rs b/src/durandal/text.rs index d76f1aa..98e9e66 100644 --- a/src/durandal/text.rs +++ b/src/durandal/text.rs @@ -1,5 +1,7 @@ //! Text conversion utilities. +use crate::durandal::err::*; + /// Dumps a slice of memory as text to stderr. pub fn dump_mem(b: &[u8]) { @@ -66,6 +68,21 @@ pub fn fuck_string(s: &[u8]) -> Vec v } +/// Reads a Pascal-style byte string with bounds checking. +pub fn pascal_str(b: &[u8]) -> ResultS<&[u8]> +{ + if b.len() < 1 { + Err(err_msg("not enough data for string")) + } else { + let s = b[0] as usize; + if s + 1 > b.len() { + Err(err_msg("not enough data in string")) + } else { + Ok(&b[1..1 + s]) + } + } +} + /// Converts input from Mac Roman to a Unicode string. pub fn mac_roman_conv(s: &[u8]) -> String { diff --git a/src/main.rs b/src/main.rs index a2d9287..119dcd8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -78,73 +78,9 @@ fn process_wad(b: &[u8]) -> ResultS<()> Ok(()) } -fn collection(b: &[u8]) -> ResultS<()> -{ - let version = b.c_u16b(0)?; - let dt_type = b.c_u16b(2)?; - let flags = b.c_u16b(4)?; - let colors = b.c_u16b(6)?; - let clu_num = b.c_u16b(8)?; - let clu_ofs = b.c_u32b(10)?; - let seq_num = b.c_u16b(14)?; - let seq_ofs = b.c_u32b(16)?; - let frm_num = b.c_u16b(20)?; - let frm_ofs = b.c_u32b(22)?; - let bmp_num = b.c_u16b(26)?; - let bmp_ofs = b.c_u32b(28)?; - let scale = b.c_i16b(30)?; - let size = b.c_u32b(32)?; - dbg!(version); - dbg!(dt_type); - dbg!(flags); - dbg!(colors); - dbg!(clu_num); - dbg!(clu_ofs); - dbg!(seq_num); - dbg!(seq_ofs); - dbg!(frm_num); - dbg!(frm_ofs); - dbg!(bmp_num); - dbg!(bmp_ofs); - dbg!(scale); - dbg!(size); - eprintln!("[end of collection]"); - - if version != 3 { - return Err(err_msg("invalid collection version number")); - } - - Ok(()) -} - fn process_shp(b: &[u8]) -> ResultS<()> { - for i in 0..32 { - let p = 32 * i; - let status = b.c_u16b(p + 0)?; - let flags = b.c_u16b(p + 2)?; - let offset_lo = b.c_u32b(p + 4)? as usize; - let length_lo = b.c_u32b(p + 8)? as usize; - let offset_hi = b.c_u32b(p + 12)? as usize; - let length_hi = b.c_u32b(p + 16)? as usize; - dbg!(i); - dbg!(status); - dbg!(flags); - dbg!(offset_lo); - dbg!(length_lo); - dbg!(offset_hi); - dbg!(length_hi); - if offset_lo != u32::max_value() as usize { - eprintln!("collection {} has lo-res frames", i); - collection(&b[offset_lo..offset_lo + length_lo])?; - } - if offset_hi != u32::max_value() as usize { - eprintln!("collection {} has hi-res frames", i); - collection(&b[offset_hi..offset_hi + length_hi])?; - } - } - - Ok(()) + shp::testfn_replaceme(b) } fn main() -> ResultS<()> diff --git a/src/marathon/mod.rs b/src/marathon/mod.rs index 55cf3b6..6554a31 100644 --- a/src/marathon/mod.rs +++ b/src/marathon/mod.rs @@ -3,6 +3,7 @@ pub mod machdr; pub mod map; pub mod pict; +pub mod shp; pub mod term; pub mod wad; diff --git a/src/marathon/shp.rs b/src/marathon/shp.rs new file mode 100644 index 0000000..129cfc3 --- /dev/null +++ b/src/marathon/shp.rs @@ -0,0 +1,204 @@ +//! Marathon Shapes format handling. + +use crate::durandal::{bin::*, err::*, fx32::*, /*image::*,*/ text::*}; +use bitflags::bitflags; + +fn color(b: &[u8]) -> ResultS<()> +{ + let lum = b[0]; + let ind = b[1]; + let r = b.c_u16b(2)?; + let g = b.c_u16b(4)?; + let b = b.c_u16b(6)?; + // col = Color::from_rgb16(r, g, b); + let lum = match lum { + 128 => true, + 0 => false, + _ => { + return Err(err_msg("invalid flag in color")); + } + }; + + dbg!(lum); + dbg!(ind); + dbg!(r); + dbg!(g); + dbg!(b); + + Ok(()) +} + +fn frame(b: &[u8]) -> ResultS<()> +{ + let flags = b.c_u16b(0)?; + let minlight = b.c_u32b(2)?; + let bmp_ind = b.c_u16b(6)?; + // orig_x = b.c_i16b(8)?; + // orig_y = b.c_i16b(10)?; + // key_x = b.c_i16b(12)?; + // key_y = b.c_i16b(14)?; + let wrl_l = b.c_i16b(16)?; + let wrl_r = b.c_i16b(18)?; + let wrl_t = b.c_i16b(20)?; + let wrl_b = b.c_i16b(22)?; + let wrl_x = b.c_i16b(24)?; + let wrl_y = b.c_i16b(26)?; + let flags = FrameFlags::from_bits(flags).ok_or_else(bad_flag)?; + let minlight = Fx32::from_bits(minlight); + + dbg!(flags); + dbg!(minlight); + dbg!(bmp_ind); + dbg!(wrl_l); + dbg!(wrl_r); + dbg!(wrl_t); + dbg!(wrl_b); + dbg!(wrl_x); + dbg!(wrl_y); + + Ok(()) +} + +fn sequence(b: &[u8]) -> ResultS<()> +{ + // sq_type = b.c_u16b(0)?; + // flags = b.c_u16b(2)?; + let name = mac_roman_conv(pascal_str(&b[4..38])?); + let v_type = b.c_u16b(38)?; + let frames = b.c_u16b(40)?; + let ticks = b.c_u16b(42)?; + let key = b.c_u16b(44)?; + let xfer = b.c_u16b(46)?; + let xfer_pd = b.c_u16b(48)?; + let snd_beg = b.c_u16b(50)?; + let snd_key = b.c_u16b(52)?; + let snd_end = b.c_u16b(54)?; + // xform = b.c_u16b(56)?; + let loop_f = b.c_u16b(58)?; + let snd_beg = ObjID::from_repr(snd_beg); + let snd_key = ObjID::from_repr(snd_key); + let snd_end = ObjID::from_repr(snd_end); + + dbg!(name); + dbg!(v_type); + dbg!(frames); + dbg!(ticks); + dbg!(key); + dbg!(xfer); + dbg!(xfer_pd); + dbg!(snd_beg); + dbg!(snd_key); + dbg!(snd_end); + dbg!(loop_f); + + Ok(()) +} + +fn collection(b: &[u8]) -> ResultS<()> +{ + let version = b.c_u16b(0)?; + let cl_type = b.c_u16b(2)?; + // flags = b.c_u16b(4)?; + let colors = b.c_u16b(6)? as usize; + let clu_num = b.c_u16b(8)? as usize; + let clu_ofs = b.c_u32b(10)? as usize; + let seq_num = b.c_u16b(14)? as usize; + let seq_ofs = b.c_u32b(16)? as usize; + let frm_num = b.c_u16b(20)? as usize; + let frm_ofs = b.c_u32b(22)? as usize; + let bmp_num = b.c_u16b(26)? as usize; + let bmp_ofs = b.c_u32b(28)? as usize; + // xform = b.c_i16b(30)?; + let size = b.c_u32b(32)? as usize; + let cl_type = CollectionType::from_repr(cl_type)?; + + dbg!(version); + dbg!(cl_type); + dbg!(colors); + dbg!(clu_num); + dbg!(clu_ofs); + dbg!(seq_num); + dbg!(seq_ofs); + dbg!(frm_num); + dbg!(frm_ofs); + dbg!(bmp_num); + dbg!(bmp_ofs); + dbg!(size); + eprintln!("[end of collection]"); + + if version != 3 { + return Err(err_msg("invalid collection version number")); + } + + for i in 0..clu_num { + for j in 0..colors { + let p = clu_ofs + 8 * j + i * 8 * colors; + color(&b[p..])?; + } + } + + for i in 0..frm_num { + let p = b.c_u32b(frm_ofs + 4 * i)? as usize; + frame(&b[p..])?; + } + + for i in 0..seq_num { + let p = b.c_u32b(seq_ofs + 4 * i)? as usize; + sequence(&b[p..])?; + } + + Ok(()) +} + +pub fn testfn_replaceme(b: &[u8]) -> ResultS<()> +{ + for i in 0..32 { + let p = 32 * i; + let status = b.c_u16b(p + 0)?; + let flags = b.c_u16b(p + 2)?; + let offset_lo = b.c_u32b(p + 4)? as usize; + let length_lo = b.c_u32b(p + 8)? as usize; + let offset_hi = b.c_u32b(p + 12)? as usize; + let length_hi = b.c_u32b(p + 16)? as usize; + + dbg!(i); + dbg!(status); + dbg!(flags); + dbg!(offset_lo); + dbg!(length_lo); + dbg!(offset_hi); + dbg!(length_hi); + + if offset_lo != u32::max_value() as usize { + collection(&b[offset_lo..offset_lo + length_lo])?; + } + if offset_hi != u32::max_value() as usize { + collection(&b[offset_hi..offset_hi + length_hi])?; + } + } + + Ok(()) +} + +bitflags! { + pub struct FrameFlags: u16 + { + const Obscure = 0x20_00; + const FlipY = 0x40_00; + const FlipX = 0x80_00; + } +} + +c_enum! { + #[derive(Debug)] + pub enum CollectionType: u16 + { + 0 => Unused, + 1 => Wall, + 2 => Object, + 3 => Interface, + 4 => Scenery, + } +} + +// EOF