Compare commits

...

4 Commits

Author SHA1 Message Date
an daebfd2da6 maraiah: fix tests and move code to root 2019-06-22 00:55:08 -04:00
an bfb91792ec maraiah: rewrite how maps work 2019-06-21 21:34:10 -04:00
an be8d72df7d data: dang it bungie 2019-06-21 21:07:16 -04:00
an 91d171c8a6 maraiah: fix invisible dependencies in macros 2019-06-19 06:55:56 -04:00
128 changed files with 2903 additions and 601 deletions

View File

@ -14,10 +14,10 @@ publish = false
serde_obj = ["serde"]
[workspace]
members = ["source/leela", "source/tycho"]
members = ["leela", "tycho"]
[dependencies]
bitflags = "1.0"
bitflags = "1.1"
failure = {version = "0.1", features = ["std"]}
serde = {version = "1.0", features = ["derive"], optional = true}
memchr = "2.0"
@ -31,4 +31,4 @@ lto = true
[lib]
name = "maraiah"
path = "source/lib.rs"
path = "maraiah/lib.rs"

View File

@ -926,8 +926,9 @@ Random Sound is 32 bytes.
### Media Data ###
Media Data is 32 bytes. "Media" refers to liquids, presumably because of the
plural of the definition of "medium," a "middle place or degree," as in, it's a
part of the map in the middle of a wall.
plural of the definition of "medium," a "material which waves pass through," in
this case liquid. (This is likely the case of whoever programmed this system
learning physics before rendering, or conflating the two.)
| Name | Type | Offset |
| ---- | ---- | ------ |

14
leela/Cargo.toml Normal file
View File

@ -0,0 +1,14 @@
[package]
name = "maraiah-leela"
version = "0.0.0"
edition = "2018"
[dependencies]
clap = "2"
maraiah = {path = "..", features = ["serde_obj"]}
serde = "1.0"
serde_yaml = "0.8"
[[bin]]
name = "leela"
path = "main.rs"

View File

@ -1,13 +1,13 @@
#![allow(clippy::unit_arg)]
use maraiah::{err::*, file::*, image::*, sound::*,
machdr, map, ppm, shp, snd, tga, wav};
use maraiah::{err::*, file::*, image::*, machdr, map, shp, snd, sound::*};
use std::{collections::HashSet, fs, io, slice::from_ref};
fn open(path: &str) -> ResultS<memmap::Mmap>
/*
fn open(path: &str) -> ResultS<io::BufReader>
{
let fp = fs::File::open(path)?;
Ok(unsafe {memmap::Mmap::map(&fp)?})
Ok(io::BufReader::new(fp))
}
fn file_read<T, F>(path: &str, f: F) -> ResultS<T>
@ -22,14 +22,15 @@ fn file_read<T, F>(path: &str, f: F) -> ResultS<T>
fn exists(path: String) -> Result<(), String>
{
match std::fs::metadata(path) {
Ok(_) => Ok(()),
Ok(_) => Ok(()),
Err(e) => Err(e.to_string()),
}
}
fn each_value<F>(opt: &clap::ArgMatches<'_>,
name: &str,
mut f: F) -> ResultS<()>
mut f: F)
-> ResultS<()>
where F: FnMut(&str) -> ResultS<()>
{
if let Some(values) = opt.values_of(name) {
@ -91,43 +92,60 @@ fn sub_info_c(opt: &clap::ArgMatches<'_>) -> ResultS<()>
Ok(())
}
*/
fn main() -> ResultS<()>
{
use std::io::prelude::*;
let inp = include_bytes!("../tests/data/map/Test.in");
let mut rd = std::io::BufReader::new(&inp[..]);
let mp = map::head::read(&mut rd).unwrap();
let en = map::entr::read_all(&mp).unwrap();
let ed = map::data::read_all(mp.head(), &en).unwrap();
write!(&mut std::fs::File::create("dicks.txt").unwrap(), "{:#?}", ed);
/*
use clap::clap_app;
let sub_data =
clap_app!(@subcommand data =>
(about: "Dumps data into a discrete folder/YAML format"));
let sub_data = clap_app! {
@subcommand data =>
(about: "Dumps data into a discrete folder/YAML format")
};
let sub_dump =
clap_app!(@subcommand dump =>
let sub_dump = clap_app! {
@subcommand dump =>
(about: "Dumps particular parts of data")
(@arg chunks: -c --chunks [name]... "Dumps named chunks from an entry")
(@group files =>
(@attributes +required +multiple)
(@arg map: -m --map [file]... {exists} "Loads Map files")
(@arg shp: -s --shp [file]... {exists} "Loads Shapes files")
(@arg snd: -n --snd [file]... {exists} "Loads Sounds files")));
(@attributes +required +multiple)
(@arg map: -m --map [file]... {exists} "Loads Map files")
(@arg shp: -s --shp [file]... {exists} "Loads Shapes files")
(@arg snd: -n --snd [file]... {exists} "Loads Sounds files"))
};
let sub_info =
clap_app!(@subcommand info =>
let sub_info = clap_app! {
@subcommand info =>
(about: "Outputs debug info")
(@group files =>
(@attributes +required +multiple)
(@arg map: -m --map [file]... {exists} "Loads Map files")
(@arg shp: -s --shp [file]... {exists} "Loads Shapes files")
(@arg snd: -n --snd [file]... {exists} "Loads Sounds files")));
(@attributes +required +multiple)
(@arg map: -m --map [file]... {exists} "Loads Map files")
(@arg shp: -s --shp [file]... {exists} "Loads Shapes files")
(@arg snd: -n --snd [file]... {exists} "Loads Sounds files"))
};
let opt =
clap_app!((env!("CARGO_PKG_NAME")) =>
(version: env!("CARGO_PKG_VERSION"))
(author: env!("CARGO_PKG_AUTHORS"))
(about: env!("CARGO_PKG_DESCRIPTION"))
let opt = clap_app! {
(env!("CARGO_PKG_NAME")) =>
(version: maraiah::meta::version())
(author: maraiah::meta::authors().replace(':', ", "))
(about: maraiah::meta::description())
(setting: clap::AppSettings::SubcommandRequiredElseHelp)
(subcommand: sub_data)
(subcommand: sub_dump)
(subcommand: sub_info));
(subcommand: sub_info)
};
let opt = opt.get_matches();
@ -137,6 +155,7 @@ fn main() -> ResultS<()>
("info", Some(opt)) => sub_info_c(opt)?,
_ => unreachable!(),
}
*/
Ok(())
}

View File

