Compare commits
3 Commits
51f4eab9fe
...
b33dc356c4
Author | SHA1 | Date |
---|---|---|
an | b33dc356c4 | |
an | b5dfcf3ee2 | |
an | 152d8a0b60 |
|
@ -131,7 +131,8 @@ macro_rules! _durandal_read_impl {
|
|||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This macro will not panic unless any index expression used exceeds `size`.
|
||||
/// This macro will not panic unless any index expression used exceeds or
|
||||
/// equals `size`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -465,7 +466,7 @@ impl fmt::Debug for Ident
|
|||
/// ```
|
||||
#[derive(Clone, Copy, Default, PartialEq)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct Ident(pub [u8; 4]);
|
||||
pub struct Ident(/** The individual bytes of this identifier. */ pub [u8; 4]);
|
||||
|
||||
/// An object identified by a `u16` which may be `u16::max_value()` to
|
||||
/// represent a nulled value.
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
//! Bit streams.
|
||||
|
||||
use crate::durandal::err::*;
|
||||
|
||||
/// Reads `width` bits from `b` starting at bit `cr_ptr` into an integer.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// The function will return an error if `width` is 0 or more than 64, or if
|
||||
/// `(cr_ptr + width - 1) / 8` would overflow an index into `b`.
|
||||
pub fn read_bits(b: &[u8], cr_ptr: usize, width: u8) -> ResultS<(usize, u64)>
|
||||
{
|
||||
if width < 1 || width > 64 {
|
||||
bail!("invalid number of bits");
|
||||
}
|
||||
|
||||
let nx_ptr = cr_ptr + usize::from(width);
|
||||
let ed_ptr = nx_ptr - 1;
|
||||
|
||||
let first_byte = cr_ptr / 8;
|
||||
let last_byte = ed_ptr / 8;
|
||||
|
||||
if b.len() <= last_byte {
|
||||
bail!("not enough data");
|
||||
}
|
||||
|
||||
let first_bits = cr_ptr as u32 % 8;
|
||||
let last_bits = nx_ptr as u32 % 8;
|
||||
|
||||
let last_mask = ((1u128 << last_bits) - 1) as u64;
|
||||
|
||||
let num_bytes = last_byte - first_byte;
|
||||
|
||||
let bytes = get_bytes(b, num_bytes, first_byte);
|
||||
|
||||
let bits = u64::from_be_bytes(bytes);
|
||||
let bits = bits.wrapping_shl(first_bits);
|
||||
let bits = bits >> (64 - width);
|
||||
|
||||
// special case for over byte boundary
|
||||
let bits = if num_bytes == 8 {
|
||||
let lbyt = u64::from(b[last_byte]);
|
||||
let lbyt = lbyt >> (8 - last_bits);
|
||||
let lbyt = lbyt & last_mask;
|
||||
|
||||
(bits & !last_mask) | lbyt
|
||||
} else {
|
||||
bits
|
||||
};
|
||||
|
||||
Ok((nx_ptr, bits))
|
||||
}
|
||||
|
||||
fn get_bytes(b: &[u8], num_bytes: usize, f: usize) -> [u8; 8]
|
||||
{
|
||||
match num_bytes {
|
||||
8 |
|
||||
7 => [b[f], b[f+1], b[f+2], b[f+3], b[f+4], b[f+5], b[f+6], b[f+7]],
|
||||
6 => [b[f], b[f+1], b[f+2], b[f+3], b[f+4], b[f+5], b[f+6], 0],
|
||||
5 => [b[f], b[f+1], b[f+2], b[f+3], b[f+4], b[f+5], 0, 0],
|
||||
4 => [b[f], b[f+1], b[f+2], b[f+3], b[f+4], 0, 0, 0],
|
||||
3 => [b[f], b[f+1], b[f+2], b[f+3], 0, 0, 0, 0],
|
||||
2 => [b[f], b[f+1], b[f+2], 0, 0, 0, 0, 0],
|
||||
1 => [b[f], b[f+1], 0, 0, 0, 0, 0, 0],
|
||||
0 => [b[f], 0, 0, 0, 0, 0, 0, 0],
|
||||
_ => panic!("invalid number of bytes to read ({})", num_bytes),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bit_tests()
|
||||
{
|
||||
const INPUT: &[u8] = &[0b011_00101, 0b10101010, 0b00010000, 0b00000000,
|
||||
0b11111111, 0b11100001, 0b10101100, 0b00110011,
|
||||
0b10_1001_01, 0b11100_000, 0b00000111, 0b000000_01,
|
||||
0b11001010, 0b10101111, 0b00101011, 0b0_1101010,
|
||||
0b11010101, 0b10100011, 0b01010101, 0b11_000001];
|
||||
|
||||
let (p, n) = read_bits(INPUT, 0, 3).unwrap();
|
||||
assert_eq!(n, 0b011);
|
||||
|
||||
let (p, n) = read_bits(INPUT, p, 63).unwrap();
|
||||
assert_eq!(n, 0x16A8_4003_FF86_B0CE);
|
||||
|
||||
let (p, n) = read_bits(INPUT, p, 4).unwrap();
|
||||
assert_eq!(n, 0b1001);
|
||||
|
||||
let (p, n) = read_bits(INPUT, p, 7).unwrap();
|
||||
assert_eq!(n, 0b0111100);
|
||||
|
||||
let (p, n) = read_bits(INPUT, p, 17).unwrap();
|
||||
assert_eq!(n, 0b00000000111000000);
|
||||
|
||||
let (p, n) = read_bits(INPUT, p, 27).unwrap();
|
||||
assert_eq!(n, 0b011100101010101111001010110);
|
||||
|
||||
let (p, n) = read_bits(INPUT, p, 33).unwrap();
|
||||
assert_eq!(n, 0b110101011010101101000110101010111);
|
||||
|
||||
let (p, n) = read_bits(INPUT, p, 6).unwrap();
|
||||
assert_eq!(n, 1);
|
||||
|
||||
let e = read_bits(INPUT, p, 1);
|
||||
assert!(if let Err(_) = e {true} else {false});
|
||||
|
||||
let e = read_bits(INPUT, p, 2);
|
||||
assert!(if let Err(_) = e {true} else {false});
|
||||
}
|
||||
|
||||
// EOF
|
|
@ -38,7 +38,7 @@ macro_rules! c_enum
|
|||
$(#[$outer:meta])*
|
||||
$vi:vis enum $t:ident: $ti:ty
|
||||
{
|
||||
$($va:expr => $en:ident,)+
|
||||
$($(#[$inner:meta])* $va:expr => $en:ident,)+
|
||||
}
|
||||
) => {
|
||||
$(#[$outer])*
|
||||
|
@ -54,8 +54,8 @@ macro_rules! c_enum
|
|||
$vi fn from_repr(n: $ti) -> Result<Self, ReprError>
|
||||
{
|
||||
match n {
|
||||
$($va => Ok($t::$en),)+
|
||||
n => Err(ReprError::new(n))
|
||||
$($(#[$inner])* $va => Ok($t::$en),)+
|
||||
n => Err(ReprError::new(n))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,8 +30,7 @@ fn crc_init() -> [u32; 256]
|
|||
pub fn crc32(b: &[u8], s: u32) -> u32
|
||||
{
|
||||
let t = crc_init();
|
||||
!b.iter()
|
||||
.fold(s, |a, &o| a >> 8 ^ t[usize::from(a as u8 ^ o)])
|
||||
!b.iter().fold(s, |a, &o| a >> 8 ^ t[usize::from(a as u8 ^ o)])
|
||||
}
|
||||
|
||||
// EOF
|
||||
|
|
|
@ -237,8 +237,10 @@ pub struct Color8(u8, u8, u8);
|
|||
#[derive(Debug, serde::Serialize)]
|
||||
pub struct Image16
|
||||
{
|
||||
w: usize,
|
||||
h: usize,
|
||||
w: usize,
|
||||
h: usize,
|
||||
|
||||
/// The raw color data for this image.
|
||||
pub cr: Vec<Color16>,
|
||||
}
|
||||
|
||||
|
@ -246,8 +248,10 @@ pub struct Image16
|
|||
#[derive(Debug, serde::Serialize)]
|
||||
pub struct Image8
|
||||
{
|
||||
w: usize,
|
||||
h: usize,
|
||||
w: usize,
|
||||
h: usize,
|
||||
|
||||
/// The raw color data for this image.
|
||||
pub cr: Vec<Color8>,
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ pub mod cenum;
|
|||
#[macro_use]
|
||||
pub mod bin;
|
||||
|
||||
pub mod bit;
|
||||
pub mod crc;
|
||||
pub mod file;
|
||||
pub mod fixed;
|
||||
|
|
|
@ -126,9 +126,11 @@ impl Sound for Sound16
|
|||
/// A 16-bit PCM stream.
|
||||
pub struct Sound16
|
||||
{
|
||||
rate: u16,
|
||||
lp_beg: usize,
|
||||
lp_end: usize,
|
||||
rate: u16,
|
||||
lp_beg: usize,
|
||||
lp_end: usize,
|
||||
|
||||
/// The raw signed PCM data of this sound.
|
||||
pub data: Vec<i16>,
|
||||
}
|
||||
|
||||
|
|
|
@ -32,12 +32,8 @@ fn process_wad(opt: &Options, b: &[u8]) -> ResultS<()>
|
|||
{
|
||||
let wad = wad::read_wad(b)?;
|
||||
|
||||
if opt.wad_header {
|
||||
make_yaml(opt, &wad.head)?;
|
||||
}
|
||||
|
||||
if opt.wad_wrt_all {
|
||||
make_yaml(opt, &wad.entries)?;
|
||||
make_yaml(opt, &wad)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -106,22 +102,10 @@ fn dump_sounds(opt: &Options, st: &snd::SoundTable, c: usize) -> ResultS<()>
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn write_sounds(opt: &Options, st: &snd::SoundTable) -> ResultS<()>
|
||||
{
|
||||
if opt.snd_write {
|
||||
for sd in st.values() {
|
||||
make_yaml(opt, &sd.header)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_snd(opt: &Options, b: &[u8]) -> ResultS<()>
|
||||
{
|
||||
for (c, st) in snd::read_sounds(b)?.iter().enumerate() {
|
||||
dump_sounds(opt, st, c)?;
|
||||
write_sounds(opt, st)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -178,11 +162,6 @@ fn main() -> ResultS<()>
|
|||
StoreTrue,
|
||||
"shp: Dump all sequences as YAML to standard output");
|
||||
|
||||
arg!("--snd-write",
|
||||
opt.snd_write,
|
||||
StoreTrue,
|
||||
"snd: Dump all sound headers as YAML to standard output");
|
||||
|
||||
arg!("--snd-dump",
|
||||
opt.snd_dump,
|
||||
StoreTrue,
|
||||
|
@ -193,11 +172,6 @@ fn main() -> ResultS<()>
|
|||
StoreTrue,
|
||||
"wad: Dump all known chunks");
|
||||
|
||||
arg!("--wad-write-header",
|
||||
opt.wad_header,
|
||||
StoreTrue,
|
||||
"wad: Dump header info as YAML to standard output");
|
||||
|
||||
arg!("--out-dir",
|
||||
opt.out_dir,
|
||||
Store,
|
||||
|
@ -255,9 +229,7 @@ struct Options
|
|||
shp_frm: bool,
|
||||
shp_seq: bool,
|
||||
snd_dump: bool,
|
||||
snd_write: bool,
|
||||
wad_wrt_all: bool,
|
||||
wad_header: bool,
|
||||
}
|
||||
|
||||
// EOF
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#![deny(anonymous_parameters)]
|
||||
#![deny(bare_trait_objects)]
|
||||
#![deny(elided_lifetimes_in_paths)]
|
||||
#![deny(unreachable_pub)]
|
||||
#![warn(trivial_casts)]
|
||||
#![warn(trivial_numeric_casts)]
|
||||
#![deny(unreachable_pub)]
|
||||
#![warn(unused_import_braces)]
|
||||
#![warn(unused_qualifications)]
|
||||
#![deny(clippy::all)]
|
||||
|
@ -19,7 +19,6 @@
|
|||
#![deny(clippy::filter_map)]
|
||||
#![deny(clippy::float_arithmetic)]
|
||||
#![deny(clippy::float_cmp_const)]
|
||||
#![deny(clippy::if_not_else)]
|
||||
#![deny(clippy::invalid_upcast_comparisons)]
|
||||
#![deny(clippy::items_after_statements)]
|
||||
#![deny(clippy::large_digit_groups)]
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
//! DEFLATE loader.
|
||||
|
||||
use crate::durandal::err::*;
|
||||
|
||||
/// Loads a GZIP file header.
|
||||
pub fn load_gzip_header(b: &[u8]) -> ResultS<usize>
|
||||
{
|
||||
const FHCRC: u8 = 1 << 1;
|
||||
const FEXTRA: u8 = 1 << 2;
|
||||
const FNAME: u8 = 1 << 3;
|
||||
const FCOMMENT: u8 = 1 << 4;
|
||||
|
||||
read_data! {
|
||||
10, LE in b =>
|
||||
id = u16[0];
|
||||
cm = u8[2];
|
||||
fl = u8[3];
|
||||
}
|
||||
|
||||
if id != 0x8B1F || cm != 8 {
|
||||
bail!("not gzip format");
|
||||
}
|
||||
|
||||
let mut p = 10;
|
||||
|
||||
if fl & FEXTRA != 0 {
|
||||
read_data!(p + 2, LE in b => xlen = u16[p] usize;);
|
||||
|
||||
if p + 2 + xlen > b.len() {
|
||||
bail!("not enough data");
|
||||
}
|
||||
|
||||
p += xlen;
|
||||
}
|
||||
|
||||
if fl & FNAME != 0 {
|
||||
p = skip_zero_terminated_item(&b[p..])?;
|
||||
}
|
||||
|
||||
if fl & FCOMMENT != 0 {
|
||||
p = skip_zero_terminated_item(&b[p..])?;
|
||||
}
|
||||
|
||||
if fl & FHCRC != 0 {
|
||||
read_data!(p + 2, LE in b => _crc = u16[p];);
|
||||
|
||||
p += 2;
|
||||
}
|
||||
|
||||
Ok(p)
|
||||
}
|
||||
|
||||
fn skip_zero_terminated_item(b: &[u8]) -> ResultS<usize>
|
||||
{
|
||||
if let Some(i) = b.iter().position(|&n| n == 0) {
|
||||
Ok(i)
|
||||
} else {
|
||||
bail!("no end of zero terminated item");
|
||||
}
|
||||
}
|
||||
|
||||
// EOF
|
|
@ -936,6 +936,7 @@ c_enum! {
|
|||
}
|
||||
}
|
||||
|
||||
/// The number of game ticks per second.
|
||||
pub const TICKS_PER_SECOND: u16 = 30;
|
||||
|
||||
const OLD_LIGHT_DEFINITIONS: [Light; 8] = [
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//! Library for file format data readers.
|
||||
|
||||
pub mod defl;
|
||||
pub mod machdr;
|
||||
pub mod map;
|
||||
pub mod phy;
|
||||
|
|
|
@ -9,21 +9,23 @@ fn read_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];
|
||||
flag = u8[0];
|
||||
ind = 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 = ok!(clut.get_mut(usize::from(ind)), "bad index")?;
|
||||
|
||||
*cr = match flag {
|
||||
128 => ColorShp::Lit {r, g, b},
|
||||
0 => ColorShp::Opaque{r, g, b},
|
||||
_ => {
|
||||
return Err(err_msg("invalid flag in color"));
|
||||
}
|
||||
};
|
||||
|
||||
let cr = ColorShp::Opaque{r, g, b, l};
|
||||
*ok!(clut.get_mut(usize::from(i)), "bad index")? = cr;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -285,6 +287,7 @@ impl Color for ColorShp
|
|||
match *self {
|
||||
ColorShp::Translucent => 0,
|
||||
ColorShp::Opaque{r, ..} => r,
|
||||
ColorShp::Lit {r, ..} => r,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,6 +296,7 @@ impl Color for ColorShp
|
|||
match *self {
|
||||
ColorShp::Translucent => 0,
|
||||
ColorShp::Opaque{g, ..} => g,
|
||||
ColorShp::Lit {g, ..} => g,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,6 +305,7 @@ impl Color for ColorShp
|
|||
match *self {
|
||||
ColorShp::Translucent => 0,
|
||||
ColorShp::Opaque{b, ..} => b,
|
||||
ColorShp::Lit {b, ..} => b,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -309,6 +314,7 @@ impl Color for ColorShp
|
|||
match *self {
|
||||
ColorShp::Translucent => 0,
|
||||
ColorShp::Opaque{..} => u16::max_value(),
|
||||
ColorShp::Lit {..} => u16::max_value(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -317,14 +323,18 @@ impl Color for ColorShp
|
|||
#[derive(Copy, Clone, Debug, serde::Serialize)]
|
||||
pub enum ColorShp
|
||||
{
|
||||
/// A completely translucent color.
|
||||
Translucent,
|
||||
Opaque
|
||||
{
|
||||
r: u16,
|
||||
g: u16,
|
||||
b: u16,
|
||||
l: bool,
|
||||
},
|
||||
|
||||
/// An opaque color which may be shaded.
|
||||
Opaque{/** The red component. */ r: u16,
|
||||
/** The green component. */ g: u16,
|
||||
/** The blue component. */ b: u16},
|
||||
|
||||
/// An opaque color which may not be shaded.
|
||||
Lit{/** The red component. */ r: u16,
|
||||
/** The green component. */ g: u16,
|
||||
/** The blue component. */ b: u16},
|
||||
}
|
||||
|
||||
/// An unpacked Shape bitmap.
|
||||
|
@ -350,42 +360,89 @@ pub struct ImageShp<'a, 'b>
|
|||
#[derive(Debug, serde::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,
|
||||
/// The flags for this frame.
|
||||
pub flags: FrameFlags,
|
||||
|
||||
/// The minimum light level for this frame.
|
||||
pub min_lt: Fixed,
|
||||
|
||||
/// The index of the bitmap this frame uses.
|
||||
pub bmp_ind: usize,
|
||||
|
||||
/// The left translation for this frame.
|
||||
pub wrl_l: Unit,
|
||||
|
||||
/// The right translation for this frame.
|
||||
pub wrl_r: Unit,
|
||||
|
||||
/// The top translation for this frame.
|
||||
pub wrl_t: Unit,
|
||||
|
||||
/// The bottom translation for this frame.
|
||||
pub wrl_b: Unit,
|
||||
|
||||
/// The X translation for this frame.
|
||||
pub wrl_x: Unit,
|
||||
|
||||
/// The Y translation for this frame.
|
||||
pub wrl_y: Unit,
|
||||
}
|
||||
|
||||
/// A sequence, also known as a high level shape.
|
||||
#[derive(Debug, serde::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,
|
||||
/// The display name for this sequence.
|
||||
pub name: String,
|
||||
|
||||
/// The view type for each frame in this sequence.
|
||||
pub v_type: ViewType,
|
||||
|
||||
/// The number of frames in this sequence.
|
||||
pub frames: u16,
|
||||
|
||||
/// The number of ticks each frame in this sequence takes.
|
||||
pub ticks: u16,
|
||||
|
||||
/// The key frame index for this sequence.
|
||||
pub key: u16,
|
||||
|
||||
/// The transfer mode to play over this sequence.
|
||||
pub xfer: TransferMode,
|
||||
|
||||
/// The period in game ticks the transfer mode plays over.
|
||||
pub xfer_pd: u16,
|
||||
|
||||
/// The sound to play at the beginning of this sequence.
|
||||
pub snd_beg: OptU16,
|
||||
|
||||
/// The sound to play at the key frame of this sequence.
|
||||
pub snd_key: OptU16,
|
||||
|
||||
/// The sound to play at the end of this sequence.
|
||||
pub snd_end: OptU16,
|
||||
|
||||
/// Which frame to loop on.
|
||||
pub loop_f: u16,
|
||||
}
|
||||
|
||||
/// A collection of color tables, bitmaps, frames and sequences.
|
||||
#[derive(Debug)]
|
||||
pub struct Collection
|
||||
{
|
||||
/// The type of collection this is.
|
||||
pub ctyp: CollectionType,
|
||||
|
||||
/// All of the color tables in this collection.
|
||||
pub tabs: Vec<Vec<ColorShp>>,
|
||||
|
||||
/// All of the bitmaps in this collection.
|
||||
pub bmps: Vec<Bitmap>,
|
||||
|
||||
/// All of the frames in this collection.
|
||||
pub frms: Vec<Frame>,
|
||||
|
||||
/// All of the sequences in this collection.
|
||||
pub seqs: Vec<Sequence>,
|
||||
}
|
||||
|
||||
|
@ -405,8 +462,11 @@ bitflags! {
|
|||
#[derive(serde::Serialize)]
|
||||
pub struct FrameFlags: u16
|
||||
{
|
||||
/// The player's torso will obscure the player's legs.
|
||||
const OBSCURE = 1 << 13;
|
||||
/// The bitmap will be flipped on the vertical axis.
|
||||
const FLIP_Y = 1 << 14;
|
||||
/// The bitmap will be flipped on the horizontal axis.
|
||||
const FLIP_X = 1 << 15;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,10 +78,10 @@ pub fn read_sound_def(b: &[u8]) -> ResultS<Option<(Vec<usize>, u16, SoundDef)>>
|
|||
p += 4;
|
||||
}
|
||||
|
||||
let header = SoundHead{volume, flags, chance, pitch_lo, pitch_hi};
|
||||
let sounds = Vec::with_capacity(n_sounds);
|
||||
|
||||
Ok(Some((ofs, index, SoundDef{header, sounds})))
|
||||
Ok(Some((ofs, index,
|
||||
SoundDef{volume, flags, chance, pitch_lo, pitch_hi, sounds})))
|
||||
}
|
||||
|
||||
/// Reads all sounds from a Sound file.
|
||||
|
@ -123,21 +123,25 @@ pub fn read_sounds(b: &[u8]) -> ResultS<Vec<SoundTable>>
|
|||
Ok(sc)
|
||||
}
|
||||
|
||||
/// The header of a sound definition.
|
||||
#[derive(Debug, serde::Serialize)]
|
||||
pub struct SoundHead
|
||||
{
|
||||
pub volume: Volume,
|
||||
pub flags: SoundFlags,
|
||||
pub chance: u16,
|
||||
pub pitch_lo: Fixed,
|
||||
pub pitch_hi: Fixed,
|
||||
}
|
||||
|
||||
/// A sound definition containing one, many or no sounds.
|
||||
pub struct SoundDef
|
||||
{
|
||||
pub header: SoundHead,
|
||||
/// The volume type for this sound.
|
||||
pub volume: Volume,
|
||||
|
||||
/// The flags for this sound.
|
||||
pub flags: SoundFlags,
|
||||
|
||||
/// The chance out of `u16::max_value()` that this sound will not play.
|
||||
pub chance: u16,
|
||||
|
||||
/// The low random pitch bound.
|
||||
pub pitch_lo: Fixed,
|
||||
|
||||
/// The high random pitch bound.
|
||||
pub pitch_hi: Fixed,
|
||||
|
||||
/// All of the sounds in this collection.
|
||||
pub sounds: Vec<Sound16>,
|
||||
}
|
||||
|
||||
|
@ -145,16 +149,23 @@ pub struct SoundDef
|
|||
pub type SoundTable = BTreeMap<u16, SoundDef>;
|
||||
|
||||
bitflags! {
|
||||
/// Flags for `SoundHead`.
|
||||
/// Flags for `SoundDef`.
|
||||
#[derive(serde::Serialize)]
|
||||
pub struct SoundFlags: u16
|
||||
{
|
||||
/// The sound will not restart when trying to play over itself.
|
||||
const NO_RESTART = 1;
|
||||
/// The sound will not switch channels when trying to play over itself.
|
||||
const NO_CHANNEL_SWITCH = 1 << 1;
|
||||
/// The pitch variance will be halved.
|
||||
const LESS_PITCH_CHANGE = 1 << 2;
|
||||
/// The pitch variance will be nullified.
|
||||
const NO_PITCH_CHANGE = 1 << 3;
|
||||
/// The sound will play even when completely obstructed by walls.
|
||||
const NO_OBSTRUCTION = 1 << 4;
|
||||
/// The sound will play even when completely obstructed by media.
|
||||
const NO_MEDIA_OBSTRUCT = 1 << 5;
|
||||
/// The sound will have special stereo effects.
|
||||
const AMBIENT = 1 << 6;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,11 +128,11 @@ pub struct Group
|
|||
#[derive(Debug)]
|
||||
pub struct InterGroup
|
||||
{
|
||||
flags: GroupFlags,
|
||||
ttype: GroupType,
|
||||
lines: u16,
|
||||
beg: usize,
|
||||
len: usize,
|
||||
pub flags: GroupFlags,
|
||||
pub ttype: GroupType,
|
||||
pub lines: u16,
|
||||
pub beg: usize,
|
||||
pub len: usize,
|
||||
}
|
||||
|
||||
/// The command of a `Group`.
|
||||
|
@ -163,7 +163,9 @@ bitflags! {
|
|||
#[derive(Default, serde::Serialize)]
|
||||
pub struct GroupFlags: u16
|
||||
{
|
||||
/// Draws the picture on the right.
|
||||
const DRAW_ON_RIGHT = 1;
|
||||
/// Draws the picture in the center.
|
||||
const DRAW_CENTER = 1 << 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,13 +111,11 @@ pub fn read_wad(b: &[u8]) -> ResultS<Wad>
|
|||
siz_went = u16[82] usize;
|
||||
}
|
||||
|
||||
let ver_wad = Ver::from_repr(ver_wad)?;
|
||||
|
||||
let old_wad = match ver_wad {
|
||||
let old_dat = ver_dat == 0;
|
||||
let old_wad = match Ver::from_repr(ver_wad)? {
|
||||
Ver::Base => true,
|
||||
_ => false,
|
||||
};
|
||||
let old_dat = ver_dat == 0;
|
||||
|
||||
let siz_ent = if old_wad {8 } else {10};
|
||||
let siz_cnk = if old_wad {12} else {16};
|
||||
|
@ -132,60 +130,82 @@ pub fn read_wad(b: &[u8]) -> ResultS<Wad>
|
|||
|
||||
let entries = read_entries(b, old_wad, old_dat, siz_app, siz_ent, siz_cnk)?;
|
||||
|
||||
Ok(Wad{head: WadHeader{ver_wad, old_dat, siz_app, name}, entries})
|
||||
Ok(Wad{name, siz_app, entries})
|
||||
}
|
||||
|
||||
/// Any kind of chunk in an `Entry`.
|
||||
#[derive(Debug, serde::Serialize)]
|
||||
pub enum Chunk
|
||||
{
|
||||
/// A `PICT` chunk.
|
||||
Pict(image::Image8),
|
||||
/// A `Minf` chunk.
|
||||
Minf(map::Minf),
|
||||
/// An `iidx` chunk.
|
||||
Iidx(Vec<u16>),
|
||||
/// A `PNTS` chunk.
|
||||
Pnts(Vec<map::Point>),
|
||||
/// A `LINS` chunk.
|
||||
Lins(Vec<map::Line>),
|
||||
/// A `SIDS` chunk.
|
||||
Sids(Vec<map::Side>),
|
||||
/// A `POLY` chunk.
|
||||
Poly(Vec<map::Polygon>),
|
||||
/// A `LITE` chunk.
|
||||
Lite(Vec<map::Light>),
|
||||
/// An `OBJS` chunk.
|
||||
Objs(Vec<map::Object>),
|
||||
/// A `plac` chunk.
|
||||
Plac(Vec<map::ObjectFreq>),
|
||||
/// An `ambi` chunk.
|
||||
Ambi(Vec<map::SoundAmbi>),
|
||||
/// A `bonk` chunk.
|
||||
Bonk(Vec<map::SoundRand>),
|
||||
/// A `medi` chunk.
|
||||
Medi(Vec<map::Media>),
|
||||
/// A `plat` chunk.
|
||||
Plat(Vec<map::Platform>),
|
||||
/// A `NOTE` chunk.
|
||||
Note(Vec<map::Note>),
|
||||
/// A `term` chunk.
|
||||
Term(Vec<trm::Terminal>),
|
||||
/// A `FXpx` chunk.
|
||||
Fxpx(Vec<phy::Effect>),
|
||||
/// A `MNpx` chunk.
|
||||
Mnpx(Vec<phy::Monster>),
|
||||
/// A `PRpx` chunk.
|
||||
Prpx(Vec<phy::Projectile>),
|
||||
/// A `PXpx` chunk.
|
||||
Pxpx(Vec<phy::Physics>),
|
||||
/// A `WPpx` chunk.
|
||||
Wppx(Vec<phy::Weapon>),
|
||||
Data{iden: Ident, data: Vec<u8>},
|
||||
/// Any other type of chunk, which may have arbitrary data in it.
|
||||
Data{/** The name of the chunk. */ iden: Ident,
|
||||
/** The data. */ data: Vec<u8>},
|
||||
}
|
||||
|
||||
/// An entry containing chunks and application-specific data.
|
||||
#[derive(Debug, serde::Serialize)]
|
||||
pub struct Entry
|
||||
{
|
||||
pub chunks: Vec<Chunk>,
|
||||
pub appdata: Vec<u8>,
|
||||
}
|
||||
/// All of the chunks in this `Entry`.
|
||||
pub chunks: Vec<Chunk>,
|
||||
|
||||
/// The header of a `Wad`.
|
||||
#[derive(Debug, serde::Serialize)]
|
||||
pub struct WadHeader
|
||||
{
|
||||
pub ver_wad: Ver,
|
||||
pub old_dat: bool,
|
||||
pub name: String,
|
||||
pub siz_app: usize,
|
||||
/// The application specific data for this Entry.
|
||||
pub appdata: Vec<u8>,
|
||||
}
|
||||
|
||||
/// A Map file containing entries.
|
||||
#[derive(Debug, serde::Serialize)]
|
||||
pub struct Wad
|
||||
{
|
||||
pub head: WadHeader,
|
||||
/// The original name of this file.
|
||||
pub name: String,
|
||||
|
||||
/// The size of each `Entry`'s `appdata` field.
|
||||
pub siz_app: usize,
|
||||
|
||||
/// All of the entries in this `Wad`.
|
||||
pub entries: BTreeMap<u16, Entry>,
|
||||
}
|
||||
|
||||
|
|
|
@ -47,9 +47,16 @@ pub type Point = (Coord, Coord);
|
|||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Rect
|
||||
{
|
||||
/// The horizontal coordinate to start at, from the left.
|
||||
pub x: Coord,
|
||||
|
||||
/// The vertical coordinate to start at, from the top.
|
||||
pub y: Coord,
|
||||
|
||||
/// The width of the rectangle.
|
||||
pub w: Coord,
|
||||
|
||||
/// The height of the rectangle.
|
||||
pub h: Coord,
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,29 @@
|
|||
use maraiah::marathon::defl::{self, load_gzip_header};
|
||||
|
||||
include!("data/rand.rs");
|
||||
|
||||
#[test]
|
||||
fn defl_must_succeed()
|
||||
{
|
||||
assert!(load_gzip_header(include_bytes!("data/gzipok1.bin")).is_ok());
|
||||
assert!(load_gzip_header(include_bytes!("data/gzipok2.bin")).is_ok());
|
||||
assert!(load_gzip_header(include_bytes!("data/gzipok3.bin")).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn defl_must_not_succeed()
|
||||
{
|
||||
for inp in &RANDOM {
|
||||
assert!(defl::load_gzip_header(inp).is_err());
|
||||
}
|
||||
|
||||
assert!(load_gzip_header(include_bytes!("data/gzipbad1.bin")).is_err());
|
||||
assert!(load_gzip_header(include_bytes!("data/gzipbad2.bin")).is_err());
|
||||
assert!(load_gzip_header(include_bytes!("data/gzipbad3.bin")).is_err());
|
||||
assert!(load_gzip_header(include_bytes!("data/gzipbad4.bin")).is_err());
|
||||
assert!(load_gzip_header(include_bytes!("data/gzipbad5.bin")).is_err());
|
||||
assert!(load_gzip_header(include_bytes!("data/gzipbad6.bin")).is_err());
|
||||
assert!(load_gzip_header(include_bytes!("data/gzipbad7.bin")).is_err());
|
||||
}
|
||||
|
||||
// EOF
|
|
@ -30,7 +30,6 @@ fn read_epnt_must_process()
|
|||
#[test]
|
||||
fn map_must_not_process()
|
||||
{
|
||||
// these functions must not succeed
|
||||
for inp in &RANDOM {
|
||||
assert!(map::read_minf(inp).is_err());
|
||||
assert!(map::read_old_minf(inp).is_err());
|
||||
|
@ -50,9 +49,8 @@ fn map_must_not_process()
|
|||
|
||||
#[test]
|
||||
#[allow(unused_must_use)]
|
||||
fn map_wont_panic()
|
||||
fn map_must_not_panic()
|
||||
{
|
||||
// these functions can succeed but must never panic
|
||||
for inp in &RANDOM {
|
||||
bin::rd_array(inp, map::read_ambi);
|
||||
bin::rd_array(inp, map::read_bonk);
|
||||
|
|
|
@ -5,7 +5,6 @@ include!("data/rand.rs");
|
|||
#[test]
|
||||
fn phy_must_not_process()
|
||||
{
|
||||
// these functions must not succeed
|
||||
for inp in &RANDOM {
|
||||
assert!(bin::rd_array(inp, phy::read_fxpx).is_err());
|
||||
assert!(bin::rd_array(inp, phy::read_mnpx).is_err());
|
||||
|
@ -16,9 +15,8 @@ fn phy_must_not_process()
|
|||
|
||||
#[test]
|
||||
#[allow(unused_must_use)]
|
||||
fn phy_wont_panic()
|
||||
fn phy_must_not_panic()
|
||||
{
|
||||
// these functions can succeed but must never panic
|
||||
for inp in &RANDOM {
|
||||
bin::rd_array(inp, phy::read_pxpx);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ fn trm_must_not_process()
|
|||
|
||||
#[test]
|
||||
#[allow(unused_must_use)]
|
||||
fn trm_wont_panic()
|
||||
fn trm_must_not_panic()
|
||||
{
|
||||
for inp in &RANDOM {
|
||||
bin::rd_array(inp, trm::read_face);
|
||||
|
|
Loading…
Reference in New Issue