@ -6,98 +6,133 @@ use std::{convert::{TryFrom, TryInto}, fmt, num::NonZeroU16};
#[doc(hidden)]
#[macro_export]
macro_rules! rd_impl {
// worker - creates let statement
// worker, creates let statement for 16 bit numbers
(W $b:expr, $pth:path, $nam:ident, $n:expr) => {
let $nam = $pth([$b[$n], $b[$n + 1]]);
};
// worker, creates let statement for 32 bit numbers
(D $b:expr, $pth:path, $nam:ident, $n:expr) => {
let $nam = $pth([$b[$n], $b[$n + 1], $b[$n + 2], $b[$n + 3]]);
};
// big endian
// big endian, u16
(BIG, $b:expr, $at:expr, $n:expr; $nam:ident, u16) => {
$crate::rd_impl!(W $b, u16::from_be_bytes, $nam, $n + $at);
};
// big endian, i16
(BIG, $b:expr, $at:expr, $n:expr; $nam:ident, i16) => {
$crate::rd_impl!(W $b, i16::from_be_bytes, $nam, $n + $at);
};
// big endian, u32
(BIG, $b:expr, $at:expr, $n:expr; $nam:ident, u32) => {
$crate::rd_impl!(D $b, u32::from_be_bytes, $nam, $n + $at);
};
// big endian, i32
(BIG, $b:expr, $at:expr, $n:expr; $nam:ident, i32) => {
$crate::rd_impl!(D $b, i32::from_be_bytes, $nam, $n + $at);
};
// little endian
// little endian, u16
(LITTLE, $b:expr, $at:expr, $n:expr; $nam:ident, u16) => {
$crate::rd_impl!(W $b, u16::from_le_bytes, $nam, $n + $at);
};
// little endian, i16
(LITTLE, $b:expr, $at:expr, $n:expr; $nam:ident, i16) => {
$crate::rd_impl!(W $b, i16::from_le_bytes, $nam, $n + $at);
};
// little endian, u32
(LITTLE, $b:expr, $at:expr, $n:expr; $nam:ident, u32) => {
$crate::rd_impl!(D $b, u32::from_le_bytes, $nam, $n + $at);
};
// little endian, i32
(LITTLE, $b:expr, $at:expr, $n:expr; $nam:ident, i32) => {
$crate::rd_impl!(D $b, i32::from_le_bytes, $nam, $n + $at);
};
// either endianness
// either endianness, Angle
($e:ident, $b:expr, $at:expr, $n:expr; $nam:ident, Angle) => {
$crate::rd_impl!($e, $b, $at, $n; $nam, u16);
let $nam = Angle::from_bits($nam);
let $nam = $crate::fixed::Angle::from_bits($nam);
};
// either endianness, Fixed
($e:ident, $b:expr, $at:expr, $n:expr; $nam:ident, Fixed) => {
$crate::rd_impl!($e, $b, $at, $n; $nam, u32);
let $nam = Fixed::from_bits($nam);
let $nam = $crate::fixed::Fixed::from_bits($nam);
};
// either endianness, Unit
($e:ident, $b:expr, $at:expr, $n:expr; $nam:ident, Unit) => {
$crate::rd_impl!($e, $b, $at, $n; $nam, u16);
let $nam = Unit::from_bits($nam);
let $nam = $crate::fixed::Unit::from_bits($nam);
};
// either endianness, OptU16
($e:ident, $b:expr, $at:expr, $n:expr; $nam:ident, OptU16) => {
$crate::rd_impl!($e, $b, $at, $n; $nam, u16);
let $nam = OptU16::from($nam);
let $nam = $crate::bin::OptU16::from($nam);
};
// either endianness, u16 -> usize
($e:ident, $b:expr, $at:expr, $n:expr; $nam:ident, usize, u16) => {
$crate::rd_impl!($e, $b, $at, $n; $nam, u16);
let $nam = usize::from($nam);
};
// either endianness, u32 -> usize
($e:ident, $b:expr, $at:expr, $n:expr; $nam:ident, usize, u32) => {
$crate::rd_impl!($e, $b, $at, $n; $nam, u32);
let $nam = usize_from_u32($nam);
let $nam = $crate::bin::usize_from_u32($nam);
};
// either endianness, enum type with TryFrom
($e:ident, $b:expr, $at:expr, $n:expr;
$nam:ident, enum, $et:ident$(::$etc:ident)*, $t:ident
) => {
$nam:ident, enum, $et:ident$(::$etc:ident)*, $t:ident) => {
$crate::rd_impl!($e, $b, $at, $n; $nam, $t);
let $nam = $et$(::$etc)*::try_from($nam)?;
let $nam: $et$(::$etc)* = std::convert::TryFrom::try_from($nam)?;
};
// either endianness, bitflag type
($e:ident, $b:expr, $at:expr, $n:expr;
$nam:ident, flag, $ft:ident$(::$ftc:ident)*, $t:ident
) => {
$nam:ident, flag, $ft:ident$(::$ftc:ident)*, $t:ident) => {
$crate::rd_impl!($e, $b, $at, $n; $nam, $t);
let $nam = flag_ok!($ft$(::$ftc)*, $nam)?;
};
// no endianness
// no endianness, u8
($_:ident, $b:expr, $at:expr, $n:expr; $nam:ident, u8) => {
let $nam = $b[$n + $at];
};
// no endianness, i8
($_:ident, $b:expr, $at:expr, $n:expr; $nam:ident, i8) => {
let $nam = $b[$n + $at] as i8;
};
// no endianness, [u8]
($_:ident, $b:expr, $at:expr, $n:expr; $rn:expr; $nam:ident, u8) => {
let $nam = &$b[$n + $at..$n + $at + $rn];
};
// no endianness, Ident
($_:ident, $b:expr, $at:expr, $n:expr; $nam:ident, Ident) => {
$crate::rd_impl!(D $b, Ident, $nam, $n + $at);
};
// no endianness, fn([u8]) -> T
($_:ident, $b:expr, $at:expr, $n:expr; $rn:expr;
$nam:ident, no_try, $f:expr
) => {
$nam:ident, no_try, $f:expr) => {
let $nam = $f(&$b[$n + $at..$n + $at + $rn]);
};
// no endianness, fn([u8]) -> Result<T>
($_:ident, $b:expr, $at:expr, $n:expr; $rn:expr; $nam:ident, $f:expr) => {
let $nam = $f(&$b[$n + $at..$n + $at + $rn])?;
};
@ -524,7 +559,7 @@ impl OptU16
}
}
impl fmt::Debug for OptU16
impl fmt::Display for OptU16
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
@ -535,6 +570,17 @@ impl fmt::Debug for OptU16
}
}
impl fmt::Debug for OptU16
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
match self.get() {
None => write!(f, "OptU16::none()"),
Some(n) => write!(f, "OptU16::from({})", n),
}
}
}
impl PartialEq<[u8; 4]> for Ident
{
#[inline]

View File

@ -16,7 +16,6 @@
/// use std::convert::TryFrom;
///
/// c_enum! {
/// #[derive(Debug)]
/// enum MyEnum: u16
/// {
/// Zero = 0,
@ -43,7 +42,7 @@ macro_rules! c_enum
}
) => {
$(#[$outer])*
#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
#[repr($ti)]
$vi enum $t
{
@ -74,7 +73,6 @@ mod test
use std::convert::TryFrom;
c_enum! {
#[derive(Debug)]
enum TestEnum: u16
{
Zero = 0,

View File

@ -8,7 +8,7 @@ macro_rules! ok {
($v:expr, $msg:expr) => {
match $v {
Some(v) => Ok(v),
None => Err(err_msg($msg)),
None => Err($crate::err::err_msg($msg)),
}
};
}
@ -17,14 +17,14 @@ macro_rules! flag_ok {
($t:ident$(::$tc:ident)*, $v:expr) => {
match $t$(::$tc)*::from_bits($v) {
Some(v) => Ok(v),
None => Err(err_msg(concat!("bad ", stringify!($t)))),
None => Err($crate::err::err_msg(concat!("bad ", stringify!($t)))),
}
};
}
macro_rules! bail {
($e:expr) => {
return Err(err_msg($e));
return Err($crate::err::err_msg($e));
};
}

View File

@ -588,7 +588,9 @@ macro_rules! define_fixed_types {
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
fmt::Display::fmt(self, f)
write!(f,
concat!(stringify!($t), "::from_bits({})"),
self.to_bits())
}
}
)*};

View File

@ -1,7 +1,6 @@
//! QuickDraw PICT `PixMap` headers.
use crate::{bin::*, err::*, image::*};
use std::convert::TryFrom;
/// Reads a `PixMap` header.
pub fn read<'a>(b: &'a [u8],

39
maraiah/map.rs Normal file
View File

@ -0,0 +1,39 @@
//! Marathon Map format handling.
pub mod ambi;
pub mod attk;
pub mod bonk;
pub mod damg;
pub mod data;
pub mod entr;
pub mod epnt;
pub mod fxpx;
pub mod head;
pub mod iidx;
pub mod lins;
pub mod lite;
pub mod ltfn;
pub mod medi;
pub mod minf;
pub mod mnpx;
pub mod name;
pub mod note;
pub mod objs;
pub mod plac;
pub mod plat;
pub mod pnts;
pub mod poly;
pub mod prpx;
pub mod pxpx;
pub mod sids;
pub mod stex;
pub mod term;
pub mod trig;
pub mod trmf;
pub mod trmg;
pub mod wppx;
/// The number of game ticks per second.
pub const TICKS_PER_SECOND: u16 = 30;
// EOF

View File

@ -17,7 +17,7 @@ pub fn read(b: &[u8]) -> ResultS<(SoundAmbi, usize)>
/// An ambient sound definition.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SoundAmbi
{
pub index: u16,

View File

@ -27,7 +27,7 @@ pub fn read(b: &[u8]) -> ResultS<(SoundRand, usize)>
/// A randomly played sound definition.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SoundRand
{
pub flags: SoundRandFlags,

View File

@ -2,7 +2,6 @@
use crate::{err::*, fixed::Fixed};
use bitflags::bitflags;
use std::convert::TryFrom;
/// Reads a `Damage` object.
pub fn read(b: &[u8]) -> ResultS<Damage>
@ -76,7 +75,6 @@ bitflags! {
c_enum! {
/// A named type of damage taken by something.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug)]
pub enum DamageType: u16
{
Explosion = 0,

114
maraiah/map/data.rs Normal file
View File

@ -0,0 +1,114 @@
//! Map file entry data.
use crate::{bin::*, err::*, image::{self, pict}, map};
use super::{entr, head};
use std::collections::BTreeMap;
/// Reads all chunks in an entry.
pub fn read(head: &head::Header, b: &[u8]) -> ResultS<EntryData>
{
let mut data = EntryData::default();
let old = head.old_data();
let rd_cminf = if old {map::minf::read_old} else {map::minf::read};
let rd_csids = if old {map::sids::read_old} else {map::sids::read};
let rd_cpoly = if old {map::poly::read_old} else {map::poly::read};
let rd_clite = if old {map::lite::read_old} else {map::lite::read};
let mut p = 0;
while p < b.len() {
read_data! {
endian: BIG, buf: b, size: head.size_chunk(), start: p, data {
let iden = Ident[0];
let size = u32[8] usize;
}
}
let beg = p + head.size_chunk();
let end = beg + size;
let buf = ok!(b.get(beg..end), "not enough data")?;
match &iden.0 {
b"EPNT" => data.epnt = Some(rd_array(buf, map::epnt::read)?),
b"FXpx" => data.fxpx = Some(rd_array(buf, map::fxpx::read)?),
b"LINS" => data.lins = Some(rd_array(buf, map::lins::read)?),
b"LITE" => data.lite = Some(rd_array(buf, rd_clite)?),
b"MNpx" => data.mnpx = Some(rd_array(buf, map::mnpx::read)?),
b"Minf" => data.minf = Some(rd_cminf(buf)?),
b"NAME" => data.name = Some(rd_array(buf, map::name::read)?),
b"NOTE" => data.note = Some(rd_array(buf, map::note::read)?),
b"OBJS" => data.objs = Some(rd_array(buf, map::objs::read)?),
b"PICT" => data.pict = Some(pict::read(buf)?),
b"PNTS" => data.pnts = Some(rd_array(buf, map::pnts::read)?),
b"POLY" => data.poly = Some(rd_array(buf, rd_cpoly)?),
b"PRpx" => data.prpx = Some(rd_array(buf, map::prpx::read)?),
b"PXpx" => data.pxpx = Some(rd_array(buf, map::pxpx::read)?),
b"SIDS" => data.sids = Some(rd_array(buf, rd_csids)?),
b"WPpx" => data.wppx = Some(rd_array(buf, map::wppx::read)?),
b"ambi" => data.ambi = Some(rd_array(buf, map::ambi::read)?),
b"bonk" => data.bonk = Some(rd_array(buf, map::bonk::read)?),
b"iidx" => data.iidx = Some(rd_array(buf, map::iidx::read)?),
b"medi" => data.medi = Some(rd_array(buf, map::medi::read)?),
b"plac" => data.plac = Some(rd_array(buf, map::plac::read)?),
b"plat" => data.plat = Some(rd_array(buf, map::plat::read)?),
b"term" => data.term = Some(rd_array(buf, map::term::read)?),
_ => data.unkn.push((iden, buf.to_vec())),
}
p = end;
}
Ok(data)
}
/// Reads all of the data from an entry map.
pub fn read_all(head: &head::Header,
map: &entr::EntryMap<'_>) -> ResultS<EntryDataMap>
{
let mut dmap = EntryDataMap::new();
for (&index, entry) in map {
dmap.insert(index, read(head, &entry.data)?);
}
Ok(dmap)
}
/// The loaded data of a Map file entry.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Default, Eq, PartialEq)]
pub struct EntryData
{
/** `EPNT` chunk data. */ pub epnt: Option<Vec<map::epnt::Endpoint>>,
/** `FXpx` chunk data. */ pub fxpx: Option<Vec<map::fxpx::Effect>>,
/** `LINS` chunk data. */ pub lins: Option<Vec<map::lins::Line>>,
/** `LITE` chunk data. */ pub lite: Option<Vec<map::lite::Light>>,
/** `MNpx` chunk data. */ pub mnpx: Option<Vec<map::mnpx::Monster>>,
/** `Minf` chunk data. */ pub minf: Option<map::minf::Info>,
/** `NAME` chunk data. */ pub name: Option<Vec<String>>,
/** `NOTE` chunk data. */ pub note: Option<Vec<map::note::Note>>,
/** `OBJS` chunk data. */ pub objs: Option<Vec<map::objs::Object>>,
/** `PICT` chunk data. */ pub pict: Option<image::Image8>,
/** `PNTS` chunk data. */ pub pnts: Option<Vec<map::pnts::Point>>,
/** `POLY` chunk data. */ pub poly: Option<Vec<map::poly::Polygon>>,
/** `PRpx` chunk data. */ pub prpx: Option<Vec<map::prpx::Projectile>>,
/** `PXpx` chunk data. */ pub pxpx: Option<Vec<map::pxpx::Physics>>,
/** `SIDS` chunk data. */ pub sids: Option<Vec<map::sids::Side>>,
/** `WPpx` chunk data. */ pub wppx: Option<Vec<map::wppx::Weapon>>,
/** `ambi` chunk data. */ pub ambi: Option<Vec<map::ambi::SoundAmbi>>,
/** `bonk` chunk data. */ pub bonk: Option<Vec<map::bonk::SoundRand>>,
/** `iidx` chunk data. */ pub iidx: Option<Vec<u16>>,
/** `medi` chunk data. */ pub medi: Option<Vec<map::medi::Media>>,
/** `plac` chunk data. */ pub plac: Option<Vec<map::plac::ObjectFreq>>,
/** `plat` chunk data. */ pub plat: Option<Vec<map::plat::Platform>>,
/** `term` chunk data. */ pub term: Option<Vec<map::term::Terminal>>,
pub unkn: Vec<(Ident, Vec<u8>)>,
}
/// A map of indexed entries.
pub type EntryDataMap = BTreeMap<u16, EntryData>;
// EOF

60
maraiah/map/entr.rs Normal file
View File

@ -0,0 +1,60 @@
//! Map file entry type.
use crate::err::*;
use super::head;
use std::collections::BTreeMap;
/// Read an entry from a Map file.
pub fn read(map: &head::Map, i: usize) -> ResultS<(u16, Entry<'_>)>
{
let size = map.head().size_entry();
read_data! {
endian: BIG, buf: map.dir(), size: size, start: size * i, data {
let offset = u32[0] usize;
let dsize = u32[4] usize;
let index = u16[8];
let app_data = u8[10; map.head().size_appl()];
}
}
let data = &map.data()[offset..offset + dsize];
let index = if map.head().old_wad() {i as u16} else {index};
Ok((index, Entry{data, app_data}))
}
/// Reads all entries in a Map file.
pub fn read_all(map: &head::Map) -> ResultS<EntryMap<'_>>
{
let mut entries = EntryMap::new();
for i in 0..map.num_ent() {
let (index, entry) = read(map, i)?;
if entries.contains_key(&index) {
bail!("entry index already exists");
}
entries.insert(index, entry);
}
Ok(entries)
}
/// An entry containing chunked data and application-specific data.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
pub struct Entry<'a>
{
/// The data in this `Entry`.
pub data: &'a [u8],
/// The application specific data for this Entry.
pub app_data: &'a [u8],
}
/// A map of indexed entries.
pub type EntryMap<'a> = BTreeMap<u16, Entry<'a>>;
// EOF

147
maraiah/map/head.rs Normal file
View File

@ -0,0 +1,147 @@
//! Map file header.
use crate::{err::*, text::mac_roman_cstr};
use std::io::prelude::*;
/// Reads a Map file.
pub fn read(rd: &mut impl Read) -> ResultS<Map>
{
let mut data = Vec::new();
rd.read_to_end(&mut data)?;
read_data! {
endian: BIG, buf: &data, size: 128, start: 0, data {
let ver_wad = u16[0] enum Ver;
let ver_data = u16[2];
let name = mac_roman_cstr[4; 64] no_try;
let dir_ofs = u32[72] usize;
let num_ent = u16[76] usize;
let size_appl = u16[78] usize;
let size_wcnk = u16[80] usize;
let size_went = u16[82] usize;
}
}
let head = Header::new(size_appl, ver_data, ver_wad, Some(name));
if !head.old_wad() && head.size_entry_base() != size_went {
bail!("invalid entry size");
}
if !head.old_wad() && head.size_chunk() != size_wcnk {
bail!("invalid chunk size");
}
let map = Map{head, data, dir_ofs, num_ent};
if map.dir_end() > map.data.len() {
bail!("not enough data in map file");
}
Ok(map)
}
impl Header
{
/// Creates a new `Header`.
pub fn new(size_appl: usize,
ver_data: u16,
ver_wad: Ver,
name: Option<String>) -> Self
{
let name = name.unwrap_or(String::new());
Header{name, size_appl, ver_data, ver_wad}
}
/// Returns `true` if the data is in Marathon 1 format.
#[inline]
pub fn old_data(&self) -> bool {self.ver_data() == 0}
/// Returns `true` if the Map file is in Marathon 1 format.
#[inline]
pub fn old_wad(&self) -> bool {self.ver_wad() == Ver::Base}
/// The data version of this file.
#[inline]
pub const fn ver_data(&self) -> u16 {self.ver_data}
/// The format version of this file.
#[inline]
pub const fn ver_wad(&self) -> Ver {self.ver_wad}
/// The size of each `Entry`'s `appdata` field.
#[inline]
pub const fn size_appl(&self) -> usize {self.size_appl}
/// The size of each `Entry`'s data.
#[inline]
pub fn size_entry_base(&self) -> usize {if self.old_wad() {8} else {10}}
/// The size of each `Entry`.
#[inline]
pub fn size_entry(&self) -> usize {self.size_entry_base() + self.size_appl()}
/// The size of each chunk's header.
#[inline]
pub fn size_chunk(&self) -> usize {if self.old_wad() {12} else {16}}
}
impl Map
{
/// The header for this map.
pub fn head(&self) -> &Header {&self.head}
/// The data section of this map.
pub fn data(&self) -> &[u8] {&self.data[..]}
/// The directory section of this map.
pub fn dir(&self) -> &[u8] {&self.data[self.dir_beg()..self.dir_end()]}
/// The number of entries in the directory.
pub fn num_ent(&self) -> usize {self.num_ent}
fn dir_beg(&self) -> usize {self.dir_ofs}
fn dir_end(&self) -> usize
{
self.dir_ofs + self.head.size_entry() * self.num_ent
}
}
/// A Map header.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
pub struct Header
{
/// The original name of this file.
pub name: String,
size_appl: usize,
ver_data: u16,
ver_wad: Ver,
}
/// A Map file.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
pub struct Map
{
head: Header,
data: Vec<u8>,
dir_ofs: usize,
num_ent: usize,
}
c_enum! {
/// The version of a Map file.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub enum Ver: u16
{
Base = 0,
Dir = 1,
Over = 2,
Inf = 4,
}
}
// EOF

View File

@ -23,7 +23,7 @@ pub fn read(b: &[u8]) -> ResultS<(Line, usize)>
/// A line segment.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Line
{
pub flags: LineFlags,

View File

@ -3,7 +3,6 @@
use super::{ltfn, TICKS_PER_SECOND};
use crate::{err::*, fixed::Fixed};
use bitflags::bitflags;
use std::convert::TryFrom;
/// Reads a `LITE` chunk.
pub fn read(b: &[u8]) -> ResultS<(Light, usize)>
@ -73,7 +72,7 @@ pub fn read_old(b: &[u8]) -> ResultS<(Light, usize)>
/// A dynamic polygon light.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Light
{
pub ltype: LightType,
@ -102,7 +101,6 @@ bitflags! {
c_enum! {
/// The type of a `Light`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug)]
pub enum LightType: u16
{
Normal = 0,

View File

@ -1,7 +1,6 @@
//! `LightFunc` type.
use crate::{err::*, fixed::Fixed};
use std::convert::TryFrom;
/// Reads a `LightFunc` object.
pub fn read(b: &[u8]) -> ResultS<LightFunc>
@ -33,7 +32,7 @@ pub fn write(v: &LightFunc) -> Vec<u8>
/// A light function.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct LightFunc
{
pub ftype: LightFuncType,
@ -46,7 +45,6 @@ pub struct LightFunc
c_enum! {
/// The type of function for a `LightFunc`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug)]
pub enum LightFuncType: u16
{
Constant = 0,

View File

@ -6,7 +6,6 @@ use crate::{bin::OptU16,
fixed::{Angle, Fixed, Unit},
xfer::TransferMode};
use bitflags::bitflags;
use std::convert::TryFrom;
/// Reads a `medi` chunk.
pub fn read(b: &[u8]) -> ResultS<(Media, usize)>
@ -34,7 +33,7 @@ pub fn read(b: &[u8]) -> ResultS<(Media, usize)>
/// A media, as in a part of a polygon which goes up the middle of the wall.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Media
{
pub mtype: MediaType,
@ -54,7 +53,6 @@ pub struct Media
c_enum! {
/// The liquid type of a `Media`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug)]
pub enum MediaType: u16
{
Water = 0,

View File

@ -11,10 +11,10 @@ pub fn read(b: &[u8]) -> ResultS<Info>
let texture_id = u16[0];
let physics_id = u16[2];
let skypict_id = u16[4];
let miss_flags = u16[6] flag MsnFlags;
let envi_flags = u16[8] flag EnvFlags;
let miss_flags = u16[6] flag MissionFlags;
let envi_flags = u16[8] flag EnvironmentFlags;
let level_name = mac_roman_cstr[18; 66] no_try;
let entr_flags = u32[84] flag EntFlags;
let entr_flags = u32[84] flag EntryFlags;
}
}
@ -42,13 +42,13 @@ pub fn read_old(b: &[u8]) -> ResultS<Info>
let minf = read(b)?;
let mut entr_flags = if minf.entr_flags.is_empty() {
EntFlags::SOLO
EntryFlags::SOLO
} else {
minf.entr_flags
};
if entr_flags.intersects(EntFlags::SOLO | EntFlags::CARNAGE) {
entr_flags.insert(EntFlags::CO_OP)
if entr_flags.intersects(EntryFlags::SOLO | EntryFlags::CARNAGE) {
entr_flags.insert(EntryFlags::CO_OP)
}
Ok(Info{entr_flags, ..minf})
@ -61,9 +61,9 @@ impl Default for Info
Self{texture_id: 0,
physics_id: 1,
skypict_id: 0,
miss_flags: MsnFlags::empty(),
envi_flags: EnvFlags::empty(),
entr_flags: EntFlags::SOLO,
miss_flags: MissionFlags::empty(),
envi_flags: EnvironmentFlags::empty(),
entr_flags: EntryFlags::SOLO,
level_name: "Map".to_string()}
}
}
@ -76,16 +76,16 @@ pub struct Info
pub texture_id: u16,
pub physics_id: u16,
pub skypict_id: u16,
pub miss_flags: MsnFlags,
pub envi_flags: EnvFlags,
pub entr_flags: EntFlags,
pub miss_flags: MissionFlags,
pub envi_flags: EnvironmentFlags,
pub entr_flags: EntryFlags,
pub level_name: String,
}
bitflags! {
/// Static environment flags.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct EnvFlags: u16
pub struct EnvironmentFlags: u16
{
const VACUUM = 1;
const MAGNETIC = 1 << 1;
@ -104,7 +104,7 @@ bitflags! {
bitflags! {
/// Static entry point flags.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct EntFlags: u32
pub struct EntryFlags: u32
{
const SOLO = 1;
const CO_OP = 1 << 1;
@ -120,7 +120,7 @@ bitflags! {
bitflags! {
/// Static mission flags.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct MsnFlags: u16
pub struct MissionFlags: u16
{
const EXTERMINATION = 1;
const EXPLORATION = 1 << 1;

View File

@ -19,7 +19,7 @@ pub fn read(b: &[u8]) -> ResultS<(Note, usize)>
/// Overhead map annotations.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Note
{
pub pos: pnts::Point,

View File

@ -29,7 +29,7 @@ pub fn read(b: &[u8]) -> ResultS<(Object, usize)>
/// An object in the world.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Object
{
pub group: u16,

View File

@ -22,7 +22,7 @@ pub fn read(b: &[u8]) -> ResultS<(ObjectFreq, usize)>
/// The difficulty definition for various object types.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ObjectFreq
{
pub flags: ObjectFreqFlags,

View File

@ -24,7 +24,7 @@ pub fn read(b: &[u8]) -> ResultS<(Platform, usize)>
/// Extra information for polygons with platforms.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Platform
{
pub ptype: u16,

View File

@ -3,7 +3,6 @@
use super::pnts;
use crate::{bin::OptU16, err::*, fixed::Unit, xfer::TransferMode};
use bitflags::bitflags;
use std::convert::TryFrom;
/// Reads a polygon for either M1 or M2.
pub fn read_poly_inter(b: &[u8]) -> ResultS<Polygon>
@ -43,7 +42,7 @@ pub fn read(b: &[u8]) -> ResultS<(Polygon, usize)>
}
let poly = read_poly_inter(b)?;
let ptype = PolyType::new(ptype, pdata)?;
let ptype = PolygonType::new(ptype, pdata)?;
Ok((Polygon{ptype, ori_flr, ori_cei, med_ind, med_ctl, snd_ind, snd_amb,
snd_rnd, ..poly}, 128))
@ -60,81 +59,81 @@ pub fn read_old(b: &[u8]) -> ResultS<(Polygon, usize)>
}
let poly = read_poly_inter(b)?;
let ptype = PolyType::new_old(ptype, pdata)?;
let ptype = PolygonType::new_old(ptype, pdata)?;
Ok((Polygon{ptype, ..poly}, 128))
}
impl PolyType
impl PolygonType
{
/// Creates a `PolyType` from a `n`/`pdata` pair.
/// Creates a `PolygonType` from a `n`/`pdata` pair.
pub fn new(n: u16, pdata: u16) -> Result<Self, ReprError>
{
match n {
0 => Ok(PolyType::Normal),
1 => Ok(PolyType::ImpassItem),
2 => Ok(PolyType::ImpassMons),
3 => Ok(PolyType::Hill),
4 => Ok(PolyType::Base),
5 => Ok(PolyType::Platform(pdata)),
6 => Ok(PolyType::TrigLightOn(pdata)),
7 => Ok(PolyType::TrigPlatOn(pdata)),
8 => Ok(PolyType::TrigLightOff(pdata)),
9 => Ok(PolyType::TrigPlatOff(pdata)),
10 => Ok(PolyType::Teleporter(pdata)),
11 => Ok(PolyType::ZoneBorder),
12 => Ok(PolyType::Goal),
13 => Ok(PolyType::TrigMonsVis),
14 => Ok(PolyType::TrigMonsInv),
15 => Ok(PolyType::TrigMonsDual),
16 => Ok(PolyType::TrigItems),
17 => Ok(PolyType::MustExplore),
18 => Ok(PolyType::AutoExit),
19 => Ok(PolyType::OuchMinor),
20 => Ok(PolyType::OuchMajor),
21 => Ok(PolyType::Glue),
22 => Ok(PolyType::GlueTrigger(pdata)),
23 => Ok(PolyType::GlueSuper),
0 => Ok(PolygonType::Normal),
1 => Ok(PolygonType::ImpassItem),
2 => Ok(PolygonType::ImpassMons),
3 => Ok(PolygonType::Hill),
4 => Ok(PolygonType::Base),
5 => Ok(PolygonType::Platform(pdata)),
6 => Ok(PolygonType::TrigLightOn(pdata)),
7 => Ok(PolygonType::TrigPlatOn(pdata)),
8 => Ok(PolygonType::TrigLightOff(pdata)),
9 => Ok(PolygonType::TrigPlatOff(pdata)),
10 => Ok(PolygonType::Teleporter(pdata)),
11 => Ok(PolygonType::ZoneBorder),
12 => Ok(PolygonType::Goal),
13 => Ok(PolygonType::TrigMonsVis),
14 => Ok(PolygonType::TrigMonsInv),
15 => Ok(PolygonType::TrigMonsDual),
16 => Ok(PolygonType::TrigItems),
17 => Ok(PolygonType::MustExplore),
18 => Ok(PolygonType::AutoExit),
19 => Ok(PolygonType::OuchMinor),
20 => Ok(PolygonType::OuchMajor),
21 => Ok(PolygonType::Glue),
22 => Ok(PolygonType::GlueTrigger(pdata)),
23 => Ok(PolygonType::GlueSuper),
n => Err(ReprError::new(n)),
}
}
/// Creates a `PolyType` from a Marathon 1 compatible `n`/`pdata` pair.
/// Creates a `PolygonType` from a Marathon 1 compatible `n`/`pdata` pair.
fn new_old(n: u16, pdata: u16) -> Result<Self, ReprError>
{
match n {
0 => Ok(PolyType::Normal),
1 => Ok(PolyType::ImpassItem),
2 => Ok(PolyType::ImpassMons),
3 => Ok(PolyType::OuchMinor),
4 => Ok(PolyType::OuchMajor),
5 => Ok(PolyType::Platform(pdata)),
6 => Ok(PolyType::TrigLightOn(pdata)),
7 => Ok(PolyType::TrigPlatOn(pdata)),
8 => Ok(PolyType::TrigLightOff(pdata)),
9 => Ok(PolyType::TrigPlatOff(pdata)),
10 => Ok(PolyType::Teleporter(pdata)),
11 => Ok(PolyType::Glue),
12 => Ok(PolyType::GlueTrigger(pdata)),
13 => Ok(PolyType::GlueSuper),
14 => Ok(PolyType::MustExplore),
15 => Ok(PolyType::AutoExit),
0 => Ok(PolygonType::Normal),
1 => Ok(PolygonType::ImpassItem),
2 => Ok(PolygonType::ImpassMons),
3 => Ok(PolygonType::OuchMinor),
4 => Ok(PolygonType::OuchMajor),
5 => Ok(PolygonType::Platform(pdata)),
6 => Ok(PolygonType::TrigLightOn(pdata)),
7 => Ok(PolygonType::TrigPlatOn(pdata)),
8 => Ok(PolygonType::TrigLightOff(pdata)),
9 => Ok(PolygonType::TrigPlatOff(pdata)),
10 => Ok(PolygonType::Teleporter(pdata)),
11 => Ok(PolygonType::Glue),
12 => Ok(PolygonType::GlueTrigger(pdata)),
13 => Ok(PolygonType::GlueSuper),
14 => Ok(PolygonType::MustExplore),
15 => Ok(PolygonType::AutoExit),
n => Err(ReprError::new(n)),
}
}
}
impl Default for PolyType
impl Default for PolygonType
{
fn default() -> Self {PolyType::Normal}
fn default() -> Self {PolygonType::Normal}
}
/// A polygon segment.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Default, Eq, PartialEq)]
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Polygon
{
pub ptype: PolyType,
pub ptype: PolygonType,
pub tex_flr: OptU16,
pub tex_cei: OptU16,
pub hei_flr: Unit,
@ -154,8 +153,8 @@ pub struct Polygon
/// The action type of a `Polygon`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
pub enum PolyType
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum PolygonType
{
Normal,
ImpassItem,
@ -186,7 +185,7 @@ pub enum PolyType
bitflags! {
/// Flags for `Polygon`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct PolyFlags: u16
pub struct PolygonFlags: u16
{
const DETACHED = 1 << 14;
}

View File

@ -3,7 +3,6 @@
use super::stex;
use crate::{bin::OptU16, err::*, fixed::Fixed, xfer::TransferMode};
use bitflags::bitflags;
use std::convert::TryFrom;
/// Reads a `SIDS` chunk.
pub fn read(b: &[u8]) -> ResultS<(Side, usize)>
@ -41,7 +40,7 @@ pub fn read_old(b: &[u8]) -> ResultS<(Side, usize)>
/// One side of a line segment.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Side
{
pub stype: SideType,
@ -76,7 +75,6 @@ bitflags! {
c_enum! {
/// The texture type of a `Side`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug)]
pub enum SideType: u16
{
Full = 0,

View File

@ -27,7 +27,7 @@ pub fn write(v: &SideTex) -> Vec<u8>
/// The texture of a side segment.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SideTex
{
pub offs: pnts::Point,

View File

@ -1,7 +1,6 @@
//! `Monster` type.
use crate::{bin::OptU16, err::*, fixed::Unit};
use std::convert::TryFrom;
/// Reads a `Trigger` object.
pub fn read(b: &[u8]) -> ResultS<Trigger>
@ -62,7 +61,6 @@ pub struct Trigger
c_enum! {
/// A bullet shell casing emitted by a weapon.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug)]
pub enum CasingType: u16
{
Rifle = 0,

View File

@ -2,7 +2,6 @@
use crate::{bin::OptU16, err::*, fixed::Fixed};
use bitflags::bitflags;
use std::convert::TryFrom;
use super::trig;
@ -100,7 +99,6 @@ bitflags! {
c_enum! {
/// The type of functionality a weapon provides.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug)]
pub enum WeaponType: u16
{
Melee = 0,

50
maraiah/meta.rs Normal file
View File

@ -0,0 +1,50 @@
//! Meta-information of this crate.
macro_rules! meta_str {
($($(#[$outer:meta])* $name:ident = $e:expr;)*) => {
$($(#[$outer])* pub const fn $name() -> &'static str {$e})*
pub mod ffi
{
$(
doc_comment! {
concat!("FFI variant of [`",
stringify!($name),
"`]\n\n[`",
stringify!($name),
"`]: ../fn.",
stringify!($name),
".html"),
pub const fn $name() -> crate::ffi::NT {c_str!($e)}
}
)*
}
}
}
meta_str!(
/// The authors of this crate, `:` separated.
authors = env!("CARGO_PKG_AUTHORS");
/// The description of this crate.
description = env!("CARGO_PKG_DESCRIPTION");
/// The home page of this crate.
homepage = env!("CARGO_PKG_HOMEPAGE");
/// The full license text of this crate.
license_text = include_str!("../LICENSE");
/// The name of this crate.
name = env!("CARGO_PKG_NAME");
/// The repository of this crate.
repository = env!("CARGO_PKG_REPOSITORY");
/// The full version of this crate.
version = env!("CARGO_PKG_VERSION");
/// The major version of this crate.
version_major = env!("CARGO_PKG_VERSION_MAJOR");
/// The minor version of this crate.
version_minor = env!("CARGO_PKG_VERSION_MINOR");
/// The patch version of this crate.
version_patch = env!("CARGO_PKG_VERSION_PATCH");
/// The pre-release version of this crate.
version_pre = env!("CARGO_PKG_VERSION_PRE");
);
// EOF

View File

@ -1,8 +1,7 @@
//! Shapes file collection type.
use crate::{bin::{rd_ofstable, usize_from_u32}, err::*};
use crate::{bin::rd_ofstable, err::*};
use super::{bmap, clut, fram, sequ};
use std::convert::TryFrom;
/// Reads a `Collection`.
pub fn read(b: &[u8]) -> ResultS<Collection>
@ -58,7 +57,6 @@ pub struct Collection
c_enum! {
/// The type of a collection.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug)]
pub enum CollectionType: u16
{
Unused = 0,

View File

@ -3,7 +3,6 @@
use crate::{bin::OptU16, err::*,
text::{mac_roman_conv, pascal_str},
xfer::TransferMode};
use std::convert::TryFrom;
/// Reads a `Sequence`.
pub fn read(b: &[u8]) -> ResultS<Sequence>
@ -72,7 +71,6 @@ pub struct Sequence
c_enum! {
/// The type of or number of views for a sequence.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug)]
pub enum ViewType: u16
{
Anim = 1,

View File

@ -1,7 +1,6 @@
//! Sounds format definition type.
use crate::{bin::{u32b, usize_from_u32}, err::*, fixed::*, sound::Sound16};
use std::convert::TryFrom;
use bitflags::bitflags;
/// Reads a sound definition.
@ -90,7 +89,6 @@ bitflags! {
c_enum! {
/// The type of volume this sound has.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug)]
pub enum Volume: u16
{
Quiet = 0,

View File

@ -1,6 +1,6 @@
//! Sounds file audio type.
use crate::{bin::usize_from_u32, err::*, sound::Sound16};
use crate::{err::*, sound::Sound16};
/// Reads a sound.
pub fn read(b: &[u8]) -> ResultS<Sound16>

View File

@ -8,7 +8,6 @@ impl Default for TransferMode
c_enum! {
/// A rendering style for many things.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug)]
pub enum TransferMode: u16
{
Normal = 0,

View File

@ -1,17 +0,0 @@
[package]
name = "maraiah-leela"
version = "0.1.0"
authors = ["Alison Watson <marrub@greyserv.net>"]
description = "Maraiah testbed program."
edition = "2018"
[dependencies]
clap = "2"
maraiah = {path = "../..", features = ["serde_obj"]}
memmap = "0.7"
serde = "1.0"
serde_yaml = "0.8"
[[bin]]
name = "leela"
path = "main.rs"

View File

@ -1,107 +0,0 @@
//! Marathon Map format handling.
pub mod ambi;
pub mod attk;
pub mod bonk;
pub mod chnk;
pub mod damg;
pub mod entr;
pub mod epnt;
pub mod fxpx;
pub mod iidx;
pub mod lins;
pub mod lite;
pub mod ltfn;
pub mod medi;
pub mod minf;
pub mod mnpx;
pub mod name;
pub mod note;
pub mod objs;
pub mod plac;
pub mod plat;
pub mod pnts;
pub mod poly;
pub mod prpx;
pub mod pxpx;
pub mod sids;
pub mod stex;
pub mod term;
pub mod trig;
pub mod trmf;
pub mod trmg;
pub mod wppx;
use crate::{err::*, text::mac_roman_cstr};
use std::convert::TryFrom;
/// Reads a Map file.
pub fn read(b: &[u8]) -> ResultS<Wad>
{
read_data! {
endian: BIG, buf: b, size: 128, start: 0, data {
let ver_wad = u16[0] enum Ver;
let ver_dat = u16[2];
let name = mac_roman_cstr[4; 64] no_try;
let siz_app = u16[78] usize;
let siz_wcnk = u16[80] usize;
let siz_went = u16[82] usize;
}
}
let old_dat = ver_dat == 0;
let old_wad = match ver_wad {
Ver::Base => true,
_ => false,
};
let siz_ent = if old_wad {8 } else {10};
let siz_cnk = if old_wad {12} else {16};
if !old_wad && siz_ent != siz_went {
bail!("invalid entry size");
}
if !old_wad && siz_cnk != siz_wcnk {
bail!("invalid chunk size");
}
let entries = entr::read(b, old_wad, siz_app, siz_ent, siz_cnk)?;
Ok(Wad{name, siz_app, old_dat, entries})
}
/// A Map file containing entries.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
pub struct Wad
{
/// The original name of this file.
pub name: String,
/// The size of each `Entry`'s `appdata` field.
pub siz_app: usize,
/// If the data is in Marathon 1 format.
pub old_dat: bool,
/// All of the entries in this `Wad`.
pub entries: entr::EntryMap,
}
c_enum! {
// The version of a `Wad`.
#[derive(Debug)]
enum Ver: u16
{
Base = 0,
Dir = 1,
Over = 2,
Inf = 4,
}
}
/// The number of game ticks per second.
pub const TICKS_PER_SECOND: u16 = 30;
// EOF

View File

@ -1,120 +0,0 @@
//! Wad file chunk type.
use crate::{bin::*, err::*, image::{self, pict}, map};
/// Reads all chunks in an entry.
pub fn read(b: &[u8], siz_cnk: usize) -> ResultS<Vec<ChunkData>>
{
let mut chunks = Vec::new();
let mut p = 0;
while p < b.len() {
read_data! {
endian: BIG, buf: b, size: siz_cnk, start: p, data {
let iden = Ident[0];
let size = u32[8] usize;
}
}
let beg = p + siz_cnk;
let end = beg + size;
let data = ok!(b.get(beg..end), "not enough data")?.to_vec();
chunks.push(ChunkData{iden, data});
p = end;
}
Ok(chunks)
}
/// Loads structured data from chunk data.
pub fn load(chunk_data: &[ChunkData], old: bool) -> ResultS<Vec<Chunk>>
{
let mut chunks = Vec::new();
let read_chunk_minf = if old {map::minf::read_old} else {map::minf::read};
let read_chunk_sids = if old {map::sids::read_old} else {map::sids::read};
let read_chunk_poly = if old {map::poly::read_old} else {map::poly::read};
let read_chunk_lite = if old {map::lite::read_old} else {map::lite::read};
for chunk in chunk_data.iter() {
let data = &chunk.data;
let chunk = match &chunk.iden.0 {
b"EPNT" => Chunk::Epnt(rd_array(data, map::epnt::read)?),
b"FXpx" => Chunk::Fxpx(rd_array(data, map::fxpx::read)?),
b"LINS" => Chunk::Lins(rd_array(data, map::lins::read)?),
b"LITE" => Chunk::Lite(rd_array(data, read_chunk_lite)?),
b"MNpx" => Chunk::Mnpx(rd_array(data, map::mnpx::read)?),
b"Minf" => Chunk::Minf(read_chunk_minf(data)?),
b"NAME" => Chunk::Name(rd_array(data, map::name::read)?),
b"NOTE" => Chunk::Note(rd_array(data, map::note::read)?),
b"OBJS" => Chunk::Objs(rd_array(data, map::objs::read)?),
b"PICT" => Chunk::Pict(pict::read(data)?),
b"PNTS" => Chunk::Pnts(rd_array(data, map::pnts::read)?),
b"POLY" => Chunk::Poly(rd_array(data, read_chunk_poly)?),
b"PRpx" => Chunk::Prpx(rd_array(data, map::prpx::read)?),
b"PXpx" => Chunk::Pxpx(rd_array(data, map::pxpx::read)?),
b"SIDS" => Chunk::Sids(rd_array(data, read_chunk_sids)?),
b"WPpx" => Chunk::Wppx(rd_array(data, map::wppx::read)?),
b"ambi" => Chunk::Ambi(rd_array(data, map::ambi::read)?),
b"bonk" => Chunk::Bonk(rd_array(data, map::bonk::read)?),
b"iidx" => Chunk::Iidx(rd_array(data, map::iidx::read)?),
b"medi" => Chunk::Medi(rd_array(data, map::medi::read)?),
b"plac" => Chunk::Plac(rd_array(data, map::plac::read)?),
b"plat" => Chunk::Plat(rd_array(data, map::plat::read)?),
b"term" => Chunk::Term(rd_array(data, map::term::read)?),
_ => Chunk::Data(chunk.clone()),
};
chunks.push(chunk);
}
Ok(chunks)
}
/// The data of a Chunk read from a file.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ChunkData
{
/// The name of the chunk.
pub iden: Ident,
/// The data.
pub data: Vec<u8>,
}
/// Any kind of chunk in an `Entry`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
pub enum Chunk
{
/** `EPNT` chunks. */ Epnt(Vec<map::epnt::Endpoint>),
/** `FXpx` chunks. */ Fxpx(Vec<map::fxpx::Effect>),
/** `LINS` chunks. */ Lins(Vec<map::lins::Line>),
/** `LITE` chunks. */ Lite(Vec<map::lite::Light>),
/** `MNpx` chunks. */ Mnpx(Vec<map::mnpx::Monster>),
/** `Minf` chunks. */ Minf(map::minf::Info),
/** `NAME` chunks. */ Name(Vec<String>),
/** `NOTE` chunks. */ Note(Vec<map::note::Note>),
/** `OBJS` chunks. */ Objs(Vec<map::objs::Object>),
/** `PICT` chunks. */ Pict(image::Image8),
/** `PNTS` chunks. */ Pnts(Vec<map::pnts::Point>),
/** `POLY` chunks. */ Poly(Vec<map::poly::Polygon>),
/** `PRpx` chunks. */ Prpx(Vec<map::prpx::Projectile>),
/** `PXpx` chunks. */ Pxpx(Vec<map::pxpx::Physics>),
/** `SIDS` chunks. */ Sids(Vec<map::sids::Side>),
/** `WPpx` chunks. */ Wppx(Vec<map::wppx::Weapon>),
/** `ambi` chunks. */ Ambi(Vec<map::ambi::SoundAmbi>),
/** `bonk` chunks. */ Bonk(Vec<map::bonk::SoundRand>),
/** `iidx` chunks. */ Iidx(Vec<u16>),
/** `medi` chunks. */ Medi(Vec<map::medi::Media>),
/** `plac` chunks. */ Plac(Vec<map::plac::ObjectFreq>),
/** `plat` chunks. */ Plat(Vec<map::plat::Platform>),
/** `term` chunks. */ Term(Vec<map::term::Terminal>),
/** Unknown chunk. */ Data(ChunkData),
}
// EOF

View File

@ -1,61 +0,0 @@
//! Wad file entry type.
use crate::{bin::usize_from_u32, err::*};
use super::chnk;
use std::collections::BTreeMap;
/// Reads all entries in a `Wad`.
pub fn read(b: &[u8],
old_wad: bool,
siz_app: usize,
siz_ent: usize,
siz_cnk: usize) -> ResultS<EntryMap>
{
read_data! {
endian: BIG, buf: b, size: 128, start: 0, data {
let dirofs = u32[72] usize;
let numents = u16[76] usize;
}
}
let mut entries = EntryMap::new();
let mut p = dirofs;
for i in 0..numents {
read_data! {
endian: BIG, buf: b, size: siz_ent, start: p, data {
let offset = u32[0] usize;
let size = u32[4] usize;
let index = u16[8];
}
}
let index = if old_wad {i as u16} else {index};
let chunks = chnk::read(&b[offset..offset + size], siz_cnk)?;
let appdata = b[p..p + siz_app].to_vec();
entries.insert(index, Entry{chunks, appdata});
p += siz_ent + siz_app;
}
Ok(entries)
}
/// An entry containing chunks and application-specific data.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
pub struct Entry
{
/// All of the chunks in this `Entry`.
pub chunks: Vec<chnk::ChunkData>,
/// The application specific data for this Entry.
pub appdata: Vec<u8>,
}
/// A map of indexed entries.
pub type EntryMap = BTreeMap<u16, Entry>;
// EOF

View File

@ -1,51 +0,0 @@
//! Meta-information of this crate.
macro_rules! meta_str {
($($(#[$outer:meta])* $name:ident = $cname:ident = $e:expr;)*) => {
$(
$(#[$outer])* pub const $name: &'static str = $e;
)*
pub mod ffi
{
$(
doc_comment! {
concat!("FFI variant of [`",
stringify!($name),
"`]\n\n[`",
stringify!($name),
"`]: ../constant.",
stringify!($name),
".html"),
pub const $cname: crate::ffi::NT = c_str!($e);
}
)*
}
}
}
meta_str!(
/// The authors of this crate, `:` separated.
AUTHORS = AUTHORS_C = env!("CARGO_PKG_AUTHORS");
/// The description of this crate.
DESCRIPTION = DESCRIPTION_C = env!("CARGO_PKG_DESCRIPTION");
/// The home page of this crate.
HOMEPAGE = HOMEPAGE_C = env!("CARGO_PKG_HOMEPAGE");
/// The full license text of this crate.
LICENSE_TEXT = LICENSE_TEXT_C = include_str!("../LICENSE");
/// The name of this crate.
NAME = NAME_C = env!("CARGO_PKG_NAME");
/// The repository of this crate.
REPOSITORY = REPOSITORY_C = env!("CARGO_PKG_REPOSITORY");
/// The full version of this crate.
VERSION = VERSION_C = env!("CARGO_PKG_VERSION");
/// The major version of this crate.
VERSION_MAJOR = VERSION_MAJOR_C = env!("CARGO_PKG_VERSION_MAJOR");
/// The minor version of this crate.
VERSION_MINOR = VERSION_MINOR_C = env!("CARGO_PKG_VERSION_MINOR");
/// The patch version of this crate.
VERSION_PATCH = VERSION_PATCH_C = env!("CARGO_PKG_VERSION_PATCH");
/// The pre-release version of this crate.
VERSION_PRE = VERSION_PRE_C = env!("CARGO_PKG_VERSION_PRE");
);
// EOF

BIN
tests/data/m2/Map Normal file

Binary file not shown.

View File

@ -2,8 +2,8 @@ map::minf::Info{
texture_id: 0,
physics_id: 1,
skypict_id: 1,
miss_flags: map::minf::MsnFlags::REPAIR,
envi_flags: map::minf::EnvFlags::empty(),
entr_flags: map::minf::EntFlags::SOLO | map::minf::EntFlags::CO_OP,
miss_flags: map::minf::MissionFlags::REPAIR,
envi_flags: map::minf::EnvironmentFlags::empty(),
entr_flags: map::minf::EntryFlags::SOLO | map::minf::EntryFlags::CO_OP,
level_name: "Waterloo Waterpark".to_owned()
}

BIN
tests/data/map/testmap.in Normal file

Binary file not shown.

2185
tests/data/map/testmap.out Normal file

File diff suppressed because it is too large Load Diff

View File

@ -36,7 +36,7 @@ fn defl_alice_2()
fn defl_shapes()
{
const INPUT: &[u8] = include_bytes!("data/defl/Shapes.in");
const OUTPUT: &[u8] = include_bytes!("data/defl/Shapes.out");
const OUTPUT: &[u8] = include_bytes!("data/m2/Shapes");
defl_gzip(INPUT, OUTPUT);
}

View File

@ -51,25 +51,65 @@ fn read_term_must_process()
}
}
#[test]
fn map_m2()
{
let inp = include_bytes!("data/m2/Map");
let mut rd = std::io::BufReader::new(&inp[..]);
let mp = map::head::read(&mut rd).unwrap();
let en = map::entr::read_all(&mp).unwrap();
assert!(map::data::read_all(mp.head(), &en).is_ok());
}
#[test]
#[ignore]
fn map_full_check()
{
use maraiah::{bin::OptU16,
map::{data::*, lins::*, lite::*, ltfn::*, minf::*, objs::*,
plac::*, pnts::*, poly::*},
xfer::TransferMode};
use std::collections::BTreeMap;
let inp = include_bytes!("data/map/testmap.in");
let mut rd = std::io::BufReader::new(&inp[..]);
let mp = map::head::read(&mut rd).unwrap();
let en = map::entr::read_all(&mp).unwrap();
let ed = map::data::read_all(mp.head(), &en).unwrap();
let mut out = BTreeMap::new();
out.insert(0, include!("data/map/testmap.out"));
assert_eq!(out, ed);
}
#[test]
fn map_must_not_process()
{
for inp in &RANDOM {
map::minf::read(inp).err().unwrap();
map::minf::read_old(inp).err().unwrap();
bin::rd_array(inp, map::fxpx::read).err().unwrap();
bin::rd_array(inp, map::lins::read).err().unwrap();
bin::rd_array(inp, map::lite::read).err().unwrap();
bin::rd_array(inp, map::lite::read_old).err().unwrap();
bin::rd_array(inp, map::medi::read).err().unwrap();
bin::rd_array(inp, map::mnpx::read).err().unwrap();
bin::rd_array(inp, map::note::read).err().unwrap();
bin::rd_array(inp, map::objs::read).err().unwrap();
bin::rd_array(inp, map::plat::read).err().unwrap();
bin::rd_array(inp, map::poly::read).err().unwrap();
bin::rd_array(inp, map::poly::read_old).err().unwrap();
bin::rd_array(inp, map::prpx::read).err().unwrap();
bin::rd_array(inp, map::sids::read).err().unwrap();
bin::rd_array(inp, map::sids::read_old).err().unwrap();
bin::rd_array(inp, map::term::read).err().unwrap();
bin::rd_array(inp, map::trmg::read).err().unwrap();
bin::rd_array(inp, map::lite::read_old).err().unwrap();
bin::rd_array(inp, map::poly::read_old).err().unwrap();
bin::rd_array(inp, map::sids::read_old).err().unwrap();
bin::rd_array(inp, map::wppx::read).err().unwrap();
map::minf::read(inp).err().unwrap();
map::minf::read_old(inp).err().unwrap();
}
}
@ -82,27 +122,9 @@ fn map_must_not_panic()
drop(bin::rd_array(inp, map::epnt::read));
drop(bin::rd_array(inp, map::iidx::read));
drop(bin::rd_array(inp, map::plac::read));
drop(bin::rd_array(inp, map::pxpx::read));
drop(bin::rd_array(inp, map::trmf::read));
}
}
#[test]
fn phy_must_not_process()
{
for inp in &RANDOM {
bin::rd_array(inp, map::fxpx::read).err().unwrap();
bin::rd_array(inp, map::mnpx::read).err().unwrap();
bin::rd_array(inp, map::prpx::read).err().unwrap();
bin::rd_array(inp, map::wppx::read).err().unwrap();
}
}
#[test]
fn phy_must_not_panic()
{
for inp in &RANDOM {
drop(bin::rd_array(inp, map::pxpx::read));
}
}
// EOF

View File

@ -1,4 +1,4 @@
use maraiah::{image::{Color8, pict}};
use maraiah::image::{pict, Color8};
include!("data/rand.rs");

View File

@ -5,12 +5,11 @@ edition = "2018"
build = "build.rs"
[dependencies]
maraiah = {path = "../.."}
memmap = "0.7"
maraiah = {path = ".."}
[build-dependencies]
cmake = "0.1"
maraiah = {path = "../.."}
maraiah = {path = ".."}
rust_qt_binding_generator = "0.3"
[[bin]]

Some files were not shown because too many files have changed in this diff Show More