spaces->tabs

master
an 2019-07-05 23:21:11 -04:00
parent 8354207c75
commit e3eaeeec66
100 changed files with 8587 additions and 8590 deletions

View File

@ -5,34 +5,34 @@ err_bad_arg=1
err_bad_run=2 err_bad_run=2
rm_if() { rm_if() {
if [[ -d $1 ]]; if [[ -d $1 ]];
then then
rm -rf "$1" && echo "removed dir $1" rm -rf "$1" && echo "removed dir $1"
elif [[ -f $1 ]] elif [[ -f $1 ]]
then then
rm -f "$1" && echo "removed file $1" rm -f "$1" && echo "removed file $1"
fi fi
return 0 return 0
} }
perish() { perish() {
rm_if "${tmpdir}" rm_if "${tmpdir}"
exit "$1" exit "$1"
} }
err() { err() {
echo "error, dropping build" echo "error, dropping build"
rm_if "${appdir}" rm_if "${appdir}"
rm_if "${dmg}" rm_if "${dmg}"
perish $1 perish $1
} }
:() { :() {
echo "$@" echo "$@"
echo echo
eval "$@" || err ${err_bad_run} eval "$@" || err ${err_bad_run}
} }
declare -A icon_names=( declare -A icon_names=(
[Tycho]="resources/color/pfhor-hand.png" [Tycho]="resources/color/pfhor-hand.png"
) )
name=$1 name=$1
@ -40,14 +40,14 @@ exe=$2
if [[ ! $name ]] if [[ ! $name ]]
then then
echo "program name needed (available: Tycho)" echo "program name needed (available: Tycho)"
err ${err_bad_arg} err ${err_bad_arg}
fi fi
if [[ ! $exe ]] if [[ ! $exe ]]
then then
echo "full path to executable required (ex. '$0 $name ~/bin/maraiah-tycho')" echo "full path to executable required (ex. '$0 $name ~/bin/maraiah-tycho')"
err ${err_bad_arg} err ${err_bad_arg}
fi fi
app=${name}.app app=${name}.app
@ -89,25 +89,25 @@ dmg=${exedir}/${name}.dmg
while IFS= read -r lnk while IFS= read -r lnk
do do
lnk=$(dirname "${lnk}") lnk=$(dirname "${lnk}")
: cp -r "${lnk}" "${appdir}/Contents/Frameworks" : cp -r "${lnk}" "${appdir}/Contents/Frameworks"
done < "${exedir}"/build/maraiah-tycho-*/out/etc/link.txt done < "${exedir}"/build/maraiah-tycho-*/out/etc/link.txt
echo "success: bundle written to ${appdir}" echo "success: bundle written to ${appdir}"
if [[ ! "$NO_DMG" ]] if [[ ! "$NO_DMG" ]]
then then
echo "creating the disk image..." echo "creating the disk image..."
: rm_if "${dmg}" : rm_if "${dmg}"
: mkdir -p "${diskdir}" : mkdir -p "${diskdir}"
: cp -r "${appdir}" "${diskdir}" : cp -r "${appdir}" "${diskdir}"
: cp "${srcdir}/resources/Image.DS_Store" "${diskdir}/.DS_Store" : cp "${srcdir}/resources/Image.DS_Store" "${diskdir}/.DS_Store"
: ln -s /Applications "${diskdir}" : ln -s /Applications "${diskdir}"
: hdiutil create -volname "${name}" -srcfolder "${diskdir}" "${dmg}" : hdiutil create -volname "${name}" -srcfolder "${diskdir}" "${dmg}"
echo "success: dmg written to ${dmg}" echo "success: dmg written to ${dmg}"
fi fi
perish ${err_ok} perish ${err_ok}

View File

@ -6,158 +6,156 @@ use std::{collections::HashSet, fs, io, slice::from_ref};
/* /*
fn open(path: &str) -> ResultS<io::BufReader> fn open(path: &str) -> ResultS<io::BufReader>
{ {
let fp = fs::File::open(path)?; let fp = fs::File::open(path)?;
Ok(io::BufReader::new(fp)) Ok(io::BufReader::new(fp))
} }
fn file_read<T, F>(path: &str, f: F) -> ResultS<T> fn file_read<T, F>(path: &str, f: F) -> ResultS<T>
where F: FnOnce(&[u8]) -> ResultS<T> where F: FnOnce(&[u8]) -> ResultS<T>
{ {
let mm = open(path)?; let mm = open(path)?;
let bp = &mm[machdr::try_mac_header(&mm)..]; let bp = &mm[machdr::try_mac_header(&mm)..];
f(bp) f(bp)
} }
fn exists(path: String) -> Result<(), String> fn exists(path: String) -> Result<(), String>
{ {
match std::fs::metadata(path) { match std::fs::metadata(path) {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(e) => Err(e.to_string()), Err(e) => Err(e.to_string()),
} }
} }
fn each_value<F>(opt: &clap::ArgMatches<'_>, fn each_value<F>(opt: &clap::ArgMatches<'_>,
name: &str, name: &str,
mut f: F) mut f: F) -> ResultS<()>
-> ResultS<()> where F: FnMut(&str) -> ResultS<()>
where F: FnMut(&str) -> ResultS<()>
{ {
if let Some(values) = opt.values_of(name) { if let Some(values) = opt.values_of(name) {
for value in values { for value in values {
f(value)?; f(value)?;
} }
} }
Ok(()) Ok(())
} }
fn dbg_info(data: impl std::fmt::Debug) fn dbg_info(data: impl std::fmt::Debug)
{ {
println!("{:#?}", data); println!("{:#?}", data);
} }
fn dump_map(opt: &clap::ArgMatches<'_>, f: &str) -> ResultS<()> fn dump_map(opt: &clap::ArgMatches<'_>, f: &str) -> ResultS<()>
{ {
let mut cnks = HashSet::new(); let mut cnks = HashSet::new();
if let Some(opt_cnks) = opt.values_of("chunks") { if let Some(opt_cnks) = opt.values_of("chunks") {
for typ in opt_cnks { for typ in opt_cnks {
cnks.insert(typ); cnks.insert(typ);
} }
} }
Ok(()) Ok(())
} }
fn dump_shp(opt: &clap::ArgMatches<'_>, f: &str) -> ResultS<()> fn dump_shp(opt: &clap::ArgMatches<'_>, f: &str) -> ResultS<()>
{ {
unimplemented!(); unimplemented!();
} }
fn dump_snd(opt: &clap::ArgMatches<'_>, f: &str) -> ResultS<()> fn dump_snd(opt: &clap::ArgMatches<'_>, f: &str) -> ResultS<()>
{ {
unimplemented!(); unimplemented!();
} }
fn sub_data_c(_opt: &clap::ArgMatches<'_>) -> ResultS<()> fn sub_data_c(_opt: &clap::ArgMatches<'_>) -> ResultS<()>
{ {
unimplemented!(); unimplemented!();
} }
fn sub_dump_c(opt: &clap::ArgMatches<'_>) -> ResultS<()> fn sub_dump_c(opt: &clap::ArgMatches<'_>) -> ResultS<()>
{ {
each_value(opt, "map", |f| dump_map(opt, f))?; each_value(opt, "map", |f| dump_map(opt, f))?;
each_value(opt, "shp", |f| dump_shp(opt, f))?; each_value(opt, "shp", |f| dump_shp(opt, f))?;
each_value(opt, "snd", |f| dump_snd(opt, f))?; each_value(opt, "snd", |f| dump_snd(opt, f))?;
Ok(()) Ok(())
} }
fn sub_info_c(opt: &clap::ArgMatches<'_>) -> ResultS<()> fn sub_info_c(opt: &clap::ArgMatches<'_>) -> ResultS<()>
{ {
each_value(opt, "map", |f| Ok(dbg_info(file_read(f, map::read)?)))?; each_value(opt, "map", |f| Ok(dbg_info(file_read(f, map::read)?)))?;
each_value(opt, "shp", |f| Ok(dbg_info(file_read(f, shp::read)?)))?; each_value(opt, "shp", |f| Ok(dbg_info(file_read(f, shp::read)?)))?;
each_value(opt, "snd", |f| Ok(dbg_info(file_read(f, snd::read)?)))?; each_value(opt, "snd", |f| Ok(dbg_info(file_read(f, snd::read)?)))?;
Ok(()) Ok(())
} }
*/ */
fn main() -> ResultS<()> fn main() -> ResultS<()>
{ {
use std::io::prelude::*; use std::io::prelude::*;
let inp = include_bytes!("../tests/data/map/Test.in"); let inp = include_bytes!("../tests/data/map/Test.in");
let mut rd = std::io::BufReader::new(&inp[..]); let mut rd = std::io::BufReader::new(&inp[..]);
let mp = map::head::read(&mut rd).unwrap(); let mp = map::head::read(&mut rd).unwrap();
let en = map::entr::read_all(&mp).unwrap(); let en = map::entr::read_all(&mp).unwrap();
let ed = map::data::read_all(mp.head(), &en).unwrap(); let ed = map::data::read_all(mp.head(), &en).unwrap();
write!(&mut std::fs::File::create("dicks.txt").unwrap(), "{:#?}", ed); write!(&mut std::fs::File::create("dicks.txt").unwrap(), "{:#?}", ed);
/* use clap::clap_app;
use clap::clap_app;
let sub_data = clap_app! { let sub_data = clap_app! {
@subcommand data => @subcommand data =>
(about: "Dumps data into a discrete folder/YAML format") (about: "Dumps data into a discrete folder/YAML format")
}; };
let sub_dump = clap_app! { let sub_dump = clap_app! {
@subcommand dump => @subcommand dump =>
(about: "Dumps particular parts of data") (about: "Dumps particular parts of data")
(@arg chunks: -c --chunks [name]... "Dumps named chunks from an entry") (@arg chunks: -c --chunks [name]... "Dumps named chunks from an entry")
(@group files => (@group files =>
(@attributes +required +multiple) (@attributes +required +multiple)
(@arg map: -m --map [file]... {exists} "Loads Map files") (@arg map: -m --map [file]... {exists} "Loads Map files")
(@arg shp: -s --shp [file]... {exists} "Loads Shapes files") (@arg shp: -s --shp [file]... {exists} "Loads Shapes files")
(@arg snd: -n --snd [file]... {exists} "Loads Sounds files")) (@arg snd: -n --snd [file]... {exists} "Loads Sounds files"))
}; };
let sub_info = clap_app! { let sub_info = clap_app! {
@subcommand info => @subcommand info =>
(about: "Outputs debug info") (about: "Outputs debug info")
(@group files => (@group files =>
(@attributes +required +multiple) (@attributes +required +multiple)
(@arg map: -m --map [file]... {exists} "Loads Map files") (@arg map: -m --map [file]... {exists} "Loads Map files")
(@arg shp: -s --shp [file]... {exists} "Loads Shapes files") (@arg shp: -s --shp [file]... {exists} "Loads Shapes files")
(@arg snd: -n --snd [file]... {exists} "Loads Sounds files")) (@arg snd: -n --snd [file]... {exists} "Loads Sounds files"))
}; };
let opt = clap_app! { let opt = clap_app! {
(env!("CARGO_PKG_NAME")) => (env!("CARGO_PKG_NAME")) =>
(version: maraiah::meta::version()) (version: maraiah::meta::version())
(author: maraiah::meta::authors().replace(':', ", ")) (author: maraiah::meta::authors().replace(':', ", "))
(about: maraiah::meta::description()) (about: maraiah::meta::description())
(setting: clap::AppSettings::SubcommandRequiredElseHelp) (setting: clap::AppSettings::SubcommandRequiredElseHelp)
(subcommand: sub_data) (subcommand: sub_data)
(subcommand: sub_dump) (subcommand: sub_dump)
(subcommand: sub_info) (subcommand: sub_info)
}; };
let opt = opt.get_matches(); let opt = opt.get_matches();
match opt.subcommand() { match opt.subcommand() {
("data", Some(opt)) => sub_data_c(opt)?, ("data", Some(opt)) => sub_data_c(opt)?,
("dump", Some(opt)) => sub_dump_c(opt)?, ("dump", Some(opt)) => sub_dump_c(opt)?,
("info", Some(opt)) => sub_info_c(opt)?, ("info", Some(opt)) => sub_info_c(opt)?,
_ => unreachable!(), _ => unreachable!(),
} }
*/ */
Ok(()) Ok(())
} }
// EOF // EOF

View File

@ -6,136 +6,136 @@ use std::{convert::{TryFrom, TryInto}, fmt, num::NonZeroU16};
#[doc(hidden)] #[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! rd_impl { macro_rules! rd_impl {
// worker, creates let statement for 16 bit numbers // worker, creates let statement for 16 bit numbers
(W $b:expr, $pth:path, $nam:ident, $n:expr) => { (W $b:expr, $pth:path, $nam:ident, $n:expr) => {
let $nam = $pth([$b[$n], $b[$n + 1]]); let $nam = $pth([$b[$n], $b[$n + 1]]);
}; };
// worker, creates let statement for 32 bit numbers // worker, creates let statement for 32 bit numbers
(D $b:expr, $pth:path, $nam:ident, $n:expr) => { (D $b:expr, $pth:path, $nam:ident, $n:expr) => {
let $nam = $pth([$b[$n], $b[$n + 1], $b[$n + 2], $b[$n + 3]]); let $nam = $pth([$b[$n], $b[$n + 1], $b[$n + 2], $b[$n + 3]]);
}; };
// big endian, u16 // big endian, u16
(BIG, $b:expr, $at:expr, $n:expr; $nam:ident, u16) => { (BIG, $b:expr, $at:expr, $n:expr; $nam:ident, u16) => {
$crate::rd_impl!(W $b, u16::from_be_bytes, $nam, $n + $at); $crate::rd_impl!(W $b, u16::from_be_bytes, $nam, $n + $at);
}; };
// big endian, i16 // big endian, i16
(BIG, $b:expr, $at:expr, $n:expr; $nam:ident, i16) => { (BIG, $b:expr, $at:expr, $n:expr; $nam:ident, i16) => {
$crate::rd_impl!(W $b, i16::from_be_bytes, $nam, $n + $at); $crate::rd_impl!(W $b, i16::from_be_bytes, $nam, $n + $at);
}; };
// big endian, u32 // big endian, u32
(BIG, $b:expr, $at:expr, $n:expr; $nam:ident, u32) => { (BIG, $b:expr, $at:expr, $n:expr; $nam:ident, u32) => {
$crate::rd_impl!(D $b, u32::from_be_bytes, $nam, $n + $at); $crate::rd_impl!(D $b, u32::from_be_bytes, $nam, $n + $at);
}; };
// big endian, i32 // big endian, i32
(BIG, $b:expr, $at:expr, $n:expr; $nam:ident, i32) => { (BIG, $b:expr, $at:expr, $n:expr; $nam:ident, i32) => {
$crate::rd_impl!(D $b, i32::from_be_bytes, $nam, $n + $at); $crate::rd_impl!(D $b, i32::from_be_bytes, $nam, $n + $at);
}; };
// little endian, u16 // little endian, u16
(LITTLE, $b:expr, $at:expr, $n:expr; $nam:ident, u16) => { (LITTLE, $b:expr, $at:expr, $n:expr; $nam:ident, u16) => {
$crate::rd_impl!(W $b, u16::from_le_bytes, $nam, $n + $at); $crate::rd_impl!(W $b, u16::from_le_bytes, $nam, $n + $at);
}; };
// little endian, i16 // little endian, i16
(LITTLE, $b:expr, $at:expr, $n:expr; $nam:ident, i16) => { (LITTLE, $b:expr, $at:expr, $n:expr; $nam:ident, i16) => {
$crate::rd_impl!(W $b, i16::from_le_bytes, $nam, $n + $at); $crate::rd_impl!(W $b, i16::from_le_bytes, $nam, $n + $at);
}; };
// little endian, u32 // little endian, u32
(LITTLE, $b:expr, $at:expr, $n:expr; $nam:ident, u32) => { (LITTLE, $b:expr, $at:expr, $n:expr; $nam:ident, u32) => {
$crate::rd_impl!(D $b, u32::from_le_bytes, $nam, $n + $at); $crate::rd_impl!(D $b, u32::from_le_bytes, $nam, $n + $at);
}; };
// little endian, i32 // little endian, i32
(LITTLE, $b:expr, $at:expr, $n:expr; $nam:ident, i32) => { (LITTLE, $b:expr, $at:expr, $n:expr; $nam:ident, i32) => {
$crate::rd_impl!(D $b, i32::from_le_bytes, $nam, $n + $at); $crate::rd_impl!(D $b, i32::from_le_bytes, $nam, $n + $at);
}; };
// either endianness, Angle // either endianness, Angle
($e:ident, $b:expr, $at:expr, $n:expr; $nam:ident, Angle) => { ($e:ident, $b:expr, $at:expr, $n:expr; $nam:ident, Angle) => {
$crate::rd_impl!($e, $b, $at, $n; $nam, u16); $crate::rd_impl!($e, $b, $at, $n; $nam, u16);
let $nam = $crate::fixed::Angle::from_bits($nam); let $nam = $crate::fixed::Angle::from_bits($nam);
}; };
// either endianness, Fixed // either endianness, Fixed
($e:ident, $b:expr, $at:expr, $n:expr; $nam:ident, Fixed) => { ($e:ident, $b:expr, $at:expr, $n:expr; $nam:ident, Fixed) => {
$crate::rd_impl!($e, $b, $at, $n; $nam, u32); $crate::rd_impl!($e, $b, $at, $n; $nam, u32);
let $nam = $crate::fixed::Fixed::from_bits($nam); let $nam = $crate::fixed::Fixed::from_bits($nam);
}; };
// either endianness, Unit // either endianness, Unit
($e:ident, $b:expr, $at:expr, $n:expr; $nam:ident, Unit) => { ($e:ident, $b:expr, $at:expr, $n:expr; $nam:ident, Unit) => {
$crate::rd_impl!($e, $b, $at, $n; $nam, u16); $crate::rd_impl!($e, $b, $at, $n; $nam, u16);
let $nam = $crate::fixed::Unit::from_bits($nam); let $nam = $crate::fixed::Unit::from_bits($nam);
}; };
// either endianness, OptU16 // either endianness, OptU16
($e:ident, $b:expr, $at:expr, $n:expr; $nam:ident, OptU16) => { ($e:ident, $b:expr, $at:expr, $n:expr; $nam:ident, OptU16) => {
$crate::rd_impl!($e, $b, $at, $n; $nam, u16); $crate::rd_impl!($e, $b, $at, $n; $nam, u16);
let $nam = $crate::bin::OptU16::from($nam); let $nam = $crate::bin::OptU16::from($nam);
}; };
// either endianness, u16 -> usize // either endianness, u16 -> usize
($e:ident, $b:expr, $at:expr, $n:expr; $nam:ident, usize, u16) => { ($e:ident, $b:expr, $at:expr, $n:expr; $nam:ident, usize, u16) => {
$crate::rd_impl!($e, $b, $at, $n; $nam, u16); $crate::rd_impl!($e, $b, $at, $n; $nam, u16);
let $nam = usize::from($nam); let $nam = usize::from($nam);
}; };
// either endianness, u32 -> usize // either endianness, u32 -> usize
($e:ident, $b:expr, $at:expr, $n:expr; $nam:ident, usize, u32) => { ($e:ident, $b:expr, $at:expr, $n:expr; $nam:ident, usize, u32) => {
$crate::rd_impl!($e, $b, $at, $n; $nam, u32); $crate::rd_impl!($e, $b, $at, $n; $nam, u32);
let $nam = $crate::bin::usize_from_u32($nam); let $nam = $crate::bin::usize_from_u32($nam);
}; };
// either endianness, enum type with TryFrom // either endianness, enum type with TryFrom
($e:ident, $b:expr, $at:expr, $n:expr; ($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); $crate::rd_impl!($e, $b, $at, $n; $nam, $t);
let $nam: $et$(::$etc)* = std::convert::TryFrom::try_from($nam)?; let $nam: $et$(::$etc)* = std::convert::TryFrom::try_from($nam)?;
}; };
// either endianness, bitflag type // either endianness, bitflag type
($e:ident, $b:expr, $at:expr, $n:expr; ($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); $crate::rd_impl!($e, $b, $at, $n; $nam, $t);
let $nam = flag_ok!($ft$(::$ftc)*, $nam)?; let $nam = flag_ok!($ft$(::$ftc)*, $nam)?;
}; };
// no endianness, u8 // no endianness, u8
($_:ident, $b:expr, $at:expr, $n:expr; $nam:ident, u8) => { ($_:ident, $b:expr, $at:expr, $n:expr; $nam:ident, u8) => {
let $nam = $b[$n + $at]; let $nam = $b[$n + $at];
}; };
// no endianness, i8 // no endianness, i8
($_:ident, $b:expr, $at:expr, $n:expr; $nam:ident, i8) => { ($_:ident, $b:expr, $at:expr, $n:expr; $nam:ident, i8) => {
let $nam = $b[$n + $at] as i8; let $nam = $b[$n + $at] as i8;
}; };
// no endianness, [u8] // no endianness, [u8]
($_:ident, $b:expr, $at:expr, $n:expr; $rn:expr; $nam:ident, u8) => { ($_:ident, $b:expr, $at:expr, $n:expr; $rn:expr; $nam:ident, u8) => {
let $nam = &$b[$n + $at..$n + $at + $rn]; let $nam = &$b[$n + $at..$n + $at + $rn];
}; };
// no endianness, Ident // no endianness, Ident
($_:ident, $b:expr, $at:expr, $n:expr; $nam:ident, Ident) => { ($_:ident, $b:expr, $at:expr, $n:expr; $nam:ident, Ident) => {
$crate::rd_impl!(D $b, Ident, $nam, $n + $at); $crate::rd_impl!(D $b, Ident, $nam, $n + $at);
}; };
// no endianness, fn([u8]) -> T // no endianness, fn([u8]) -> T
($_:ident, $b:expr, $at:expr, $n:expr; $rn:expr; ($_: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]); let $nam = $f(&$b[$n + $at..$n + $at + $rn]);
}; };
// no endianness, fn([u8]) -> Result<T> // no endianness, fn([u8]) -> Result<T>
($_:ident, $b:expr, $at:expr, $n:expr; $rn:expr; $nam:ident, $f:expr) => { ($_:ident, $b:expr, $at:expr, $n:expr; $rn:expr; $nam:ident, $f:expr) => {
let $nam = $f(&$b[$n + $at..$n + $at + $rn])?; let $nam = $f(&$b[$n + $at..$n + $at + $rn])?;
}; };
} }
/// Reads structured data from a byte slice. /// Reads structured data from a byte slice.
@ -201,12 +201,12 @@ macro_rules! rd_impl {
/// let buffer = &[4, 0, 2, 0, 0, 0, 6]; /// let buffer = &[4, 0, 2, 0, 0, 0, 6];
/// ///
/// read_data! { /// read_data! {
/// endian: LITTLE, buf: buffer, size: 7, start: 0, data { /// endian: LITTLE, buf: buffer, size: 7, start: 0, data {
/// let four = u16[0]; /// let four = u16[0];
/// let two = u32[2]; /// let two = u32[2];
/// let six = u8[6]; /// let six = u8[6];
/// let byte = u8[2; 4]; /// let byte = u8[2; 4];
/// } /// }
/// } /// }
/// ///
/// assert_eq!(four, 4_u16); /// assert_eq!(four, 4_u16);
@ -218,16 +218,16 @@ macro_rules! rd_impl {
/// ``` /// ```
#[macro_export] #[macro_export]
macro_rules! read_data { macro_rules! read_data {
( (
endian: $e:ident, buf: $b:expr, size: $sz:expr, start: $at:expr, data { endian: $e:ident, buf: $b:expr, size: $sz:expr, start: $at:expr, data {
$(let $nam:ident = $t:ident$(::$tc:ident)*[$n:expr $(; $rn:expr)?] $(let $nam:ident = $t:ident$(::$tc:ident)*[$n:expr $(; $rn:expr)?]
$($ex:ident$(::$exc:ident)*)*;)* $($ex:ident$(::$exc:ident)*)*;)*
} }
) => { ) => {
$crate::bin::check_data($b, $at + $sz)?; $crate::bin::check_data($b, $at + $sz)?;
$($crate::rd_impl!($e, $b, $at, $n; $($crate::rd_impl!($e, $b, $at, $n;
$($rn;)? $nam, $($ex$(::$exc)*,)* $t$(::$tc)*);)* $($rn;)? $nam, $($ex$(::$exc)*,)* $t$(::$tc)*);)*
}; };
} }
/// Checks if there is enough data in `b`. /// Checks if there is enough data in `b`.
@ -238,11 +238,11 @@ macro_rules! read_data {
#[inline] #[inline]
pub fn check_data<T>(b: &[T], sz: usize) -> ResultS<()> pub fn check_data<T>(b: &[T], sz: usize) -> ResultS<()>
{ {
if b.len() < sz { if b.len() < sz {
Err(err_msg("not enough data")) Err(err_msg("not enough data"))
} else { } else {
Ok(()) Ok(())
} }
} }
/// Casts a `u32` to a `usize`. /// Casts a `u32` to a `usize`.
@ -262,7 +262,7 @@ pub fn check_data<T>(b: &[T], sz: usize) -> ResultS<()>
#[inline] #[inline]
pub fn usize_from_u32(n: u32) -> usize pub fn usize_from_u32(n: u32) -> usize
{ {
usize::try_from(n).expect("platform is 16-bit") usize::try_from(n).expect("platform is 16-bit")
} }
/// Creates an `Ident` from a slice. /// Creates an `Ident` from a slice.
@ -281,7 +281,7 @@ pub fn usize_from_u32(n: u32) -> usize
#[inline] #[inline]
pub fn ident(b: &[u8]) -> Ident pub fn ident(b: &[u8]) -> Ident
{ {
Ident(b[0..4].try_into().expect("not enough data")) Ident(b[0..4].try_into().expect("not enough data"))
} }
/// Applies `u32::from_be_bytes` to a slice. /// Applies `u32::from_be_bytes` to a slice.
@ -300,7 +300,7 @@ pub fn ident(b: &[u8]) -> Ident
#[inline] #[inline]
pub fn u32b(b: &[u8]) -> u32 pub fn u32b(b: &[u8]) -> u32
{ {
u32::from_be_bytes(b[0..4].try_into().expect("not enough data")) u32::from_be_bytes(b[0..4].try_into().expect("not enough data"))
} }
/// Applies `u16::from_be_bytes` to a slice. /// Applies `u16::from_be_bytes` to a slice.
@ -319,7 +319,7 @@ pub fn u32b(b: &[u8]) -> u32
#[inline] #[inline]
pub fn u16b(b: &[u8]) -> u16 pub fn u16b(b: &[u8]) -> u16
{ {
u16::from_be_bytes(b[0..2].try_into().expect("not enough data")) u16::from_be_bytes(b[0..2].try_into().expect("not enough data"))
} }
/// Applies `i32::from_be_bytes` to a slice. /// Applies `i32::from_be_bytes` to a slice.
@ -338,7 +338,7 @@ pub fn u16b(b: &[u8]) -> u16
#[inline] #[inline]
pub fn i32b(b: &[u8]) -> i32 pub fn i32b(b: &[u8]) -> i32
{ {
i32::from_be_bytes(b[0..4].try_into().expect("not enough data")) i32::from_be_bytes(b[0..4].try_into().expect("not enough data"))
} }
/// Applies `i16::from_be_bytes` to a slice. /// Applies `i16::from_be_bytes` to a slice.
@ -357,7 +357,7 @@ pub fn i32b(b: &[u8]) -> i32
#[inline] #[inline]
pub fn i16b(b: &[u8]) -> i16 pub fn i16b(b: &[u8]) -> i16
{ {
i16::from_be_bytes(b[0..2].try_into().expect("not enough data")) i16::from_be_bytes(b[0..2].try_into().expect("not enough data"))
} }
/// Applies a read function over a slice. /// Applies a read function over a slice.
@ -387,19 +387,19 @@ pub fn i16b(b: &[u8]) -> i16
/// assert_eq!(rd_array(inp, read_a_u16).unwrap(), vec![7_777u16, 777u16]); /// assert_eq!(rd_array(inp, read_a_u16).unwrap(), vec![7_777u16, 777u16]);
/// ``` /// ```
pub fn rd_array<T, F>(b: &[u8], read: F) -> ResultS<Vec<T>> pub fn rd_array<T, F>(b: &[u8], read: F) -> ResultS<Vec<T>>
where T: Sized, where T: Sized,
F: Fn(&[u8]) -> ResultS<(T, usize)> F: Fn(&[u8]) -> ResultS<(T, usize)>
{ {
let mut v = Vec::new(); let mut v = Vec::new();
let mut p = 0; let mut p = 0;
while p < b.len() { while p < b.len() {
let (r, s) = read(&b[p..])?; let (r, s) = read(&b[p..])?;
v.push(r); v.push(r);
p += s; p += s;
} }
Ok(v) Ok(v)
} }
/// Applies a read function a number of times over a slice. /// Applies a read function a number of times over a slice.
@ -420,19 +420,19 @@ pub fn rd_array<T, F>(b: &[u8], read: F) -> ResultS<Vec<T>>
pub fn rd_array_num<T, F>(b: &[u8], pub fn rd_array_num<T, F>(b: &[u8],
n: usize, n: usize,
read: F) -> ResultS<(Vec<T>, usize)> read: F) -> ResultS<(Vec<T>, usize)>
where T: Sized, where T: Sized,
F: Fn(&[u8]) -> ResultS<(T, usize)> F: Fn(&[u8]) -> ResultS<(T, usize)>
{ {
let mut v = Vec::with_capacity(n); let mut v = Vec::with_capacity(n);
let mut p = 0; let mut p = 0;
for _ in 0..n { for _ in 0..n {
let (r, s) = read(&b[p..])?; let (r, s) = read(&b[p..])?;
v.push(r); v.push(r);
p += s; p += s;
} }
Ok((v, p)) Ok((v, p))
} }
/// Applies a read function over a slice with an offset table. /// Applies a read function over a slice with an offset table.
@ -454,150 +454,150 @@ pub fn rd_ofstable<T, F>(b: &[u8],
mut p: usize, mut p: usize,
num: usize, num: usize,
read: F) -> ResultS<Vec<T>> read: F) -> ResultS<Vec<T>>
where T: Sized, where T: Sized,
F: Fn(&[u8]) -> ResultS<T> F: Fn(&[u8]) -> ResultS<T>
{ {
let mut v = Vec::with_capacity(num); let mut v = Vec::with_capacity(num);
for _ in 0..num { for _ in 0..num {
let ofs = usize_from_u32(u32b(&b[p..p + 4])); let ofs = usize_from_u32(u32b(&b[p..p + 4]));
check_data(b, ofs)?; check_data(b, ofs)?;
v.push(read(&b[ofs..])?); v.push(read(&b[ofs..])?);
p += 4; p += 4;
} }
Ok(v) Ok(v)
} }
impl From<u16> for OptU16 impl From<u16> for OptU16
{ {
#[inline] #[inline]
fn from(n: u16) -> Self fn from(n: u16) -> Self
{ {
if n == u16::max_value() { if n == u16::max_value() {
Self(None) Self(None)
} else { } else {
Self(NonZeroU16::new(n + 1)) Self(NonZeroU16::new(n + 1))
} }
} }
} }
impl Into<u16> for OptU16 impl Into<u16> for OptU16
{ {
/// Returns the `u16` representation. /// Returns the `u16` representation.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use maraiah::bin::OptU16; /// use maraiah::bin::OptU16;
/// ///
/// let u16_max = u16::max_value(); /// let u16_max = u16::max_value();
/// ///
/// // These type annotations are necessary. /// // These type annotations are necessary.
/// ///
/// assert_eq!(<OptU16 as Into<u16>>::into(OptU16::from(500u16)), 500u16); /// assert_eq!(<OptU16 as Into<u16>>::into(OptU16::from(500u16)), 500u16);
/// assert_eq!(<OptU16 as Into<u16>>::into(OptU16::from(u16_max)), u16_max); /// assert_eq!(<OptU16 as Into<u16>>::into(OptU16::from(u16_max)), u16_max);
/// assert_eq!(<OptU16 as Into<u16>>::into(OptU16::from(0u16)), 0u16); /// assert_eq!(<OptU16 as Into<u16>>::into(OptU16::from(0u16)), 0u16);
/// ``` /// ```
#[inline] #[inline]
fn into(self) -> u16 fn into(self) -> u16
{ {
match self.0 { match self.0 {
None => u16::max_value(), None => u16::max_value(),
Some(n) => n.get() - 1, Some(n) => n.get() - 1,
} }
} }
} }
impl OptU16 impl OptU16
{ {
/// Creates an `OptU16` representing `None`. /// Creates an `OptU16` representing `None`.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use maraiah::bin::OptU16; /// use maraiah::bin::OptU16;
/// ///
/// assert_eq!(OptU16::none(), OptU16::from(u16::max_value())); /// assert_eq!(OptU16::none(), OptU16::from(u16::max_value()));
/// ``` /// ```
#[inline] #[inline]
pub const fn none() -> Self {Self(None)} pub const fn none() -> Self {Self(None)}
/// Returns the `Option` representation. /// Returns the `Option` representation.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use maraiah::bin::OptU16; /// use maraiah::bin::OptU16;
/// ///
/// assert_eq!(OptU16::from(500u16).get(), Some(500u16)); /// assert_eq!(OptU16::from(500u16).get(), Some(500u16));
/// assert_eq!(OptU16::from(u16::max_value()).get(), None); /// assert_eq!(OptU16::from(u16::max_value()).get(), None);
/// assert_eq!(OptU16::from(0u16).get(), Some(0u16)); /// assert_eq!(OptU16::from(0u16).get(), Some(0u16));
/// ``` /// ```
#[inline] #[inline]
pub fn get(self) -> Option<u16> pub fn get(self) -> Option<u16>
{ {
match self.0 { match self.0 {
None => None, None => None,
Some(n) => Some(n.get() - 1), Some(n) => Some(n.get() - 1),
} }
} }
/// Return the memory representation of this integer as a byte array /// Return the memory representation of this integer as a byte array
/// in big-endian (network) byte order. /// in big-endian (network) byte order.
#[inline] #[inline]
pub fn to_be_bytes(self) -> [u8; 2] pub fn to_be_bytes(self) -> [u8; 2]
{ {
<Self as Into<u16>>::into(self).to_be_bytes() <Self as Into<u16>>::into(self).to_be_bytes()
} }
/// Return the memory representation of this integer as a byte array /// Return the memory representation of this integer as a byte array
/// in little-endian byte order. /// in little-endian byte order.
#[inline] #[inline]
pub fn to_le_bytes(self) -> [u8; 2] pub fn to_le_bytes(self) -> [u8; 2]
{ {
<Self as Into<u16>>::into(self).to_le_bytes() <Self as Into<u16>>::into(self).to_le_bytes()
} }
} }
impl fmt::Display for OptU16 impl fmt::Display for OptU16
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{ {
match self.get() { match self.get() {
None => write!(f, "None"), None => write!(f, "None"),
Some(n) => write!(f, "Some({})", n), Some(n) => write!(f, "Some({})", n),
} }
} }
} }
impl fmt::Debug for OptU16 impl fmt::Debug for OptU16
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{ {
match self.get() { match self.get() {
None => write!(f, "OptU16::none()"), None => write!(f, "OptU16::none()"),
Some(n) => write!(f, "OptU16::from({})", n), Some(n) => write!(f, "OptU16::from({})", n),
} }
} }
} }
impl PartialEq<[u8; 4]> for Ident impl PartialEq<[u8; 4]> for Ident
{ {
#[inline] #[inline]
fn eq(&self, o: &[u8; 4]) -> bool {self.0 == *o} fn eq(&self, o: &[u8; 4]) -> bool {self.0 == *o}
} }
impl<'a> PartialEq<[u8; 4]> for &'a Ident impl<'a> PartialEq<[u8; 4]> for &'a Ident
{ {
#[inline] #[inline]
fn eq(&self, o: &[u8; 4]) -> bool {PartialEq::eq(*self, o)} fn eq(&self, o: &[u8; 4]) -> bool {PartialEq::eq(*self, o)}
} }
impl<'a> PartialEq<&'a [u8; 4]> for Ident impl<'a> PartialEq<&'a [u8; 4]> for Ident
{ {
#[inline] #[inline]
fn eq(&self, o: &&'a [u8; 4]) -> bool {PartialEq::eq(self, *o)} fn eq(&self, o: &&'a [u8; 4]) -> bool {PartialEq::eq(self, *o)}
} }
/// A four-character-code identifier. /// A four-character-code identifier.

View File

@ -11,152 +11,152 @@ use crate::err::*;
/// `(cr_bit + width - 1) / 8` would overflow an index into `b`. /// `(cr_bit + width - 1) / 8` would overflow an index into `b`.
pub fn read_bits_b(b: &[u8], cr_bit: usize, width: u8) -> ResultS<u64> pub fn read_bits_b(b: &[u8], cr_bit: usize, width: u8) -> ResultS<u64>
{ {
if width == 0 { if width == 0 {
return Ok(0); return Ok(0);
} }
if width > 64 { if width > 64 {
bail!("invalid number of bits"); bail!("invalid number of bits");
} }
let last = (cr_bit + usize::from(width) - 1) / 8; let last = (cr_bit + usize::from(width) - 1) / 8;
if last >= b.len() { if last >= b.len() {
bail!("not enough data"); bail!("not enough data");
} }
let mut byte_ptr = cr_bit / 8; let mut byte_ptr = cr_bit / 8;
let mut bits_ptr = cr_bit % 8; let mut bits_ptr = cr_bit % 8;
let mut res = 0; let mut res = 0;
for _ in 0..width { for _ in 0..width {
res <<= 1; res <<= 1;
if b[byte_ptr] & (1 << bits_ptr) != 0 { if b[byte_ptr] & (1 << bits_ptr) != 0 {
res |= 1; res |= 1;
} }
bits_ptr += 1; bits_ptr += 1;
if bits_ptr > 7 { if bits_ptr > 7 {
bits_ptr = 0; bits_ptr = 0;
byte_ptr += 1; byte_ptr += 1;
} }
} }
Ok(res) Ok(res)
} }
/// The same as `read_bits_b`, but least-significant bit first. /// The same as `read_bits_b`, but least-significant bit first.
pub fn read_bits_l(b: &[u8], cr_bit: usize, width: u8) -> ResultS<u64> pub fn read_bits_l(b: &[u8], cr_bit: usize, width: u8) -> ResultS<u64>
{ {
if width == 0 { if width == 0 {
Ok(0) Ok(0)
} else { } else {
let res = read_bits_b(b, cr_bit, width)?; let res = read_bits_b(b, cr_bit, width)?;
Ok(reverse_bits(res) >> (64 - width)) Ok(reverse_bits(res) >> (64 - width))
} }
} }
// FIXME: change this to u64::reverse_bits when stabilized // FIXME: change this to u64::reverse_bits when stabilized
const fn reverse_bits(v: u64) -> u64 const fn reverse_bits(v: u64) -> u64
{ {
let v = v >> 1 & 0x5555_5555_5555_5555 | ((v & 0x5555_5555_5555_5555) << 1); let v = v >> 1 & 0x5555_5555_5555_5555 | ((v & 0x5555_5555_5555_5555) << 1);
let v = v >> 2 & 0x3333_3333_3333_3333 | ((v & 0x3333_3333_3333_3333) << 2); let v = v >> 2 & 0x3333_3333_3333_3333 | ((v & 0x3333_3333_3333_3333) << 2);
let v = v >> 4 & 0x0F0F_0F0F_0F0F_0F0F | ((v & 0x0F0F_0F0F_0F0F_0F0F) << 4); let v = v >> 4 & 0x0F0F_0F0F_0F0F_0F0F | ((v & 0x0F0F_0F0F_0F0F_0F0F) << 4);
v.swap_bytes() v.swap_bytes()
} }
#[test] #[test]
fn bit_tests() fn bit_tests()
{ {
const INPUT: &[u8] = &[0b01100101, 0b10101010, 0b00010000, 0b00000000, const INPUT: &[u8] = &[0b01100101, 0b10101010, 0b00010000, 0b00000000,
0b11111111, 0b11100001, 0b10101100, 0b00110011, 0b11111111, 0b11100001, 0b10101100, 0b00110011,
0b10100101, 0b11100000, 0b00000111, 0b00000001, 0b10100101, 0b11100000, 0b00000111, 0b00000001,
0b11001010, 0b10101111, 0b00101011, 0b01101010, 0b11001010, 0b10101111, 0b00101011, 0b01101010,
0b11010101, 0b10100011, 0b01010101, 0b11000001]; 0b11010101, 0b10100011, 0b01010101, 0b11000001];
let mut p = 0; let mut p = 0;
let n = read_bits_b(INPUT, p, 3).unwrap(); let n = read_bits_b(INPUT, p, 3).unwrap();
assert_eq!(n, 0b101); assert_eq!(n, 0b101);
p += 3; p += 3;
let n = read_bits_b(INPUT, p, 63).unwrap(); let n = read_bits_b(INPUT, p, 63).unwrap();
assert_eq!(n, 0b001100101010100001000000000001111111110000111001101011100110010); assert_eq!(n, 0b001100101010100001000000000001111111110000111001101011100110010);
p += 63; p += 63;
let n = read_bits_b(INPUT, p, 4).unwrap(); let n = read_bits_b(INPUT, p, 4).unwrap();
assert_eq!(n, 0b1001); assert_eq!(n, 0b1001);
p += 4; p += 4;
let n = read_bits_b(INPUT, p, 7).unwrap(); let n = read_bits_b(INPUT, p, 7).unwrap();
assert_eq!(n, 0b0100000); assert_eq!(n, 0b0100000);
p += 7; p += 7;
let n = read_bits_b(INPUT, p, 17).unwrap(); let n = read_bits_b(INPUT, p, 17).unwrap();
assert_eq!(n, 0b11111100000100000); assert_eq!(n, 0b11111100000100000);
p += 17; p += 17;
let n = read_bits_b(INPUT, p, 27).unwrap(); let n = read_bits_b(INPUT, p, 27).unwrap();
assert_eq!(n, 0b000101001111110101110101000); assert_eq!(n, 0b000101001111110101110101000);
p += 27; p += 27;
let n = read_bits_b(INPUT, p, 33).unwrap(); let n = read_bits_b(INPUT, p, 33).unwrap();
assert_eq!(n, 0b101011010101011110001011010101010); assert_eq!(n, 0b101011010101011110001011010101010);
p += 33; p += 33;
let n = read_bits_b(INPUT, p, 6).unwrap(); let n = read_bits_b(INPUT, p, 6).unwrap();
assert_eq!(n, 0b000011); assert_eq!(n, 0b000011);
p += 6; p += 6;
let e = read_bits_b(INPUT, p, 1); let e = read_bits_b(INPUT, p, 1);
assert!(if let Err(_) = e {true} else {false}); assert!(if let Err(_) = e {true} else {false});
let e = read_bits_b(INPUT, p, 2); let e = read_bits_b(INPUT, p, 2);
assert!(if let Err(_) = e {true} else {false}); assert!(if let Err(_) = e {true} else {false});
let mut p = 0; let mut p = 0;
let n = read_bits_l(INPUT, 0, 3).unwrap(); let n = read_bits_l(INPUT, 0, 3).unwrap();
assert_eq!(n, 0b101); assert_eq!(n, 0b101);
p += 3; p += 3;
let n = read_bits_l(INPUT, p, 63).unwrap(); let n = read_bits_l(INPUT, p, 63).unwrap();
assert_eq!(n, 0b010011001110101100111000011111111100000000000100001010101001100); assert_eq!(n, 0b010011001110101100111000011111111100000000000100001010101001100);
p += 63; p += 63;
let n = read_bits_l(INPUT, p, 4).unwrap(); let n = read_bits_l(INPUT, p, 4).unwrap();
assert_eq!(n, 0b1001); assert_eq!(n, 0b1001);
p += 4; p += 4;
let n = read_bits_l(INPUT, p, 7).unwrap(); let n = read_bits_l(INPUT, p, 7).unwrap();
assert_eq!(n, 0b0000010); assert_eq!(n, 0b0000010);
p += 7; p += 7;
let n = read_bits_l(INPUT, p, 17).unwrap(); let n = read_bits_l(INPUT, p, 17).unwrap();
assert_eq!(n, 0b00000100000111111); assert_eq!(n, 0b00000100000111111);
p += 17; p += 17;
let n = read_bits_l(INPUT, p, 27).unwrap(); let n = read_bits_l(INPUT, p, 27).unwrap();
assert_eq!(n, 0b000101011101011111100101000); assert_eq!(n, 0b000101011101011111100101000);
p += 27; p += 27;
let n = read_bits_l(INPUT, p, 33).unwrap(); let n = read_bits_l(INPUT, p, 33).unwrap();
assert_eq!(n, 0b010101010110100011110101010110101); assert_eq!(n, 0b010101010110100011110101010110101);
p += 33; p += 33;
let n = read_bits_l(INPUT, p, 6).unwrap(); let n = read_bits_l(INPUT, p, 6).unwrap();
assert_eq!(n, 0b110000); assert_eq!(n, 0b110000);
p += 6; p += 6;
let e = read_bits_l(INPUT, p, 1); let e = read_bits_l(INPUT, p, 1);
assert!(if let Err(_) = e {true} else {false}); assert!(if let Err(_) = e {true} else {false});
let e = read_bits_l(INPUT, p, 2); let e = read_bits_l(INPUT, p, 2);
assert!(if let Err(_) = e {true} else {false}); assert!(if let Err(_) = e {true} else {false});
} }
// EOF // EOF

View File

@ -4,85 +4,85 @@
#[macro_export] #[macro_export]
macro_rules! c_bitfield macro_rules! c_bitfield
{ {
( (
$(#[$outer:meta])* $(#[$outer:meta])*
pub struct $t:ident: $ti:ty { pub struct $t:ident: $ti:ty {
$( $(
$(#[$inner:ident $($args:tt)*])* $(#[$inner:ident $($args:tt)*])*
$f:ident = $v:expr $f:ident = $v:expr
),+ ),+
$(,)? $(,)?
} }
) => { ) => {
bitflags! { bitflags! {
$(#[$outer])* $(#[$outer])*
pub struct $t: $ti { pub struct $t: $ti {
$( $(
$(#[$inner $($args)*])* $(#[$inner $($args)*])*
const $f = 1 << $v; const $f = 1 << $v;
)+ )+
} }
} }
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
impl std::str::FromStr for $t impl std::str::FromStr for $t
{ {
type Err = $crate::err::ParseFlagError; type Err = $crate::err::ParseFlagError;
fn from_str(s: &str) -> Result<Self, Self::Err> fn from_str(s: &str) -> Result<Self, Self::Err>
{ {
let mut flags = Self::empty(); let mut flags = Self::empty();
for s in s.split('|') { for s in s.split('|') {
match s { match s {
$( $(
stringify!($f) => flags.insert(Self::$f), stringify!($f) => flags.insert(Self::$f),
)+ )+
"(none)" => (), "(none)" => (),
_ => return Err(Self::Err::new(stringify!($t))) _ => return Err(Self::Err::new(stringify!($t)))
} }
} }
Ok(flags) Ok(flags)
} }
} }
} }
} }
#[cfg(test)] #[cfg(test)]
mod test mod test
{ {
use crate::err::ParseFlagError; use crate::err::ParseFlagError;
use std::str::FromStr; use std::str::FromStr;
c_bitfield! { c_bitfield! {
pub struct TestFlag: u16 { pub struct TestFlag: u16 {
ZERO = 0, ZERO = 0,
ONE = 1, ONE = 1,
TWO = 2, TWO = 2,
} }
} }
#[test] #[test]
fn c_bitfield() fn c_bitfield()
{ {
assert_eq!(TestFlag::from_bits(0), Some(TestFlag::empty())); assert_eq!(TestFlag::from_bits(0), Some(TestFlag::empty()));
assert_eq!(TestFlag::from_bits(1), Some(TestFlag::ZERO)); assert_eq!(TestFlag::from_bits(1), Some(TestFlag::ZERO));
assert_eq!(TestFlag::from_bits(2), Some(TestFlag::ONE)); assert_eq!(TestFlag::from_bits(2), Some(TestFlag::ONE));
assert_eq!(TestFlag::from_bits(4), Some(TestFlag::TWO)); assert_eq!(TestFlag::from_bits(4), Some(TestFlag::TWO));
assert_eq!(TestFlag::from_bits(8), None); assert_eq!(TestFlag::from_bits(8), None);
assert_eq!(TestFlag::from_str("(none)"), Ok(TestFlag::empty())); assert_eq!(TestFlag::from_str("(none)"), Ok(TestFlag::empty()));
assert_eq!(TestFlag::from_str("ZERO"), Ok(TestFlag::ZERO)); assert_eq!(TestFlag::from_str("ZERO"), Ok(TestFlag::ZERO));
assert_eq!(TestFlag::from_str("ONE"), Ok(TestFlag::ONE)); assert_eq!(TestFlag::from_str("ONE"), Ok(TestFlag::ONE));
assert_eq!(TestFlag::from_str("TWO"), Ok(TestFlag::TWO)); assert_eq!(TestFlag::from_str("TWO"), Ok(TestFlag::TWO));
assert_eq!(TestFlag::from_str("ZERO|ONE|TWO"), Ok(TestFlag::all())); assert_eq!(TestFlag::from_str("ZERO|ONE|TWO"), Ok(TestFlag::all()));
assert_eq!(TestFlag::from_str("TWO|ZERO|ONE"), Ok(TestFlag::all())); assert_eq!(TestFlag::from_str("TWO|ZERO|ONE"), Ok(TestFlag::all()));
assert_eq!(TestFlag::from_str("ONE|ONE|ONE"), Ok(TestFlag::ONE)); assert_eq!(TestFlag::from_str("ONE|ONE|ONE"), Ok(TestFlag::ONE));
assert_eq!(TestFlag::from_str("(none)|(none)"), Ok(TestFlag::empty())); assert_eq!(TestFlag::from_str("(none)|(none)"), Ok(TestFlag::empty()));
assert_eq!(TestFlag::from_str("(none)|ONE"), Ok(TestFlag::ONE)); assert_eq!(TestFlag::from_str("(none)|ONE"), Ok(TestFlag::ONE));
assert_eq!(TestFlag::from_str("THREE"), assert_eq!(TestFlag::from_str("THREE"),
Err(ParseFlagError::new("TestFlag"))); Err(ParseFlagError::new("TestFlag")));
} }
} }
// EOF // EOF

View File

@ -16,11 +16,11 @@
/// use std::convert::TryFrom; /// use std::convert::TryFrom;
/// ///
/// c_enum! { /// c_enum! {
/// enum MyEnum: u16 { /// enum MyEnum: u16 {
/// Zero = 0, /// Zero = 0,
/// One = 1, /// One = 1,
/// Two = 2 /// Two = 2
/// } /// }
/// } /// }
/// ///
/// assert_eq!(MyEnum::try_from(0), Ok(MyEnum::Zero)); /// assert_eq!(MyEnum::try_from(0), Ok(MyEnum::Zero));
@ -33,88 +33,88 @@
#[macro_export] #[macro_export]
macro_rules! c_enum macro_rules! c_enum
{ {
( (
$(#[$outer:meta])* $(#[$outer:meta])*
$vi:vis enum $t:ident: $ti:ident { $vi:vis enum $t:ident: $ti:ident {
$( $(
$(#[$inner:meta])* $(#[$inner:meta])*
$en:ident = $va:expr $en:ident = $va:expr
),+ ),+
$(,)? $(,)?
} }
) => { ) => {
$(#[$outer])* $(#[$outer])*
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
#[repr($ti)] #[repr($ti)]
$vi enum $t { $vi enum $t {
$( $(
$(#[$inner])* $(#[$inner])*
$en = $va, $en = $va,
)+ )+
} }
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
impl std::convert::TryFrom<$ti> for $t impl std::convert::TryFrom<$ti> for $t
{ {
type Error = $crate::err::ReprError; type Error = $crate::err::ReprError;
/// Returns, if representable, the variant of `Self` from `n`. /// Returns, if representable, the variant of `Self` from `n`.
fn try_from(n: $ti) -> Result<Self, Self::Error> fn try_from(n: $ti) -> Result<Self, Self::Error>
{ {
match n { match n {
$($va => Ok($t::$en),)+ $($va => Ok($t::$en),)+
n => Err(Self::Error::new(stringify!($t), n)) n => Err(Self::Error::new(stringify!($t), n))
} }
} }
} }
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
impl std::str::FromStr for $t impl std::str::FromStr for $t
{ {
type Err = $crate::err::ParseEnumError; type Err = $crate::err::ParseEnumError;
fn from_str(s: &str) -> Result<Self, Self::Err> fn from_str(s: &str) -> Result<Self, Self::Err>
{ {
match s { match s {
$( $(
stringify!($en) => Ok($t::$en), stringify!($en) => Ok($t::$en),
)+ )+
_ => Err(Self::Err::new(stringify!($t))) _ => Err(Self::Err::new(stringify!($t)))
} }
} }
} }
}; };
} }
#[cfg(test)] #[cfg(test)]
mod test mod test
{ {
use crate::err::{ParseEnumError, ReprError}; use crate::err::{ParseEnumError, ReprError};
use std::{convert::TryFrom, str::FromStr}; use std::{convert::TryFrom, str::FromStr};
c_enum! { c_enum! {
enum TestEnum: u16 { enum TestEnum: u16 {
Zero = 0, Zero = 0,
One = 1, One = 1,
Two = 2, Two = 2,
} }
} }
#[test] #[test]
fn c_enum() fn c_enum()
{ {
assert_eq!(TestEnum::try_from(0), Ok(TestEnum::Zero)); assert_eq!(TestEnum::try_from(0), Ok(TestEnum::Zero));
assert_eq!(TestEnum::try_from(1), Ok(TestEnum::One)); assert_eq!(TestEnum::try_from(1), Ok(TestEnum::One));
assert_eq!(TestEnum::try_from(2), Ok(TestEnum::Two)); assert_eq!(TestEnum::try_from(2), Ok(TestEnum::Two));
assert_eq!(TestEnum::try_from(3), Err(ReprError::new("TestEnum", 3))); assert_eq!(TestEnum::try_from(3), Err(ReprError::new("TestEnum", 3)));
assert_eq!(TestEnum::try_from(4), Err(ReprError::new("TestEnum", 4))); assert_eq!(TestEnum::try_from(4), Err(ReprError::new("TestEnum", 4)));
assert_eq!(TestEnum::try_from(5), Err(ReprError::new("TestEnum", 5))); assert_eq!(TestEnum::try_from(5), Err(ReprError::new("TestEnum", 5)));
assert_eq!(TestEnum::from_str("Zero"), Ok(TestEnum::Zero)); assert_eq!(TestEnum::from_str("Zero"), Ok(TestEnum::Zero));
assert_eq!(TestEnum::from_str("One"), Ok(TestEnum::One)); assert_eq!(TestEnum::from_str("One"), Ok(TestEnum::One));
assert_eq!(TestEnum::from_str("Two"), Ok(TestEnum::Two)); assert_eq!(TestEnum::from_str("Two"), Ok(TestEnum::Two));
assert_eq!(TestEnum::from_str("Three"), assert_eq!(TestEnum::from_str("Three"),
Err(ParseEnumError::new("TestEnum"))); Err(ParseEnumError::new("TestEnum")));
} }
} }
// EOF // EOF

View File

@ -3,22 +3,22 @@
// Accumulator for CRC function. // Accumulator for CRC function.
fn crc_accum(a: u32, _: u32) -> u32 fn crc_accum(a: u32, _: u32) -> u32
{ {
if a & 1 == 1 { if a & 1 == 1 {
ISO_3309_POLYNOMIAL ^ a >> 1 ISO_3309_POLYNOMIAL ^ a >> 1
} else { } else {
a >> 1 a >> 1
} }
} }
// Initializes a CRC array. // Initializes a CRC array.
// FIXME: use const fn when stabilized // FIXME: use const fn when stabilized
fn crc_init() -> [u32; 256] fn crc_init() -> [u32; 256]
{ {
let mut t = [0; 256]; let mut t = [0; 256];
for (n, v) in t.iter_mut().enumerate() { for (n, v) in t.iter_mut().enumerate() {
*v = (0..8).fold(n as u32, crc_accum); *v = (0..8).fold(n as u32, crc_accum);
} }
t t
} }
/// Creates an ADLER32 of all bytes in `b`. /// Creates an ADLER32 of all bytes in `b`.
@ -32,16 +32,16 @@ fn crc_init() -> [u32; 256]
/// ``` /// ```
pub fn adler32(b: &[u8]) -> u32 pub fn adler32(b: &[u8]) -> u32
{ {
let mut x = 1; let mut x = 1;
let mut y = 0; let mut y = 0;
for &z in b { for &z in b {
let z = u32::from(z); let z = u32::from(z);
x = (x + z) % ADLER32_MODULO; x = (x + z) % ADLER32_MODULO;
y = (y + x) % ADLER32_MODULO; y = (y + x) % ADLER32_MODULO;
} }
(y << 16) | x (y << 16) | x
} }
/// Creates a CRC-32 of all bytes in `b` with the starting sum `s`. The /// Creates a CRC-32 of all bytes in `b` with the starting sum `s`. The
@ -56,8 +56,8 @@ pub fn adler32(b: &[u8]) -> u32
/// ``` /// ```
pub fn crc32(b: &[u8], s: u32) -> u32 pub fn crc32(b: &[u8], s: u32) -> u32
{ {
let t = crc_init(); 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)])
} }
const ISO_3309_POLYNOMIAL: u32 = 0xEDB8_8320; const ISO_3309_POLYNOMIAL: u32 = 0xEDB8_8320;

View File

@ -6,209 +6,209 @@ use std::cmp::Ordering;
/// Loads a ZLIB file header. /// Loads a ZLIB file header.
pub fn load_zlib_header(b: &[u8]) -> ResultS<usize> pub fn load_zlib_header(b: &[u8]) -> ResultS<usize>
{ {
const CM: u8 = 0b0000_1111; const CM: u8 = 0b0000_1111;
const CINFO: u8 = 0b1111_0000; const CINFO: u8 = 0b1111_0000;
const FDICT: u8 = 0b0010_0000; const FDICT: u8 = 0b0010_0000;
read_data! { read_data! {
endian: BIG, buf: b, size: 2, start: 0, data { endian: BIG, buf: b, size: 2, start: 0, data {
let fcheck = u16[0]; let fcheck = u16[0];
let cmf = u8[0]; let cmf = u8[0];
let flg = u8[1]; let flg = u8[1];
} }
} }
let cm = cmf & CM; let cm = cmf & CM;
let cinfo = cmf & CINFO; let cinfo = cmf & CINFO;
if cm != 8 { if cm != 8 {
bail!("unknown compression method"); bail!("unknown compression method");
} }
if cinfo > 7 << 4 { if cinfo > 7 << 4 {
bail!("lz77 window size logarithm is invalid"); bail!("lz77 window size logarithm is invalid");
} }
if fcheck % 31 != 0 { if fcheck % 31 != 0 {
bail!("invalid fcheck"); bail!("invalid fcheck");
} }
if flg & FDICT != 0 { if flg & FDICT != 0 {
bail!("dictionary not supported"); bail!("dictionary not supported");
} }
Ok(2) Ok(2)
} }
/// Loads a GZIP file header. /// Loads a GZIP file header.
pub fn load_gzip_header(b: &[u8]) -> ResultS<usize> pub fn load_gzip_header(b: &[u8]) -> ResultS<usize>
{ {
const FHCRC: u8 = 1 << 1; const FHCRC: u8 = 1 << 1;
const FEXTRA: u8 = 1 << 2; const FEXTRA: u8 = 1 << 2;
const FNAME: u8 = 1 << 3; const FNAME: u8 = 1 << 3;
const FCOMMENT: u8 = 1 << 4; const FCOMMENT: u8 = 1 << 4;
const FRESERVED: u8 = 0xe0; const FRESERVED: u8 = 0xe0;
read_data! { read_data! {
endian: LITTLE, buf: b, size: 10, start: 0, data { endian: LITTLE, buf: b, size: 10, start: 0, data {
let id = u16[0]; let id = u16[0];
let cm = u8[2]; let cm = u8[2];
let fl = u8[3]; let fl = u8[3];
} }
} }
if id != 0x8b1f || cm != 8 { if id != 0x8b1f || cm != 8 {
bail!("not gzip format"); bail!("not gzip format");
} }
let mut p = 10; let mut p = 10;
if fl & FRESERVED != 0 { if fl & FRESERVED != 0 {
bail!("reserved flags set"); bail!("reserved flags set");
} }
if fl & FEXTRA != 0 { if fl & FEXTRA != 0 {
read_data! { read_data! {
endian: LITTLE, buf: b, size: 2, start: p, data { endian: LITTLE, buf: b, size: 2, start: p, data {
let xlen = u16[0] usize; let xlen = u16[0] usize;
} }
} }
p += 2 + xlen; p += 2 + xlen;
check_data(b, p)?; check_data(b, p)?;
} }
if fl & FNAME != 0 { if fl & FNAME != 0 {
p += skip_zero_terminated_item(&b[p..])?; p += skip_zero_terminated_item(&b[p..])?;
} }
if fl & FCOMMENT != 0 { if fl & FCOMMENT != 0 {
p += skip_zero_terminated_item(&b[p..])?; p += skip_zero_terminated_item(&b[p..])?;
} }
if fl & FHCRC != 0 { if fl & FHCRC != 0 {
p += 2; p += 2;
check_data(b, p)?; check_data(b, p)?;
} }
Ok(p) Ok(p)
} }
fn skip_zero_terminated_item(b: &[u8]) -> ResultS<usize> fn skip_zero_terminated_item(b: &[u8]) -> ResultS<usize>
{ {
if let Some(i) = b.iter().position(|&n| n == 0) { if let Some(i) = b.iter().position(|&n| n == 0) {
Ok(i + 1) Ok(i + 1)
} else { } else {
bail!("no end of zero terminated item"); bail!("no end of zero terminated item");
} }
} }
/// Decompresses a DEFLATE compressed bitstream. /// Decompresses a DEFLATE compressed bitstream.
pub fn load_deflate(b: &[u8]) -> ResultS<(usize, Vec<u8>)> pub fn load_deflate(b: &[u8]) -> ResultS<(usize, Vec<u8>)>
{ {
let mut v = Vec::new(); let mut v = Vec::new();
let mut p = 0; let mut p = 0;
loop { loop {
let bfinal = read_bits_l(b, p, 1)?; let bfinal = read_bits_l(b, p, 1)?;
p += 1; p += 1;
let btype = read_bits_l(b, p, 2)?; let btype = read_bits_l(b, p, 2)?;
p += 2; p += 2;
match btype { match btype {
0b10 => p = stream_dynamic(&mut v, b, p)?, 0b10 => p = stream_dynamic(&mut v, b, p)?,
0b01 => p = stream_s_table(&mut v, b, p)?, 0b01 => p = stream_s_table(&mut v, b, p)?,
0b00 => p = stream_literal(&mut v, b, p)?, 0b00 => p = stream_literal(&mut v, b, p)?,
_ => bail!("bad btype"), _ => bail!("bad btype"),
} }
if bfinal == 1 { if bfinal == 1 {
return Ok((p / 8, v)); return Ok((p / 8, v));
} }
} }
} }
fn stream_dynamic(v: &mut Vec<u8>, b: &[u8], mut p: usize) -> ResultS<usize> fn stream_dynamic(v: &mut Vec<u8>, b: &[u8], mut p: usize) -> ResultS<usize>
{ {
const CODE_ORDERING: [usize; 19] = const CODE_ORDERING: [usize; 19] =
[16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]; [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
// read header (number of literal alphabet codes, number of distance // read header (number of literal alphabet codes, number of distance
// alphabet codes, and number of lengths for decoding the alphabet) // alphabet codes, and number of lengths for decoding the alphabet)
let hlit = read_bits_l(b, p, 5)?; let hlit = read_bits_l(b, p, 5)?;
p += 5; p += 5;
let hdist = read_bits_l(b, p, 5)?; let hdist = read_bits_l(b, p, 5)?;
p += 5; p += 5;
let hclen = read_bits_l(b, p, 4)?; let hclen = read_bits_l(b, p, 4)?;
p += 4; p += 4;
let hlit = 257 + hlit as usize; let hlit = 257 + hlit as usize;
let hdist = 1 + hdist as usize; let hdist = 1 + hdist as usize;
let hclen = 4 + hclen as usize; let hclen = 4 + hclen as usize;
// first, get the huffman coding for the alphabet (which is also compressed) // first, get the huffman coding for the alphabet (which is also compressed)
let mut code_table = [0; 19]; let mut code_table = [0; 19];
for i in 0..hclen { for i in 0..hclen {
let len = read_bits_l(b, p, 3)? as u16; let len = read_bits_l(b, p, 3)? as u16;
p += 3; p += 3;
code_table[CODE_ORDERING[i]] = len; code_table[CODE_ORDERING[i]] = len;
} }
// then, we decode the alphabet (doing both types at the same time, because // then, we decode the alphabet (doing both types at the same time, because
// they're encoded the same anyways) // they're encoded the same anyways)
let code_table = HuffmanTable::new(&code_table)?; let code_table = HuffmanTable::new(&code_table)?;
let mut alphabet = vec![0; hlit + hdist]; let mut alphabet = vec![0; hlit + hdist];
p = read_alphabet(b, p, &mut alphabet, code_table)?; p = read_alphabet(b, p, &mut alphabet, code_table)?;
if alphabet[256] == 0 { if alphabet[256] == 0 {
bail!("no way to end block"); bail!("no way to end block");
} }
// build the length and distance tables from this information // build the length and distance tables from this information
let table_len = HuffmanTable::new(&alphabet[0..hlit])?; let table_len = HuffmanTable::new(&alphabet[0..hlit])?;
let table_dst = HuffmanTable::new(&alphabet[hlit..hlit + hdist])?; let table_dst = HuffmanTable::new(&alphabet[hlit..hlit + hdist])?;
output_tables(v, b, p, table_len, table_dst) output_tables(v, b, p, table_len, table_dst)
} }
#[allow(clippy::needless_range_loop)] #[allow(clippy::needless_range_loop)]
fn stream_s_table(v: &mut Vec<u8>, b: &[u8], p: usize) -> ResultS<usize> fn stream_s_table(v: &mut Vec<u8>, b: &[u8], p: usize) -> ResultS<usize>
{ {
let mut len = [0; 288]; let mut len = [0; 288];
for i in 0..144 {len[i] = 8;} for i in 0..144 {len[i] = 8;}
for i in 144..256 {len[i] = 9;} for i in 144..256 {len[i] = 9;}
for i in 256..280 {len[i] = 7;} for i in 256..280 {len[i] = 7;}
for i in 280..288 {len[i] = 8;} for i in 280..288 {len[i] = 8;}
let dst = [5; 30]; let dst = [5; 30];
let table_len = HuffmanTable::new(&len)?; let table_len = HuffmanTable::new(&len)?;
let table_dst = HuffmanTable::new(&dst)?; let table_dst = HuffmanTable::new(&dst)?;
output_tables(v, b, p, table_len, table_dst) output_tables(v, b, p, table_len, table_dst)
} }
fn stream_literal(v: &mut Vec<u8>, b: &[u8], p: usize) -> ResultS<usize> fn stream_literal(v: &mut Vec<u8>, b: &[u8], p: usize) -> ResultS<usize>
{ {
// copy data directly from byte boundary // copy data directly from byte boundary
let mut p = p / 8 + 1; let mut p = p / 8 + 1;
read_data! { read_data! {
endian: LITTLE, buf: b, size: 4, start: p, data { endian: LITTLE, buf: b, size: 4, start: p, data {
let len = u16[0] usize; let len = u16[0] usize;
} }
} }
p += 4; p += 4;
v.extend(ok!(b.get(p..p + len), "not enough data")?); v.extend(ok!(b.get(p..p + len), "not enough data")?);
Ok((p + len) * 8) Ok((p + len) * 8)
} }
fn read_alphabet(b: &[u8], fn read_alphabet(b: &[u8],
@ -216,63 +216,63 @@ fn read_alphabet(b: &[u8],
alphabet: &mut [u16], alphabet: &mut [u16],
code_table: HuffmanTable) -> ResultS<usize> code_table: HuffmanTable) -> ResultS<usize>
{ {
let mut i = 0; let mut i = 0;
while i < alphabet.len() { while i < alphabet.len() {
let (bits, sym) = code_table.decode(b, p)?; let (bits, sym) = code_table.decode(b, p)?;
p += bits; p += bits;
match sym { match sym {
0..=15 => { 0..=15 => {
// raw code // raw code
alphabet[i] = sym; alphabet[i] = sym;
i += 1; i += 1;
} }
16 => { 16 => {
// copy previous code 3-6 times // copy previous code 3-6 times
if i == 0 { if i == 0 {
bail!("cannot copy on first alphabet code"); bail!("cannot copy on first alphabet code");
} }
let len = usize::from(read_bits_l(b, p, 2)? as u8 + 3); let len = usize::from(read_bits_l(b, p, 2)? as u8 + 3);
let lst = alphabet[i - 1]; let lst = alphabet[i - 1];
p += 2; p += 2;
for _ in 0..len { for _ in 0..len {
alphabet[i] = lst; alphabet[i] = lst;
i += 1; i += 1;
} }
} }
17 => { 17 => {
// repeat '0' 3-10 times // repeat '0' 3-10 times
let len = usize::from(read_bits_l(b, p, 3)? as u8 + 3); let len = usize::from(read_bits_l(b, p, 3)? as u8 + 3);
p += 3; p += 3;
for _ in 0..len { for _ in 0..len {
alphabet[i] = 0; alphabet[i] = 0;
i += 1; i += 1;
} }
} }
18 => { 18 => {
// repeat '0' 11-138 times // repeat '0' 11-138 times
let len = usize::from(read_bits_l(b, p, 7)? as u8 + 11); let len = usize::from(read_bits_l(b, p, 7)? as u8 + 11);
p += 7; p += 7;
for _ in 0..len { for _ in 0..len {
alphabet[i] = 0; alphabet[i] = 0;
i += 1; i += 1;
} }
} }
_ => { _ => {
bail!("bad symbol in alphabet"); bail!("bad symbol in alphabet");
} }
} }
if i > alphabet.len() { if i > alphabet.len() {
bail!("too many codes"); bail!("too many codes");
} }
} }
Ok(p) Ok(p)
} }
fn output_tables(v: &mut Vec<u8>, fn output_tables(v: &mut Vec<u8>,
@ -281,145 +281,145 @@ fn output_tables(v: &mut Vec<u8>,
table_len: HuffmanTable, table_len: HuffmanTable,
table_dst: HuffmanTable) -> ResultS<usize> table_dst: HuffmanTable) -> ResultS<usize>
{ {
const LEN_BASE: [usize; 29] = [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, const LEN_BASE: [usize; 29] = [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19,
23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115,
131, 163, 195, 227, 258]; 131, 163, 195, 227, 258];
const LEN_EXTRA_BITS: [u8; 29] = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, const LEN_EXTRA_BITS: [u8; 29] = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2,
2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5,
0]; 0];
const DST_BASE: [usize; 30] = [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, const DST_BASE: [usize; 30] = [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65,
97, 129, 193, 257, 385, 513, 769, 1025, 97, 129, 193, 257, 385, 513, 769, 1025,
1537, 2049, 3073, 4097, 0x1801, 0x2001, 1537, 2049, 3073, 4097, 0x1801, 0x2001,
0x3001, 0x4001, 0x6001]; 0x3001, 0x4001, 0x6001];
const DST_EXTRA_BITS: [u8; 30] = [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, const DST_EXTRA_BITS: [u8; 30] = [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5,
6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
12, 12, 13, 13]; 12, 12, 13, 13];
loop { loop {
let (bits, sym) = table_len.decode(b, p)?; let (bits, sym) = table_len.decode(b, p)?;
p += bits; p += bits;
match sym.cmp(&256) { match sym.cmp(&256) {
Ordering::Less => { Ordering::Less => {
// direct byte // direct byte
v.push(sym as u8); v.push(sym as u8);
} }
Ordering::Equal => { Ordering::Equal => {
return Ok(p); return Ok(p);
} }
Ordering::Greater => { Ordering::Greater => {
// this is a <len, dst> pair // this is a <len, dst> pair
let sym = sym - 257; let sym = sym - 257;
if sym > 29 { if sym > 29 {
bail!("invalid fixed code"); bail!("invalid fixed code");
} }
let sym = usize::from(sym); let sym = usize::from(sym);
// first get the actual length and any extra bits it may have // first get the actual length and any extra bits it may have
let bits = LEN_EXTRA_BITS[sym]; let bits = LEN_EXTRA_BITS[sym];
let leng = LEN_BASE[sym] + read_bits_l(b, p, bits)? as usize; let leng = LEN_BASE[sym] + read_bits_l(b, p, bits)? as usize;
p += usize::from(bits); p += usize::from(bits);
// decode the distance with its alphabet // decode the distance with its alphabet
let (bits, sym) = table_dst.decode(b, p)?; let (bits, sym) = table_dst.decode(b, p)?;
p += bits; p += bits;
let sym = usize::from(sym); let sym = usize::from(sym);
// get the actual distance and any extra bits it may have // get the actual distance and any extra bits it may have
let bits = DST_EXTRA_BITS[sym]; let bits = DST_EXTRA_BITS[sym];
let dist = DST_BASE[sym] + read_bits_l(b, p, bits)? as usize; let dist = DST_BASE[sym] + read_bits_l(b, p, bits)? as usize;
p += usize::from(bits); p += usize::from(bits);
if dist > v.len() { if dist > v.len() {
bail!("bad distance"); bail!("bad distance");
} }
// copy bytes from earlier // copy bytes from earlier
for _ in 0..leng { for _ in 0..leng {
v.push(v[v.len() - dist]); v.push(v[v.len() - dist]);
} }
} }
} }
} }
} }
impl HuffmanTable impl HuffmanTable
{ {
fn new(table: &[u16]) -> ResultS<Self> fn new(table: &[u16]) -> ResultS<Self>
{ {
let mut syms = vec![0; table.len()]; let mut syms = vec![0; table.len()];
let mut nums = [0; 16]; let mut nums = [0; 16];
// count the number of symbols for each bit length // count the number of symbols for each bit length
for &length in table { for &length in table {
nums[usize::from(length)] += 1; nums[usize::from(length)] += 1;
} }
if usize::from(nums[0]) == table.len() { if usize::from(nums[0]) == table.len() {
bail!("bad table lengths"); bail!("bad table lengths");
} }
// make offsets into the symbol table for each bit count // make offsets into the symbol table for each bit count
let mut ofs = [0; 16]; let mut ofs = [0; 16];
for i in 1..=14 { for i in 1..=14 {
ofs[i + 1] = ofs[i] + usize::from(nums[i]); ofs[i + 1] = ofs[i] + usize::from(nums[i]);
} }
// make the actual bit pattern table // make the actual bit pattern table
for (n, &length) in table.iter().enumerate() { for (n, &length) in table.iter().enumerate() {
// length 0 means this code isn't used, so only try to make bit // length 0 means this code isn't used, so only try to make bit
// patterns for codes that actually exist // patterns for codes that actually exist
if length != 0 { if length != 0 {
// make sure to make each offset unique // make sure to make each offset unique
let offset = &mut ofs[usize::from(length)]; let offset = &mut ofs[usize::from(length)];
syms[*offset] = n as u16; syms[*offset] = n as u16;
*offset += 1; *offset += 1;
} }
} }
Ok(Self{nums, syms}) Ok(Self{nums, syms})
} }
fn decode(&self, b: &[u8], mut p: usize) -> ResultS<(usize, u16)> fn decode(&self, b: &[u8], mut p: usize) -> ResultS<(usize, u16)>
{ {
let mut code = 0_u16; let mut code = 0_u16;
let mut first = 0_u16; let mut first = 0_u16;
let mut index = 0_u16; let mut index = 0_u16;
for i in 1..=15 { for i in 1..=15 {
// add bit from file // add bit from file
code |= read_bits_l(b, p, 1)? as u16; code |= read_bits_l(b, p, 1)? as u16;
p += 1; p += 1;
// check our symbol table for this one (quick tree check) // check our symbol table for this one (quick tree check)
let count = self.nums[i]; let count = self.nums[i];
if i32::from(code) - i32::from(count) < i32::from(first) { if i32::from(code) - i32::from(count) < i32::from(first) {
return Ok((i, self.syms[usize::from(index + code - first)])); return Ok((i, self.syms[usize::from(index + code - first)]));
} }
// continue on, trying to find the correct sequence // continue on, trying to find the correct sequence
index += count; index += count;
first += count; first += count;
first <<= 1; first <<= 1;
code <<= 1; code <<= 1;
} }
Err(ReprError::new("DEFLATE code", code).into()) Err(ReprError::new("DEFLATE code", code).into())
} }
} }
struct HuffmanTable { struct HuffmanTable {
nums: [u16; 16], nums: [u16; 16],
syms: Vec<u16>, syms: Vec<u16>,
} }
// EOF // EOF

View File

@ -8,15 +8,15 @@
/// use maraiah::doc_comment; /// use maraiah::doc_comment;
/// ///
/// doc_comment! { /// doc_comment! {
/// concat!("Have a nice", " day", "!"), /// concat!("Have a nice", " day", "!"),
/// const A: u32 = 5; /// const A: u32 = 5;
/// } /// }
/// ///
/// assert_eq!(A, 5); /// assert_eq!(A, 5);
/// ``` /// ```
#[macro_export] #[macro_export]
macro_rules! doc_comment { macro_rules! doc_comment {
($x:expr, $($tt:tt)*) => {#[doc = $x] $($tt)*} ($x:expr, $($tt:tt)*) => {#[doc = $x] $($tt)*}
} }
// EOF // EOF

View File

@ -5,40 +5,40 @@ pub use failure::{Error, Fail};
use std::fmt; use std::fmt;
macro_rules! ok { macro_rules! ok {
($v:expr, $msg:expr) => { ($v:expr, $msg:expr) => {
match $v { match $v {
Some(v) => Ok(v), Some(v) => Ok(v),
None => Err($crate::err::err_msg($msg)), None => Err($crate::err::err_msg($msg)),
} }
}; };
} }
macro_rules! flag_ok { macro_rules! flag_ok {
($t:ident$(::$tc:ident)*, $v:expr) => { ($t:ident$(::$tc:ident)*, $v:expr) => {
{ {
let v = $v; let v = $v;
match $t$(::$tc)*::from_bits(v) { match $t$(::$tc)*::from_bits(v) {
Some(v) => Ok(v), Some(v) => Ok(v),
None => Err($crate::err::ReprError::new(stringify!($t), v)), None => Err($crate::err::ReprError::new(stringify!($t), v)),
} }
} }
}; };
} }
macro_rules! bail { macro_rules! bail {
($e:expr) => { ($e:expr) => {
return Err($crate::err::err_msg($e)); return Err($crate::err::err_msg($e));
}; };
} }
#[macro_export] #[macro_export]
macro_rules! backtrace { macro_rules! backtrace {
($e:expr) => { ($e:expr) => {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
dbg!($e.backtrace()); dbg!($e.backtrace());
} }
} }
} }
/// Returns an `Error` with a static string. /// Returns an `Error` with a static string.
@ -55,58 +55,58 @@ pub fn err_msg(msg: &'static str) -> Error {ErrMsg(msg).into()}
impl ParseEnumError impl ParseEnumError
{ {
/// Returns an `Error` with a message for enumeration parsing errata. /// Returns an `Error` with a message for enumeration parsing errata.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use maraiah::err::ParseEnumError; /// use maraiah::err::ParseEnumError;
/// ///
/// assert_eq!(format!("{}", ParseEnumError::new("TypeName")), /// assert_eq!(format!("{}", ParseEnumError::new("TypeName")),
/// "could not parse TypeName"); /// "could not parse TypeName");
/// ``` /// ```
#[inline] #[inline]
pub const fn new(t: &'static str) -> Self pub const fn new(t: &'static str) -> Self
{ {
Self(t) Self(t)
} }
} }
impl ParseFlagError impl ParseFlagError
{ {
/// Returns an `Error` with a message for flag parsing errata. /// Returns an `Error` with a message for flag parsing errata.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use maraiah::err::ParseFlagError; /// use maraiah::err::ParseFlagError;
/// ///
/// assert_eq!(format!("{}", ParseFlagError::new("TypeName")), /// assert_eq!(format!("{}", ParseFlagError::new("TypeName")),
/// "could not parse TypeName"); /// "could not parse TypeName");
/// ``` /// ```
#[inline] #[inline]
pub const fn new(t: &'static str) -> Self pub const fn new(t: &'static str) -> Self
{ {
Self(t) Self(t)
} }
} }
impl ReprError impl ReprError
{ {
/// Returns an `Error` with a message for representation errata. /// Returns an `Error` with a message for representation errata.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use maraiah::err::ReprError; /// use maraiah::err::ReprError;
/// ///
/// assert_eq!(format!("{}", ReprError::new("TypeName", 77)), /// assert_eq!(format!("{}", ReprError::new("TypeName", 77)),
/// "bad TypeName (77)"); /// "bad TypeName (77)");
/// ``` /// ```
pub fn new<T: Into<i64>>(t: &'static str, n: T) -> Self pub fn new<T: Into<i64>>(t: &'static str, n: T) -> Self
{ {
Self(t, n.into()) Self(t, n.into())
} }
} }
impl Fail for ErrMsg {} impl Fail for ErrMsg {}
@ -116,34 +116,34 @@ impl Fail for ReprError {}
impl fmt::Display for ParseEnumError impl fmt::Display for ParseEnumError
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{ {
write!(f, "could not parse {}", self.0) write!(f, "could not parse {}", self.0)
} }
} }
impl fmt::Display for ParseFlagError impl fmt::Display for ParseFlagError
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{ {
write!(f, "could not parse {}", self.0) write!(f, "could not parse {}", self.0)
} }
} }
impl fmt::Display for ReprError impl fmt::Display for ReprError
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{ {
write!(f, "bad {} ({})", self.0, self.1) write!(f, "bad {} ({})", self.0, self.1)
} }
} }
impl fmt::Display for ErrMsg impl fmt::Display for ErrMsg
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{ {
f.write_str(self.0) f.write_str(self.0)
} }
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]

View File

@ -19,14 +19,14 @@ pub use std::{ffi::*, os::raw::*, ptr::{null, null_mut}};
/// assert!(!st.is_null()); /// assert!(!st.is_null());
/// ///
/// unsafe { /// unsafe {
/// assert_eq!(std::slice::from_raw_parts(st, 5), &[116, 101, 115, 116, 0]); /// assert_eq!(std::slice::from_raw_parts(st, 5), &[116, 101, 115, 116, 0]);
/// } /// }
/// ``` /// ```
#[macro_export] #[macro_export]
macro_rules! c_str { macro_rules! c_str {
($s:expr) => { ($s:expr) => {
concat!($s, "\0").as_ptr() as $crate::ffi::NT concat!($s, "\0").as_ptr() as $crate::ffi::NT
}; };
} }
/// Returns [`null`] as a [`*const c_void`]. /// Returns [`null`] as a [`*const c_void`].
@ -45,49 +45,49 @@ pub const fn null_mut_void() -> *mut c_void {null_mut()}
impl CStringVec impl CStringVec
{ {
/// Creates a new `CStringVec` from an iterator. /// Creates a new `CStringVec` from an iterator.
#[inline] #[inline]
pub fn new_from_iter<'a, I>(it: I) -> ResultS<Self> pub fn new_from_iter<'a, I>(it: I) -> ResultS<Self>
where I: Iterator<Item = &'a str> where I: Iterator<Item = &'a str>
{ {
let mut v = Self::default(); let mut v = Self::default();
for st in it { for st in it {
v.push(CString::new(st)?); v.push(CString::new(st)?);
} }
Ok(v) Ok(v)
} }
/// Pushes a new `CString`. /// Pushes a new `CString`.
#[inline] #[inline]
pub fn push(&mut self, st: CString) pub fn push(&mut self, st: CString)
{ {
self.cv.insert(self.cv.len() - 1, st.as_ptr()); self.cv.insert(self.cv.len() - 1, st.as_ptr());
self.sv.push(st); self.sv.push(st);
} }
/// Returns the FFI pointer. /// Returns the FFI pointer.
#[inline] #[inline]
pub fn as_ptr(&self) -> *const NT {self.cv.as_ptr()} pub fn as_ptr(&self) -> *const NT {self.cv.as_ptr()}
/// Returns the FFI pointer mutably. /// Returns the FFI pointer mutably.
#[inline] #[inline]
pub fn as_mut_ptr(&mut self) -> *mut NT {self.cv.as_mut_ptr()} pub fn as_mut_ptr(&mut self) -> *mut NT {self.cv.as_mut_ptr()}
} }
impl Default for CStringVec impl Default for CStringVec
{ {
/// Creates a new empty CStringVec. /// Creates a new empty CStringVec.
#[inline] #[inline]
fn default() -> Self {Self{sv: Vec::new(), cv: vec![null()]}} fn default() -> Self {Self{sv: Vec::new(), cv: vec![null()]}}
} }
/// An owned null-terminated string vector. /// An owned null-terminated string vector.
#[derive(Debug)] #[derive(Debug)]
pub struct CStringVec { pub struct CStringVec {
sv: Vec<CString>, sv: Vec<CString>,
cv: Vec<NT>, cv: Vec<NT>,
} }
/// A null-terminated byte string pointer. /// A null-terminated byte string pointer.

View File

@ -6,62 +6,62 @@ use std::{fs, path::Path, io::{SeekFrom, prelude::*}};
/// Confirms that the path `p` is a folder. /// Confirms that the path `p` is a folder.
pub fn validate_folder_path(p: &str) -> ResultS<()> pub fn validate_folder_path(p: &str) -> ResultS<()>
{ {
let at = fs::metadata(p)?; let at = fs::metadata(p)?;
if at.is_dir() { if at.is_dir() {
Ok(()) Ok(())
} else { } else {
Err(err_msg("not a directory")) Err(err_msg("not a directory"))
} }
} }
/// Opens the file at `path` and skips past any macintosh headers. /// Opens the file at `path` and skips past any macintosh headers.
pub fn open_mac<P: AsRef<Path>>(path: P) -> ResultS<fs::File> pub fn open_mac<P: AsRef<Path>>(path: P) -> ResultS<fs::File>
{ {
let mut fp = fs::File::open(path)?; let mut fp = fs::File::open(path)?;
machdr::skip_mac_header(&mut fp); machdr::skip_mac_header(&mut fp);
Ok(fp) Ok(fp)
} }
impl<T> Drop for SeekBackToStart<T> impl<T> Drop for SeekBackToStart<T>
where T: Seek where T: Seek
{ {
fn drop(&mut self) {if self.fl {let _ = self.seek(SeekFrom::Start(0));}} fn drop(&mut self) {if self.fl {let _ = self.seek(SeekFrom::Start(0));}}
} }
impl<T> std::ops::Deref for SeekBackToStart<T> impl<T> std::ops::Deref for SeekBackToStart<T>
where T: Seek where T: Seek
{ {
type Target = T; type Target = T;
fn deref(&self) -> &Self::Target {&self.sc} fn deref(&self) -> &Self::Target {&self.sc}
} }
impl<T> std::ops::DerefMut for SeekBackToStart<T> impl<T> std::ops::DerefMut for SeekBackToStart<T>
where T: Seek where T: Seek
{ {
fn deref_mut(&mut self) -> &mut Self::Target {&mut self.sc} fn deref_mut(&mut self) -> &mut Self::Target {&mut self.sc}
} }
impl<T> SeekBackToStart<T> impl<T> SeekBackToStart<T>
where T: Seek where T: Seek
{ {
/// Creates a new `SeekBackToStart` object. /// Creates a new `SeekBackToStart` object.
pub fn new(sc: T) -> Self {Self{sc, fl: true}} pub fn new(sc: T) -> Self {Self{sc, fl: true}}
/// Sets the seek-back flag. /// Sets the seek-back flag.
pub fn set_seek(&mut self, fl: bool) {self.fl = fl;} pub fn set_seek(&mut self, fl: bool) {self.fl = fl;}
/// Returns the seek-back flag. /// Returns the seek-back flag.
pub fn get_seek(&self) -> bool {self.fl} pub fn get_seek(&self) -> bool {self.fl}
} }
/// Seeks back to the starting position of the inner object when losing scope, /// Seeks back to the starting position of the inner object when losing scope,
/// unless a flag is set. /// unless a flag is set.
pub struct SeekBackToStart<T: Seek> { pub struct SeekBackToStart<T: Seek> {
sc: T, sc: T,
fl: bool, fl: bool,
} }
// EOF // EOF

File diff suppressed because it is too large Load Diff

View File

@ -16,10 +16,10 @@ pub mod tga;
#[inline] #[inline]
pub const fn r5g5b5_to_rgb8(rgb: u16) -> Color8 pub const fn r5g5b5_to_rgb8(rgb: u16) -> Color8
{ {
let r = (rgb >> 10) as u8 & 0x1f; let r = (rgb >> 10) as u8 & 0x1f;
let g = (rgb >> 5) as u8 & 0x1f; let g = (rgb >> 5) as u8 & 0x1f;
let b = rgb as u8 & 0x1f; let b = rgb as u8 & 0x1f;
Color8::new(r << 3, g << 3, b << 3) Color8::new(r << 3, g << 3, b << 3)
} }
/// Creates a RGB16 color from a R5G5B5 format color. /// Creates a RGB16 color from a R5G5B5 format color.
@ -35,10 +35,10 @@ pub const fn r5g5b5_to_rgb8(rgb: u16) -> Color8
#[inline] #[inline]
pub const fn r5g5b5_to_rgb16(rgb: u16) -> Color16 pub const fn r5g5b5_to_rgb16(rgb: u16) -> Color16
{ {
let r = rgb >> 10 & 0x1f; let r = rgb >> 10 & 0x1f;
let g = rgb >> 5 & 0x1f; let g = rgb >> 5 & 0x1f;
let b = rgb & 0x1f; let b = rgb & 0x1f;
Color16::new(r << 11, g << 11, b << 11) Color16::new(r << 11, g << 11, b << 11)
} }
/// Creates a RGB16 color from a RGB8 format color. /// Creates a RGB16 color from a RGB8 format color.
@ -55,174 +55,174 @@ pub const fn r5g5b5_to_rgb16(rgb: u16) -> Color16
/// ``` /// ```
pub fn rgb8_to_rgb16(cr: Color8) -> Color16 pub fn rgb8_to_rgb16(cr: Color8) -> Color16
{ {
Color16::new(cr.r(), cr.g(), cr.b()) Color16::new(cr.r(), cr.g(), cr.b())
} }
/// A generic color matrix image. /// A generic color matrix image.
pub trait Image pub trait Image
{ {
/// The type of color this image uses for each pixel. /// The type of color this image uses for each pixel.
type Output: Color; type Output: Color;
/// Returns the width of the image. /// Returns the width of the image.
fn w(&self) -> usize; fn w(&self) -> usize;
/// Returns the height of the image. /// Returns the height of the image.
fn h(&self) -> usize; fn h(&self) -> usize;
/// Returns the color of the pixel at column `x` at row `y`. /// Returns the color of the pixel at column `x` at row `y`.
/// ///
/// # Panics /// # Panics
/// ///
/// Panics if `x` is greater than the width of the image or `y` is greater /// Panics if `x` is greater than the width of the image or `y` is greater
/// than the height of the image. /// than the height of the image.
fn index(&self, x: usize, y: usize) -> &Self::Output; fn index(&self, x: usize, y: usize) -> &Self::Output;
/// The same as `index`, but will not panic if out of bounds. /// The same as `index`, but will not panic if out of bounds.
fn get(&self, x: usize, y: usize) -> Option<&Self::Output> fn get(&self, x: usize, y: usize) -> Option<&Self::Output>
{ {
if x < self.w() && y < self.h() { if x < self.w() && y < self.h() {
Some(self.index(x, y)) Some(self.index(x, y))
} else { } else {
None None
} }
} }
} }
/// A generic color matrix image, which may be mutated. /// A generic color matrix image, which may be mutated.
pub trait ImageMut: Image pub trait ImageMut: Image
{ {
/// Returns the color of the pixel at column `x` at row `y`. /// Returns the color of the pixel at column `x` at row `y`.
/// ///
/// # Panics /// # Panics
/// ///
/// Panics if `x` is greater than the width of the image or `y` is greater /// Panics if `x` is greater than the width of the image or `y` is greater
/// than the height of the image. /// than the height of the image.
fn index_mut(&mut self, x: usize, y: usize) -> &mut Self::Output; fn index_mut(&mut self, x: usize, y: usize) -> &mut Self::Output;
/// The same as `index_mut`, but will not panic if out of bounds. /// The same as `index_mut`, but will not panic if out of bounds.
fn get_mut(&mut self, x: usize, y: usize) -> Option<&mut Self::Output> fn get_mut(&mut self, x: usize, y: usize) -> Option<&mut Self::Output>
{ {
if x < self.w() && y < self.h() { if x < self.w() && y < self.h() {
Some(self.index_mut(x, y)) Some(self.index_mut(x, y))
} else { } else {
None None
} }
} }
} }
/// Any color which may be represented as RGBA16. /// Any color which may be represented as RGBA16.
pub trait Color: Sized + Copy + Clone + Eq + PartialEq pub trait Color: Sized + Copy + Clone + Eq + PartialEq
{ {
/// Returns the red component. /// Returns the red component.
fn r(&self) -> u16; fn r(&self) -> u16;
/// Returns the green component. /// Returns the green component.
fn g(&self) -> u16; fn g(&self) -> u16;
/// Returns the blue component. /// Returns the blue component.
fn b(&self) -> u16; fn b(&self) -> u16;
/// Returns the alpha component. /// Returns the alpha component.
fn a(&self) -> u16; fn a(&self) -> u16;
} }
impl Image16 impl Image16
{ {
/// Creates a new Image16 with no canvas. /// Creates a new Image16 with no canvas.
pub fn new(w: usize, h: usize) -> Self pub fn new(w: usize, h: usize) -> Self
{ {
Self{w, h, cr: Vec::with_capacity(w * h)} Self{w, h, cr: Vec::with_capacity(w * h)}
} }
/// Creates a new Image16 with an empty canvas. /// Creates a new Image16 with an empty canvas.
pub fn new_empty(w: usize, h: usize) -> Self pub fn new_empty(w: usize, h: usize) -> Self
{ {
Self{w, h, cr: vec![Color16::new(0, 0, 0); w * h]} Self{w, h, cr: vec![Color16::new(0, 0, 0); w * h]}
} }
} }
impl Image for Image16 impl Image for Image16
{ {
type Output = Color16; type Output = Color16;
fn w(&self) -> usize {self.w} fn w(&self) -> usize {self.w}
fn h(&self) -> usize {self.h} fn h(&self) -> usize {self.h}
fn index(&self, x: usize, y: usize) -> &Self::Output fn index(&self, x: usize, y: usize) -> &Self::Output
{ {
&self.cr[x + y * self.w] &self.cr[x + y * self.w]
} }
} }
impl ImageMut for Image16 impl ImageMut for Image16
{ {
fn index_mut(&mut self, x: usize, y: usize) -> &mut Self::Output fn index_mut(&mut self, x: usize, y: usize) -> &mut Self::Output
{ {
&mut self.cr[x + y * self.w] &mut self.cr[x + y * self.w]
} }
} }
impl Image8 impl Image8
{ {
/// Creates a new Image8 with no canvas. /// Creates a new Image8 with no canvas.
pub fn new(w: usize, h: usize) -> Self pub fn new(w: usize, h: usize) -> Self
{ {
Self{w, h, cr: Vec::with_capacity(w * h)} Self{w, h, cr: Vec::with_capacity(w * h)}
} }
/// Creates a new Image8 with an empty canvas. /// Creates a new Image8 with an empty canvas.
pub fn new_empty(w: usize, h: usize) -> Self pub fn new_empty(w: usize, h: usize) -> Self
{ {
Self{w, h, cr: vec![Color8::new(0, 0, 0); w * h]} Self{w, h, cr: vec![Color8::new(0, 0, 0); w * h]}
} }
} }
impl Image for Image8 impl Image for Image8
{ {
type Output = Color8; type Output = Color8;
fn w(&self) -> usize {self.w} fn w(&self) -> usize {self.w}
fn h(&self) -> usize {self.h} fn h(&self) -> usize {self.h}
fn index(&self, x: usize, y: usize) -> &Self::Output fn index(&self, x: usize, y: usize) -> &Self::Output
{ {
&self.cr[x + y * self.w] &self.cr[x + y * self.w]
} }
} }
impl ImageMut for Image8 impl ImageMut for Image8
{ {
fn index_mut(&mut self, x: usize, y: usize) -> &mut Self::Output fn index_mut(&mut self, x: usize, y: usize) -> &mut Self::Output
{ {
&mut self.cr[x + y * self.w] &mut self.cr[x + y * self.w]
} }
} }
impl Color16 impl Color16
{ {
pub const fn new(r: u16, g: u16, b: u16) -> Self {Self(r, g, b)} pub const fn new(r: u16, g: u16, b: u16) -> Self {Self(r, g, b)}
} }
impl Color for Color16 impl Color for Color16
{ {
fn r(&self) -> u16 {self.0} fn r(&self) -> u16 {self.0}
fn g(&self) -> u16 {self.1} fn g(&self) -> u16 {self.1}
fn b(&self) -> u16 {self.2} fn b(&self) -> u16 {self.2}
fn a(&self) -> u16 {u16::max_value()} fn a(&self) -> u16 {u16::max_value()}
} }
impl Color8 impl Color8
{ {
pub const fn new(r: u8, g: u8, b: u8) -> Self {Self(r, g, b)} pub const fn new(r: u8, g: u8, b: u8) -> Self {Self(r, g, b)}
} }
impl Color for Color8 impl Color for Color8
{ {
fn r(&self) -> u16 {u16::from(self.0) << 8} fn r(&self) -> u16 {u16::from(self.0) << 8}
fn g(&self) -> u16 {u16::from(self.1) << 8} fn g(&self) -> u16 {u16::from(self.1) << 8}
fn b(&self) -> u16 {u16::from(self.2) << 8} fn b(&self) -> u16 {u16::from(self.2) << 8}
fn a(&self) -> u16 {u16::max_value()} fn a(&self) -> u16 {u16::max_value()}
} }
/// An RGB16 color. /// An RGB16 color.
@ -239,22 +239,22 @@ pub struct Color8(u8, u8, u8);
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct Image16 { pub struct Image16 {
w: usize, w: usize,
h: usize, h: usize,
/// The raw color data for this image. /// The raw color data for this image.
pub cr: Vec<Color16>, pub cr: Vec<Color16>,
} }
/// An RGB8 image. /// An RGB8 image.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct Image8 { pub struct Image8 {
w: usize, w: usize,
h: usize, h: usize,
/// The raw color data for this image. /// The raw color data for this image.
pub cr: Vec<Color8>, pub cr: Vec<Color8>,
} }
// EOF // EOF

View File

@ -9,109 +9,109 @@ use crate::{bin::*, err::*, image::*};
/// Load a `PICT` image. /// Load a `PICT` image.
pub fn read(b: &[u8]) -> ResultS<Image8> pub fn read(b: &[u8]) -> ResultS<Image8>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 10, start: 0, data { endian: BIG, buf: b, size: 10, start: 0, data {
let h = u16[6] usize; let h = u16[6] usize;
let w = u16[8] usize; let w = u16[8] usize;
} }
} }
if w * h > 16_000_000 { if w * h > 16_000_000 {
bail!("image is too large"); bail!("image is too large");
} }
let im = Image8::new(w, h); let im = Image8::new(w, h);
let mut p = 10; // size of header let mut p = 10; // size of header
while p < b.len() { while p < b.len() {
read_data! { read_data! {
endian: BIG, buf: b, size: 2, start: p, data { endian: BIG, buf: b, size: 2, start: p, data {
let op = u16[0]; let op = u16[0];
} }
} }
p += 2; p += 2;
match op { match op {
0x0098 => { 0x0098 => {
// PackBitsRect // PackBitsRect
return pm::area::read(im, &b[p..], true, false); return pm::area::read(im, &b[p..], true, false);
} }
0x0099 => { 0x0099 => {
// PackBitsRgn // PackBitsRgn
return pm::area::read(im, &b[p..], true, true); return pm::area::read(im, &b[p..], true, true);
} }
0x009a => { 0x009a => {
// DirectBitsRect // DirectBitsRect
return pm::area::read(im, &b[p..], false, false); return pm::area::read(im, &b[p..], false, false);
} }
0x009b => { 0x009b => {
// DirectBitsRgn // DirectBitsRgn
return pm::area::read(im, &b[p..], false, true); return pm::area::read(im, &b[p..], false, true);
} }
0x8200 => { 0x8200 => {
// CompressedQuickTime // CompressedQuickTime
unimplemented!(); unimplemented!();
} }
0x00ff => { 0x00ff => {
// OpEndPic // OpEndPic
break; break;
} }
// help i'm trapped in an awful metafile format from the 80s // help i'm trapped in an awful metafile format from the 80s
0x0000 | // NoOp 0x0000 | // NoOp
0x001c | // HiliteMode 0x001c | // HiliteMode
0x001e | // DefHilite 0x001e | // DefHilite
0x0038 | // FrameSameRect 0x0038 | // FrameSameRect
0x0039 | // PaintSameRect 0x0039 | // PaintSameRect
0x003a | // EraseSameRect 0x003a | // EraseSameRect
0x003b | // InvertSameRect 0x003b | // InvertSameRect
0x003c | // FillSameRect 0x003c | // FillSameRect
0x8000 | // Reserved 0x8000 | // Reserved
0x8100 => (), // Reserved 0x8100 => (), // Reserved
0x0003 | // TxFont 0x0003 | // TxFont
0x0004 | // TxFace 0x0004 | // TxFace
0x0005 | // TxMode 0x0005 | // TxMode
0x0008 | // PnMode 0x0008 | // PnMode
0x000d | // TxSize 0x000d | // TxSize
0x0011 | // VersionOp 0x0011 | // VersionOp
0x0015 | // PnLocHFrac 0x0015 | // PnLocHFrac
0x0016 | // ChExtra 0x0016 | // ChExtra
0x0023 | // ShortLineFrom 0x0023 | // ShortLineFrom
0x00a0 => p += 2, // ShortComment 0x00a0 => p += 2, // ShortComment
0x0006 | // SpExtra 0x0006 | // SpExtra
0x0007 | // PnSize 0x0007 | // PnSize
0x000b | // OvSize 0x000b | // OvSize
0x000c | // Origin 0x000c | // Origin
0x000e | // FgCol 0x000e | // FgCol
0x000f | // BkCol 0x000f | // BkCol
0x0021 => p += 4, // LineFrom 0x0021 => p += 4, // LineFrom
0x001a | // RGBFgCol 0x001a | // RGBFgCol
0x001b | // RGBBkCol 0x001b | // RGBBkCol
0x001d | // TxRatio 0x001d | // TxRatio
0x0022 => p += 6, // ShortLine 0x0022 => p += 6, // ShortLine
0x0002 | // BkPat 0x0002 | // BkPat
0x0009 | // PnPat 0x0009 | // PnPat
0x0010 | // TxRatio 0x0010 | // TxRatio
0x0020 | // Line 0x0020 | // Line
0x002e | // GlyphState 0x002e | // GlyphState
0x0030 | // FrameRect 0x0030 | // FrameRect
0x0031 | // PaintRect 0x0031 | // PaintRect
0x0032 | // EraseRect 0x0032 | // EraseRect
0x0033 | // InvertRect 0x0033 | // InvertRect
0x0034 => p += 8, // FillRect 0x0034 => p += 8, // FillRect
0x002d => p += 10, // LineJustify 0x002d => p += 10, // LineJustify
0x0001 => p += usize::from(u16b(&b[p.. ]) & !1), // Clip 0x0001 => p += usize::from(u16b(&b[p.. ]) & !1), // Clip
0x00a1 => p += usize::from(u16b(&b[p+2..]) & !1) + 2, // LongComment 0x00a1 => p += usize::from(u16b(&b[p+2..]) & !1) + 2, // LongComment
0x100..= 0x100..=
0x7fff => p += usize::from(op >> 8) * 2, // Reserved 0x7fff => p += usize::from(op >> 8) * 2, // Reserved
_ => { _ => {
bail!("invalid op in PICT"); bail!("invalid op in PICT");
} }
} }
} }
Err(err_msg("no image in data")) Err(err_msg("no image in data"))
} }
// EOF // EOF

View File

@ -5,38 +5,38 @@ use crate::{err::*, image::*};
/// Read a `ColorTable` structure. /// Read a `ColorTable` structure.
pub fn read(b: &[u8]) -> ResultS<(Vec<Color8>, usize)> pub fn read(b: &[u8]) -> ResultS<(Vec<Color8>, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 8, start: 0, data { endian: BIG, buf: b, size: 8, start: 0, data {
let dev = u16[4]; let dev = u16[4];
let num = u16[6] usize; let num = u16[6] usize;
} }
} }
let dev = dev & 0x8000 != 0; let dev = dev & 0x8000 != 0;
let num = num + 1; let num = num + 1;
let mut p = 8; let mut p = 8;
let mut clut = vec![Color8::new(0, 0, 0); num]; let mut clut = vec![Color8::new(0, 0, 0); num];
for i in 0..num { for i in 0..num {
read_data! { read_data! {
endian: BIG, buf: b, size: 8, start: p, data { endian: BIG, buf: b, size: 8, start: p, data {
let n = u16[0] usize; let n = u16[0] usize;
let r = u8[2]; let r = u8[2];
let g = u8[4]; let g = u8[4];
let b = u8[6]; let b = u8[6];
} }
} }
// with device mapping, we ignore the index entirely // with device mapping, we ignore the index entirely
let n = if dev {i} else {n}; let n = if dev {i} else {n};
*ok!(clut.get_mut(n), "invalid index")? = Color8::new(r, g, b); *ok!(clut.get_mut(n), "invalid index")? = Color8::new(r, g, b);
p += 8; p += 8;
} }
Ok((clut, p)) Ok((clut, p))
} }
// EOF // EOF

View File

@ -5,17 +5,17 @@ use crate::{err::*, image::{*, pict::pm}};
/// Process a `CopyBits` operation. /// Process a `CopyBits` operation.
pub fn read(im: Image8, b: &[u8], pack: bool, clip: bool) -> ResultS<Image8> pub fn read(im: Image8, b: &[u8], pack: bool, clip: bool) -> ResultS<Image8>
{ {
let p = if pack {0} else {4}; let p = if pack {0} else {4};
let (b, hdr) = pm::head::read(&b[p..], pack, clip, &im)?; let (b, hdr) = pm::head::read(&b[p..], pack, clip, &im)?;
match hdr.depth { match hdr.depth {
pm::head::Depth::_1 | pm::head::Depth::_1 |
pm::head::Depth::_2 | pm::head::Depth::_2 |
pm::head::Depth::_4 | pm::head::Depth::_4 |
pm::head::Depth::_8 => pm::ind::read(im, b, hdr), pm::head::Depth::_8 => pm::ind::read(im, b, hdr),
pm::head::Depth::_16 => pm::r5g5b5::read(im, b, hdr), pm::head::Depth::_16 => pm::r5g5b5::read(im, b, hdr),
pm::head::Depth::_32 => pm::rgb8::read(im, b, hdr), pm::head::Depth::_32 => pm::rgb8::read(im, b, hdr),
} }
} }
// EOF // EOF

View File

@ -8,79 +8,79 @@ pub fn read<'a>(b: &'a [u8],
clip: bool, clip: bool,
im: &Image8) -> ResultS<(&'a [u8], Header)> im: &Image8) -> ResultS<(&'a [u8], Header)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 36, start: 0, data { endian: BIG, buf: b, size: 36, start: 0, data {
let pt_fl = u16[0]; let pt_fl = u16[0];
let top = u16[2] usize; let top = u16[2] usize;
let left = u16[4] usize; let left = u16[4] usize;
let bottom = u16[6] usize; let bottom = u16[6] usize;
let right = u16[8] usize; let right = u16[8] usize;
let pack_t = u16[12] enum PackType; let pack_t = u16[12] enum PackType;
let depth = u16[28] enum Depth; let depth = u16[28] enum Depth;
} }
} }
if pt_fl & 0x8000 == 0 { if pt_fl & 0x8000 == 0 {
bail!("PICT1 not supported"); bail!("PICT1 not supported");
} }
if right - left != im.w() || bottom - top != im.h() { if right - left != im.w() || bottom - top != im.h() {
bail!("image bounds are incorrect"); bail!("image bounds are incorrect");
} }
let mut p = 46; let mut p = 46;
// get CLUT if packed // get CLUT if packed
let clut = if pack { let clut = if pack {
let (clut, sz) = pict::clut::read(&b[p..])?; let (clut, sz) = pict::clut::read(&b[p..])?;
p += sz; p += sz;
Some(clut) Some(clut)
} else { } else {
None None
}; };
p += 18; // srcRect, dstRect, mode p += 18; // srcRect, dstRect, mode
if clip { if clip {
p += usize::from(u16b(&b[p..])); // maskRgn p += usize::from(u16b(&b[p..])); // maskRgn
} }
let rle = pack_t == PackType::Default || let rle = pack_t == PackType::Default ||
pack_t == PackType::Rle16 && depth == Depth::_16 || pack_t == PackType::Rle16 && depth == Depth::_16 ||
pack_t == PackType::Rle32 && depth == Depth::_32; pack_t == PackType::Rle32 && depth == Depth::_32;
let pitch = usize::from(pt_fl & 0x3FFF); let pitch = usize::from(pt_fl & 0x3FFF);
Ok((&b[p..], Header{pitch, pack_t, depth, clut, rle})) Ok((&b[p..], Header{pitch, pack_t, depth, clut, rle}))
} }
pub struct Header { pub struct Header {
pub pitch: usize, pub pitch: usize,
pub pack_t: PackType, pub pack_t: PackType,
pub depth: Depth, pub depth: Depth,
pub clut: Option<Vec<Color8>>, pub clut: Option<Vec<Color8>>,
pub rle: bool, pub rle: bool,
} }
c_enum! { c_enum! {
pub enum Depth: u16 { pub enum Depth: u16 {
_1 = 1, _1 = 1,
_2 = 2, _2 = 2,
_4 = 4, _4 = 4,
_8 = 8, _8 = 8,
_16 = 16, _16 = 16,
_32 = 32, _32 = 32,
} }
} }
c_enum! { c_enum! {
pub enum PackType: u16 { pub enum PackType: u16 {
Default = 0, Default = 0,
None = 1, None = 1,
NoPad = 2, NoPad = 2,
Rle16 = 3, Rle16 = 3,
Rle32 = 4, Rle32 = 4,
} }
} }
// EOF // EOF

View File

@ -7,81 +7,80 @@ pub fn read(mut im: Image8,
b: &[u8], b: &[u8],
hdr: pm::head::Header) -> ResultS<Image8> hdr: pm::head::Header) -> ResultS<Image8>
{ {
let clut = ok!(hdr.clut, "no CLUT in indexed mode")?; let clut = ok!(hdr.clut, "no CLUT in indexed mode")?;
let mut p = 0; let mut p = 0;
if hdr.pitch < 8 && hdr.depth == pm::head::Depth::_8 { if hdr.pitch < 8 && hdr.depth == pm::head::Depth::_8 {
// uncompressed 8-bit colormap indices // uncompressed 8-bit colormap indices
for _ in 0..im.h() { for _ in 0..im.h() {
for _ in 0..im.w() { for _ in 0..im.w() {
let idx = usize::from(b[p]); let idx = usize::from(b[p]);
im.cr.push(ok!(clut.get(idx), "invalid index")?.clone()); im.cr.push(ok!(clut.get(idx), "bad index")?.clone());
p += 1; p += 1;
} }
} }
Ok(im) Ok(im)
} else if hdr.rle { } else if hdr.rle {
// RLE compressed 1, 2, 4 or 8 bit colormap indices // RLE compressed 1, 2, 4 or 8 bit colormap indices
for _ in 0..im.h() { for _ in 0..im.h() {
let (d, pp) = rle::read::<u8>(&b[p..], hdr.pitch)?; let (d, pp) = rle::read::<u8>(&b[p..], hdr.pitch)?;
let d = if hdr.depth < pm::head::Depth::_8 { let d = if hdr.depth < pm::head::Depth::_8 {
expand_data(d, hdr.depth)? expand_data(d, hdr.depth)?
} else { } else {
d d
}; };
check_data(&d, im.w())?; check_data(&d, im.w())?;
p += pp; p += pp;
for &idx in &d { for &idx in &d {
im.cr im.cr.push(ok!(clut.get(usize::from(idx)), "bad index")?.clone());
.push(ok!(clut.get(usize::from(idx)), "invalid index")?.clone()); }
} }
}
Ok(im) Ok(im)
} else { } else {
bail!("invalid configuration") bail!("invalid configuration")
} }
} }
/// Expand packed pixel data based on bit depth. /// Expand packed pixel data based on bit depth.
pub fn expand_data(b: Vec<u8>, depth: pm::head::Depth) -> ResultS<Vec<u8>> pub fn expand_data(b: Vec<u8>, depth: pm::head::Depth) -> ResultS<Vec<u8>>
{ {
let mut o = Vec::with_capacity(match depth { let mut o = Vec::with_capacity(match depth {
pm::head::Depth::_4 => b.len() * 2, pm::head::Depth::_4 => b.len() * 2,
pm::head::Depth::_2 => b.len() * 4, pm::head::Depth::_2 => b.len() * 4,
pm::head::Depth::_1 => b.len() * 8, pm::head::Depth::_1 => b.len() * 8,
_ => bail!("invalid bit depth"), _ => bail!("invalid bit depth"),
}); });
for ch in b { for ch in b {
match depth { match depth {
pm::head::Depth::_4 => { pm::head::Depth::_4 => {
for i in (0..=1).rev() { for i in (0..=1).rev() {
o.push(ch >> (i * 4) & 0xF_u8); o.push(ch >> (i * 4) & 0xF_u8);
} }
} }
pm::head::Depth::_2 => { pm::head::Depth::_2 => {
for i in (0..=3).rev() { for i in (0..=3).rev() {
o.push(ch >> (i * 2) & 0x3_u8); o.push(ch >> (i * 2) & 0x3_u8);
} }
} }
pm::head::Depth::_1 => { pm::head::Depth::_1 => {
for i in (0..=7).rev() { for i in (0..=7).rev() {
o.push(ch >> i & 0x1_u8); o.push(ch >> i & 0x1_u8);
} }
} }
_ => bail!("invalid bit depth"), _ => bail!("invalid bit depth"),
} }
} }
Ok(o) Ok(o)
} }
// EOF // EOF

View File

@ -7,38 +7,38 @@ pub fn read(mut im: Image8,
b: &[u8], b: &[u8],
hdr: pm::head::Header) -> ResultS<Image8> hdr: pm::head::Header) -> ResultS<Image8>
{ {
let mut p = 0; let mut p = 0;
if hdr.pitch < 8 || hdr.pack_t == pm::head::PackType::None { if hdr.pitch < 8 || hdr.pack_t == pm::head::PackType::None {
// uncompressed R5G5B5 // uncompressed R5G5B5
for _ in 0..im.h() { for _ in 0..im.h() {
for _ in 0..im.w() { for _ in 0..im.w() {
let cr = u16b(&b[p..]); let cr = u16b(&b[p..]);
im.cr.push(r5g5b5_to_rgb8(cr)); im.cr.push(r5g5b5_to_rgb8(cr));
p += 2; p += 2;
} }
} }
Ok(im) Ok(im)
} else if hdr.rle { } else if hdr.rle {
// RLE compressed R5G5B5 // RLE compressed R5G5B5
for _ in 0..im.h() { for _ in 0..im.h() {
let (d, pp) = rle::read::<u16>(&b[p..], hdr.pitch)?; let (d, pp) = rle::read::<u16>(&b[p..], hdr.pitch)?;
check_data(&d, im.w())?; check_data(&d, im.w())?;
p += pp; p += pp;
for &cr in &d { for &cr in &d {
im.cr.push(r5g5b5_to_rgb8(cr)); im.cr.push(r5g5b5_to_rgb8(cr));
} }
} }
Ok(im) Ok(im)
} else { } else {
bail!("invalid configuration") bail!("invalid configuration")
} }
} }
// EOF // EOF

View File

@ -7,56 +7,56 @@ pub fn read(mut im: Image8,
b: &[u8], b: &[u8],
hdr: pm::head::Header) -> ResultS<Image8> hdr: pm::head::Header) -> ResultS<Image8>
{ {
let mut p = 0; let mut p = 0;
if hdr.pitch < 8 || if hdr.pitch < 8 ||
hdr.pack_t == pm::head::PackType::None || hdr.pack_t == pm::head::PackType::None ||
hdr.pack_t == pm::head::PackType::NoPad hdr.pack_t == pm::head::PackType::NoPad
{ {
// uncompressed RGB8 or XRGB8 // uncompressed RGB8 or XRGB8
for _ in 0..im.h() { for _ in 0..im.h() {
for _ in 0..im.w() { for _ in 0..im.w() {
if hdr.pack_t != pm::head::PackType::NoPad { if hdr.pack_t != pm::head::PackType::NoPad {
p += 1; p += 1;
} }
read_data! { read_data! {
endian: BIG, buf: b, size: 3, start: p, data { endian: BIG, buf: b, size: 3, start: p, data {
let r = u8[0]; let r = u8[0];
let g = u8[1]; let g = u8[1];
let b = u8[2]; let b = u8[2];
} }
} }
im.cr.push(Color8::new(r, g, b)); im.cr.push(Color8::new(r, g, b));
p += 3; p += 3;
} }
} }
Ok(im) Ok(im)
} else if hdr.rle { } else if hdr.rle {
// RLE compressed RGB8 // RLE compressed RGB8
let pitch = hdr.pitch - im.w(); // remove padding byte from pitch let pitch = hdr.pitch - im.w(); // remove padding byte from pitch
for _ in 0..im.h() { for _ in 0..im.h() {
let (d, pp) = rle::read::<u8>(&b[p..], pitch)?; let (d, pp) = rle::read::<u8>(&b[p..], pitch)?;
check_data(&d, im.w() * 3)?; check_data(&d, im.w() * 3)?;
p += pp; p += pp;
for x in 0..im.w() { for x in 0..im.w() {
let r = d[x]; let r = d[x];
let g = d[x * 2]; let g = d[x * 2];
let b = d[x * 3]; let b = d[x * 3];
im.cr.push(Color8::new(r, g, b)); im.cr.push(Color8::new(r, g, b));
} }
} }
Ok(im) Ok(im)
} else { } else {
bail!("invalid configuration") bail!("invalid configuration")
} }
} }
// EOF // EOF

View File

@ -4,91 +4,91 @@ use crate::{bin::*, err::*};
/// Read run-length encoded data. /// Read run-length encoded data.
pub fn read<T>(b: &[u8], pitch: usize) -> ResultS<(Vec<T>, usize)> pub fn read<T>(b: &[u8], pitch: usize) -> ResultS<(Vec<T>, usize)>
where T: ReadRleData where T: ReadRleData
{ {
let mut p = 0; let mut p = 0;
let mut o = Vec::with_capacity(pitch); let mut o = Vec::with_capacity(pitch);
let sz = if pitch > 250 { let sz = if pitch > 250 {
(usize::from(u16b(b)) + 2, p += 2).0 (usize::from(u16b(b)) + 2, p += 2).0
} else { } else {
(usize::from(b[0]) + 1, p += 1).0 (usize::from(b[0]) + 1, p += 1).0
}; };
while p < sz { while p < sz {
let szf = b[p]; let szf = b[p];
let cmp = szf & 0x80 != 0; let cmp = szf & 0x80 != 0;
let len = usize::from(if cmp {!szf + 2} else {szf + 1}); let len = usize::from(if cmp {!szf + 2} else {szf + 1});
p += 1; p += 1;
o.reserve(len); o.reserve(len);
T::read_rle_data(b, &mut p, cmp, len, &mut o); T::read_rle_data(b, &mut p, cmp, len, &mut o);
} }
if o.len() == pitch { if o.len() == pitch {
Ok((o, p)) Ok((o, p))
} else { } else {
Err(err_msg("incorrect size for compressed scanline")) Err(err_msg("incorrect size for compressed scanline"))
} }
} }
pub trait ReadRleData: Sized pub trait ReadRleData: Sized
{ {
// Read a sequence of packed RLE data. // Read a sequence of packed RLE data.
fn read_rle_data(b: &[u8], fn read_rle_data(b: &[u8],
p: &mut usize, p: &mut usize,
cmp: bool, cmp: bool,
len: usize, len: usize,
out: &mut Vec<Self>); out: &mut Vec<Self>);
} }
impl ReadRleData for u16 impl ReadRleData for u16
{ {
fn read_rle_data(b: &[u8], fn read_rle_data(b: &[u8],
p: &mut usize, p: &mut usize,
cmp: bool, cmp: bool,
len: usize, len: usize,
out: &mut Vec<Self>) out: &mut Vec<Self>)
{ {
if cmp { if cmp {
let d = u16b(&b[*p..*p + 2]); let d = u16b(&b[*p..*p + 2]);
*p += 2; *p += 2;
for _ in 0..len { for _ in 0..len {
out.push(d); out.push(d);
} }
} else { } else {
for _ in 0..len { for _ in 0..len {
let d = u16b(&b[*p..*p + 2]); let d = u16b(&b[*p..*p + 2]);
*p += 2; *p += 2;
out.push(d); out.push(d);
} }
} }
} }
} }
impl ReadRleData for u8 impl ReadRleData for u8
{ {
fn read_rle_data(b: &[u8], fn read_rle_data(b: &[u8],
p: &mut usize, p: &mut usize,
cmp: bool, cmp: bool,
len: usize, len: usize,
out: &mut Vec<Self>) out: &mut Vec<Self>)
{ {
if cmp { if cmp {
let d = b[*p]; let d = b[*p];
*p += 1; *p += 1;
for _ in 0..len { for _ in 0..len {
out.push(d); out.push(d);
} }
} else { } else {
for _ in 0..len { for _ in 0..len {
let d = b[*p]; let d = b[*p];
*p += 1; *p += 1;
out.push(d); out.push(d);
} }
} }
} }
} }
// EOF // EOF

View File

@ -10,60 +10,60 @@ use std::io;
/// Errors if `out` cannot be written to. /// Errors if `out` cannot be written to.
pub fn write_ppm(out: &mut impl io::Write, im: &impl Image) -> ResultS<()> pub fn write_ppm(out: &mut impl io::Write, im: &impl Image) -> ResultS<()>
{ {
write!(out, "P3\n{} {}\n{}\n", im.w(), im.h(), u16::max_value())?; write!(out, "P3\n{} {}\n{}\n", im.w(), im.h(), u16::max_value())?;
for y in 0..im.h() { for y in 0..im.h() {
for x in 0..im.w() { for x in 0..im.w() {
let cr = im.index(x, y); let cr = im.index(x, y);
write!(out, "{} {} {} ", cr.r(), cr.g(), cr.b())?; write!(out, "{} {} {} ", cr.r(), cr.g(), cr.b())?;
} }
out.write_all(b"\n")?; out.write_all(b"\n")?;
} }
Ok(()) Ok(())
} }
/// Reads a PPM file into an image. /// Reads a PPM file into an image.
pub fn read_ppm(inp: &[u8]) -> ResultS<Image16> pub fn read_ppm(inp: &[u8]) -> ResultS<Image16>
{ {
let mut it = inp.split(|&n| n == b'\n' || n == b'\r' || n == b' '); let mut it = inp.split(|&n| n == b'\n' || n == b'\r' || n == b' ');
if ok!(it.next(), "no magic number")? != b"P3" { if ok!(it.next(), "no magic number")? != b"P3" {
bail!("not P3 format"); bail!("not P3 format");
} }
let mut get_num = move || -> ResultS<u16> { let mut get_num = move || -> ResultS<u16> {
let st = loop { let st = loop {
match ok!(it.next(), "no more strings")? { match ok!(it.next(), "no more strings")? {
b"" => {} b"" => {}
st => break st st => break st
} }
}; };
let st = unsafe {std::str::from_utf8_unchecked(st)}; let st = unsafe {std::str::from_utf8_unchecked(st)};
let nu = u16::from_str_radix(st, 10)?; let nu = u16::from_str_radix(st, 10)?;
Ok(nu) Ok(nu)
}; };
let width = get_num()?; let width = get_num()?;
let height = get_num()?; let height = get_num()?;
let depth = i64::from(get_num()?); let depth = i64::from(get_num()?);
let mut im = Image16::new(usize::from(width), usize::from(height)); let mut im = Image16::new(usize::from(width), usize::from(height));
for _ in 0..height * width { for _ in 0..height * width {
let r = FixedLong::from_int(get_num()?.into()); let r = FixedLong::from_int(get_num()?.into());
let g = FixedLong::from_int(get_num()?.into()); let g = FixedLong::from_int(get_num()?.into());
let b = FixedLong::from_int(get_num()?.into()); let b = FixedLong::from_int(get_num()?.into());
let r = (r / depth * 0xFFFF).integ() as u16; let r = (r / depth * 0xFFFF).integ() as u16;
let g = (g / depth * 0xFFFF).integ() as u16; let g = (g / depth * 0xFFFF).integ() as u16;
let b = (b / depth * 0xFFFF).integ() as u16; let b = (b / depth * 0xFFFF).integ() as u16;
im.cr.push(Color16::new(r, g, b)); im.cr.push(Color16::new(r, g, b));
} }
Ok(im) Ok(im)
} }
// EOF // EOF

View File

@ -10,32 +10,32 @@ use std::io;
/// Errors if `out` cannot be written to. /// Errors if `out` cannot be written to.
pub fn write_tga(out: &mut impl io::Write, im: &impl Image) -> ResultS<()> pub fn write_tga(out: &mut impl io::Write, im: &impl Image) -> ResultS<()>
{ {
// id len, color map type, image type // id len, color map type, image type
out.write_all(&[0, 0, 2])?; out.write_all(&[0, 0, 2])?;
// color map spec // color map spec
out.write_all(&[0, 0, 0, 0, 0])?; out.write_all(&[0, 0, 0, 0, 0])?;
// x origin // x origin
out.write_all(&[0, 0])?; out.write_all(&[0, 0])?;
// y origin // y origin
out.write_all(&[0, 0])?; out.write_all(&[0, 0])?;
// width // width
out.write_all(&u16::to_le_bytes(im.w() as u16))?; out.write_all(&u16::to_le_bytes(im.w() as u16))?;
// height // height
out.write_all(&u16::to_le_bytes(im.h() as u16))?; out.write_all(&u16::to_le_bytes(im.h() as u16))?;
// depth, descriptor // depth, descriptor
out.write_all(&[32, 0])?; out.write_all(&[32, 0])?;
for y in (0..im.h()).rev() { for y in (0..im.h()).rev() {
for x in 0..im.w() { for x in 0..im.w() {
let cr = im.index(x, y); let cr = im.index(x, y);
out.write_all(&[(cr.b() >> 8) as u8, out.write_all(&[(cr.b() >> 8) as u8,
(cr.g() >> 8) as u8, (cr.g() >> 8) as u8,
(cr.r() >> 8) as u8, (cr.r() >> 8) as u8,
(cr.a() >> 8) as u8])?; (cr.a() >> 8) as u8])?;
} }
} }
Ok(()) Ok(())
} }
// EOF // EOF

View File

@ -5,112 +5,112 @@ use std::io::{SeekFrom, prelude::*};
/// Skips over an Apple Single header. Returns true if one was found. /// Skips over an Apple Single header. Returns true if one was found.
pub fn skip_apple_single<R>(fp: &mut R) -> bool pub fn skip_apple_single<R>(fp: &mut R) -> bool
where R: Read + Seek where R: Read + Seek
{ {
let mut fp = SeekBackToStart::new(fp); let mut fp = SeekBackToStart::new(fp);
let mut magic = [0; 8]; let mut magic = [0; 8];
let magic = if fp.read(&mut magic).is_ok() {magic} else {return false;}; let magic = if fp.read(&mut magic).is_ok() {magic} else {return false;};
// check magic numbers // check magic numbers
if magic != [0, 5, 22, 0, 0, 2, 0, 0] { if magic != [0, 5, 22, 0, 0, 2, 0, 0] {
return false; return false;
} }
let mut num = [0; 2]; let mut num = [0; 2];
let num = if fp.read(&mut num).is_ok() {num} else {return false;}; let num = if fp.read(&mut num).is_ok() {num} else {return false;};
let num = u64::from(u16::from_be_bytes(num)); let num = u64::from(u16::from_be_bytes(num));
if fp.seek(SeekFrom::Start(26 + 12 * num)).is_err() | if fp.seek(SeekFrom::Start(26 + 12 * num)).is_err() |
fp.seek(SeekFrom::Start(26)).is_err() { fp.seek(SeekFrom::Start(26)).is_err() {
return false; return false;
} }
// get the resource fork (entity 1) // get the resource fork (entity 1)
for _ in 0..num { for _ in 0..num {
let mut ent = [0; 4]; let mut ent = [0; 4];
let mut ofs = [0; 4]; let mut ofs = [0; 4];
let mut len = [0; 4]; let mut len = [0; 4];
let ent = if fp.read(&mut ent).is_ok() {ent} else {return false;}; let ent = if fp.read(&mut ent).is_ok() {ent} else {return false;};
let ofs = if fp.read(&mut ofs).is_ok() {ofs} else {return false;}; let ofs = if fp.read(&mut ofs).is_ok() {ofs} else {return false;};
let len = if fp.read(&mut len).is_ok() {len} else {return false;}; let len = if fp.read(&mut len).is_ok() {len} else {return false;};
let ent = u32::from_be_bytes(ent); let ent = u32::from_be_bytes(ent);
let ofs = u64::from(u32::from_be_bytes(ofs)); let ofs = u64::from(u32::from_be_bytes(ofs));
let len = u64::from(u32::from_be_bytes(len)); let len = u64::from(u32::from_be_bytes(len));
if ent == 1 { if ent == 1 {
if fp.seek(SeekFrom::Start(ofs + len)).is_ok() & if fp.seek(SeekFrom::Start(ofs + len)).is_ok() &
fp.seek(SeekFrom::Start(ofs)).is_ok() { fp.seek(SeekFrom::Start(ofs)).is_ok() {
fp.set_seek(false); fp.set_seek(false);
return true; return true;
} else { } else {
return false; return false;
} }
} }
} }
// no resource fork // no resource fork
false false
} }
/// Skips over a Mac Binary II header. Returns true if one was found. /// Skips over a Mac Binary II header. Returns true if one was found.
pub fn skip_macbin<R>(fp: &mut R) -> bool pub fn skip_macbin<R>(fp: &mut R) -> bool
where R: Read + Seek where R: Read + Seek
{ {
let mut fp = SeekBackToStart::new(fp); let mut fp = SeekBackToStart::new(fp);
let mut head = [0; 128]; let mut head = [0; 128];
let head = if fp.read(&mut head).is_ok() {head} else {return false;}; let head = if fp.read(&mut head).is_ok() {head} else {return false;};
// check legacy version, length, zero fill, and macbin2 version. I swear, // check legacy version, length, zero fill, and macbin2 version. I swear,
// this isn't *completely* magic // this isn't *completely* magic
if head[0] != 0 || head[1] > 63 || head[74] != 0 || head[123] > 129 { if head[0] != 0 || head[1] > 63 || head[74] != 0 || head[123] > 129 {
return false; return false;
} }
let mut crc = 0; let mut crc = 0;
// check header crc // check header crc
for &byte in head.iter().take(124) { for &byte in head.iter().take(124) {
for j in 8..16 { for j in 8..16 {
let d = u16::from(byte) << j; let d = u16::from(byte) << j;
if (d ^ crc) & 0x8000 == 0 { if (d ^ crc) & 0x8000 == 0 {
crc <<= 1; crc <<= 1;
} else { } else {
crc = crc << 1 ^ 0x1021; crc = crc << 1 ^ 0x1021;
} }
} }
} }
// if ok, resource fork follows // if ok, resource fork follows
if crc == u16::from_be_bytes([head[124], head[125]]) { if crc == u16::from_be_bytes([head[124], head[125]]) {
fp.set_seek(false); fp.set_seek(false);
true true
} else { } else {
false false
} }
} }
/// Reads a `MacBin` or `AppleSingle` header if there is one and skips past it /// Reads a `MacBin` or `AppleSingle` header if there is one and skips past it
/// from the start of the header to the resource fork (if one is found.) Returns /// from the start of the header to the resource fork (if one is found.) Returns
/// true if either one was found. /// true if either one was found.
pub fn skip_mac_header<R>(fp: &mut R) -> bool pub fn skip_mac_header<R>(fp: &mut R) -> bool
where R: Read + Seek where R: Read + Seek
{ {
if skip_macbin(fp) { if skip_macbin(fp) {
return true; return true;
} }
let _ = fp.seek(SeekFrom::Start(0)); let _ = fp.seek(SeekFrom::Start(0));
if skip_apple_single(fp) { if skip_apple_single(fp) {
return true; return true;
} }
let _ = fp.seek(SeekFrom::Start(0)); let _ = fp.seek(SeekFrom::Start(0));
false false
} }
// EOF // EOF

View File

@ -5,22 +5,22 @@ use crate::err::*;
/// Reads an `ambi` chunk. /// Reads an `ambi` chunk.
pub fn read(b: &[u8]) -> ResultS<(SoundAmbi, usize)> pub fn read(b: &[u8]) -> ResultS<(SoundAmbi, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 16, start: 0, data { endian: BIG, buf: b, size: 16, start: 0, data {
let index = u16[2]; let index = u16[2];
let volume = u16[4]; let volume = u16[4];
} }
} }
Ok((SoundAmbi{index, volume}, 16)) Ok((SoundAmbi{index, volume}, 16))
} }
/// An ambient sound definition. /// An ambient sound definition.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct SoundAmbi { pub struct SoundAmbi {
pub index: u16, pub index: u16,
pub volume: u16, pub volume: u16,
} }
// EOF // EOF

View File

@ -5,34 +5,34 @@ use crate::{bin::OptU16, err::*, fixed::{Angle, Unit}};
/// Reads an `Attack` object. /// Reads an `Attack` object.
pub fn read(b: &[u8]) -> ResultS<Attack> pub fn read(b: &[u8]) -> ResultS<Attack>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 16, start: 0, data { endian: BIG, buf: b, size: 16, start: 0, data {
let ptype = OptU16[0]; let ptype = OptU16[0];
let rep = u16[2]; let rep = u16[2];
let error = Angle[4]; let error = Angle[4];
let range = Unit[6]; let range = Unit[6];
let shape = u16[8]; let shape = u16[8];
let ofs_x = Unit[10]; let ofs_x = Unit[10];
let ofs_y = Unit[12]; let ofs_y = Unit[12];
let ofs_z = Unit[14]; let ofs_z = Unit[14];
} }
} }
Ok(Attack{ptype, rep, error, range, shape, ofs_x, ofs_y, ofs_z}) Ok(Attack{ptype, rep, error, range, shape, ofs_x, ofs_y, ofs_z})
} }
/// The definition of a monster's attack. /// The definition of a monster's attack.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct Attack { pub struct Attack {
pub ptype: OptU16, pub ptype: OptU16,
pub rep: u16, pub rep: u16,
pub error: Angle, pub error: Angle,
pub range: Unit, pub range: Unit,
pub shape: u16, pub shape: u16,
pub ofs_x: Unit, pub ofs_x: Unit,
pub ofs_y: Unit, pub ofs_y: Unit,
pub ofs_z: Unit, pub ofs_z: Unit,
} }
// EOF // EOF

View File

@ -5,48 +5,48 @@ use crate::{err::*, fixed::{Angle, Fixed}};
/// Reads a `bonk` chunk. /// Reads a `bonk` chunk.
pub fn read(b: &[u8]) -> ResultS<(SoundRand, usize)> pub fn read(b: &[u8]) -> ResultS<(SoundRand, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 32, start: 0, data { endian: BIG, buf: b, size: 32, start: 0, data {
let flags = u16[0] flag SoundRandFlags; let flags = u16[0] flag SoundRandFlags;
let index = u16[2]; let index = u16[2];
let vol_nrm = u16[4]; let vol_nrm = u16[4];
let vol_dta = u16[6]; let vol_dta = u16[6];
let prd_nrm = u16[8]; let prd_nrm = u16[8];
let prd_dta = u16[10]; let prd_dta = u16[10];
let yaw_nrm = Angle[12]; let yaw_nrm = Angle[12];
let yaw_dta = Angle[14]; let yaw_dta = Angle[14];
let pit_nrm = Fixed[16]; let pit_nrm = Fixed[16];
let pit_dta = Fixed[20]; let pit_dta = Fixed[20];
} }
} }
Ok((SoundRand{flags, index, vol_nrm, vol_dta, prd_nrm, prd_dta, yaw_nrm, Ok((SoundRand{flags, index, vol_nrm, vol_dta, prd_nrm, prd_dta, yaw_nrm,
yaw_dta, pit_nrm, pit_dta}, 32)) yaw_dta, pit_nrm, pit_dta}, 32))
} }
/// A randomly played sound definition. /// A randomly played sound definition.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct SoundRand { pub struct SoundRand {
pub flags: SoundRandFlags, pub flags: SoundRandFlags,
pub index: u16, pub index: u16,
pub vol_nrm: u16, pub vol_nrm: u16,
pub vol_dta: u16, pub vol_dta: u16,
pub prd_nrm: u16, pub prd_nrm: u16,
pub prd_dta: u16, pub prd_dta: u16,
pub yaw_nrm: Angle, pub yaw_nrm: Angle,
pub yaw_dta: Angle, pub yaw_dta: Angle,
pub pit_nrm: Fixed, pub pit_nrm: Fixed,
pub pit_dta: Fixed, pub pit_dta: Fixed,
} }
c_bitfield! { c_bitfield! {
/// Flags for `SoundRand`. /// Flags for `SoundRand`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct SoundRandFlags: u16 { pub struct SoundRandFlags: u16 {
NO_DIRECTION = 0, NO_DIRECTION = 0,
_2 = 1, _2 = 1,
} }
} }
// EOF // EOF

View File

@ -5,99 +5,99 @@ use crate::{err::*, fixed::Fixed};
/// Reads a `Damage` object. /// Reads a `Damage` object.
pub fn read(b: &[u8]) -> ResultS<Damage> pub fn read(b: &[u8]) -> ResultS<Damage>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 12, start: 0, data { endian: BIG, buf: b, size: 12, start: 0, data {
let dtype = u16[0] enum DamageType; let dtype = u16[0] enum DamageType;
let flags = u16[2] flag DamageFlags; let flags = u16[2] flag DamageFlags;
let dmg_base = u16[4]; let dmg_base = u16[4];
let dmg_rand = u16[6]; let dmg_rand = u16[6];
let scale = Fixed[8]; let scale = Fixed[8];
} }
} }
Ok(Damage{dtype, flags, dmg_base, dmg_rand, scale}) Ok(Damage{dtype, flags, dmg_base, dmg_rand, scale})
} }
/// A damage definition. /// A damage definition.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct Damage { pub struct Damage {
pub dtype: DamageType, pub dtype: DamageType,
pub flags: DamageFlags, pub flags: DamageFlags,
pub dmg_base: u16, pub dmg_base: u16,
pub dmg_rand: u16, pub dmg_rand: u16,
pub scale: Fixed, pub scale: Fixed,
} }
c_bitfield! { c_bitfield! {
/// The composite type of damage taken by something. /// The composite type of damage taken by something.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct DamageTypeFlags: u32 { pub struct DamageTypeFlags: u32 {
EXPLOSION = 0, EXPLOSION = 0,
ELECTRICAL_STAFF = 1, ELECTRICAL_STAFF = 1,
PROJECTILE = 2, PROJECTILE = 2,
ABSORBED = 3, ABSORBED = 3,
FLAME = 4, FLAME = 4,
HOUND_CLAWS = 5, HOUND_CLAWS = 5,
ALIEN_PROJECTILE = 6, ALIEN_PROJECTILE = 6,
HULK_SLAP = 7, HULK_SLAP = 7,
COMPILER_BOLT = 8, COMPILER_BOLT = 8,
FUSION_BOLT = 9, FUSION_BOLT = 9,
HUNTER_BOLT = 10, HUNTER_BOLT = 10,
FIST = 11, FIST = 11,
TELEPORTER = 12, TELEPORTER = 12,
DEFENDER = 13, DEFENDER = 13,
YETI_CLAWS = 14, YETI_CLAWS = 14,
YETI_PROJECTILE = 15, YETI_PROJECTILE = 15,
CRUSHING = 16, CRUSHING = 16,
LAVA = 17, LAVA = 17,
SUFFOCATION = 18, SUFFOCATION = 18,
GOO = 19, GOO = 19,
ENERGY_DRAIN = 20, ENERGY_DRAIN = 20,
OXYGEN_DRAIN = 21, OXYGEN_DRAIN = 21,
HUMMER_BOLT = 22, HUMMER_BOLT = 22,
SHOTGUN_PROJECTILE = 23, SHOTGUN_PROJECTILE = 23,
} }
} }
c_bitfield! { c_bitfield! {
/// Flags for `Damage`. /// Flags for `Damage`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct DamageFlags: u16 { pub struct DamageFlags: u16 {
ALIEN = 0, ALIEN = 0,
} }
} }
c_enum! { c_enum! {
/// A named type of damage taken by something. /// A named type of damage taken by something.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub enum DamageType: u16 { pub enum DamageType: u16 {
Explosion = 0, Explosion = 0,
ElectricalStaff = 1, ElectricalStaff = 1,
Projectile = 2, Projectile = 2,
Absorbed = 3, Absorbed = 3,
Flame = 4, Flame = 4,
HoundClaws = 5, HoundClaws = 5,
AlienProjectile = 6, AlienProjectile = 6,
HulkSlap = 7, HulkSlap = 7,
CompilerBolt = 8, CompilerBolt = 8,
FusionBolt = 9, FusionBolt = 9,
HunterBolt = 10, HunterBolt = 10,
Fist = 11, Fist = 11,
Teleporter = 12, Teleporter = 12,
Defender = 13, Defender = 13,
YetiClaws = 14, YetiClaws = 14,
YetiProjectile = 15, YetiProjectile = 15,
Crushing = 16, Crushing = 16,
Lava = 17, Lava = 17,
Suffocation = 18, Suffocation = 18,
Goo = 19, Goo = 19,
EnergyDrain = 20, EnergyDrain = 20,
OxygenDrain = 21, OxygenDrain = 21,
HummerBolt = 22, HummerBolt = 22,
ShotgunProjectile = 23, ShotgunProjectile = 23,
None = 0xFFFF, None = 0xFFFF,
} }
} }
// EOF // EOF

View File

@ -7,187 +7,187 @@ use std::collections::BTreeMap;
/// Reads all chunks in an entry. /// Reads all chunks in an entry.
pub fn read(head: &head::Header, b: &[u8]) -> ResultS<EntryData> pub fn read(head: &head::Header, b: &[u8]) -> ResultS<EntryData>
{ {
let mut data = EntryData::default(); let mut data = EntryData::default();
let old = head.old_data(); let old = head.old_data();
let rd_cminf = if old {map::minf::read_old} else {map::minf::read}; 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_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_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 rd_clite = if old {map::lite::read_old} else {map::lite::read};
let mut p = 0; let mut p = 0;
while p < b.len() { while p < b.len() {
read_data! { read_data! {
endian: BIG, buf: b, size: head.size_chunk(), start: p, data { endian: BIG, buf: b, size: head.size_chunk(), start: p, data {
let iden = Ident[0]; let iden = Ident[0];
let size = u32[8] usize; let size = u32[8] usize;
} }
} }
let beg = p + head.size_chunk(); let beg = p + head.size_chunk();
let end = beg + size; let end = beg + size;
let buf = ok!(b.get(beg..end), "not enough data")?; let buf = ok!(b.get(beg..end), "not enough data")?;
match &iden.0 { match &iden.0 {
b"EPNT" => data.epnt = Some(rd_array(buf, map::epnt::read)?), b"EPNT" => data.epnt = Some(rd_array(buf, map::epnt::read)?),
b"FXpx" => data.fxpx = Some(rd_array(buf, map::fxpx::read)?), b"FXpx" => data.fxpx = Some(rd_array(buf, map::fxpx::read)?),
b"LINS" => data.lins = Some(rd_array(buf, map::lins::read)?), b"LINS" => data.lins = Some(rd_array(buf, map::lins::read)?),
b"LITE" => data.lite = Some(rd_array(buf, rd_clite)?), b"LITE" => data.lite = Some(rd_array(buf, rd_clite)?),
b"MNpx" => data.mnpx = Some(rd_array(buf, map::mnpx::read)?), b"MNpx" => data.mnpx = Some(rd_array(buf, map::mnpx::read)?),
b"Minf" => data.minf = Some(rd_cminf(buf)?), b"Minf" => data.minf = Some(rd_cminf(buf)?),
b"NAME" => data.name = Some(rd_array(buf, map::name::read)?), b"NAME" => data.name = Some(rd_array(buf, map::name::read)?),
b"NOTE" => data.note = Some(rd_array(buf, map::note::read)?), b"NOTE" => data.note = Some(rd_array(buf, map::note::read)?),
b"OBJS" => data.objs = Some(rd_array(buf, map::objs::read)?), b"OBJS" => data.objs = Some(rd_array(buf, map::objs::read)?),
b"PICT" => data.pict = Some(pict::read(buf)?), b"PICT" => data.pict = Some(pict::read(buf)?),
b"PNTS" => data.pnts = Some(rd_array(buf, map::pnts::read)?), b"PNTS" => data.pnts = Some(rd_array(buf, map::pnts::read)?),
b"POLY" => data.poly = Some(rd_array(buf, rd_cpoly)?), b"POLY" => data.poly = Some(rd_array(buf, rd_cpoly)?),
b"PRpx" => data.prpx = Some(rd_array(buf, map::prpx::read)?), b"PRpx" => data.prpx = Some(rd_array(buf, map::prpx::read)?),
b"PXpx" => data.pxpx = Some(rd_array(buf, map::pxpx::read)?), b"PXpx" => data.pxpx = Some(rd_array(buf, map::pxpx::read)?),
b"SIDS" => data.sids = Some(rd_array(buf, rd_csids)?), b"SIDS" => data.sids = Some(rd_array(buf, rd_csids)?),
b"WPpx" => data.wppx = Some(rd_array(buf, map::wppx::read)?), b"WPpx" => data.wppx = Some(rd_array(buf, map::wppx::read)?),
b"ambi" => data.ambi = Some(rd_array(buf, map::ambi::read)?), b"ambi" => data.ambi = Some(rd_array(buf, map::ambi::read)?),
b"bonk" => data.bonk = Some(rd_array(buf, map::bonk::read)?), b"bonk" => data.bonk = Some(rd_array(buf, map::bonk::read)?),
b"iidx" => data.iidx = Some(rd_array(buf, map::iidx::read)?), b"iidx" => data.iidx = Some(rd_array(buf, map::iidx::read)?),
b"medi" => data.medi = Some(rd_array(buf, map::medi::read)?), b"medi" => data.medi = Some(rd_array(buf, map::medi::read)?),
b"plac" => data.plac = Some(rd_array(buf, map::plac::read)?), b"plac" => data.plac = Some(rd_array(buf, map::plac::read)?),
b"plat" => data.plat = Some(rd_array(buf, map::plat::read)?), b"plat" => data.plat = Some(rd_array(buf, map::plat::read)?),
b"term" => data.term = Some(rd_array(buf, map::term::read)?), b"term" => data.term = Some(rd_array(buf, map::term::read)?),
_ => data.unkn.push((iden, buf.to_vec())), _ => data.unkn.push((iden, buf.to_vec())),
} }
p = end; p = end;
} }
Ok(data) Ok(data)
} }
/// Reads all of the data from an entry map. /// Reads all of the data from an entry map.
pub fn read_all(head: &head::Header, pub fn read_all(head: &head::Header,
map: &entr::EntryMap<'_>) -> ResultS<EntryDataMap> map: &entr::EntryMap<'_>) -> ResultS<EntryDataMap>
{ {
let mut data_map = EntryDataMap::new(); let mut data_map = EntryDataMap::new();
for (&index, entry) in map { for (&index, entry) in map {
data_map.insert(index, read(head, entry.data)?); data_map.insert(index, read(head, entry.data)?);
} }
Ok(data_map) Ok(data_map)
} }
impl EntryData impl EntryData
{ {
pub fn get_type(&self) -> EntryType pub fn get_type(&self) -> EntryType
{ {
if self.has_minf() { if self.has_minf() {
EntryType::Map EntryType::Map
} else if self.has_fxpx() || } else if self.has_fxpx() ||
self.has_mnpx() || self.has_mnpx() ||
self.has_prpx() || self.has_prpx() ||
self.has_pxpx() || self.has_pxpx() ||
self.has_wppx() { self.has_wppx() {
EntryType::Physics EntryType::Physics
} else if self.has_pict() { } else if self.has_pict() {
EntryType::Image EntryType::Image
} else { } else {
EntryType::Other EntryType::Other
} }
} }
pub fn has_epnt(&self) -> bool {self.epnt.is_some()} pub fn has_epnt(&self) -> bool {self.epnt.is_some()}
pub fn has_fxpx(&self) -> bool {self.fxpx.is_some()} pub fn has_fxpx(&self) -> bool {self.fxpx.is_some()}
pub fn has_lins(&self) -> bool {self.lins.is_some()} pub fn has_lins(&self) -> bool {self.lins.is_some()}
pub fn has_lite(&self) -> bool {self.lite.is_some()} pub fn has_lite(&self) -> bool {self.lite.is_some()}
pub fn has_mnpx(&self) -> bool {self.mnpx.is_some()} pub fn has_mnpx(&self) -> bool {self.mnpx.is_some()}
pub fn has_minf(&self) -> bool {self.minf.is_some()} pub fn has_minf(&self) -> bool {self.minf.is_some()}
pub fn has_name(&self) -> bool {self.name.is_some()} pub fn has_name(&self) -> bool {self.name.is_some()}
pub fn has_note(&self) -> bool {self.note.is_some()} pub fn has_note(&self) -> bool {self.note.is_some()}
pub fn has_objs(&self) -> bool {self.objs.is_some()} pub fn has_objs(&self) -> bool {self.objs.is_some()}
pub fn has_pict(&self) -> bool {self.pict.is_some()} pub fn has_pict(&self) -> bool {self.pict.is_some()}
pub fn has_pnts(&self) -> bool {self.pnts.is_some()} pub fn has_pnts(&self) -> bool {self.pnts.is_some()}
pub fn has_poly(&self) -> bool {self.poly.is_some()} pub fn has_poly(&self) -> bool {self.poly.is_some()}
pub fn has_prpx(&self) -> bool {self.prpx.is_some()} pub fn has_prpx(&self) -> bool {self.prpx.is_some()}
pub fn has_pxpx(&self) -> bool {self.pxpx.is_some()} pub fn has_pxpx(&self) -> bool {self.pxpx.is_some()}
pub fn has_sids(&self) -> bool {self.sids.is_some()} pub fn has_sids(&self) -> bool {self.sids.is_some()}
pub fn has_wppx(&self) -> bool {self.wppx.is_some()} pub fn has_wppx(&self) -> bool {self.wppx.is_some()}
pub fn has_ambi(&self) -> bool {self.ambi.is_some()} pub fn has_ambi(&self) -> bool {self.ambi.is_some()}
pub fn has_bonk(&self) -> bool {self.bonk.is_some()} pub fn has_bonk(&self) -> bool {self.bonk.is_some()}
pub fn has_iidx(&self) -> bool {self.iidx.is_some()} pub fn has_iidx(&self) -> bool {self.iidx.is_some()}
pub fn has_medi(&self) -> bool {self.medi.is_some()} pub fn has_medi(&self) -> bool {self.medi.is_some()}
pub fn has_plac(&self) -> bool {self.plac.is_some()} pub fn has_plac(&self) -> bool {self.plac.is_some()}
pub fn has_plat(&self) -> bool {self.plat.is_some()} pub fn has_plat(&self) -> bool {self.plat.is_some()}
pub fn has_term(&self) -> bool {self.term.is_some()} pub fn has_term(&self) -> bool {self.term.is_some()}
pub fn num_unknown(&self) -> usize {self.unkn.len()} pub fn num_unknown(&self) -> usize {self.unkn.len()}
pub fn len(&self) -> usize pub fn len(&self) -> usize
{ {
self.num_unknown() + self.num_unknown() +
usize::from(self.has_epnt()) + usize::from(self.has_epnt()) +
usize::from(self.has_fxpx()) + usize::from(self.has_fxpx()) +
usize::from(self.has_lins()) + usize::from(self.has_lins()) +
usize::from(self.has_lite()) + usize::from(self.has_lite()) +
usize::from(self.has_mnpx()) + usize::from(self.has_mnpx()) +
usize::from(self.has_minf()) + usize::from(self.has_minf()) +
usize::from(self.has_name()) + usize::from(self.has_name()) +
usize::from(self.has_note()) + usize::from(self.has_note()) +
usize::from(self.has_objs()) + usize::from(self.has_objs()) +
usize::from(self.has_pict()) + usize::from(self.has_pict()) +
usize::from(self.has_pnts()) + usize::from(self.has_pnts()) +
usize::from(self.has_poly()) + usize::from(self.has_poly()) +
usize::from(self.has_prpx()) + usize::from(self.has_prpx()) +
usize::from(self.has_pxpx()) + usize::from(self.has_pxpx()) +
usize::from(self.has_sids()) + usize::from(self.has_sids()) +
usize::from(self.has_wppx()) + usize::from(self.has_wppx()) +
usize::from(self.has_ambi()) + usize::from(self.has_ambi()) +
usize::from(self.has_bonk()) + usize::from(self.has_bonk()) +
usize::from(self.has_iidx()) + usize::from(self.has_iidx()) +
usize::from(self.has_medi()) + usize::from(self.has_medi()) +
usize::from(self.has_plac()) + usize::from(self.has_plac()) +
usize::from(self.has_plat()) usize::from(self.has_plat())
} }
pub fn is_empty(&self) -> bool {self.len() == 0} pub fn is_empty(&self) -> bool {self.len() == 0}
} }
/// The abstract type of an entry. /// The abstract type of an entry.
pub enum EntryType { pub enum EntryType {
Other, Other,
Map, Map,
Image, Image,
Physics, Physics,
} }
/// The loaded data of a Map file entry. /// The loaded data of a Map file entry.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Default, Eq, PartialEq)] #[derive(Debug, Default, Eq, PartialEq)]
pub struct EntryData { pub struct EntryData {
/** `EPNT` chunk data. */ pub epnt: Option<Vec<map::epnt::Endpoint>>, /** `EPNT` chunk data. */ pub epnt: Option<Vec<map::epnt::Endpoint>>,
/** `FXpx` chunk data. */ pub fxpx: Option<Vec<map::fxpx::Effect>>, /** `FXpx` chunk data. */ pub fxpx: Option<Vec<map::fxpx::Effect>>,
/** `LINS` chunk data. */ pub lins: Option<Vec<map::lins::Line>>, /** `LINS` chunk data. */ pub lins: Option<Vec<map::lins::Line>>,
/** `LITE` chunk data. */ pub lite: Option<Vec<map::lite::Light>>, /** `LITE` chunk data. */ pub lite: Option<Vec<map::lite::Light>>,
/** `MNpx` chunk data. */ pub mnpx: Option<Vec<map::mnpx::Monster>>, /** `MNpx` chunk data. */ pub mnpx: Option<Vec<map::mnpx::Monster>>,
/** `Minf` chunk data. */ pub minf: Option<map::minf::Info>, /** `Minf` chunk data. */ pub minf: Option<map::minf::Info>,
/** `NAME` chunk data. */ pub name: Option<Vec<String>>, /** `NAME` chunk data. */ pub name: Option<Vec<String>>,
/** `NOTE` chunk data. */ pub note: Option<Vec<map::note::Note>>, /** `NOTE` chunk data. */ pub note: Option<Vec<map::note::Note>>,
/** `OBJS` chunk data. */ pub objs: Option<Vec<map::objs::Object>>, /** `OBJS` chunk data. */ pub objs: Option<Vec<map::objs::Object>>,
/** `PICT` chunk data. */ pub pict: Option<image::Image8>, /** `PICT` chunk data. */ pub pict: Option<image::Image8>,
/** `PNTS` chunk data. */ pub pnts: Option<Vec<map::pnts::Point>>, /** `PNTS` chunk data. */ pub pnts: Option<Vec<map::pnts::Point>>,
/** `POLY` chunk data. */ pub poly: Option<Vec<map::poly::Polygon>>, /** `POLY` chunk data. */ pub poly: Option<Vec<map::poly::Polygon>>,
/** `PRpx` chunk data. */ pub prpx: Option<Vec<map::prpx::Projectile>>, /** `PRpx` chunk data. */ pub prpx: Option<Vec<map::prpx::Projectile>>,
/** `PXpx` chunk data. */ pub pxpx: Option<Vec<map::pxpx::Physics>>, /** `PXpx` chunk data. */ pub pxpx: Option<Vec<map::pxpx::Physics>>,
/** `SIDS` chunk data. */ pub sids: Option<Vec<map::sids::Side>>, /** `SIDS` chunk data. */ pub sids: Option<Vec<map::sids::Side>>,
/** `WPpx` chunk data. */ pub wppx: Option<Vec<map::wppx::Weapon>>, /** `WPpx` chunk data. */ pub wppx: Option<Vec<map::wppx::Weapon>>,
/** `ambi` chunk data. */ pub ambi: Option<Vec<map::ambi::SoundAmbi>>, /** `ambi` chunk data. */ pub ambi: Option<Vec<map::ambi::SoundAmbi>>,
/** `bonk` chunk data. */ pub bonk: Option<Vec<map::bonk::SoundRand>>, /** `bonk` chunk data. */ pub bonk: Option<Vec<map::bonk::SoundRand>>,
/** `iidx` chunk data. */ pub iidx: Option<Vec<u16>>, /** `iidx` chunk data. */ pub iidx: Option<Vec<u16>>,
/** `medi` chunk data. */ pub medi: Option<Vec<map::medi::Media>>, /** `medi` chunk data. */ pub medi: Option<Vec<map::medi::Media>>,
/** `plac` chunk data. */ pub plac: Option<Vec<map::plac::ObjectFreq>>, /** `plac` chunk data. */ pub plac: Option<Vec<map::plac::ObjectFreq>>,
/** `plat` chunk data. */ pub plat: Option<Vec<map::plat::Platform>>, /** `plat` chunk data. */ pub plat: Option<Vec<map::plat::Platform>>,
/** `term` chunk data. */ pub term: Option<Vec<map::term::Terminal>>, /** `term` chunk data. */ pub term: Option<Vec<map::term::Terminal>>,
pub unkn: Vec<(Ident, Vec<u8>)>, pub unkn: Vec<(Ident, Vec<u8>)>,
} }
/// A map of indexed entries. /// A map of indexed entries.

View File

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

View File

@ -6,44 +6,44 @@ use crate::{err::*, fixed::Unit};
/// Reads an `EPNT` chunk. /// Reads an `EPNT` chunk.
pub fn read(b: &[u8]) -> ResultS<(Endpoint, usize)> pub fn read(b: &[u8]) -> ResultS<(Endpoint, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 16, start: 0, data { endian: BIG, buf: b, size: 16, start: 0, data {
let flags = u16[0] flag EndpointFlags; let flags = u16[0] flag EndpointFlags;
let hei_hi = Unit[2]; let hei_hi = Unit[2];
let hei_lo = Unit[4]; let hei_lo = Unit[4];
let pos = pnts::read_o[6; 4]; let pos = pnts::read_o[6; 4];
let support = u16[10]; let support = u16[10];
} }
} }
Ok((Endpoint{flags, hei_hi, hei_lo, pos, support}, 16)) Ok((Endpoint{flags, hei_hi, hei_lo, pos, support}, 16))
} }
/// Converts a vector of `Endpoint`s to a vector of `Point`s. /// Converts a vector of `Endpoint`s to a vector of `Point`s.
pub fn to_pnts(v: &[Endpoint]) -> Vec<pnts::Point> pub fn to_pnts(v: &[Endpoint]) -> Vec<pnts::Point>
{ {
v.iter().map(|p| p.pos).collect() v.iter().map(|p| p.pos).collect()
} }
/// A pre-processed point in world-space. /// A pre-processed point in world-space.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct Endpoint { pub struct Endpoint {
pub flags: EndpointFlags, pub flags: EndpointFlags,
pub hei_hi: Unit, pub hei_hi: Unit,
pub hei_lo: Unit, pub hei_lo: Unit,
pub pos: pnts::Point, pub pos: pnts::Point,
pub support: u16, pub support: u16,
} }
c_bitfield! { c_bitfield! {
/// Flags for `Endpoint`. /// Flags for `Endpoint`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct EndpointFlags: u16 { pub struct EndpointFlags: u16 {
SOLID = 0, SOLID = 0,
SAME_HEIGHT = 1, SAME_HEIGHT = 1,
TRANSPARENT = 2, TRANSPARENT = 2,
} }
} }
// EOF // EOF

View File

@ -5,42 +5,42 @@ use crate::{bin::OptU16, err::*, fixed::Fixed};
/// Reads a `FXpx` chunk. /// Reads a `FXpx` chunk.
pub fn read(b: &[u8]) -> ResultS<(Effect, usize)> pub fn read(b: &[u8]) -> ResultS<(Effect, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 14, start: 0, data { endian: BIG, buf: b, size: 14, start: 0, data {
let collection = u16[0]; let collection = u16[0];
let shape = u16[2]; let shape = u16[2];
let pitch = Fixed[4]; let pitch = Fixed[4];
let flags = u16[8] flag EffectFlags; let flags = u16[8] flag EffectFlags;
let delay = OptU16[10]; let delay = OptU16[10];
let delay_snd = OptU16[12]; let delay_snd = OptU16[12];
} }
} }
Ok((Effect{collection, shape, pitch, flags, delay, delay_snd}, 14)) Ok((Effect{collection, shape, pitch, flags, delay, delay_snd}, 14))
} }
/// An effect definition. /// An effect definition.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct Effect { pub struct Effect {
pub collection: u16, pub collection: u16,
pub shape: u16, pub shape: u16,
pub pitch: Fixed, pub pitch: Fixed,
pub flags: EffectFlags, pub flags: EffectFlags,
pub delay: OptU16, pub delay: OptU16,
pub delay_snd: OptU16, pub delay_snd: OptU16,
} }
c_bitfield! { c_bitfield! {
/// Flags for an effect. /// Flags for an effect.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct EffectFlags: u16 { pub struct EffectFlags: u16 {
END_ON_LOOP = 0, END_ON_LOOP = 0,
END_ON_XFER_LOOP = 1, END_ON_XFER_LOOP = 1,
SOUND_ONLY = 2, SOUND_ONLY = 2,
MAKE_TWIN_VISIBLE = 3, MAKE_TWIN_VISIBLE = 3,
MEDIA_EFFECT = 4, MEDIA_EFFECT = 4,
} }
} }
// EOF // EOF

View File

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

View File

@ -5,9 +5,9 @@ use crate::{bin::{check_data, u16b}, err::*};
/// Reads an `iidx` chunk. /// Reads an `iidx` chunk.
pub fn read(b: &[u8]) -> ResultS<(u16, usize)> pub fn read(b: &[u8]) -> ResultS<(u16, usize)>
{ {
check_data(b, 2)?; check_data(b, 2)?;
Ok((u16b(b), 2)) Ok((u16b(b), 2))
} }
// EOF // EOF

View File

@ -5,45 +5,45 @@ use crate::{bin::OptU16, err::*};
/// Reads a `LINS` chunk. /// Reads a `LINS` chunk.
pub fn read(b: &[u8]) -> ResultS<(Line, usize)> pub fn read(b: &[u8]) -> ResultS<(Line, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 32, start: 0, data { endian: BIG, buf: b, size: 32, start: 0, data {
let pnt_beg = u16[0]; let pnt_beg = u16[0];
let pnt_end = u16[2]; let pnt_end = u16[2];
let flags = u16[4] flag LineFlags; let flags = u16[4] flag LineFlags;
let side_fr = OptU16[12]; let side_fr = OptU16[12];
let side_bk = OptU16[14]; let side_bk = OptU16[14];
let poly_fr = OptU16[16]; let poly_fr = OptU16[16];
let poly_bk = OptU16[18]; let poly_bk = OptU16[18];
} }
} }
Ok((Line{flags, pnt_beg, pnt_end, side_fr, side_bk, poly_fr, poly_bk}, 32)) Ok((Line{flags, pnt_beg, pnt_end, side_fr, side_bk, poly_fr, poly_bk}, 32))
} }
/// A line segment. /// A line segment.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct Line { pub struct Line {
pub flags: LineFlags, pub flags: LineFlags,
pub pnt_beg: u16, pub pnt_beg: u16,
pub pnt_end: u16, pub pnt_end: u16,
pub side_fr: OptU16, pub side_fr: OptU16,
pub side_bk: OptU16, pub side_bk: OptU16,
pub poly_fr: OptU16, pub poly_fr: OptU16,
pub poly_bk: OptU16, pub poly_bk: OptU16,
} }
c_bitfield! { c_bitfield! {
/// Flags for `Line`. /// Flags for `Line`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct LineFlags: u16 { pub struct LineFlags: u16 {
TRANS_SIDE = 9, TRANS_SIDE = 9,
ELEV_VAR = 10, ELEV_VAR = 10,
ELEVATION = 11, ELEVATION = 11,
LANDSCAPE = 12, LANDSCAPE = 12,
TRANSPARENT = 13, TRANSPARENT = 13,
SOLID = 14, SOLID = 14,
} }
} }
// EOF // EOF

View File

@ -6,393 +6,393 @@ use crate::{err::*, fixed::Fixed};
/// Reads a `LITE` chunk. /// Reads a `LITE` chunk.
pub fn read(b: &[u8]) -> ResultS<(Light, usize)> pub fn read(b: &[u8]) -> ResultS<(Light, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 100, start: 0, data { endian: BIG, buf: b, size: 100, start: 0, data {
let ltype = u16[0] enum LightType; let ltype = u16[0] enum LightType;
let flags = u16[2] flag LightFlags; let flags = u16[2] flag LightFlags;
let phase = i16[4]; let phase = i16[4];
let act_pri = ltfn::read[6; 14]; let act_pri = ltfn::read[6; 14];
let act_sec = ltfn::read[20; 14]; let act_sec = ltfn::read[20; 14];
let act_mid = ltfn::read[34; 14]; let act_mid = ltfn::read[34; 14];
let ina_pri = ltfn::read[48; 14]; let ina_pri = ltfn::read[48; 14];
let ina_sec = ltfn::read[62; 14]; let ina_sec = ltfn::read[62; 14];
let ina_mid = ltfn::read[76; 14]; let ina_mid = ltfn::read[76; 14];
let tag = u16[90]; let tag = u16[90];
} }
} }
Ok((Light{ltype, flags, phase, act_pri, act_sec, act_mid, ina_pri, ina_sec, Ok((Light{ltype, flags, phase, act_pri, act_sec, act_mid, ina_pri, ina_sec,
ina_mid, tag}, 100)) ina_mid, tag}, 100))
} }
/// Reads an old `LITE` chunk. /// Reads an old `LITE` chunk.
pub fn read_old(b: &[u8]) -> ResultS<(Light, usize)> pub fn read_old(b: &[u8]) -> ResultS<(Light, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 32, start: 0, data { endian: BIG, buf: b, size: 32, start: 0, data {
let ltype = u16[2] usize; let ltype = u16[2] usize;
let mode = u16[4]; let mode = u16[4];
let phase = i16[6]; let phase = i16[6];
let min = Fixed[8]; let min = Fixed[8];
let max = Fixed[12]; let max = Fixed[12];
let prd = u16[16]; let prd = u16[16];
} }
} }
if OLD_LIGHT_DEFINITIONS.len() < ltype { if OLD_LIGHT_DEFINITIONS.len() < ltype {
bail!("bad old light type"); bail!("bad old light type");
} }
let lite = &OLD_LIGHT_DEFINITIONS[ltype]; let lite = &OLD_LIGHT_DEFINITIONS[ltype];
let on = mode == 0 || mode == 1; let on = mode == 0 || mode == 1;
let strobe = ltype == 3; let strobe = ltype == 3;
let flags = if on {lite.flags | LightFlags::INIT_ACTIVE} else {lite.flags}; let flags = if on {lite.flags | LightFlags::INIT_ACTIVE} else {lite.flags};
// modify each old light function accordingly // modify each old light function accordingly
let old_lfun = move |func: &ltfn::LightFunc| -> ltfn::LightFunc { let old_lfun = move |func: &ltfn::LightFunc| -> ltfn::LightFunc {
ltfn::LightFunc{ftype: func.ftype, ltfn::LightFunc{ftype: func.ftype,
prd_nrm: if strobe {prd / 4 + 1} else {func.prd_nrm}, prd_nrm: if strobe {prd / 4 + 1} else {func.prd_nrm},
prd_dta: func.prd_dta, prd_dta: func.prd_dta,
val_nrm: if func.val_nrm > 0.into() {max} else {min}, val_nrm: if func.val_nrm > 0.into() {max} else {min},
val_dta: func.val_dta} val_dta: func.val_dta}
}; };
Ok((Light{flags, Ok((Light{flags,
phase, phase,
act_pri: old_lfun(&lite.act_pri), act_pri: old_lfun(&lite.act_pri),
act_sec: old_lfun(&lite.act_sec), act_sec: old_lfun(&lite.act_sec),
act_mid: old_lfun(&lite.act_mid), act_mid: old_lfun(&lite.act_mid),
ina_pri: old_lfun(&lite.ina_pri), ina_pri: old_lfun(&lite.ina_pri),
ina_sec: old_lfun(&lite.ina_sec), ina_sec: old_lfun(&lite.ina_sec),
ina_mid: old_lfun(&lite.ina_mid), ina_mid: old_lfun(&lite.ina_mid),
tag: 0, tag: 0,
..*lite}, 32)) ..*lite}, 32))
} }
/// A dynamic polygon light. /// A dynamic polygon light.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct Light { pub struct Light {
pub ltype: LightType, pub ltype: LightType,
pub flags: LightFlags, pub flags: LightFlags,
pub phase: i16, pub phase: i16,
pub act_pri: ltfn::LightFunc, pub act_pri: ltfn::LightFunc,
pub act_sec: ltfn::LightFunc, pub act_sec: ltfn::LightFunc,
pub act_mid: ltfn::LightFunc, pub act_mid: ltfn::LightFunc,
pub ina_pri: ltfn::LightFunc, pub ina_pri: ltfn::LightFunc,
pub ina_sec: ltfn::LightFunc, pub ina_sec: ltfn::LightFunc,
pub ina_mid: ltfn::LightFunc, pub ina_mid: ltfn::LightFunc,
pub tag: u16, pub tag: u16,
} }
c_bitfield! { c_bitfield! {
/// Flags for `Light`. /// Flags for `Light`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct LightFlags: u16 { pub struct LightFlags: u16 {
INIT_ACTIVE = 0, INIT_ACTIVE = 0,
SLAVE_VALUE = 1, SLAVE_VALUE = 1,
STATELESS = 2, STATELESS = 2,
} }
} }
c_enum! { c_enum! {
/// The type of a `Light`. /// The type of a `Light`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub enum LightType: u16 { pub enum LightType: u16 {
Normal = 0, Normal = 0,
Strobe = 1, Strobe = 1,
Media = 2, Media = 2,
} }
} }
const OLD_LIGHT_DEFINITIONS: [Light; 8] = [ const OLD_LIGHT_DEFINITIONS: [Light; 8] = [
// Normal // Normal
Light{ltype: LightType::Normal, Light{ltype: LightType::Normal,
flags: LightFlags::SLAVE_VALUE, flags: LightFlags::SLAVE_VALUE,
phase: 0, phase: 0,
act_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, act_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
act_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, act_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
act_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, act_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: 1, prd_nrm: 1,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, ina_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, ina_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, ina_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: 1, prd_nrm: 1,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
tag: 0}, tag: 0},
// Rheostat // Rheostat
Light{ltype: LightType::Normal, Light{ltype: LightType::Normal,
flags: LightFlags::SLAVE_VALUE, flags: LightFlags::SLAVE_VALUE,
phase: 0, phase: 0,
act_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, act_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
act_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, act_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
act_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Smooth, act_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Smooth,
prd_nrm: TICKS_PER_SECOND * 3, prd_nrm: TICKS_PER_SECOND * 3,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, ina_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, ina_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Smooth, ina_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Smooth,
prd_nrm: TICKS_PER_SECOND * 3, prd_nrm: TICKS_PER_SECOND * 3,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
tag: 0}, tag: 0},
// Flourescent // Flourescent
Light{ltype: LightType::Normal, Light{ltype: LightType::Normal,
flags: LightFlags::SLAVE_VALUE, flags: LightFlags::SLAVE_VALUE,
phase: 0, phase: 0,
act_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, act_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
act_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, act_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
act_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Fluorescent, act_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Fluorescent,
prd_nrm: TICKS_PER_SECOND * 3, prd_nrm: TICKS_PER_SECOND * 3,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, ina_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, ina_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, ina_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: 1, prd_nrm: 1,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
tag: 0}, tag: 0},
// Strobe // Strobe
Light{ltype: LightType::Normal, Light{ltype: LightType::Normal,
flags: LightFlags::SLAVE_VALUE, flags: LightFlags::SLAVE_VALUE,
phase: 0, phase: 0,
act_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, act_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
act_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, act_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
act_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, act_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: 1, prd_nrm: 1,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, ina_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, ina_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, ina_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: 1, prd_nrm: 1,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
tag: 0}, tag: 0},
// Flicker // Flicker
Light{ltype: LightType::Normal, Light{ltype: LightType::Normal,
flags: LightFlags::SLAVE_VALUE, flags: LightFlags::SLAVE_VALUE,
phase: 0, phase: 0,
act_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, act_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
act_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, act_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
act_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Flicker, act_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Flicker,
prd_nrm: TICKS_PER_SECOND * 3, prd_nrm: TICKS_PER_SECOND * 3,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, ina_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, ina_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, ina_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: 1, prd_nrm: 1,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
tag: 0}, tag: 0},
// Pulsate // Pulsate
Light{ltype: LightType::Normal, Light{ltype: LightType::Normal,
flags: LightFlags::SLAVE_VALUE, flags: LightFlags::SLAVE_VALUE,
phase: 0, phase: 0,
act_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Smooth, act_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Smooth,
prd_nrm: TICKS_PER_SECOND * 2, prd_nrm: TICKS_PER_SECOND * 2,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
act_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Smooth, act_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Smooth,
prd_nrm: TICKS_PER_SECOND * 2 - 1, prd_nrm: TICKS_PER_SECOND * 2 - 1,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
act_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Smooth, act_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Smooth,
prd_nrm: TICKS_PER_SECOND * 2 - 1, prd_nrm: TICKS_PER_SECOND * 2 - 1,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Smooth, ina_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Smooth,
prd_nrm: TICKS_PER_SECOND * 2, prd_nrm: TICKS_PER_SECOND * 2,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Smooth, ina_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Smooth,
prd_nrm: TICKS_PER_SECOND * 2 - 1, prd_nrm: TICKS_PER_SECOND * 2 - 1,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Smooth, ina_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Smooth,
prd_nrm: TICKS_PER_SECOND * 2, prd_nrm: TICKS_PER_SECOND * 2,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
tag: 0}, tag: 0},
// Annoying // Annoying
Light{ltype: LightType::Normal, Light{ltype: LightType::Normal,
flags: LightFlags::SLAVE_VALUE, flags: LightFlags::SLAVE_VALUE,
phase: 0, phase: 0,
act_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Random, act_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Random,
prd_nrm: 2, prd_nrm: 2,
prd_dta: 1, prd_dta: 1,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
act_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, act_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: 2, prd_nrm: 2,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
act_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Random, act_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Random,
prd_nrm: 1, prd_nrm: 1,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, ina_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, ina_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, ina_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
tag: 0}, tag: 0},
// Energy Efficient // Energy Efficient
Light{ltype: LightType::Normal, Light{ltype: LightType::Normal,
flags: LightFlags::SLAVE_VALUE, flags: LightFlags::SLAVE_VALUE,
phase: 0, phase: 0,
act_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, act_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
act_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, act_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
act_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Linear, act_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Linear,
prd_nrm: TICKS_PER_SECOND * 2, prd_nrm: TICKS_PER_SECOND * 2,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(1), val_nrm: Fixed::from_int(1),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, ina_pri: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant, ina_sec: ltfn::LightFunc{ftype: ltfn::LightFuncType::Constant,
prd_nrm: TICKS_PER_SECOND, prd_nrm: TICKS_PER_SECOND,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
ina_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Linear, ina_mid: ltfn::LightFunc{ftype: ltfn::LightFuncType::Linear,
prd_nrm: TICKS_PER_SECOND * 2, prd_nrm: TICKS_PER_SECOND * 2,
prd_dta: 0, prd_dta: 0,
val_nrm: Fixed::from_int(0), val_nrm: Fixed::from_int(0),
val_dta: Fixed::from_int(0)}, val_dta: Fixed::from_int(0)},
tag: 0}, tag: 0},
]; ];
// EOF // EOF

View File

@ -5,53 +5,53 @@ use crate::{err::*, fixed::Fixed};
/// Reads a `LightFunc` object. /// Reads a `LightFunc` object.
pub fn read(b: &[u8]) -> ResultS<LightFunc> pub fn read(b: &[u8]) -> ResultS<LightFunc>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 14, start: 0, data { endian: BIG, buf: b, size: 14, start: 0, data {
let ftype = u16[0] enum LightFuncType; let ftype = u16[0] enum LightFuncType;
let prd_nrm = u16[2]; let prd_nrm = u16[2];
let prd_dta = u16[4]; let prd_dta = u16[4];
let val_nrm = Fixed[6]; let val_nrm = Fixed[6];
let val_dta = Fixed[10]; let val_dta = Fixed[10];
} }
} }
Ok(LightFunc{ftype, prd_nrm, prd_dta, val_nrm, val_dta}) Ok(LightFunc{ftype, prd_nrm, prd_dta, val_nrm, val_dta})
} }
/// Writes a `LightFunc` object. /// Writes a `LightFunc` object.
pub fn write(v: &LightFunc) -> Vec<u8> pub fn write(v: &LightFunc) -> Vec<u8>
{ {
let mut o = Vec::with_capacity(14); let mut o = Vec::with_capacity(14);
o.extend(&(v.ftype as u16).to_be_bytes()); o.extend(&(v.ftype as u16).to_be_bytes());
o.extend(&v.prd_nrm.to_be_bytes()); o.extend(&v.prd_nrm.to_be_bytes());
o.extend(&v.prd_dta.to_be_bytes()); o.extend(&v.prd_dta.to_be_bytes());
o.extend(&v.val_nrm.to_be_bytes()); o.extend(&v.val_nrm.to_be_bytes());
o.extend(&v.val_dta.to_be_bytes()); o.extend(&v.val_dta.to_be_bytes());
o o
} }
/// A light function. /// A light function.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct LightFunc { pub struct LightFunc {
pub ftype: LightFuncType, pub ftype: LightFuncType,
pub prd_nrm: u16, pub prd_nrm: u16,
pub prd_dta: u16, pub prd_dta: u16,
pub val_nrm: Fixed, pub val_nrm: Fixed,
pub val_dta: Fixed, pub val_dta: Fixed,
} }
c_enum! { c_enum! {
/// The type of function for a `LightFunc`. /// The type of function for a `LightFunc`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub enum LightFuncType: u16 { pub enum LightFuncType: u16 {
Constant = 0, Constant = 0,
Linear = 1, Linear = 1,
Smooth = 2, Smooth = 2,
Flicker = 3, Flicker = 3,
Random = 4, Random = 4,
Fluorescent = 5, Fluorescent = 5,
} }
} }
// EOF // EOF

View File

@ -9,63 +9,63 @@ use crate::{bin::OptU16,
/// Reads a `medi` chunk. /// Reads a `medi` chunk.
pub fn read(b: &[u8]) -> ResultS<(Media, usize)> pub fn read(b: &[u8]) -> ResultS<(Media, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 32, start: 0, data { endian: BIG, buf: b, size: 32, start: 0, data {
let mtype = u16[0] enum MediaType; let mtype = u16[0] enum MediaType;
let flags = u8[3] flag MediaFlags; let flags = u8[3] flag MediaFlags;
let control = u16[4]; let control = u16[4];
let dir = Angle[6]; let dir = Angle[6];
let mag = Unit[8]; let mag = Unit[8];
let hei_lo = Unit[10]; let hei_lo = Unit[10];
let hei_hi = Unit[12]; let hei_hi = Unit[12];
let orig = pnts::read_o[14; 4]; let orig = pnts::read_o[14; 4];
let hei_nrm = Unit[18]; let hei_nrm = Unit[18];
let min_lt = Fixed[20]; let min_lt = Fixed[20];
let texture = OptU16[24]; let texture = OptU16[24];
let xfer = u16[26] enum TransferMode; let xfer = u16[26] enum TransferMode;
} }
} }
Ok((Media{mtype, flags, control, dir, mag, hei_lo, hei_hi, orig, hei_nrm, Ok((Media{mtype, flags, control, dir, mag, hei_lo, hei_hi, orig, hei_nrm,
min_lt, texture, xfer}, 32)) min_lt, texture, xfer}, 32))
} }
/// A media, as in a part of a polygon which goes up the middle of the wall. /// 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))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct Media { pub struct Media {
pub mtype: MediaType, pub mtype: MediaType,
pub flags: MediaFlags, pub flags: MediaFlags,
pub control: u16, pub control: u16,
pub dir: Angle, pub dir: Angle,
pub mag: Unit, pub mag: Unit,
pub hei_lo: Unit, pub hei_lo: Unit,
pub hei_hi: Unit, pub hei_hi: Unit,
pub orig: pnts::Point, pub orig: pnts::Point,
pub hei_nrm: Unit, pub hei_nrm: Unit,
pub min_lt: Fixed, pub min_lt: Fixed,
pub texture: OptU16, pub texture: OptU16,
pub xfer: TransferMode, pub xfer: TransferMode,
} }
c_enum! { c_enum! {
/// The liquid type of a `Media`. /// The liquid type of a `Media`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub enum MediaType: u16 { pub enum MediaType: u16 {
Water = 0, Water = 0,
Lava = 1, Lava = 1,
Goo = 2, Goo = 2,
Sewage = 3, Sewage = 3,
Jjaro = 4, Jjaro = 4,
} }
} }
c_bitfield! { c_bitfield! {
/// Flags for `Media`. /// Flags for `Media`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct MediaFlags: u8 { pub struct MediaFlags: u8 {
OBSTRUCT = 0, OBSTRUCT = 0,
} }
} }
// EOF // EOF

View File

@ -5,127 +5,127 @@ use crate::{err::*, text::*};
/// Reads a `Minf` chunk. /// Reads a `Minf` chunk.
pub fn read(b: &[u8]) -> ResultS<Info> pub fn read(b: &[u8]) -> ResultS<Info>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 88, start: 0, data { endian: BIG, buf: b, size: 88, start: 0, data {
let texture_id = u16[0]; let texture_id = u16[0];
let physics_id = u16[2]; let physics_id = u16[2];
let skypict_id = u16[4]; let skypict_id = u16[4];
let miss_flags = u16[6] flag MissionFlags; let miss_flags = u16[6] flag MissionFlags;
let envi_flags = u16[8] flag EnvironmentFlags; let envi_flags = u16[8] flag EnvironmentFlags;
let level_name = mac_roman_cstr[18; 66] no_try; let level_name = mac_roman_cstr[18; 66] no_try;
let entr_flags = u32[84] flag EntryFlags; let entr_flags = u32[84] flag EntryFlags;
} }
} }
Ok(Info{texture_id, physics_id, skypict_id, miss_flags, envi_flags, Ok(Info{texture_id, physics_id, skypict_id, miss_flags, envi_flags,
entr_flags, level_name}) entr_flags, level_name})
} }
/// Writes a `Minf` chunk. /// Writes a `Minf` chunk.
pub fn write(v: &Info) -> Vec<u8> pub fn write(v: &Info) -> Vec<u8>
{ {
let mut o = Vec::with_capacity(4); let mut o = Vec::with_capacity(4);
o.extend(&v.texture_id.to_be_bytes()); o.extend(&v.texture_id.to_be_bytes());
o.extend(&v.physics_id.to_be_bytes()); o.extend(&v.physics_id.to_be_bytes());
o.extend(&v.skypict_id.to_be_bytes()); o.extend(&v.skypict_id.to_be_bytes());
o.extend(&v.miss_flags.bits().to_be_bytes()); o.extend(&v.miss_flags.bits().to_be_bytes());
o.extend(&v.envi_flags.bits().to_be_bytes()); o.extend(&v.envi_flags.bits().to_be_bytes());
o.extend(&pad_zero(to_mac_roman(&v.level_name), 66)); o.extend(&pad_zero(to_mac_roman(&v.level_name), 66));
o.extend(&v.entr_flags.bits().to_be_bytes()); o.extend(&v.entr_flags.bits().to_be_bytes());
o o
} }
/// Reads an old `Minf` chunk. /// Reads an old `Minf` chunk.
pub fn read_old(b: &[u8]) -> ResultS<Info> pub fn read_old(b: &[u8]) -> ResultS<Info>
{ {
let minf = read(b)?; let minf = read(b)?;
let mut entr_flags = if minf.entr_flags.is_empty() { let mut entr_flags = if minf.entr_flags.is_empty() {
EntryFlags::SOLO EntryFlags::SOLO
} else { } else {
minf.entr_flags minf.entr_flags
}; };
if entr_flags.intersects(EntryFlags::SOLO | EntryFlags::CARNAGE) { if entr_flags.intersects(EntryFlags::SOLO | EntryFlags::CARNAGE) {
entr_flags.insert(EntryFlags::CO_OP) entr_flags.insert(EntryFlags::CO_OP)
} }
Ok(Info{entr_flags, ..minf}) Ok(Info{entr_flags, ..minf})
} }
impl Default for Info impl Default for Info
{ {
fn default() -> Self fn default() -> Self
{ {
Self{texture_id: 0, Self{texture_id: 0,
physics_id: 1, physics_id: 1,
skypict_id: 0, skypict_id: 0,
miss_flags: MissionFlags::empty(), miss_flags: MissionFlags::empty(),
envi_flags: EnvironmentFlags::empty(), envi_flags: EnvironmentFlags::empty(),
entr_flags: EntryFlags::SOLO, entr_flags: EntryFlags::SOLO,
level_name: "Map".to_string()} level_name: "Map".to_string()}
} }
} }
/// Static map information. /// Static map information.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct Info { pub struct Info {
pub texture_id: u16, pub texture_id: u16,
pub physics_id: u16, pub physics_id: u16,
pub skypict_id: u16, pub skypict_id: u16,
pub miss_flags: MissionFlags, pub miss_flags: MissionFlags,
pub envi_flags: EnvironmentFlags, pub envi_flags: EnvironmentFlags,
pub entr_flags: EntryFlags, pub entr_flags: EntryFlags,
pub level_name: String, pub level_name: String,
} }
c_bitfield! { c_bitfield! {
/// Static environment flags. /// Static environment flags.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct EnvironmentFlags: u16 { pub struct EnvironmentFlags: u16 {
VACUUM = 0, VACUUM = 0,
MAGNETIC = 1, MAGNETIC = 1,
REBELLION = 2, REBELLION = 2,
LOW_GRAV = 3, LOW_GRAV = 3,
M1_GLUE = 4, M1_GLUE = 4,
LAVA_FLOOR = 5, LAVA_FLOOR = 5,
REBELLION2 = 6, REBELLION2 = 6,
MUSIC = 7, MUSIC = 7,
TERM_PAUSE = 8, TERM_PAUSE = 8,
M1_MONSTER = 9, M1_MONSTER = 9,
M1_WEPS = 10, M1_WEPS = 10,
} }
} }
c_bitfield! { c_bitfield! {
/// Static entry point flags. /// Static entry point flags.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct EntryFlags: u32 { pub struct EntryFlags: u32 {
SOLO = 0, SOLO = 0,
CO_OP = 1, CO_OP = 1,
CARNAGE = 2, CARNAGE = 2,
KTMWTB = 3, KTMWTB = 3,
KOTH = 4, KOTH = 4,
DEFENSE = 5, DEFENSE = 5,
RUGBY = 6, RUGBY = 6,
CTF = 7, CTF = 7,
} }
} }
c_bitfield! { c_bitfield! {
/// Static mission flags. /// Static mission flags.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct MissionFlags: u16 { pub struct MissionFlags: u16 {
EXTERMINATION = 0, EXTERMINATION = 0,
EXPLORATION = 1, EXPLORATION = 1,
RETRIEVAL = 2, RETRIEVAL = 2,
REPAIR = 3, REPAIR = 3,
RESCUE = 4, RESCUE = 4,
M1_EXPLORATION = 5, M1_EXPLORATION = 5,
M1_RESCUE = 6, M1_RESCUE = 6,
M1_REPAIR = 7, M1_REPAIR = 7,
} }
} }
// EOF // EOF

View File

@ -7,194 +7,194 @@ use super::{attk, damg};
/// Reads a `MNpx` chunk. /// Reads a `MNpx` chunk.
pub fn read(b: &[u8]) -> ResultS<(Monster, usize)> pub fn read(b: &[u8]) -> ResultS<(Monster, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 156, start: 0, data { endian: BIG, buf: b, size: 156, start: 0, data {
let collection = u16[0]; let collection = u16[0];
let vitality = u16[2]; let vitality = u16[2];
let dty_immune = u32[4] flag damg::DamageTypeFlags; let dty_immune = u32[4] flag damg::DamageTypeFlags;
let dty_weak = u32[8] flag damg::DamageTypeFlags; let dty_weak = u32[8] flag damg::DamageTypeFlags;
let flags = u32[12] flag MonsterFlags; let flags = u32[12] flag MonsterFlags;
let cls_self = u32[16] flag MonsterClass; let cls_self = u32[16] flag MonsterClass;
let cls_friend = u32[20]; let cls_friend = u32[20];
let cls_enemy = u32[24]; let cls_enemy = u32[24];
let snd_pitch = Fixed[28]; let snd_pitch = Fixed[28];
let snd_see_enemy = OptU16[32]; let snd_see_enemy = OptU16[32];
let snd_see_friend = OptU16[34]; let snd_see_friend = OptU16[34];
let snd_seeclear = OptU16[36]; let snd_seeclear = OptU16[36];
let snd_kill = OptU16[38]; let snd_kill = OptU16[38];
let snd_apologize = OptU16[40]; let snd_apologize = OptU16[40];
let snd_amicide = OptU16[42]; let snd_amicide = OptU16[42];
let snd_flaming = OptU16[44]; let snd_flaming = OptU16[44];
let snd_active = OptU16[46]; let snd_active = OptU16[46];
let snd_active_mask = u16[48]; let snd_active_mask = u16[48];
let typ_item = OptU16[50]; let typ_item = OptU16[50];
let radius = Unit[52]; let radius = Unit[52];
let height = Unit[54]; let height = Unit[54];
let height_hover = Unit[56]; let height_hover = Unit[56];
let ledge_min = Unit[58]; let ledge_min = Unit[58];
let ledge_max = Unit[60]; let ledge_max = Unit[60];
let ext_vel_scale = Fixed[62]; let ext_vel_scale = Fixed[62];
let fxt_impact = OptU16[66]; let fxt_impact = OptU16[66];
let fxt_impact_melee = OptU16[68]; let fxt_impact_melee = OptU16[68];
let fxt_trail = OptU16[70]; let fxt_trail = OptU16[70];
let half_fov_horz = u16[72]; let half_fov_horz = u16[72];
let half_fov_vert = u16[74]; let half_fov_vert = u16[74];
let view_range = Unit[76]; let view_range = Unit[76];
let view_range_dark = Unit[78]; let view_range_dark = Unit[78];
let intelligence = u16[80]; let intelligence = u16[80];
let speed = u16[82]; let speed = u16[82];
let gravity = u16[84]; let gravity = u16[84];
let vel_terminal = u16[86]; let vel_terminal = u16[86];
let door_try_mask = u16[88]; let door_try_mask = u16[88];
let expl_radius = OptU16[90]; let expl_radius = OptU16[90];
let expl_damage = damg::read[92; 12]; let expl_damage = damg::read[92; 12];
let seq_hit = OptU16[104]; let seq_hit = OptU16[104];
let seq_dying_hard = OptU16[106]; let seq_dying_hard = OptU16[106];
let seq_dying_soft = OptU16[108]; let seq_dying_soft = OptU16[108];
let seq_dead_hard = OptU16[110]; let seq_dead_hard = OptU16[110];
let seq_dead_soft = OptU16[112]; let seq_dead_soft = OptU16[112];
let seq_standing = u16[114]; let seq_standing = u16[114];
let seq_moving = u16[116]; let seq_moving = u16[116];
let seq_tele_in = OptU16[118]; let seq_tele_in = OptU16[118];
let seq_tele_out = OptU16[120]; let seq_tele_out = OptU16[120];
let atk_frequency = u16[122]; let atk_frequency = u16[122];
let atk_melee = attk::read[124; 16]; let atk_melee = attk::read[124; 16];
let atk_range = attk::read[140; 16]; let atk_range = attk::read[140; 16];
} }
} }
// friend and enemy fields MUST truncate because the original source code // friend and enemy fields MUST truncate because the original source code
// used `-1` to represent "all classes" which should be invalid normally // used `-1` to represent "all classes" which should be invalid normally
let cls_friend = MonsterClass::from_bits_truncate(cls_friend); let cls_friend = MonsterClass::from_bits_truncate(cls_friend);
let cls_enemy = MonsterClass::from_bits_truncate(cls_enemy); let cls_enemy = MonsterClass::from_bits_truncate(cls_enemy);
Ok((Monster{collection, vitality, dty_immune, dty_weak, flags, cls_self, Ok((Monster{collection, vitality, dty_immune, dty_weak, flags, cls_self,
cls_friend, cls_enemy, snd_pitch, snd_see_enemy, snd_see_friend, cls_friend, cls_enemy, snd_pitch, snd_see_enemy, snd_see_friend,
snd_seeclear, snd_kill, snd_apologize, snd_amicide, snd_flaming, snd_seeclear, snd_kill, snd_apologize, snd_amicide, snd_flaming,
snd_active, snd_active_mask, typ_item, radius, height, snd_active, snd_active_mask, typ_item, radius, height,
height_hover, ledge_min, ledge_max, ext_vel_scale, fxt_impact, height_hover, ledge_min, ledge_max, ext_vel_scale, fxt_impact,
fxt_impact_melee, fxt_trail, half_fov_horz, half_fov_vert, fxt_impact_melee, fxt_trail, half_fov_horz, half_fov_vert,
view_range, view_range_dark, intelligence, speed, gravity, view_range, view_range_dark, intelligence, speed, gravity,
vel_terminal, door_try_mask, expl_radius, expl_damage, seq_hit, vel_terminal, door_try_mask, expl_radius, expl_damage, seq_hit,
seq_dying_hard, seq_dying_soft, seq_dead_hard, seq_dead_soft, seq_dying_hard, seq_dying_soft, seq_dead_hard, seq_dead_soft,
seq_standing, seq_moving, seq_tele_in, seq_tele_out, seq_standing, seq_moving, seq_tele_in, seq_tele_out,
atk_frequency, atk_melee, atk_range}, 156)) atk_frequency, atk_melee, atk_range}, 156))
} }
/// A monster definition. /// A monster definition.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct Monster { pub struct Monster {
pub collection: u16, pub collection: u16,
pub vitality: u16, pub vitality: u16,
pub dty_immune: damg::DamageTypeFlags, pub dty_immune: damg::DamageTypeFlags,
pub dty_weak: damg::DamageTypeFlags, pub dty_weak: damg::DamageTypeFlags,
pub flags: MonsterFlags, pub flags: MonsterFlags,
pub cls_self: MonsterClass, pub cls_self: MonsterClass,
pub cls_friend: MonsterClass, pub cls_friend: MonsterClass,
pub cls_enemy: MonsterClass, pub cls_enemy: MonsterClass,
pub snd_pitch: Fixed, pub snd_pitch: Fixed,
pub snd_see_enemy: OptU16, pub snd_see_enemy: OptU16,
pub snd_see_friend: OptU16, pub snd_see_friend: OptU16,
pub snd_seeclear: OptU16, pub snd_seeclear: OptU16,
pub snd_kill: OptU16, pub snd_kill: OptU16,
pub snd_apologize: OptU16, pub snd_apologize: OptU16,
pub snd_amicide: OptU16, pub snd_amicide: OptU16,
pub snd_flaming: OptU16, pub snd_flaming: OptU16,
pub snd_active: OptU16, pub snd_active: OptU16,
pub snd_active_mask: u16, pub snd_active_mask: u16,
pub typ_item: OptU16, pub typ_item: OptU16,
pub radius: Unit, pub radius: Unit,
pub height: Unit, pub height: Unit,
pub height_hover: Unit, pub height_hover: Unit,
pub ledge_min: Unit, pub ledge_min: Unit,
pub ledge_max: Unit, pub ledge_max: Unit,
pub ext_vel_scale: Fixed, pub ext_vel_scale: Fixed,
pub fxt_impact: OptU16, pub fxt_impact: OptU16,
pub fxt_impact_melee: OptU16, pub fxt_impact_melee: OptU16,
pub fxt_trail: OptU16, pub fxt_trail: OptU16,
pub half_fov_horz: u16, pub half_fov_horz: u16,
pub half_fov_vert: u16, pub half_fov_vert: u16,
pub view_range: Unit, pub view_range: Unit,
pub view_range_dark: Unit, pub view_range_dark: Unit,
pub intelligence: u16, pub intelligence: u16,
pub speed: u16, pub speed: u16,
pub gravity: u16, pub gravity: u16,
pub vel_terminal: u16, pub vel_terminal: u16,
pub door_try_mask: u16, pub door_try_mask: u16,
pub expl_radius: OptU16, pub expl_radius: OptU16,
pub expl_damage: damg::Damage, pub expl_damage: damg::Damage,
pub seq_hit: OptU16, pub seq_hit: OptU16,
pub seq_dying_hard: OptU16, pub seq_dying_hard: OptU16,
pub seq_dying_soft: OptU16, pub seq_dying_soft: OptU16,
pub seq_dead_hard: OptU16, pub seq_dead_hard: OptU16,
pub seq_dead_soft: OptU16, pub seq_dead_soft: OptU16,
pub seq_standing: u16, pub seq_standing: u16,
pub seq_moving: u16, pub seq_moving: u16,
pub seq_tele_in: OptU16, pub seq_tele_in: OptU16,
pub seq_tele_out: OptU16, pub seq_tele_out: OptU16,
pub atk_frequency: u16, pub atk_frequency: u16,
pub atk_melee: attk::Attack, pub atk_melee: attk::Attack,
pub atk_range: attk::Attack, pub atk_range: attk::Attack,
} }
c_bitfield! { c_bitfield! {
/// Flags for a monster. /// Flags for a monster.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct MonsterFlags: u32 { pub struct MonsterFlags: u32 {
IGNORE_LOS = 0, IGNORE_LOS = 0,
FLYING = 1, FLYING = 1,
ALIEN = 2, ALIEN = 2,
MAJOR = 3, MAJOR = 3,
MINOR = 4, MINOR = 4,
NO_OMIT = 5, NO_OMIT = 5,
FLOATS = 6, FLOATS = 6,
NO_ATTACK = 7, NO_ATTACK = 7,
SNIPE = 8, SNIPE = 8,
INVISIBLE = 9, INVISIBLE = 9,
SUBTLY_INVISIBLE = 10, SUBTLY_INVISIBLE = 10,
KAMIKAZE = 11, KAMIKAZE = 11,
BERSERKER = 12, BERSERKER = 12,
ENLARGED = 13, ENLARGED = 13,
DELAYED_DEATH = 14, DELAYED_DEATH = 14,
FIRE_SYMMETRICAL = 15, FIRE_SYMMETRICAL = 15,
NUCLEAR_DEATH = 16, NUCLEAR_DEATH = 16,
NO_FIRE_BACKWARDS = 17, NO_FIRE_BACKWARDS = 17,
CAN_DIE_IN_FLAMES = 18, CAN_DIE_IN_FLAMES = 18,
WAIT_FOR_GOOD_SHOT = 19, WAIT_FOR_GOOD_SHOT = 19,
TINY = 20, TINY = 20,
FAST_ATTACK = 21, FAST_ATTACK = 21,
LIKES_WATER = 22, LIKES_WATER = 22,
LIKES_SEWAGE = 23, LIKES_SEWAGE = 23,
LIKES_LAVA = 24, LIKES_LAVA = 24,
LIKES_GOO = 25, LIKES_GOO = 25,
TELE_UNDER_MEDIA = 26, TELE_UNDER_MEDIA = 26,
USE_RANDOM_WEAPON = 27, USE_RANDOM_WEAPON = 27,
} }
} }
c_bitfield! { c_bitfield! {
/// The composite type of a monster. /// The composite type of a monster.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct MonsterClass: u32 { pub struct MonsterClass: u32 {
PLAYER = 0, PLAYER = 0,
CIVILIAN = 1, CIVILIAN = 1,
MADD = 2, MADD = 2,
POSSESSED_HUMMER = 3, POSSESSED_HUMMER = 3,
DEFENDER = 4, DEFENDER = 4,
FIGHTER = 5, FIGHTER = 5,
TROOPER = 6, TROOPER = 6,
HUNTER = 7, HUNTER = 7,
ENFORCER = 8, ENFORCER = 8,
JUGGERNAUT = 9, JUGGERNAUT = 9,
HUMMER = 10, HUMMER = 10,
COMPILER = 11, COMPILER = 11,
CYBORG = 12, CYBORG = 12,
ASSIMILATED = 13, ASSIMILATED = 13,
TICK = 14, TICK = 14,
YETI = 15, YETI = 15,
} }
} }
// EOF // EOF

View File

@ -5,7 +5,7 @@ use crate::{err::*, text::mac_roman_cstr};
/// Reads a `NAME` chunk. /// Reads a `NAME` chunk.
pub fn read(b: &[u8]) -> ResultS<(String, usize)> pub fn read(b: &[u8]) -> ResultS<(String, usize)>
{ {
Ok((mac_roman_cstr(b), b.len())) Ok((mac_roman_cstr(b), b.len()))
} }
// EOF // EOF

View File

@ -6,24 +6,24 @@ use crate::{err::*, text::*};
/// Reads a `NOTE` chunk. /// Reads a `NOTE` chunk.
pub fn read(b: &[u8]) -> ResultS<(Note, usize)> pub fn read(b: &[u8]) -> ResultS<(Note, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 72, start: 0, data { endian: BIG, buf: b, size: 72, start: 0, data {
let pos = pnts::read_o[2; 4]; let pos = pnts::read_o[2; 4];
let poly = u16[6]; let poly = u16[6];
let text = mac_roman_cstr[8; 64] no_try; let text = mac_roman_cstr[8; 64] no_try;
} }
} }
Ok((Note{pos, poly, text}, 72)) Ok((Note{pos, poly, text}, 72))
} }
/// Overhead map annotations. /// Overhead map annotations.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct Note { pub struct Note {
pub pos: pnts::Point, pub pos: pnts::Point,
pub poly: u16, pub poly: u16,
pub text: String, pub text: String,
} }
// EOF // EOF

View File

@ -5,53 +5,53 @@ use crate::{err::*, fixed::{Angle, Unit}};
/// Reads an `OBJS` chunk. /// Reads an `OBJS` chunk.
pub fn read(b: &[u8]) -> ResultS<(Object, usize)> pub fn read(b: &[u8]) -> ResultS<(Object, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 16, start: 0, data { endian: BIG, buf: b, size: 16, start: 0, data {
let group = u16[0]; let group = u16[0];
let index = u16[2]; let index = u16[2];
let angle = Angle[4]; let angle = Angle[4];
let poly = u16[6]; let poly = u16[6];
let pos_x = Unit[8]; let pos_x = Unit[8];
let pos_y = Unit[10]; let pos_y = Unit[10];
let pos_z = Unit[12]; let pos_z = Unit[12];
let flags = u16[14]; let flags = u16[14];
} }
} }
let bias = flags & 0xF0_00; let bias = flags & 0xF0_00;
let flags = flags & 0x0F_FF; let flags = flags & 0x0F_FF;
let bias = bias >> 12; let bias = bias >> 12;
let flags = flag_ok!(ObjectFlags, flags)?; let flags = flag_ok!(ObjectFlags, flags)?;
Ok((Object{group, index, angle, poly, pos_x, pos_y, pos_z, flags, bias}, 16)) Ok((Object{group, index, angle, poly, pos_x, pos_y, pos_z, flags, bias}, 16))
} }
/// An object in the world. /// An object in the world.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct Object { pub struct Object {
pub group: u16, pub group: u16,
pub index: u16, pub index: u16,
pub angle: Angle, pub angle: Angle,
pub poly: u16, pub poly: u16,
pub pos_x: Unit, pub pos_x: Unit,
pub pos_y: Unit, pub pos_y: Unit,
pub pos_z: Unit, pub pos_z: Unit,
pub flags: ObjectFlags, pub flags: ObjectFlags,
pub bias: u16, pub bias: u16,
} }
c_bitfield! { c_bitfield! {
/// Flags for `Object`. /// Flags for `Object`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct ObjectFlags: u16 { pub struct ObjectFlags: u16 {
INVISIBLE = 0, INVISIBLE = 0,
CEILING = 1, CEILING = 1,
BLIND = 2, BLIND = 2,
DEAF = 3, DEAF = 3,
FLOATING = 4, FLOATING = 4,
NET_ONLY = 5, NET_ONLY = 5,
} }
} }
// EOF // EOF

View File

@ -5,42 +5,42 @@ use crate::err::*;
/// Reads a `plac` chunk. /// Reads a `plac` chunk.
pub fn read(b: &[u8]) -> ResultS<(ObjectFreq, usize)> pub fn read(b: &[u8]) -> ResultS<(ObjectFreq, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 12, start: 0, data { endian: BIG, buf: b, size: 12, start: 0, data {
let flags = u16[0] flag ObjectFreqFlags; let flags = u16[0] flag ObjectFreqFlags;
let cnt_ini = u16[2]; let cnt_ini = u16[2];
let cnt_min = u16[4]; let cnt_min = u16[4];
let cnt_max = u16[6]; let cnt_max = u16[6];
let cnt_rnd = u16[8]; let cnt_rnd = u16[8];
let chance = u16[10]; let chance = u16[10];
} }
} }
Ok((ObjectFreq{flags, cnt_ini, cnt_min, cnt_max, cnt_rnd, chance}, 12)) Ok((ObjectFreq{flags, cnt_ini, cnt_min, cnt_max, cnt_rnd, chance}, 12))
} }
/// The difficulty definition for various object types. /// The difficulty definition for various object types.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct ObjectFreq { pub struct ObjectFreq {
pub flags: ObjectFreqFlags, pub flags: ObjectFreqFlags,
pub cnt_ini: u16, pub cnt_ini: u16,
pub cnt_min: u16, pub cnt_min: u16,
pub cnt_max: u16, pub cnt_max: u16,
pub cnt_rnd: u16, pub cnt_rnd: u16,
pub chance: u16, pub chance: u16,
} }
c_bitfield! { c_bitfield! {
/// Flags for `ObjectFreq`. /// Flags for `ObjectFreq`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct ObjectFreqFlags: u16 { pub struct ObjectFreqFlags: u16 {
RANDOM_LOCATION = 0, RANDOM_LOCATION = 0,
_3 = 3, _3 = 3,
_4 = 4, _4 = 4,
_5 = 5, _5 = 5,
_6 = 6, _6 = 6,
} }
} }
// EOF // EOF

View File

@ -5,68 +5,68 @@ use crate::{err::*, fixed::Unit};
/// Reads a `plat` chunk. /// Reads a `plat` chunk.
pub fn read(b: &[u8]) -> ResultS<(Platform, usize)> pub fn read(b: &[u8]) -> ResultS<(Platform, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 32, start: 0, data { endian: BIG, buf: b, size: 32, start: 0, data {
let ptype = u16[0]; let ptype = u16[0];
let speed = u16[2]; let speed = u16[2];
let delay = u16[4]; let delay = u16[4];
let hei_max = Unit[6]; let hei_max = Unit[6];
let hei_min = Unit[8]; let hei_min = Unit[8];
let flags = u32[10] flag PlatformFlags; let flags = u32[10] flag PlatformFlags;
let index = u16[14]; let index = u16[14];
let tag = u16[16]; let tag = u16[16];
} }
} }
Ok((Platform{ptype, speed, delay, hei_min, hei_max, flags, index, tag}, 32)) Ok((Platform{ptype, speed, delay, hei_min, hei_max, flags, index, tag}, 32))
} }
/// Extra information for polygons with platforms. /// Extra information for polygons with platforms.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct Platform { pub struct Platform {
pub ptype: u16, pub ptype: u16,
pub speed: u16, pub speed: u16,
pub delay: u16, pub delay: u16,
pub hei_min: Unit, pub hei_min: Unit,
pub hei_max: Unit, pub hei_max: Unit,
pub flags: PlatformFlags, pub flags: PlatformFlags,
pub index: u16, pub index: u16,
pub tag: u16, pub tag: u16,
} }
c_bitfield! { c_bitfield! {
/// Flags for `Platform`. /// Flags for `Platform`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct PlatformFlags: u32 { pub struct PlatformFlags: u32 {
INIT_ACTIVE = 0, INIT_ACTIVE = 0,
INIT_EXTENDED = 1, INIT_EXTENDED = 1,
STOP_AT_EACH_LEVEL = 2, STOP_AT_EACH_LEVEL = 2,
STOP_AT_INIT_LEVEL = 3, STOP_AT_INIT_LEVEL = 3,
START_ADJ_ON_STOP = 4, START_ADJ_ON_STOP = 4,
EXTENDS_FLOOR_TO_CEIL = 5, EXTENDS_FLOOR_TO_CEIL = 5,
COMES_FROM_FLOOR = 6, COMES_FROM_FLOOR = 6,
COMES_FROM_CEIL = 7, COMES_FROM_CEIL = 7,
CAUSES_DAMAGE = 8, CAUSES_DAMAGE = 8,
NO_ACTIVATE_PARENT = 9, NO_ACTIVATE_PARENT = 9,
ACTIVATES_ONCE = 10, ACTIVATES_ONCE = 10,
ACTIVATES_LIGHT = 11, ACTIVATES_LIGHT = 11,
DEACTIVATES_LIGHT = 12, DEACTIVATES_LIGHT = 12,
PLAYER_CONTROLS = 13, PLAYER_CONTROLS = 13,
MONSTER_CONTROLS = 14, MONSTER_CONTROLS = 14,
REVERSE_ON_OBSTRUCT = 15, REVERSE_ON_OBSTRUCT = 15,
NO_EXT_DEACTIVATION = 16, NO_EXT_DEACTIVATION = 16,
USE_POLYGON_HEIGHTS = 17, USE_POLYGON_HEIGHTS = 17,
DELAYED_ACTIVATION = 18, DELAYED_ACTIVATION = 18,
START_ADJ_ON_START = 19, START_ADJ_ON_START = 19,
STOP_ADJ_ON_START = 20, STOP_ADJ_ON_START = 20,
STOP_ADJ_ON_STOP = 21, STOP_ADJ_ON_STOP = 21,
SLOW = 22, SLOW = 22,
START_AT_EACH_LEVEL = 23, START_AT_EACH_LEVEL = 23,
LOCKED = 24, LOCKED = 24,
SECRET = 25, SECRET = 25,
DOOR = 26, DOOR = 26,
} }
} }
// EOF // EOF

View File

@ -5,23 +5,23 @@ use crate::{err::*, fixed::Unit};
/// Reads a `Point` object. /// Reads a `Point` object.
pub fn read_o(b: &[u8]) -> ResultS<Point> pub fn read_o(b: &[u8]) -> ResultS<Point>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 4, start: 0, data { endian: BIG, buf: b, size: 4, start: 0, data {
let x = Unit[0]; let x = Unit[0];
let y = Unit[2]; let y = Unit[2];
} }
} }
Ok(Point{x, y}) Ok(Point{x, y})
} }
/// Writes a `Point` object. /// Writes a `Point` object.
pub fn write_o(v: Point) -> Vec<u8> pub fn write_o(v: Point) -> Vec<u8>
{ {
let mut o = Vec::with_capacity(4); let mut o = Vec::with_capacity(4);
o.extend(&v.x.to_be_bytes()); o.extend(&v.x.to_be_bytes());
o.extend(&v.y.to_be_bytes()); o.extend(&v.y.to_be_bytes());
o o
} }
/// Reads a `PNTS` chunk. /// Reads a `PNTS` chunk.
@ -31,8 +31,8 @@ pub fn read(b: &[u8]) -> ResultS<(Point, usize)> {Ok((read_o(b)?, 4))}
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct Point { pub struct Point {
pub x: Unit, pub x: Unit,
pub y: Unit, pub y: Unit,
} }
// EOF // EOF

View File

@ -6,185 +6,185 @@ use crate::{bin::OptU16, err::*, fixed::Unit, xfer::TransferMode};
/// Reads a polygon for either M1 or M2. /// Reads a polygon for either M1 or M2.
pub fn read_poly_inter(b: &[u8]) -> ResultS<Polygon> pub fn read_poly_inter(b: &[u8]) -> ResultS<Polygon>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 128, start: 0, data { endian: BIG, buf: b, size: 128, start: 0, data {
let tex_flr = OptU16[40]; let tex_flr = OptU16[40];
let tex_cei = OptU16[42]; let tex_cei = OptU16[42];
let hei_flr = Unit[44]; let hei_flr = Unit[44];
let hei_cei = Unit[46]; let hei_cei = Unit[46];
let lit_flr = u16[48]; let lit_flr = u16[48];
let lit_cei = u16[50]; let lit_cei = u16[50];
let xfr_flr = u16[64] enum TransferMode; let xfr_flr = u16[64] enum TransferMode;
let xfr_cei = u16[66] enum TransferMode; let xfr_cei = u16[66] enum TransferMode;
} }
} }
Ok(Polygon{tex_flr, tex_cei, hei_flr, hei_cei, lit_flr, lit_cei, xfr_flr, Ok(Polygon{tex_flr, tex_cei, hei_flr, hei_cei, lit_flr, lit_cei, xfr_flr,
xfr_cei, ..Polygon::default()}) xfr_cei, ..Polygon::default()})
} }
/// Reads a `POLY` chunk. /// Reads a `POLY` chunk.
pub fn read(b: &[u8]) -> ResultS<(Polygon, usize)> pub fn read(b: &[u8]) -> ResultS<(Polygon, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 128, start: 0, data { endian: BIG, buf: b, size: 128, start: 0, data {
let ptype = u16[0]; let ptype = u16[0];
let pdata = u16[4]; let pdata = u16[4];
let ori_flr = pnts::read_o[108; 4]; let ori_flr = pnts::read_o[108; 4];
let ori_cei = pnts::read_o[112; 4]; let ori_cei = pnts::read_o[112; 4];
let med_ind = OptU16[116]; let med_ind = OptU16[116];
let med_ctl = u16[118]; let med_ctl = u16[118];
let snd_amb = OptU16[122]; let snd_amb = OptU16[122];
let snd_ind = u16[120]; let snd_ind = u16[120];
let snd_rnd = OptU16[124]; let snd_rnd = OptU16[124];
} }
} }
let poly = read_poly_inter(b)?; let poly = read_poly_inter(b)?;
let ptype = PolygonType::new(ptype, pdata)?; let ptype = PolygonType::new(ptype, pdata)?;
Ok((Polygon{ptype, ori_flr, ori_cei, med_ind, med_ctl, snd_ind, snd_amb, Ok((Polygon{ptype, ori_flr, ori_cei, med_ind, med_ctl, snd_ind, snd_amb,
snd_rnd, ..poly}, 128)) snd_rnd, ..poly}, 128))
} }
/// Reads an old `POLY` chunk. /// Reads an old `POLY` chunk.
pub fn read_old(b: &[u8]) -> ResultS<(Polygon, usize)> pub fn read_old(b: &[u8]) -> ResultS<(Polygon, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 128, start: 0, data { endian: BIG, buf: b, size: 128, start: 0, data {
let ptype = u16[0]; let ptype = u16[0];
let pdata = u16[4]; let pdata = u16[4];
} }
} }
let poly = read_poly_inter(b)?; let poly = read_poly_inter(b)?;
let ptype = PolygonType::new_old(ptype, pdata)?; let ptype = PolygonType::new_old(ptype, pdata)?;
Ok((Polygon{ptype, ..poly}, 128)) Ok((Polygon{ptype, ..poly}, 128))
} }
impl PolygonType impl PolygonType
{ {
/// Creates a `PolygonType` from a `n`/`pdata` pair. /// Creates a `PolygonType` from a `n`/`pdata` pair.
pub fn new(n: u16, pdata: u16) -> Result<Self, ReprError> pub fn new(n: u16, pdata: u16) -> Result<Self, ReprError>
{ {
match n { match n {
0 => Ok(PolygonType::Normal), 0 => Ok(PolygonType::Normal),
1 => Ok(PolygonType::ImpassItem), 1 => Ok(PolygonType::ImpassItem),
2 => Ok(PolygonType::ImpassMons), 2 => Ok(PolygonType::ImpassMons),
3 => Ok(PolygonType::Hill), 3 => Ok(PolygonType::Hill),
4 => Ok(PolygonType::Base), 4 => Ok(PolygonType::Base),
5 => Ok(PolygonType::Platform(pdata)), 5 => Ok(PolygonType::Platform(pdata)),
6 => Ok(PolygonType::TrigLightOn(pdata)), 6 => Ok(PolygonType::TrigLightOn(pdata)),
7 => Ok(PolygonType::TrigPlatOn(pdata)), 7 => Ok(PolygonType::TrigPlatOn(pdata)),
8 => Ok(PolygonType::TrigLightOff(pdata)), 8 => Ok(PolygonType::TrigLightOff(pdata)),
9 => Ok(PolygonType::TrigPlatOff(pdata)), 9 => Ok(PolygonType::TrigPlatOff(pdata)),
10 => Ok(PolygonType::Teleporter(pdata)), 10 => Ok(PolygonType::Teleporter(pdata)),
11 => Ok(PolygonType::ZoneBorder), 11 => Ok(PolygonType::ZoneBorder),
12 => Ok(PolygonType::Goal), 12 => Ok(PolygonType::Goal),
13 => Ok(PolygonType::TrigMonsVis), 13 => Ok(PolygonType::TrigMonsVis),
14 => Ok(PolygonType::TrigMonsInv), 14 => Ok(PolygonType::TrigMonsInv),
15 => Ok(PolygonType::TrigMonsDual), 15 => Ok(PolygonType::TrigMonsDual),
16 => Ok(PolygonType::TrigItems), 16 => Ok(PolygonType::TrigItems),
17 => Ok(PolygonType::MustExplore), 17 => Ok(PolygonType::MustExplore),
18 => Ok(PolygonType::AutoExit), 18 => Ok(PolygonType::AutoExit),
19 => Ok(PolygonType::OuchMinor), 19 => Ok(PolygonType::OuchMinor),
20 => Ok(PolygonType::OuchMajor), 20 => Ok(PolygonType::OuchMajor),
21 => Ok(PolygonType::Glue), 21 => Ok(PolygonType::Glue),
22 => Ok(PolygonType::GlueTrigger(pdata)), 22 => Ok(PolygonType::GlueTrigger(pdata)),
23 => Ok(PolygonType::GlueSuper), 23 => Ok(PolygonType::GlueSuper),
n => Err(ReprError::new("PolygonType", n)), n => Err(ReprError::new("PolygonType", n)),
} }
} }
/// Creates a `PolygonType` 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> fn new_old(n: u16, pdata: u16) -> Result<Self, ReprError>
{ {
match n { match n {
0 => Ok(PolygonType::Normal), 0 => Ok(PolygonType::Normal),
1 => Ok(PolygonType::ImpassItem), 1 => Ok(PolygonType::ImpassItem),
2 => Ok(PolygonType::ImpassMons), 2 => Ok(PolygonType::ImpassMons),
3 => Ok(PolygonType::OuchMinor), 3 => Ok(PolygonType::OuchMinor),
4 => Ok(PolygonType::OuchMajor), 4 => Ok(PolygonType::OuchMajor),
5 => Ok(PolygonType::Platform(pdata)), 5 => Ok(PolygonType::Platform(pdata)),
6 => Ok(PolygonType::TrigLightOn(pdata)), 6 => Ok(PolygonType::TrigLightOn(pdata)),
7 => Ok(PolygonType::TrigPlatOn(pdata)), 7 => Ok(PolygonType::TrigPlatOn(pdata)),
8 => Ok(PolygonType::TrigLightOff(pdata)), 8 => Ok(PolygonType::TrigLightOff(pdata)),
9 => Ok(PolygonType::TrigPlatOff(pdata)), 9 => Ok(PolygonType::TrigPlatOff(pdata)),
10 => Ok(PolygonType::Teleporter(pdata)), 10 => Ok(PolygonType::Teleporter(pdata)),
11 => Ok(PolygonType::Glue), 11 => Ok(PolygonType::Glue),
12 => Ok(PolygonType::GlueTrigger(pdata)), 12 => Ok(PolygonType::GlueTrigger(pdata)),
13 => Ok(PolygonType::GlueSuper), 13 => Ok(PolygonType::GlueSuper),
14 => Ok(PolygonType::MustExplore), 14 => Ok(PolygonType::MustExplore),
15 => Ok(PolygonType::AutoExit), 15 => Ok(PolygonType::AutoExit),
n => Err(ReprError::new("PolygonType", n)), n => Err(ReprError::new("PolygonType", n)),
} }
} }
} }
impl Default for PolygonType impl Default for PolygonType
{ {
fn default() -> Self {PolygonType::Normal} fn default() -> Self {PolygonType::Normal}
} }
/// A polygon segment. /// A polygon segment.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Clone, Debug, Default, Eq, PartialEq)] #[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Polygon { pub struct Polygon {
pub ptype: PolygonType, pub ptype: PolygonType,
pub tex_flr: OptU16, pub tex_flr: OptU16,
pub tex_cei: OptU16, pub tex_cei: OptU16,
pub hei_flr: Unit, pub hei_flr: Unit,
pub hei_cei: Unit, pub hei_cei: Unit,
pub lit_flr: u16, pub lit_flr: u16,
pub lit_cei: u16, pub lit_cei: u16,
pub xfr_flr: TransferMode, pub xfr_flr: TransferMode,
pub xfr_cei: TransferMode, pub xfr_cei: TransferMode,
pub ori_flr: pnts::Point, pub ori_flr: pnts::Point,
pub ori_cei: pnts::Point, pub ori_cei: pnts::Point,
pub med_ind: OptU16, pub med_ind: OptU16,
pub med_ctl: u16, pub med_ctl: u16,
pub snd_ind: u16, pub snd_ind: u16,
pub snd_amb: OptU16, pub snd_amb: OptU16,
pub snd_rnd: OptU16, pub snd_rnd: OptU16,
} }
/// The action type of a `Polygon`. /// The action type of a `Polygon`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum PolygonType { pub enum PolygonType {
Normal, Normal,
ImpassItem, ImpassItem,
ImpassMons, ImpassMons,
Hill, Hill,
Base, Base,
Platform(u16), Platform(u16),
TrigLightOn(u16), TrigLightOn(u16),
TrigPlatOn(u16), TrigPlatOn(u16),
TrigLightOff(u16), TrigLightOff(u16),
TrigPlatOff(u16), TrigPlatOff(u16),
Teleporter(u16), Teleporter(u16),
ZoneBorder, ZoneBorder,
Goal, Goal,
TrigMonsVis, TrigMonsVis,
TrigMonsInv, TrigMonsInv,
TrigMonsDual, TrigMonsDual,
TrigItems, TrigItems,
MustExplore, MustExplore,
AutoExit, AutoExit,
OuchMinor, OuchMinor,
OuchMajor, OuchMajor,
Glue, Glue,
GlueTrigger(u16), GlueTrigger(u16),
GlueSuper, GlueSuper,
} }
c_bitfield! { c_bitfield! {
/// Flags for `Polygon`. /// Flags for `Polygon`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct PolygonFlags: u16 { pub struct PolygonFlags: u16 {
DETACHED = 14, DETACHED = 14,
} }
} }
// EOF // EOF

View File

@ -7,83 +7,83 @@ use super::damg;
/// Reads a `PRpx` chunk. /// Reads a `PRpx` chunk.
pub fn read(b: &[u8]) -> ResultS<(Projectile, usize)> pub fn read(b: &[u8]) -> ResultS<(Projectile, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 48, start: 0, data { endian: BIG, buf: b, size: 48, start: 0, data {
let collection = OptU16[0]; let collection = OptU16[0];
let shape = u16[2]; let shape = u16[2];
let fxt_explode = OptU16[4]; let fxt_explode = OptU16[4];
let fxt_exp_media = OptU16[6]; let fxt_exp_media = OptU16[6];
let fxt_trail = OptU16[8]; let fxt_trail = OptU16[8];
let tic_trail = u16[10]; let tic_trail = u16[10];
let max_trail = OptU16[12]; let max_trail = OptU16[12];
let typ_media = OptU16[14]; let typ_media = OptU16[14];
let radius = Unit[16]; let radius = Unit[16];
let dmg_rad = Unit[18]; let dmg_rad = Unit[18];
let dmg_def = damg::read[20; 12]; let dmg_def = damg::read[20; 12];
let flags = u32[32] flag ProjectileFlags; let flags = u32[32] flag ProjectileFlags;
let speed = Unit[36]; let speed = Unit[36];
let range = Unit[38]; let range = Unit[38];
let snd_pitch = Fixed[40]; let snd_pitch = Fixed[40];
let snd_fly = OptU16[44]; let snd_fly = OptU16[44];
let snd_bounce = OptU16[46]; let snd_bounce = OptU16[46];
} }
} }
Ok((Projectile{collection, shape, fxt_explode, fxt_exp_media, fxt_trail, Ok((Projectile{collection, shape, fxt_explode, fxt_exp_media, fxt_trail,
tic_trail, max_trail, typ_media, radius, dmg_rad, dmg_def, tic_trail, max_trail, typ_media, radius, dmg_rad, dmg_def,
flags, speed, range, snd_pitch, snd_fly, snd_bounce}, 48)) flags, speed, range, snd_pitch, snd_fly, snd_bounce}, 48))
} }
/// A projectile definition. /// A projectile definition.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct Projectile { pub struct Projectile {
pub collection: OptU16, pub collection: OptU16,
pub shape: u16, pub shape: u16,
pub fxt_explode: OptU16, pub fxt_explode: OptU16,
pub fxt_exp_media: OptU16, pub fxt_exp_media: OptU16,
pub fxt_trail: OptU16, pub fxt_trail: OptU16,
pub tic_trail: u16, pub tic_trail: u16,
pub max_trail: OptU16, pub max_trail: OptU16,
pub typ_media: OptU16, pub typ_media: OptU16,
pub radius: Unit, pub radius: Unit,
pub dmg_rad: Unit, pub dmg_rad: Unit,
pub dmg_def: damg::Damage, pub dmg_def: damg::Damage,
pub flags: ProjectileFlags, pub flags: ProjectileFlags,
pub speed: Unit, pub speed: Unit,
pub range: Unit, pub range: Unit,
pub snd_pitch: Fixed, pub snd_pitch: Fixed,
pub snd_fly: OptU16, pub snd_fly: OptU16,
pub snd_bounce: OptU16, pub snd_bounce: OptU16,
} }
c_bitfield! { c_bitfield! {
/// Flags for a projectile. /// Flags for a projectile.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct ProjectileFlags: u32 { pub struct ProjectileFlags: u32 {
GUIDED = 0, GUIDED = 0,
STOP_ON_LOOP = 1, STOP_ON_LOOP = 1,
PERSISTENT = 2, PERSISTENT = 2,
ALIEN = 3, ALIEN = 3,
GRAVITY = 4, GRAVITY = 4,
NO_HORZ_ERROR = 5, NO_HORZ_ERROR = 5,
NO_VERT_ERROR = 6, NO_VERT_ERROR = 6,
TOGGLE_PANELS = 7, TOGGLE_PANELS = 7,
POS_VERT_ERROR = 8, POS_VERT_ERROR = 8,
MELEE = 9, MELEE = 9,
RIPPER = 10, RIPPER = 10,
PASS_TRANS_RANDOM = 11, PASS_TRANS_RANDOM = 11,
PASS_TRANS_MORE = 12, PASS_TRANS_MORE = 12,
DOUBLE_GRAVITY = 13, DOUBLE_GRAVITY = 13,
REBOUND_FLOOR = 14, REBOUND_FLOOR = 14,
THROUGH_MEDIA = 15, THROUGH_MEDIA = 15,
BECOME_ITEM = 16, BECOME_ITEM = 16,
BLOODY = 17, BLOODY = 17,
WANDER_HORZ = 18, WANDER_HORZ = 18,
WANDER_VERT = 19, WANDER_VERT = 19,
USE_LOW_GRAV = 20, USE_LOW_GRAV = 20,
PASS_MEDIA = 21, PASS_MEDIA = 21,
} }
} }
// EOF // EOF

View File

@ -5,73 +5,73 @@ use crate::{err::*, fixed::Fixed};
/// Reads a `PXpx` chunk. /// Reads a `PXpx` chunk.
pub fn read(b: &[u8]) -> ResultS<(Physics, usize)> pub fn read(b: &[u8]) -> ResultS<(Physics, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 104, start: 0, data { endian: BIG, buf: b, size: 104, start: 0, data {
let vel_fwd = Fixed[0]; let vel_fwd = Fixed[0];
let vel_bkw = Fixed[4]; let vel_bkw = Fixed[4];
let vel_prp = Fixed[8]; let vel_prp = Fixed[8];
let acc_nrm = Fixed[12]; let acc_nrm = Fixed[12];
let dec_nrm = Fixed[16]; let dec_nrm = Fixed[16];
let dec_air = Fixed[20]; let dec_air = Fixed[20];
let acc_grv = Fixed[24]; let acc_grv = Fixed[24];
let acc_cli = Fixed[28]; let acc_cli = Fixed[28];
let vel_trm = Fixed[32]; let vel_trm = Fixed[32];
let dec_ext = Fixed[36]; let dec_ext = Fixed[36];
let acc_ang = Fixed[40]; let acc_ang = Fixed[40];
let dec_ang = Fixed[44]; let dec_ang = Fixed[44];
let vel_ang = Fixed[48]; let vel_ang = Fixed[48];
let vel_rec = Fixed[52]; let vel_rec = Fixed[52];
let fng_vel = Fixed[56]; let fng_vel = Fixed[56];
let fng_max = Fixed[60]; let fng_max = Fixed[60];
let ele_max = Fixed[64]; let ele_max = Fixed[64];
let dec_xng = Fixed[68]; let dec_xng = Fixed[68];
let stp_dta = Fixed[72]; let stp_dta = Fixed[72];
let stp_amp = Fixed[76]; let stp_amp = Fixed[76];
let ply_rad = Fixed[80]; let ply_rad = Fixed[80];
let ply_hei = Fixed[84]; let ply_hei = Fixed[84];
let ply_dhi = Fixed[88]; let ply_dhi = Fixed[88];
let ply_cam = Fixed[92]; let ply_cam = Fixed[92];
let ply_spl = Fixed[96]; let ply_spl = Fixed[96];
let ply_hcm = Fixed[100]; let ply_hcm = Fixed[100];
} }
} }
Ok((Physics{acc_ang, acc_cli, acc_grv, acc_nrm, dec_air, dec_ang, dec_ext, Ok((Physics{acc_ang, acc_cli, acc_grv, acc_nrm, dec_air, dec_ang, dec_ext,
dec_nrm, dec_xng, ele_max, fng_max, fng_vel, ply_cam, ply_dhi, dec_nrm, dec_xng, ele_max, fng_max, fng_vel, ply_cam, ply_dhi,
ply_hcm, ply_hei, ply_rad, ply_spl, stp_amp, stp_dta, vel_ang, ply_hcm, ply_hei, ply_rad, ply_spl, stp_amp, stp_dta, vel_ang,
vel_bkw, vel_fwd, vel_prp, vel_rec, vel_trm}, 104)) vel_bkw, vel_fwd, vel_prp, vel_rec, vel_trm}, 104))
} }
/// Static physics information. /// Static physics information.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct Physics { pub struct Physics {
pub acc_ang: Fixed, pub acc_ang: Fixed,
pub acc_cli: Fixed, pub acc_cli: Fixed,
pub acc_grv: Fixed, pub acc_grv: Fixed,
pub acc_nrm: Fixed, pub acc_nrm: Fixed,
pub dec_air: Fixed, pub dec_air: Fixed,
pub dec_ang: Fixed, pub dec_ang: Fixed,
pub dec_ext: Fixed, pub dec_ext: Fixed,
pub dec_nrm: Fixed, pub dec_nrm: Fixed,
pub dec_xng: Fixed, pub dec_xng: Fixed,
pub ele_max: Fixed, pub ele_max: Fixed,
pub fng_max: Fixed, pub fng_max: Fixed,
pub fng_vel: Fixed, pub fng_vel: Fixed,
pub ply_cam: Fixed, pub ply_cam: Fixed,
pub ply_dhi: Fixed, pub ply_dhi: Fixed,
pub ply_hcm: Fixed, pub ply_hcm: Fixed,
pub ply_hei: Fixed, pub ply_hei: Fixed,
pub ply_rad: Fixed, pub ply_rad: Fixed,
pub ply_spl: Fixed, pub ply_spl: Fixed,
pub stp_amp: Fixed, pub stp_amp: Fixed,
pub stp_dta: Fixed, pub stp_dta: Fixed,
pub vel_ang: Fixed, pub vel_ang: Fixed,
pub vel_bkw: Fixed, pub vel_bkw: Fixed,
pub vel_fwd: Fixed, pub vel_fwd: Fixed,
pub vel_prp: Fixed, pub vel_prp: Fixed,
pub vel_rec: Fixed, pub vel_rec: Fixed,
pub vel_trm: Fixed, pub vel_trm: Fixed,
} }
// EOF // EOF

View File

@ -6,79 +6,79 @@ use crate::{bin::OptU16, err::*, fixed::Fixed, xfer::TransferMode};
/// Reads a `SIDS` chunk. /// Reads a `SIDS` chunk.
pub fn read(b: &[u8]) -> ResultS<(Side, usize)> pub fn read(b: &[u8]) -> ResultS<(Side, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 64, start: 0, data { endian: BIG, buf: b, size: 64, start: 0, data {
let stype = u16[0] enum SideType; let stype = u16[0] enum SideType;
let flags = u8[3] flag SideFlags; let flags = u8[3] flag SideFlags;
let tex_pri = stex::read[4; 6]; let tex_pri = stex::read[4; 6];
let tex_sec = stex::read[10; 6]; let tex_sec = stex::read[10; 6];
let tex_tra = stex::read[16; 6]; let tex_tra = stex::read[16; 6];
let paneltyp = u16[38]; let paneltyp = u16[38];
let paneldat = i16[40]; let paneldat = i16[40];
let xfer_pri = u16[42] enum TransferMode; let xfer_pri = u16[42] enum TransferMode;
let xfer_sec = u16[44] enum TransferMode; let xfer_sec = u16[44] enum TransferMode;
let xfer_tra = u16[46] enum TransferMode; let xfer_tra = u16[46] enum TransferMode;
let shade = Fixed[48]; let shade = Fixed[48];
} }
} }
Ok((Side{stype, flags, tex_pri, tex_sec, tex_tra, paneltyp, paneldat, Ok((Side{stype, flags, tex_pri, tex_sec, tex_tra, paneltyp, paneldat,
xfer_pri, xfer_sec, xfer_tra, shade}, 64)) xfer_pri, xfer_sec, xfer_tra, shade}, 64))
} }
/// Reads an old `SIDS` chunk. /// Reads an old `SIDS` chunk.
pub fn read_old(b: &[u8]) -> ResultS<(Side, usize)> pub fn read_old(b: &[u8]) -> ResultS<(Side, usize)>
{ {
let (side, siz) = read(b)?; let (side, siz) = read(b)?;
Ok((Side{tex_tra: stex::SideTex{tex_id: OptU16::none(), ..side.tex_tra}, Ok((Side{tex_tra: stex::SideTex{tex_id: OptU16::none(), ..side.tex_tra},
shade: 0.into(), shade: 0.into(),
flags: side.flags | SideFlags::ITEM_OPT, flags: side.flags | SideFlags::ITEM_OPT,
..side}, siz)) ..side}, siz))
} }
/// One side of a line segment. /// One side of a line segment.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct Side { pub struct Side {
pub stype: SideType, pub stype: SideType,
pub flags: SideFlags, pub flags: SideFlags,
pub tex_pri: stex::SideTex, pub tex_pri: stex::SideTex,
pub tex_sec: stex::SideTex, pub tex_sec: stex::SideTex,
pub tex_tra: stex::SideTex, pub tex_tra: stex::SideTex,
pub paneltyp: u16, pub paneltyp: u16,
pub paneldat: i16, pub paneldat: i16,
pub xfer_pri: TransferMode, pub xfer_pri: TransferMode,
pub xfer_sec: TransferMode, pub xfer_sec: TransferMode,
pub xfer_tra: TransferMode, pub xfer_tra: TransferMode,
pub shade: Fixed, pub shade: Fixed,
} }
c_bitfield! { c_bitfield! {
/// Flags for `Side`. /// Flags for `Side`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct SideFlags: u8 { pub struct SideFlags: u8 {
STATUS = 0, STATUS = 0,
PANEL = 1, PANEL = 1,
REPAIR = 2, REPAIR = 2,
ITEM_USE = 3, ITEM_USE = 3,
LIGHTED = 4, LIGHTED = 4,
CAN_DESTROY = 5, CAN_DESTROY = 5,
HIT_ONLY = 6, HIT_ONLY = 6,
ITEM_OPT = 7, ITEM_OPT = 7,
} }
} }
c_enum! { c_enum! {
/// The texture type of a `Side`. /// The texture type of a `Side`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub enum SideType: u16 { pub enum SideType: u16 {
Full = 0, Full = 0,
High = 1, High = 1,
Low = 2, Low = 2,
Composite = 3, Composite = 3,
Split = 4, Split = 4,
} }
} }
// EOF // EOF

View File

@ -6,31 +6,31 @@ use super::pnts;
/// Reads a `SideTex` object. /// Reads a `SideTex` object.
pub fn read(b: &[u8]) -> ResultS<SideTex> pub fn read(b: &[u8]) -> ResultS<SideTex>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 6, start: 0, data { endian: BIG, buf: b, size: 6, start: 0, data {
let offs = pnts::read_o[0; 4]; let offs = pnts::read_o[0; 4];
let tex_id = OptU16[4]; let tex_id = OptU16[4];
} }
} }
Ok(SideTex{offs, tex_id}) Ok(SideTex{offs, tex_id})
} }
/// Writes a `SideTex` object. /// Writes a `SideTex` object.
pub fn write(v: &SideTex) -> Vec<u8> pub fn write(v: &SideTex) -> Vec<u8>
{ {
let mut o = Vec::with_capacity(6); let mut o = Vec::with_capacity(6);
o.extend(pnts::write_o(v.offs)); o.extend(pnts::write_o(v.offs));
o.extend(&v.tex_id.to_be_bytes()); o.extend(&v.tex_id.to_be_bytes());
o o
} }
/// The texture of a side segment. /// The texture of a side segment.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct SideTex { pub struct SideTex {
pub offs: pnts::Point, pub offs: pnts::Point,
pub tex_id: OptU16, pub tex_id: OptU16,
} }
// EOF // EOF

View File

@ -6,50 +6,50 @@ use crate::{bin, err::*, text};
/// Reads a `term` chunk. /// Reads a `term` chunk.
pub fn read(b: &[u8]) -> ResultS<(Terminal, usize)> pub fn read(b: &[u8]) -> ResultS<(Terminal, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 10, start: 0, data { endian: BIG, buf: b, size: 10, start: 0, data {
let end = u16[0] usize; let end = u16[0] usize;
let encoded = u16[2]; let encoded = u16[2];
let lines = u16[4]; let lines = u16[4];
let group_n = u16[6] usize; let group_n = u16[6] usize;
let face_n = u16[8] usize; let face_n = u16[8] usize;
} }
} }
let (i_grp, x) = bin::rd_array_num(&b[10..], group_n, trmg::read)?; let (i_grp, x) = bin::rd_array_num(&b[10..], group_n, trmg::read)?;
let (faces, y) = bin::rd_array_num(&b[10 + x..], face_n, trmf::read)?; let (faces, y) = bin::rd_array_num(&b[10 + x..], face_n, trmf::read)?;
let text = ok!(b.get(10 + x + y..end), "not enough data")?; let text = ok!(b.get(10 + x + y..end), "not enough data")?;
let text = if encoded != 0 { let text = if encoded != 0 {
text::fuck_string(text) text::fuck_string(text)
} else { } else {
text.to_vec() text.to_vec()
}; };
let mut groups = Vec::with_capacity(group_n); let mut groups = Vec::with_capacity(group_n);
for grp in &i_grp { for grp in &i_grp {
let flags = grp.flags; let flags = grp.flags;
let ttype = grp.ttype; let ttype = grp.ttype;
let lines = grp.lines; let lines = grp.lines;
let beg = grp.beg; let beg = grp.beg;
let len = grp.len; let len = grp.len;
let text = ok!(text.get(beg..beg + len), "bad offset")?; let text = ok!(text.get(beg..beg + len), "bad offset")?;
let text = text::mac_roman_cstr(text); let text = text::mac_roman_cstr(text);
groups.push(trmg::Group{flags, ttype, lines, text}); groups.push(trmg::Group{flags, ttype, lines, text});
} }
Ok((Terminal{lines, groups, faces}, end)) Ok((Terminal{lines, groups, faces}, end))
} }
/// A terminal definition, with collections of groups and faces. /// A terminal definition, with collections of groups and faces.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct Terminal { pub struct Terminal {
pub lines: u16, pub lines: u16,
pub groups: Vec<trmg::Group>, pub groups: Vec<trmg::Group>,
pub faces: Vec<trmf::Face>, pub faces: Vec<trmf::Face>,
} }
// EOF // EOF

View File

@ -5,69 +5,69 @@ use crate::{bin::OptU16, err::*, fixed::Unit};
/// Reads a `Trigger` object. /// Reads a `Trigger` object.
pub fn read(b: &[u8]) -> ResultS<Trigger> pub fn read(b: &[u8]) -> ResultS<Trigger>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 36, start: 0, data { endian: BIG, buf: b, size: 36, start: 0, data {
let magazine = u16[0]; let magazine = u16[0];
let typ_ammo = OptU16[2]; let typ_ammo = OptU16[2];
let tic_round = OptU16[4]; let tic_round = OptU16[4];
let tic_recover = u16[6]; let tic_recover = u16[6];
let tic_charge = u16[8]; let tic_charge = u16[8];
let recoil = Unit[10]; let recoil = Unit[10];
let snd_fire = OptU16[12]; let snd_fire = OptU16[12];
let snd_click = OptU16[14]; let snd_click = OptU16[14];
let snd_charge = OptU16[16]; let snd_charge = OptU16[16];
let snd_casing = OptU16[18]; let snd_casing = OptU16[18];
let snd_reload = OptU16[20]; let snd_reload = OptU16[20];
let snd_charged = OptU16[22]; let snd_charged = OptU16[22];
let typ_proj = u16[24]; let typ_proj = u16[24];
let theta = u16[26]; let theta = u16[26];
let dx = i16[28]; let dx = i16[28];
let dz = i16[30]; let dz = i16[30];
let typ_casing = u16[32] enum CasingType; let typ_casing = u16[32] enum CasingType;
let burst = u16[34]; let burst = u16[34];
} }
} }
Ok(Trigger{burst, dx, dz, magazine, recoil, snd_casing, snd_charge, Ok(Trigger{burst, dx, dz, magazine, recoil, snd_casing, snd_charge,
snd_charged, snd_click, snd_fire, snd_reload, theta, tic_charge, snd_charged, snd_click, snd_fire, snd_reload, theta, tic_charge,
tic_recover, tic_round, typ_ammo, typ_casing, typ_proj}) tic_recover, tic_round, typ_ammo, typ_casing, typ_proj})
} }
/// The definition of one of two triggers for a weapon. /// The definition of one of two triggers for a weapon.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct Trigger { pub struct Trigger {
pub burst: u16, pub burst: u16,
pub dx: i16, pub dx: i16,
pub dz: i16, pub dz: i16,
pub magazine: u16, pub magazine: u16,
pub recoil: Unit, pub recoil: Unit,
pub snd_casing: OptU16, pub snd_casing: OptU16,
pub snd_charge: OptU16, pub snd_charge: OptU16,
pub snd_charged: OptU16, pub snd_charged: OptU16,
pub snd_click: OptU16, pub snd_click: OptU16,
pub snd_fire: OptU16, pub snd_fire: OptU16,
pub snd_reload: OptU16, pub snd_reload: OptU16,
pub theta: u16, pub theta: u16,
pub tic_charge: u16, pub tic_charge: u16,
pub tic_recover: u16, pub tic_recover: u16,
pub tic_round: OptU16, pub tic_round: OptU16,
pub typ_ammo: OptU16, pub typ_ammo: OptU16,
pub typ_casing: CasingType, pub typ_casing: CasingType,
pub typ_proj: u16, pub typ_proj: u16,
} }
c_enum! { c_enum! {
/// A bullet shell casing emitted by a weapon. /// A bullet shell casing emitted by a weapon.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub enum CasingType: u16 { pub enum CasingType: u16 {
Rifle = 0, Rifle = 0,
Pistol = 1, Pistol = 1,
PistolLeft = 2, PistolLeft = 2,
PistolRight = 3, PistolRight = 3,
SMG = 4, SMG = 4,
None = 0xFFFF, None = 0xFFFF,
} }
} }
// EOF // EOF

View File

@ -5,24 +5,24 @@ use crate::err::*;
/// Reads a `Face`. /// Reads a `Face`.
pub fn read(b: &[u8]) -> ResultS<(Face, usize)> pub fn read(b: &[u8]) -> ResultS<(Face, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 6, start: 0, data { endian: BIG, buf: b, size: 6, start: 0, data {
let start = u16[0] usize; let start = u16[0] usize;
let face = u16[2]; let face = u16[2];
let color = u16[4]; let color = u16[4];
} }
} }
Ok((Face{start, face, color}, 6)) Ok((Face{start, face, color}, 6))
} }
/// A text face. /// A text face.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct Face { pub struct Face {
pub start: usize, pub start: usize,
pub face: u16, pub face: u16,
pub color: u16, pub color: u16,
} }
// EOF // EOF

View File

@ -5,98 +5,98 @@ use crate::err::*;
/// Reads an `InterGroup`. /// Reads an `InterGroup`.
pub fn read(b: &[u8]) -> ResultS<(InterGroup, usize)> pub fn read(b: &[u8]) -> ResultS<(InterGroup, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 12, start: 0, data { endian: BIG, buf: b, size: 12, start: 0, data {
let flags = u16[0] flag GroupFlags; let flags = u16[0] flag GroupFlags;
let ttype = u16[2]; let ttype = u16[2];
let pdata = u16[4]; let pdata = u16[4];
let beg = u16[6] usize; let beg = u16[6] usize;
let len = u16[8] usize; let len = u16[8] usize;
let lines = u16[10]; let lines = u16[10];
} }
} }
let ttype = match ttype { let ttype = match ttype {
0 => GroupType::Logon(pdata), 0 => GroupType::Logon(pdata),
1 => GroupType::Unfinished, 1 => GroupType::Unfinished,
2 => GroupType::Success, 2 => GroupType::Success,
3 => GroupType::Failure, 3 => GroupType::Failure,
4 => GroupType::Info, 4 => GroupType::Info,
5 => GroupType::End, 5 => GroupType::End,
6 => GroupType::TeleInter(pdata), 6 => GroupType::TeleInter(pdata),
7 => GroupType::TeleIntra(pdata), 7 => GroupType::TeleIntra(pdata),
8 => GroupType::Checkpoint(pdata), 8 => GroupType::Checkpoint(pdata),
9 => GroupType::Sound(pdata), 9 => GroupType::Sound(pdata),
10 => GroupType::Movie(pdata), 10 => GroupType::Movie(pdata),
11 => GroupType::Track(pdata), 11 => GroupType::Track(pdata),
12 => GroupType::Pict(pdata), 12 => GroupType::Pict(pdata),
13 => GroupType::Logoff(pdata), 13 => GroupType::Logoff(pdata),
14 => GroupType::Camera(pdata), 14 => GroupType::Camera(pdata),
15 => GroupType::Static(pdata), 15 => GroupType::Static(pdata),
16 => GroupType::Tag(pdata), 16 => GroupType::Tag(pdata),
n => return Err(ReprError::new("GroupType", n).into()), n => return Err(ReprError::new("GroupType", n).into()),
}; };
Ok((InterGroup{flags, ttype, lines, beg, len}, 12)) Ok((InterGroup{flags, ttype, lines, beg, len}, 12))
} }
impl Default for GroupType impl Default for GroupType
{ {
fn default() -> Self {GroupType::Unfinished} fn default() -> Self {GroupType::Unfinished}
} }
/// Interim structure. /// Interim structure.
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct InterGroup { pub struct InterGroup {
pub flags: GroupFlags, pub flags: GroupFlags,
pub ttype: GroupType, pub ttype: GroupType,
pub lines: u16, pub lines: u16,
pub beg: usize, pub beg: usize,
pub len: usize, pub len: usize,
} }
/// A terminal command grouping. /// A terminal command grouping.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct Group { pub struct Group {
pub flags: GroupFlags, pub flags: GroupFlags,
pub ttype: GroupType, pub ttype: GroupType,
pub lines: u16, pub lines: u16,
pub text: String, pub text: String,
} }
/// The command of a `Group`. /// The command of a `Group`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum GroupType { pub enum GroupType {
Logon(u16), Logon(u16),
Unfinished, Unfinished,
Success, Success,
Failure, Failure,
Info, Info,
End, End,
TeleInter(u16), TeleInter(u16),
TeleIntra(u16), TeleIntra(u16),
Checkpoint(u16), Checkpoint(u16),
Sound(u16), Sound(u16),
Movie(u16), Movie(u16),
Track(u16), Track(u16),
Pict(u16), Pict(u16),
Logoff(u16), Logoff(u16),
Camera(u16), Camera(u16),
Static(u16), Static(u16),
Tag(u16), Tag(u16),
} }
c_bitfield! { c_bitfield! {
/// Flags for `Group`. /// Flags for `Group`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct GroupFlags: u16 { pub struct GroupFlags: u16 {
/// Draws the picture on the right. /// Draws the picture on the right.
DRAW_ON_RIGHT = 0, DRAW_ON_RIGHT = 0,
/// Draws the picture in the center. /// Draws the picture in the center.
DRAW_CENTER = 1, DRAW_CENTER = 1,
} }
} }
// EOF // EOF

View File

@ -7,102 +7,102 @@ use super::trig;
/// Reads a `WPpx` chunk. /// Reads a `WPpx` chunk.
pub fn read(b: &[u8]) -> ResultS<(Weapon, usize)> pub fn read(b: &[u8]) -> ResultS<(Weapon, usize)>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 134, start: 0, data { endian: BIG, buf: b, size: 134, start: 0, data {
let typ_item = u16[0]; let typ_item = u16[0];
let typ_powerup = OptU16[2]; let typ_powerup = OptU16[2];
let typ_weapon = u16[4] enum WeaponType; let typ_weapon = u16[4] enum WeaponType;
let flags = u16[6] flag WeaponFlags; let flags = u16[6] flag WeaponFlags;
let lit_value = Fixed[8]; let lit_value = Fixed[8];
let lit_decay = u16[12]; let lit_decay = u16[12];
let hei_idle = Fixed[14]; let hei_idle = Fixed[14];
let amp_bob = Fixed[18]; let amp_bob = Fixed[18];
let hei_kick = Fixed[22]; let hei_kick = Fixed[22];
let hei_reload = Fixed[26]; let hei_reload = Fixed[26];
let wid_idle = Fixed[30]; let wid_idle = Fixed[30];
let amp_horz = Fixed[34]; let amp_horz = Fixed[34];
let collection = u16[38]; let collection = u16[38];
let frm_idle = u16[40]; let frm_idle = u16[40];
let frm_firing = u16[42]; let frm_firing = u16[42];
let frm_reload = OptU16[44]; let frm_reload = OptU16[44];
let frm_charge = OptU16[48]; let frm_charge = OptU16[48];
let frm_charged = OptU16[50]; let frm_charged = OptU16[50];
let tic_ready = u16[52]; let tic_ready = u16[52];
let tic_load_beg = u16[54]; let tic_load_beg = u16[54];
let tic_load_mid = u16[56]; let tic_load_mid = u16[56];
let tic_load_end = u16[58]; let tic_load_end = u16[58];
let tic_powerup = u16[60]; let tic_powerup = u16[60];
let trig_pri = trig::read[62; 36]; let trig_pri = trig::read[62; 36];
let trig_sec = trig::read[98; 36]; let trig_sec = trig::read[98; 36];
} }
} }
Ok((Weapon{amp_bob, amp_horz, collection, flags, frm_charge, frm_charged, Ok((Weapon{amp_bob, amp_horz, collection, flags, frm_charge, frm_charged,
frm_firing, frm_idle, frm_reload, hei_idle, hei_kick, hei_reload, frm_firing, frm_idle, frm_reload, hei_idle, hei_kick, hei_reload,
lit_decay, lit_value, tic_load_beg, tic_load_end, tic_load_mid, lit_decay, lit_value, tic_load_beg, tic_load_end, tic_load_mid,
tic_powerup, tic_ready, trig_pri, trig_sec, typ_item, tic_powerup, tic_ready, trig_pri, trig_sec, typ_item,
typ_powerup, typ_weapon, wid_idle}, 134)) typ_powerup, typ_weapon, wid_idle}, 134))
} }
/// A weapon definition. /// A weapon definition.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct Weapon { pub struct Weapon {
pub amp_bob: Fixed, pub amp_bob: Fixed,
pub amp_horz: Fixed, pub amp_horz: Fixed,
pub collection: u16, pub collection: u16,
pub flags: WeaponFlags, pub flags: WeaponFlags,
pub frm_charge: OptU16, pub frm_charge: OptU16,
pub frm_charged: OptU16, pub frm_charged: OptU16,
pub frm_firing: u16, pub frm_firing: u16,
pub frm_idle: u16, pub frm_idle: u16,
pub frm_reload: OptU16, pub frm_reload: OptU16,
pub hei_idle: Fixed, pub hei_idle: Fixed,
pub hei_kick: Fixed, pub hei_kick: Fixed,
pub hei_reload: Fixed, pub hei_reload: Fixed,
pub lit_decay: u16, pub lit_decay: u16,
pub lit_value: Fixed, pub lit_value: Fixed,
pub tic_load_beg: u16, pub tic_load_beg: u16,
pub tic_load_end: u16, pub tic_load_end: u16,
pub tic_load_mid: u16, pub tic_load_mid: u16,
pub tic_powerup: u16, pub tic_powerup: u16,
pub tic_ready: u16, pub tic_ready: u16,
pub trig_pri: trig::Trigger, pub trig_pri: trig::Trigger,
pub trig_sec: trig::Trigger, pub trig_sec: trig::Trigger,
pub typ_item: u16, pub typ_item: u16,
pub typ_powerup: OptU16, pub typ_powerup: OptU16,
pub typ_weapon: WeaponType, pub typ_weapon: WeaponType,
pub wid_idle: Fixed, pub wid_idle: Fixed,
} }
c_bitfield! { c_bitfield! {
/// Flags for a weapon. /// Flags for a weapon.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct WeaponFlags: u16 { pub struct WeaponFlags: u16 {
AUTOMATIC = 0, AUTOMATIC = 0,
REMOVE_AFTER_USE = 1, REMOVE_AFTER_USE = 1,
INSTANT_CASING = 2, INSTANT_CASING = 2,
OVERLOADS = 3, OVERLOADS = 3,
RANDOM_AMMO = 4, RANDOM_AMMO = 4,
TEMPORARY_POWER = 5, TEMPORARY_POWER = 5,
RELOAD_ONE_HAND = 6, RELOAD_ONE_HAND = 6,
FIRE_OUT_OF_PHASE = 7, FIRE_OUT_OF_PHASE = 7,
FIRE_UNDER_MEDIA = 8, FIRE_UNDER_MEDIA = 8,
TRIGGER_SAME_AMMO = 9, TRIGGER_SAME_AMMO = 9,
SECONDARY_FLIP = 10, SECONDARY_FLIP = 10,
} }
} }
c_enum! { c_enum! {
/// The type of functionality a weapon provides. /// The type of functionality a weapon provides.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub enum WeaponType: u16 { pub enum WeaponType: u16 {
Melee = 0, Melee = 0,
Normal = 1, Normal = 1,
DualFunc = 2, DualFunc = 2,
DualPistol = 3, DualPistol = 3,
Multipurpose = 4, Multipurpose = 4,
} }
} }
// EOF // EOF

View File

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

View File

@ -14,40 +14,40 @@ pub fn read_coll_at_offset(b: &[u8],
ofs: u32, ofs: u32,
len: usize) -> ResultS<Option<coll::Collection>> len: usize) -> ResultS<Option<coll::Collection>>
{ {
if ofs != u32::max_value() { if ofs != u32::max_value() {
let ofs = usize_from_u32(ofs); let ofs = usize_from_u32(ofs);
let dat = ok!(b.get(ofs..ofs + len), "bad offset")?; let dat = ok!(b.get(ofs..ofs + len), "bad offset")?;
Ok(Some(coll::read(dat)?)) Ok(Some(coll::read(dat)?))
} else { } else {
Ok(None) Ok(None)
} }
} }
/// Read all of the collections in a Shapes file. /// Read all of the collections in a Shapes file.
pub fn read(fp: &mut impl Read) -> ResultS<Collections> pub fn read(fp: &mut impl Read) -> ResultS<Collections>
{ {
let mut b = Vec::new(); let mut b = Vec::new();
fp.read_to_end(&mut b)?; fp.read_to_end(&mut b)?;
let mut collections = vec![(None, None); 32]; let mut collections = vec![(None, None); 32];
for (i, co) in collections.iter_mut().enumerate() { for (i, co) in collections.iter_mut().enumerate() {
read_data! { read_data! {
endian: BIG, buf: &b, size: 32, start: i * 32, data { endian: BIG, buf: &b, size: 32, start: i * 32, data {
let lo_ofs = u32[4]; let lo_ofs = u32[4];
let lo_len = u32[8] usize; let lo_len = u32[8] usize;
let hi_ofs = u32[12]; let hi_ofs = u32[12];
let hi_len = u32[16] usize; let hi_len = u32[16] usize;
} }
} }
let lo = read_coll_at_offset(&b, lo_ofs, lo_len)?; let lo = read_coll_at_offset(&b, lo_ofs, lo_len)?;
let hi = read_coll_at_offset(&b, hi_ofs, hi_len)?; let hi = read_coll_at_offset(&b, hi_ofs, hi_len)?;
*co = (lo, hi); *co = (lo, hi);
} }
Ok(collections) Ok(collections)
} }
/// A collection, which may have low- and high-definition variations, or none. /// A collection, which may have low- and high-definition variations, or none.

View File

@ -6,135 +6,135 @@ use super::clut;
/// Reads a `Bitmap`. /// Reads a `Bitmap`.
pub fn read(b: &[u8]) -> ResultS<Bitmap> pub fn read(b: &[u8]) -> ResultS<Bitmap>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 26, start: 0, data { endian: BIG, buf: b, size: 26, start: 0, data {
let width = u16[0] usize; let width = u16[0] usize;
let height = u16[2] usize; let height = u16[2] usize;
let compr = u16[4]; let compr = u16[4];
let flags = u16[6] flag BmpFlags; let flags = u16[6] flag BmpFlags;
let depth = u16[8]; let depth = u16[8];
} }
} }
let compr = compr == u16::max_value(); let compr = compr == u16::max_value();
let alpha = flags.contains(BmpFlags::TRANSPARENT); let alpha = flags.contains(BmpFlags::TRANSPARENT);
let cmajr = flags.contains(BmpFlags::COLUMN_MAJOR); let cmajr = flags.contains(BmpFlags::COLUMN_MAJOR);
if depth != 8 { if depth != 8 {
bail!("invalid bit depth (should always be 8)"); bail!("invalid bit depth (should always be 8)");
} }
let mut bmp = Bitmap::new(width, height, alpha, cmajr); let mut bmp = Bitmap::new(width, height, alpha, cmajr);
let mut p = 30 + if cmajr {4 * width} else {4 * height}; let mut p = 30 + if cmajr {4 * width} else {4 * height};
let scanlines = if cmajr {width} else {height}; let scanlines = if cmajr {width} else {height};
let pitch = if cmajr {height} else {width}; let pitch = if cmajr {height} else {width};
if compr { if compr {
// compressed scanlines (transparency RLE) // compressed scanlines (transparency RLE)
for _ in 0..scanlines { for _ in 0..scanlines {
read_data! { read_data! {
endian: BIG, buf: b, size: 4, start: p, data { endian: BIG, buf: b, size: 4, start: p, data {
let fst = u16[0] usize; let fst = u16[0] usize;
let lst = u16[2] usize; let lst = u16[2] usize;
} }
} }
let end = lst - fst; let end = lst - fst;
p += 4; p += 4;
if lst < fst || fst > pitch || lst > pitch { if lst < fst || fst > pitch || lst > pitch {
bail!("invalid compressed scanline"); bail!("invalid compressed scanline");
} }
for _ in 0..fst { for _ in 0..fst {
bmp.cr.push(0); bmp.cr.push(0);
} }
bmp.cr.extend(ok!(b.get(p..p + end), "not enough data")?); bmp.cr.extend(ok!(b.get(p..p + end), "not enough data")?);
for _ in lst..pitch { for _ in lst..pitch {
bmp.cr.push(0); bmp.cr.push(0);
} }
p += end; p += end;
} }
} else { } else {
// simple copy // simple copy
bmp.cr.extend(ok!(b.get(p..p + width * height), "not enough data")?); bmp.cr.extend(ok!(b.get(p..p + width * height), "not enough data")?);
} }
Ok(bmp) Ok(bmp)
} }
impl Bitmap impl Bitmap
{ {
/// Creates an empty bitmap. /// Creates an empty bitmap.
pub fn new(w: usize, h: usize, alpha: bool, cmajr: bool) -> Self pub fn new(w: usize, h: usize, alpha: bool, cmajr: bool) -> Self
{ {
Self{w, h, alpha, cmajr, cr: Vec::with_capacity(w * h)} Self{w, h, alpha, cmajr, cr: Vec::with_capacity(w * h)}
} }
} }
impl<'a, 'b> ImageShp<'a, 'b> impl<'a, 'b> ImageShp<'a, 'b>
{ {
/// Creates an `ImageShp` with the given bitmap. /// Creates an `ImageShp` with the given bitmap.
#[inline] #[inline]
pub const fn new(bmp: &'a Bitmap, clut: &'b [clut::ColorShp]) -> Self pub const fn new(bmp: &'a Bitmap, clut: &'b [clut::ColorShp]) -> Self
{ {
Self{bmp, clut} Self{bmp, clut}
} }
} }
impl Image for ImageShp<'_, '_> impl Image for ImageShp<'_, '_>
{ {
type Output = clut::ColorShp; type Output = clut::ColorShp;
fn w(&self) -> usize {self.bmp.w} fn w(&self) -> usize {self.bmp.w}
fn h(&self) -> usize {self.bmp.h} fn h(&self) -> usize {self.bmp.h}
fn index(&self, x: usize, y: usize) -> &Self::Output fn index(&self, x: usize, y: usize) -> &Self::Output
{ {
static TRANSLUCENT_COLOR: clut::ColorShp = clut::ColorShp::Translucent; static TRANSLUCENT_COLOR: clut::ColorShp = clut::ColorShp::Translucent;
let cr = usize::from(if self.bmp.cmajr { let cr = usize::from(if self.bmp.cmajr {
self.bmp.cr[y + x * self.bmp.h] self.bmp.cr[y + x * self.bmp.h]
} else { } else {
self.bmp.cr[x + y * self.bmp.w] self.bmp.cr[x + y * self.bmp.w]
}); });
if self.bmp.alpha && cr == 0 { if self.bmp.alpha && cr == 0 {
&TRANSLUCENT_COLOR &TRANSLUCENT_COLOR
} else { } else {
self.clut.get(cr).unwrap_or(&TRANSLUCENT_COLOR) self.clut.get(cr).unwrap_or(&TRANSLUCENT_COLOR)
} }
} }
} }
/// An unpacked Shape bitmap. /// An unpacked Shape bitmap.
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct Bitmap { pub struct Bitmap {
w: usize, w: usize,
h: usize, h: usize,
cr: Vec<u8>, cr: Vec<u8>,
alpha: bool, alpha: bool,
cmajr: bool, cmajr: bool,
} }
/// An image from a Shape. This mainly just exists so that `Bitmap` can use the /// An image from a Shape. This mainly just exists so that `Bitmap` can use the
/// `Image` trait. /// `Image` trait.
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct ImageShp<'a, 'b> { pub struct ImageShp<'a, 'b> {
bmp: &'a Bitmap, bmp: &'a Bitmap,
clut: &'b [clut::ColorShp], clut: &'b [clut::ColorShp],
} }
c_bitfield! { c_bitfield! {
pub struct BmpFlags: u16 { pub struct BmpFlags: u16 {
TRANSPARENT = 14, TRANSPARENT = 14,
COLUMN_MAJOR = 15, COLUMN_MAJOR = 15,
} }
} }
// EOF // EOF

View File

@ -5,27 +5,27 @@ use crate::{err::*, image::Color};
/// Reads a color from a color table into `clut`. /// Reads a color from a color table into `clut`.
pub fn read_color(b: &[u8], clut: &mut [ColorShp]) -> ResultS<()> pub fn read_color(b: &[u8], clut: &mut [ColorShp]) -> ResultS<()>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 8, start: 0, data { endian: BIG, buf: b, size: 8, start: 0, data {
let flag = u8[0]; let flag = u8[0];
let ind = u8[1]; let ind = u8[1];
let r = u16[2]; let r = u16[2];
let g = u16[4]; let g = u16[4];
let b = u16[6]; let b = u16[6];
} }
} }
let cr = ok!(clut.get_mut(usize::from(ind)), "bad index")?; let cr = ok!(clut.get_mut(usize::from(ind)), "bad index")?;
*cr = match flag { *cr = match flag {
128 => ColorShp::Lit {r, g, b}, 128 => ColorShp::Lit {r, g, b},
0 => ColorShp::Opaque{r, g, b}, 0 => ColorShp::Opaque{r, g, b},
_ => { _ => {
return Err(err_msg("invalid flag in color")); return Err(err_msg("invalid flag in color"));
} }
}; };
Ok(()) Ok(())
} }
/// Reads color tables from `b`. /// Reads color tables from `b`.
@ -34,78 +34,78 @@ pub fn read(b: &[u8],
tab_num: usize, tab_num: usize,
clr_num: usize) -> ResultS<Vec<Clut>> clr_num: usize) -> ResultS<Vec<Clut>>
{ {
let end = tab_num * clr_num * 8; let end = tab_num * clr_num * 8;
let b = ok!(b.get(tab_ofs..tab_ofs + end), "bad offset")?; let b = ok!(b.get(tab_ofs..tab_ofs + end), "bad offset")?;
let mut v = vec![vec![ColorShp::Translucent; clr_num]; tab_num]; let mut v = vec![vec![ColorShp::Translucent; clr_num]; tab_num];
let mut p = 0; let mut p = 0;
for clut in v.iter_mut().take(tab_num) { for clut in v.iter_mut().take(tab_num) {
for _ in 0..clr_num { for _ in 0..clr_num {
read_color(ok!(b.get(p..p + 8), "not enough data")?, clut)?; read_color(ok!(b.get(p..p + 8), "not enough data")?, clut)?;
p += 8; p += 8;
} }
} }
Ok(v) Ok(v)
} }
impl Color for ColorShp impl Color for ColorShp
{ {
fn r(&self) -> u16 fn r(&self) -> u16
{ {
match *self { match *self {
ColorShp::Translucent => 0, ColorShp::Translucent => 0,
ColorShp::Opaque{r, ..} | ColorShp::Opaque{r, ..} |
ColorShp::Lit {r, ..} => r, ColorShp::Lit {r, ..} => r,
} }
} }
fn g(&self) -> u16 fn g(&self) -> u16
{ {
match *self { match *self {
ColorShp::Translucent => 0, ColorShp::Translucent => 0,
ColorShp::Opaque{g, ..} | ColorShp::Opaque{g, ..} |
ColorShp::Lit {g, ..} => g, ColorShp::Lit {g, ..} => g,
} }
} }
fn b(&self) -> u16 fn b(&self) -> u16
{ {
match *self { match *self {
ColorShp::Translucent => 0, ColorShp::Translucent => 0,
ColorShp::Opaque{b, ..} | ColorShp::Opaque{b, ..} |
ColorShp::Lit {b, ..} => b, ColorShp::Lit {b, ..} => b,
} }
} }
fn a(&self) -> u16 fn a(&self) -> u16
{ {
match *self { match *self {
ColorShp::Translucent => 0, ColorShp::Translucent => 0,
ColorShp::Opaque{..} | ColorShp::Opaque{..} |
ColorShp::Lit {..} => u16::max_value(), ColorShp::Lit {..} => u16::max_value(),
} }
} }
} }
/// A color in a `Clut`. /// A color in a `Clut`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ColorShp { pub enum ColorShp {
/// A completely translucent color. /// A completely translucent color.
Translucent, Translucent,
/// An opaque color which may be shaded. /// An opaque color which may be shaded.
Opaque{/** The red component. */ r: u16, Opaque{/** The red component. */ r: u16,
/** The green component. */ g: u16, /** The green component. */ g: u16,
/** The blue component. */ b: u16}, /** The blue component. */ b: u16},
/// An opaque color which may not be shaded. /// An opaque color which may not be shaded.
Lit{/** The red component. */ r: u16, Lit{/** The red component. */ r: u16,
/** The green component. */ g: u16, /** The green component. */ g: u16,
/** The blue component. */ b: u16}, /** The blue component. */ b: u16},
} }
/// A color collection. /// A color collection.

View File

@ -6,63 +6,63 @@ use super::{bmap, clut, fram, sequ};
/// Reads a `Collection`. /// Reads a `Collection`.
pub fn read(b: &[u8]) -> ResultS<Collection> pub fn read(b: &[u8]) -> ResultS<Collection>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 544, start: 0, data { endian: BIG, buf: b, size: 544, start: 0, data {
let version = u16[0]; let version = u16[0];
let cl_type = u16[2] enum CollectionType; let cl_type = u16[2] enum CollectionType;
let clr_num = u16[6] usize; let clr_num = u16[6] usize;
let tab_num = u16[8] usize; let tab_num = u16[8] usize;
let tab_ofs = u32[10] usize; let tab_ofs = u32[10] usize;
let seq_num = u16[14] usize; let seq_num = u16[14] usize;
let seq_ofs = u32[16] usize; let seq_ofs = u32[16] usize;
let frm_num = u16[20] usize; let frm_num = u16[20] usize;
let frm_ofs = u32[22] usize; let frm_ofs = u32[22] usize;
let bmp_num = u16[26] usize; let bmp_num = u16[26] usize;
let bmp_ofs = u32[28] usize; let bmp_ofs = u32[28] usize;
} }
} }
if version != 3 { if version != 3 {
bail!("invalid collection definition"); bail!("invalid collection definition");
} }
let tabs = clut::read(b, tab_ofs, tab_num, clr_num)?; let tabs = clut::read(b, tab_ofs, tab_num, clr_num)?;
let bmps = rd_ofstable(b, bmp_ofs, bmp_num, bmap::read)?; let bmps = rd_ofstable(b, bmp_ofs, bmp_num, bmap::read)?;
let frms = rd_ofstable(b, frm_ofs, frm_num, fram::read)?; let frms = rd_ofstable(b, frm_ofs, frm_num, fram::read)?;
let seqs = rd_ofstable(b, seq_ofs, seq_num, sequ::read)?; let seqs = rd_ofstable(b, seq_ofs, seq_num, sequ::read)?;
Ok(Collection{ctyp: cl_type, tabs, bmps, frms, seqs}) Ok(Collection{ctyp: cl_type, tabs, bmps, frms, seqs})
} }
/// A collection of color tables, bitmaps, frames and sequences. /// A collection of color tables, bitmaps, frames and sequences.
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct Collection { pub struct Collection {
/// The type of collection this is. /// The type of collection this is.
pub ctyp: CollectionType, pub ctyp: CollectionType,
/// All of the color tables in this collection. /// All of the color tables in this collection.
pub tabs: Vec<clut::Clut>, pub tabs: Vec<clut::Clut>,
/// All of the bitmaps in this collection. /// All of the bitmaps in this collection.
pub bmps: Vec<bmap::Bitmap>, pub bmps: Vec<bmap::Bitmap>,
/// All of the frames in this collection. /// All of the frames in this collection.
pub frms: Vec<fram::Frame>, pub frms: Vec<fram::Frame>,
/// All of the sequences in this collection. /// All of the sequences in this collection.
pub seqs: Vec<sequ::Sequence>, pub seqs: Vec<sequ::Sequence>,
} }
c_enum! { c_enum! {
/// The type of a collection. /// The type of a collection.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub enum CollectionType: u16 { pub enum CollectionType: u16 {
Unused = 0, Unused = 0,
Wall = 1, Wall = 1,
Object = 2, Object = 2,
Interface = 3, Interface = 3,
Scenery = 4, Scenery = 4,
} }
} }
// EOF // EOF

View File

@ -5,66 +5,66 @@ use crate::{err::*, fixed::*};
/// Reads a `Frame`. /// Reads a `Frame`.
pub fn read(b: &[u8]) -> ResultS<Frame> pub fn read(b: &[u8]) -> ResultS<Frame>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 36, start: 0, data { endian: BIG, buf: b, size: 36, start: 0, data {
let flags = u16[0] flag FrameFlags; let flags = u16[0] flag FrameFlags;
let min_lt = Fixed[2]; let min_lt = Fixed[2];
let bmp_ind = u16[6] usize; let bmp_ind = u16[6] usize;
let wrl_l = Unit[16]; let wrl_l = Unit[16];
let wrl_r = Unit[18]; let wrl_r = Unit[18];
let wrl_t = Unit[20]; let wrl_t = Unit[20];
let wrl_b = Unit[22]; let wrl_b = Unit[22];
let wrl_x = Unit[24]; let wrl_x = Unit[24];
let wrl_y = Unit[26]; let wrl_y = Unit[26];
} }
} }
Ok(Frame{flags, min_lt, bmp_ind, wrl_l, wrl_r, wrl_t, wrl_b, wrl_x, wrl_y}) Ok(Frame{flags, min_lt, bmp_ind, wrl_l, wrl_r, wrl_t, wrl_b, wrl_x, wrl_y})
} }
/// A frame, also known as a low level shape. /// A frame, also known as a low level shape.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct Frame { pub struct Frame {
/// The flags for this frame. /// The flags for this frame.
pub flags: FrameFlags, pub flags: FrameFlags,
/// The minimum light level for this frame. /// The minimum light level for this frame.
pub min_lt: Fixed, pub min_lt: Fixed,
/// The index of the bitmap this frame uses. /// The index of the bitmap this frame uses.
pub bmp_ind: usize, pub bmp_ind: usize,
/// The left translation for this frame. /// The left translation for this frame.
pub wrl_l: Unit, pub wrl_l: Unit,
/// The right translation for this frame. /// The right translation for this frame.
pub wrl_r: Unit, pub wrl_r: Unit,
/// The top translation for this frame. /// The top translation for this frame.
pub wrl_t: Unit, pub wrl_t: Unit,
/// The bottom translation for this frame. /// The bottom translation for this frame.
pub wrl_b: Unit, pub wrl_b: Unit,
/// The X translation for this frame. /// The X translation for this frame.
pub wrl_x: Unit, pub wrl_x: Unit,
/// The Y translation for this frame. /// The Y translation for this frame.
pub wrl_y: Unit, pub wrl_y: Unit,
} }
c_bitfield! { c_bitfield! {
/// Flags for `Frame`. /// Flags for `Frame`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct FrameFlags: u16 { pub struct FrameFlags: u16 {
/// The player's torso will obscure the player's legs. /// The player's torso will obscure the player's legs.
OBSCURE = 13, OBSCURE = 13,
/// The bitmap will be flipped on the vertical axis. /// The bitmap will be flipped on the vertical axis.
FLIP_Y = 14, FLIP_Y = 14,
/// The bitmap will be flipped on the horizontal axis. /// The bitmap will be flipped on the horizontal axis.
FLIP_X = 15, FLIP_X = 15,
} }
} }
// EOF // EOF

View File

@ -7,80 +7,80 @@ use crate::{bin::OptU16, err::*,
/// Reads a `Sequence`. /// Reads a `Sequence`.
pub fn read(b: &[u8]) -> ResultS<Sequence> pub fn read(b: &[u8]) -> ResultS<Sequence>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 88, start: 0, data { endian: BIG, buf: b, size: 88, start: 0, data {
let name = u8[4; 34]; let name = u8[4; 34];
let v_type = u16[38] enum ViewType; let v_type = u16[38] enum ViewType;
let frames = u16[40]; let frames = u16[40];
let ticks = u16[42]; let ticks = u16[42];
let key = u16[44]; let key = u16[44];
let xfer = u16[46] enum TransferMode; let xfer = u16[46] enum TransferMode;
let xfer_pd = u16[48]; let xfer_pd = u16[48];
let snd_beg = OptU16[50]; let snd_beg = OptU16[50];
let snd_key = OptU16[52]; let snd_key = OptU16[52];
let snd_end = OptU16[54]; let snd_end = OptU16[54];
let loop_f = u16[58]; let loop_f = u16[58];
} }
} }
let name = mac_roman_conv(ok!(pascal_str(name), "bad string")?); let name = mac_roman_conv(ok!(pascal_str(name), "bad string")?);
Ok(Sequence{name, v_type, frames, ticks, key, xfer, xfer_pd, snd_beg, Ok(Sequence{name, v_type, frames, ticks, key, xfer, xfer_pd, snd_beg,
snd_key, snd_end, loop_f}) snd_key, snd_end, loop_f})
} }
/// A sequence, also known as a high level shape. /// A sequence, also known as a high level shape.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct Sequence { pub struct Sequence {
/// The display name for this sequence. /// The display name for this sequence.
pub name: String, pub name: String,
/// The view type for each frame in this sequence. /// The view type for each frame in this sequence.
pub v_type: ViewType, pub v_type: ViewType,
/// The number of frames in this sequence. /// The number of frames in this sequence.
pub frames: u16, pub frames: u16,
/// The number of ticks each frame in this sequence takes. /// The number of ticks each frame in this sequence takes.
pub ticks: u16, pub ticks: u16,
/// The key frame index for this sequence. /// The key frame index for this sequence.
pub key: u16, pub key: u16,
/// The transfer mode to play over this sequence. /// The transfer mode to play over this sequence.
pub xfer: TransferMode, pub xfer: TransferMode,
/// The period in game ticks the transfer mode plays over. /// The period in game ticks the transfer mode plays over.
pub xfer_pd: u16, pub xfer_pd: u16,
/// The sound to play at the beginning of this sequence. /// The sound to play at the beginning of this sequence.
pub snd_beg: OptU16, pub snd_beg: OptU16,
/// The sound to play at the key frame of this sequence. /// The sound to play at the key frame of this sequence.
pub snd_key: OptU16, pub snd_key: OptU16,
/// The sound to play at the end of this sequence. /// The sound to play at the end of this sequence.
pub snd_end: OptU16, pub snd_end: OptU16,
/// Which frame to loop on. /// Which frame to loop on.
pub loop_f: u16, pub loop_f: u16,
} }
c_enum! { c_enum! {
/// The type of or number of views for a sequence. /// The type of or number of views for a sequence.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub enum ViewType: u16 { pub enum ViewType: u16 {
Anim = 1, Anim = 1,
Anim8from2 = 2, Anim8from2 = 2,
Anim4from3 = 3, Anim4from3 = 3,
Anim4 = 4, Anim4 = 4,
Anim8from5 = 5, Anim8from5 = 5,
Anim8 = 8, Anim8 = 8,
Anim5from3 = 9, Anim5from3 = 9,
Still = 10, Still = 10,
Anim5 = 11, Anim5 = 11,
} }
} }
// EOF // EOF

View File

@ -9,43 +9,43 @@ use std::{collections::BTreeMap, io::prelude::*};
/// Reads all sounds from a Sound file. /// Reads all sounds from a Sound file.
pub fn read(fp: &mut impl Read) -> ResultS<Vec<SoundTable>> pub fn read(fp: &mut impl Read) -> ResultS<Vec<SoundTable>>
{ {
let mut b = Vec::new(); let mut b = Vec::new();
fp.read_to_end(&mut b)?; fp.read_to_end(&mut b)?;
read_data! { read_data! {
endian: BIG, buf: &b, size: 260, start: 0, data { endian: BIG, buf: &b, size: 260, start: 0, data {
let version = u32[0]; let version = u32[0];
let magic = Ident[4]; let magic = Ident[4];
let src_num = u16[8] usize; let src_num = u16[8] usize;
let snd_num = u16[10] usize; let snd_num = u16[10] usize;
} }
} }
if version != 1 || magic != b"snd2" { if version != 1 || magic != b"snd2" {
bail!("bad sound header"); bail!("bad sound header");
} }
let mut sc = Vec::with_capacity(src_num); let mut sc = Vec::with_capacity(src_num);
for i in 0..src_num { for i in 0..src_num {
let p = 260 + i * 64; let p = 260 + i * 64;
let mut st = SoundTable::new(); let mut st = SoundTable::new();
for _ in 0..snd_num { for _ in 0..snd_num {
if let Some((ofs, idx, mut def)) = defs::read(&b[p..p + 64])? { if let Some((ofs, idx, mut def)) = defs::read(&b[p..p + 64])? {
for &ofs in &ofs { for &ofs in &ofs {
def.sounds.push(snds::read(&b[ofs..])?); def.sounds.push(snds::read(&b[ofs..])?);
} }
st.insert(idx, def); st.insert(idx, def);
} }
} }
sc.push(st); sc.push(st);
} }
Ok(sc) Ok(sc)
} }
/// A table of sound definitions. /// A table of sound definitions.

View File

@ -5,92 +5,92 @@ use crate::{bin::{u32b, usize_from_u32}, err::*, fixed::*, sound::Sound16};
/// Reads a sound definition. /// Reads a sound definition.
pub fn read(b: &[u8]) -> ResultS<Option<(Vec<usize>, u16, SoundDef)>> pub fn read(b: &[u8]) -> ResultS<Option<(Vec<usize>, u16, SoundDef)>>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 64, start: 0, data { endian: BIG, buf: b, size: 64, start: 0, data {
let index = u16[0]; let index = u16[0];
let volume = u16[2] enum Volume; let volume = u16[2] enum Volume;
let flags = u16[4] flag SoundFlags; let flags = u16[4] flag SoundFlags;
let chance = u16[6]; let chance = u16[6];
let pitch_lo = Fixed[8]; let pitch_lo = Fixed[8];
let pitch_hi = Fixed[12]; let pitch_hi = Fixed[12];
let n_sounds = u16[16] usize; let n_sounds = u16[16] usize;
let grp_ofs = u32[20] usize; let grp_ofs = u32[20] usize;
} }
} }
if index == u16::max_value() { if index == u16::max_value() {
return Ok(None); return Ok(None);
} }
if n_sounds > 5 { if n_sounds > 5 {
bail!("too many sounds"); bail!("too many sounds");
} }
let mut ofs = Vec::with_capacity(n_sounds); let mut ofs = Vec::with_capacity(n_sounds);
let mut p = 36; let mut p = 36;
for _ in 0..n_sounds { for _ in 0..n_sounds {
ofs.push(grp_ofs + usize_from_u32(u32b(&b[p..]))); ofs.push(grp_ofs + usize_from_u32(u32b(&b[p..])));
p += 4; p += 4;
} }
let sounds = Vec::with_capacity(n_sounds); let sounds = Vec::with_capacity(n_sounds);
Ok(Some((ofs, index, Ok(Some((ofs, index,
SoundDef{volume, flags, chance, pitch_lo, pitch_hi, sounds}))) SoundDef{volume, flags, chance, pitch_lo, pitch_hi, sounds})))
} }
/// A sound definition containing one, many or no sounds. /// A sound definition containing one, many or no sounds.
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct SoundDef { pub struct SoundDef {
/// The volume type for this sound. /// The volume type for this sound.
pub volume: Volume, pub volume: Volume,
/// The flags for this sound. /// The flags for this sound.
pub flags: SoundFlags, pub flags: SoundFlags,
/// The chance out of `u16::max_value()` that this sound will not play. /// The chance out of `u16::max_value()` that this sound will not play.
pub chance: u16, pub chance: u16,
/// The low random pitch bound. /// The low random pitch bound.
pub pitch_lo: Fixed, pub pitch_lo: Fixed,
/// The high random pitch bound. /// The high random pitch bound.
pub pitch_hi: Fixed, pub pitch_hi: Fixed,
/// All of the sounds in this collection. /// All of the sounds in this collection.
pub sounds: Vec<Sound16>, pub sounds: Vec<Sound16>,
} }
c_bitfield! { c_bitfield! {
/// Flags for `SoundDef`. /// Flags for `SoundDef`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub struct SoundFlags: u16 { pub struct SoundFlags: u16 {
/// The sound will not restart when trying to play over itself. /// The sound will not restart when trying to play over itself.
NO_RESTART = 0, NO_RESTART = 0,
/// The sound will not switch channels when trying to play over itself. /// The sound will not switch channels when trying to play over itself.
NO_CHANNEL_SWITCH = 1, NO_CHANNEL_SWITCH = 1,
/// The pitch variance will be halved. /// The pitch variance will be halved.
LESS_PITCH_CHANGE = 2, LESS_PITCH_CHANGE = 2,
/// The pitch variance will be nullified. /// The pitch variance will be nullified.
NO_PITCH_CHANGE = 3, NO_PITCH_CHANGE = 3,
/// The sound will play even when completely obstructed by walls. /// The sound will play even when completely obstructed by walls.
NO_OBSTRUCTION = 4, NO_OBSTRUCTION = 4,
/// The sound will play even when completely obstructed by media. /// The sound will play even when completely obstructed by media.
NO_MEDIA_OBSTRUCT = 5, NO_MEDIA_OBSTRUCT = 5,
/// The sound will have special stereo effects. /// The sound will have special stereo effects.
AMBIENT = 6, AMBIENT = 6,
} }
} }
c_enum! { c_enum! {
/// The type of volume this sound has. /// The type of volume this sound has.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub enum Volume: u16 { pub enum Volume: u16 {
Quiet = 0, Quiet = 0,
Normal = 1, Normal = 1,
Loud = 2, Loud = 2,
} }
} }
// EOF // EOF

View File

@ -5,43 +5,43 @@ use crate::{err::*, sound::Sound16};
/// Reads a sound. /// Reads a sound.
pub fn read(b: &[u8]) -> ResultS<Sound16> pub fn read(b: &[u8]) -> ResultS<Sound16>
{ {
read_data! { read_data! {
endian: BIG, buf: b, size: 21, start: 0, data { endian: BIG, buf: b, size: 21, start: 0, data {
let len = u32[4] usize; let len = u32[4] usize;
let rate = u16[8]; let rate = u16[8];
let lp_beg = u32[12] usize; let lp_beg = u32[12] usize;
let lp_end = u32[16] usize; let lp_end = u32[16] usize;
let magic = u8[20]; let magic = u8[20];
} }
} }
match magic { match magic {
0 => { 0 => {
let stream = &b[22..22 + len]; let stream = &b[22..22 + len];
Ok(Sound16::new_from_8(rate, lp_beg, lp_end, stream)) Ok(Sound16::new_from_8(rate, lp_beg, lp_end, stream))
} }
0xFF => { 0xFF => {
read_data! { read_data! {
endian: BIG, buf: b, size: 42, start: 22, data { endian: BIG, buf: b, size: 42, start: 22, data {
let len = u32[0] usize; let len = u32[0] usize;
let bps = u16[26]; let bps = u16[26];
} }
} }
match bps { match bps {
16 => { 16 => {
let stream = &b[63..63 + len * 2]; let stream = &b[63..63 + len * 2];
Ok(Sound16::new_from_16(rate, lp_beg, lp_end, stream)) Ok(Sound16::new_from_16(rate, lp_beg, lp_end, stream))
} }
8 => { 8 => {
let stream = &b[63..63 + len]; let stream = &b[63..63 + len];
Ok(Sound16::new_from_8(rate, lp_beg, lp_end, stream)) Ok(Sound16::new_from_8(rate, lp_beg, lp_end, stream))
} }
_ => bail!("bad bits per sample"), _ => bail!("bad bits per sample"),
} }
} }
_ => bail!("invalid magic number"), _ => bail!("invalid magic number"),
} }
} }
// EOF // EOF

View File

@ -5,94 +5,94 @@ pub mod wav;
/// Any PCM stream which may be represented as a 16-bit PCM stream. /// Any PCM stream which may be represented as a 16-bit PCM stream.
pub trait Sound pub trait Sound
{ {
/// Returns the sample rate. /// Returns the sample rate.
fn rate(&self) -> u16; fn rate(&self) -> u16;
/// Returns the number of samples. /// Returns the number of samples.
fn len(&self) -> usize; fn len(&self) -> usize;
/// Returns the `n`th sample. /// Returns the `n`th sample.
/// ///
/// # Panics /// # Panics
/// ///
/// Panics if `n` exceeds the length of this sound. /// Panics if `n` exceeds the length of this sound.
fn index(&self, n: usize) -> i16; fn index(&self, n: usize) -> i16;
/// Returns the number of the first sample of the loop, or `0`. /// Returns the number of the first sample of the loop, or `0`.
fn lp_beg(&self) -> usize; fn lp_beg(&self) -> usize;
/// Returns the number of the last sample of the loop, or `0`. /// Returns the number of the last sample of the loop, or `0`.
fn lp_end(&self) -> usize; fn lp_end(&self) -> usize;
/// Returns `true` if there are no samples in this sound. /// Returns `true` if there are no samples in this sound.
fn is_empty(&self) -> bool {self.len() == 0} fn is_empty(&self) -> bool {self.len() == 0}
/// The same as `index`, but will not panic if out of bounds. /// The same as `index`, but will not panic if out of bounds.
fn get(&self, n: usize) -> Option<i16> fn get(&self, n: usize) -> Option<i16>
{ {
if n < self.len() { if n < self.len() {
Some(self.index(n)) Some(self.index(n))
} else { } else {
None None
} }
} }
} }
impl Sound16 impl Sound16
{ {
/// Creates a new `Sound16`. /// Creates a new `Sound16`.
pub fn new(rate: u16, lp_beg: usize, lp_end: usize, len: usize) -> Self pub fn new(rate: u16, lp_beg: usize, lp_end: usize, len: usize) -> Self
{ {
Self{rate, lp_beg, lp_end, data: Vec::with_capacity(len)} Self{rate, lp_beg, lp_end, data: Vec::with_capacity(len)}
} }
/// Creates a new `Sound16` from an unsigned 8-bit stream. /// Creates a new `Sound16` from an unsigned 8-bit stream.
pub fn new_from_8(rate: u16, lp_beg: usize, lp_end: usize, b: &[u8]) -> Self pub fn new_from_8(rate: u16, lp_beg: usize, lp_end: usize, b: &[u8]) -> Self
{ {
let mut snd = Self::new(rate, lp_beg, lp_end, b.len()); let mut snd = Self::new(rate, lp_beg, lp_end, b.len());
for &sample in b { for &sample in b {
snd.data.push(Self::sample_from_8(sample)); snd.data.push(Self::sample_from_8(sample));
} }
snd snd
} }
/// Creates a new `Sound16` from a signed 16-bit stream. /// Creates a new `Sound16` from a signed 16-bit stream.
pub fn new_from_16(rate: u16, lp_beg: usize, lp_end: usize, b: &[u8]) -> Self pub fn new_from_16(rate: u16, lp_beg: usize, lp_end: usize, b: &[u8]) -> Self
{ {
let mut snd = Self::new(rate, lp_beg, lp_end, b.len() / 2); let mut snd = Self::new(rate, lp_beg, lp_end, b.len() / 2);
for i in (0..b.len()).step_by(2) { for i in (0..b.len()).step_by(2) {
snd.data.push(i16::from_le_bytes([b[i], b[i + 1]])); snd.data.push(i16::from_le_bytes([b[i], b[i + 1]]));
} }
snd snd
} }
/// Creates a signed 16-bit sample from an unsigned 8-bit sample. /// Creates a signed 16-bit sample from an unsigned 8-bit sample.
pub fn sample_from_8(sample: u8) -> i16 {(i16::from(sample) - 0x80) << 8} pub fn sample_from_8(sample: u8) -> i16 {(i16::from(sample) - 0x80) << 8}
} }
impl Sound for Sound16 impl Sound for Sound16
{ {
fn rate(&self) -> u16 {self.rate} fn rate(&self) -> u16 {self.rate}
fn len(&self) -> usize {self.data.len()} fn len(&self) -> usize {self.data.len()}
fn index(&self, p: usize) -> i16 {self.data[p]} fn index(&self, p: usize) -> i16 {self.data[p]}
fn lp_beg(&self) -> usize {self.lp_beg} fn lp_beg(&self) -> usize {self.lp_beg}
fn lp_end(&self) -> usize {self.lp_end} fn lp_end(&self) -> usize {self.lp_end}
} }
/// A 16-bit PCM stream. /// A 16-bit PCM stream.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct Sound16 { pub struct Sound16 {
rate: u16, rate: u16,
lp_beg: usize, lp_beg: usize,
lp_end: usize, lp_end: usize,
/// The raw signed PCM data of this sound. /// The raw signed PCM data of this sound.
pub data: Vec<i16>, pub data: Vec<i16>,
} }
// EOF // EOF

View File

@ -10,36 +10,36 @@ use std::io;
/// Errors if `out` cannot be written to. /// Errors if `out` cannot be written to.
pub fn write_wav(out: &mut impl io::Write, snd: &impl Sound) -> ResultS<()> pub fn write_wav(out: &mut impl io::Write, snd: &impl Sound) -> ResultS<()>
{ {
let smp_rate = u32::from(snd.rate()); let smp_rate = u32::from(snd.rate());
let smp_size = smp_rate * 2; let smp_size = smp_rate * 2;
let dat_size = snd.len() as u32 * 2; let dat_size = snd.len() as u32 * 2;
out.write_all(b"RIFF")?; out.write_all(b"RIFF")?;
out.write_all(&u32::to_le_bytes(36 + dat_size))?; out.write_all(&u32::to_le_bytes(36 + dat_size))?;
out.write_all(b"WAVE")?; out.write_all(b"WAVE")?;
out.write_all(b"fmt ")?; out.write_all(b"fmt ")?;
out.write_all(&u32::to_le_bytes(16))?; out.write_all(&u32::to_le_bytes(16))?;
// PCM // PCM
out.write_all(&u16::to_le_bytes(1))?; out.write_all(&u16::to_le_bytes(1))?;
// mono // mono
out.write_all(&u16::to_le_bytes(1))?; out.write_all(&u16::to_le_bytes(1))?;
out.write_all(&u32::to_le_bytes(smp_rate))?; out.write_all(&u32::to_le_bytes(smp_rate))?;
out.write_all(&u32::to_le_bytes(smp_size))?; out.write_all(&u32::to_le_bytes(smp_size))?;
// block alignment // block alignment
out.write_all(&u16::to_le_bytes(2))?; out.write_all(&u16::to_le_bytes(2))?;
// bits per sample // bits per sample
out.write_all(&u16::to_le_bytes(16))?; out.write_all(&u16::to_le_bytes(16))?;
out.write_all(b"data")?; out.write_all(b"data")?;
out.write_all(&u32::to_le_bytes(dat_size))?; out.write_all(&u32::to_le_bytes(dat_size))?;
for p in 0..snd.len() { for p in 0..snd.len() {
let sample = snd.index(p); let sample = snd.index(p);
out.write_all(&sample.to_le_bytes())?; out.write_all(&sample.to_le_bytes())?;
} }
Ok(()) Ok(())
} }
// EOF // EOF

View File

@ -11,45 +11,45 @@
/// ``` /// ```
pub fn to_binsize(n: u64) -> String pub fn to_binsize(n: u64) -> String
{ {
const NAMES: [&str; 4] = ["kB", "MB", "GB", "TB"]; const NAMES: [&str; 4] = ["kB", "MB", "GB", "TB"];
// empty size // empty size
if n == 0 { if n == 0 {
return String::from("empty"); return String::from("empty");
} }
// terabytes, gigabytes, megabytes, kilobytes // terabytes, gigabytes, megabytes, kilobytes
for i in (1..=4).rev() { for i in (1..=4).rev() {
let pow = 1000_u64.pow(i as u32); let pow = 1000_u64.pow(i as u32);
if n >= pow { if n >= pow {
return format!("{:1}{}", n / pow, NAMES[i - 1]); return format!("{:1}{}", n / pow, NAMES[i - 1]);
} }
} }
// or, just bytes // or, just bytes
format!("{} {}", n, if n == 1 {"byte"} else {"bytes"}) format!("{} {}", n, if n == 1 {"byte"} else {"bytes"})
} }
/// Encodes or decodes a string in the terminal encryption format. /// Encodes or decodes a string in the terminal encryption format.
pub fn fuck_string(s: &[u8]) -> Vec<u8> pub fn fuck_string(s: &[u8]) -> Vec<u8>
{ {
let mut v = s.to_vec(); let mut v = s.to_vec();
let l = s.len(); let l = s.len();
let mut p = 0; let mut p = 0;
for _ in 0..l / 4 { for _ in 0..l / 4 {
p += 2; p += 2;
v[p] ^= 0xfe; v[p] ^= 0xfe;
v[p + 1] ^= 0xed; v[p + 1] ^= 0xed;
p += 2; p += 2;
} }
for _ in 0..l % 4 { for _ in 0..l % 4 {
v[p] ^= 0xfe; v[p] ^= 0xfe;
p += 1; p += 1;
} }
v v
} }
/// Reads a Pascal-style byte string with bounds checking. /// Reads a Pascal-style byte string with bounds checking.
@ -65,8 +65,8 @@ pub fn fuck_string(s: &[u8]) -> Vec<u8>
/// ``` /// ```
pub fn pascal_str(b: &[u8]) -> Option<&[u8]> pub fn pascal_str(b: &[u8]) -> Option<&[u8]>
{ {
let s = usize::from(*b.get(0)?); let s = usize::from(*b.get(0)?);
b.get(1..=s) b.get(1..=s)
} }
/// Converts input from Mac Roman to a Unicode string. /// Converts input from Mac Roman to a Unicode string.
@ -81,19 +81,19 @@ pub fn pascal_str(b: &[u8]) -> Option<&[u8]>
/// ``` /// ```
pub fn mac_roman_conv(s: &[u8]) -> String pub fn mac_roman_conv(s: &[u8]) -> String
{ {
let mut v = String::with_capacity(s.len()); let mut v = String::with_capacity(s.len());
for &c in s.iter() { for &c in s.iter() {
let c = match c { let c = match c {
0x80..=0xFF => TR[usize::from(c) & 0x7F], 0x80..=0xFF => TR[usize::from(c) & 0x7F],
b'\r' => '\n', b'\r' => '\n',
c => char::from(c), c => char::from(c),
}; };
v.push(c); v.push(c);
} }
v v
} }
/// Converts a C-style string from Mac Roman to Unicode. /// Converts a C-style string from Mac Roman to Unicode.
@ -110,11 +110,11 @@ pub fn mac_roman_conv(s: &[u8]) -> String
#[inline] #[inline]
pub fn mac_roman_cstr(s: &[u8]) -> String pub fn mac_roman_cstr(s: &[u8]) -> String
{ {
if let Some(n) = memchr::memchr(0, s) { if let Some(n) = memchr::memchr(0, s) {
mac_roman_conv(&s[..n]) mac_roman_conv(&s[..n])
} else { } else {
mac_roman_conv(s) mac_roman_conv(s)
} }
} }
/// Converts input from a Unicode string to Mac Roman. /// Converts input from a Unicode string to Mac Roman.
@ -129,25 +129,25 @@ pub fn mac_roman_cstr(s: &[u8]) -> String
/// ``` /// ```
pub fn to_mac_roman(s: &str) -> Vec<u8> pub fn to_mac_roman(s: &str) -> Vec<u8>
{ {
let mut v = Vec::with_capacity(s.len()); let mut v = Vec::with_capacity(s.len());
for c in s.chars() { for c in s.chars() {
let c = match c { let c = match c {
'\n' => b'\r', '\n' => b'\r',
'\0'..='\x7f' => c as u8, '\0'..='\x7f' => c as u8,
c => { c => {
if let Some(c) = TR.iter().position(|&o| o == c) { if let Some(c) = TR.iter().position(|&o| o == c) {
c as u8 + 0x80 c as u8 + 0x80
} else { } else {
0x7f 0x7f
} }
} }
}; };
v.push(c); v.push(c);
} }
v v
} }
/// Pads the output with zeroes. /// Pads the output with zeroes.
@ -167,52 +167,52 @@ pub fn to_mac_roman(s: &str) -> Vec<u8>
/// ``` /// ```
pub fn pad_zero(mut v: Vec<u8>, n: usize) -> Vec<u8> pub fn pad_zero(mut v: Vec<u8>, n: usize) -> Vec<u8>
{ {
for _ in v.len()..n { for _ in v.len()..n {
v.push(0); v.push(0);
} }
v v
} }
const TR: [char; 128] = const TR: [char; 128] =
['\u{00c4}', '\u{00c5}', '\u{00c7}', '\u{00c9}', '\u{00d1}', '\u{00d6}', ['\u{00c4}', '\u{00c5}', '\u{00c7}', '\u{00c9}', '\u{00d1}', '\u{00d6}',
'\u{00dc}', '\u{00e1}', '\u{00e0}', '\u{00e2}', '\u{00e4}', '\u{00e3}', '\u{00dc}', '\u{00e1}', '\u{00e0}', '\u{00e2}', '\u{00e4}', '\u{00e3}',
'\u{00e5}', '\u{00e7}', '\u{00e9}', '\u{00e8}', '\u{00ea}', '\u{00eb}', '\u{00e5}', '\u{00e7}', '\u{00e9}', '\u{00e8}', '\u{00ea}', '\u{00eb}',
'\u{00ed}', '\u{00ec}', '\u{00ee}', '\u{00ef}', '\u{00f1}', '\u{00f3}', '\u{00ed}', '\u{00ec}', '\u{00ee}', '\u{00ef}', '\u{00f1}', '\u{00f3}',
'\u{00f2}', '\u{00f4}', '\u{00f6}', '\u{00f5}', '\u{00fa}', '\u{00f9}', '\u{00f2}', '\u{00f4}', '\u{00f6}', '\u{00f5}', '\u{00fa}', '\u{00f9}',
'\u{00fb}', '\u{00fc}', '\u{2020}', '\u{00b0}', '\u{00a2}', '\u{00a3}', '\u{00fb}', '\u{00fc}', '\u{2020}', '\u{00b0}', '\u{00a2}', '\u{00a3}',
'\u{00a7}', '\u{2022}', '\u{00b6}', '\u{00df}', '\u{00ae}', '\u{00a9}', '\u{00a7}', '\u{2022}', '\u{00b6}', '\u{00df}', '\u{00ae}', '\u{00a9}',
'\u{2122}', '\u{00b4}', '\u{00a8}', '\u{2260}', '\u{00c6}', '\u{00d8}', '\u{2122}', '\u{00b4}', '\u{00a8}', '\u{2260}', '\u{00c6}', '\u{00d8}',
'\u{221e}', '\u{00b1}', '\u{2264}', '\u{2265}', '\u{00a5}', '\u{00b5}', '\u{221e}', '\u{00b1}', '\u{2264}', '\u{2265}', '\u{00a5}', '\u{00b5}',
'\u{2202}', '\u{2211}', '\u{220f}', '\u{03c0}', '\u{222b}', '\u{00aa}', '\u{2202}', '\u{2211}', '\u{220f}', '\u{03c0}', '\u{222b}', '\u{00aa}',
'\u{00ba}', '\u{03a9}', '\u{00e6}', '\u{00f8}', '\u{00bf}', '\u{00a1}', '\u{00ba}', '\u{03a9}', '\u{00e6}', '\u{00f8}', '\u{00bf}', '\u{00a1}',
'\u{00ac}', '\u{221a}', '\u{0192}', '\u{2248}', '\u{2206}', '\u{00ab}', '\u{00ac}', '\u{221a}', '\u{0192}', '\u{2248}', '\u{2206}', '\u{00ab}',
'\u{00bb}', '\u{2026}', '\u{00a0}', '\u{00c0}', '\u{00c3}', '\u{00d5}', '\u{00bb}', '\u{2026}', '\u{00a0}', '\u{00c0}', '\u{00c3}', '\u{00d5}',
'\u{0152}', '\u{0153}', '\u{2013}', '\u{2014}', '\u{201c}', '\u{201d}', '\u{0152}', '\u{0153}', '\u{2013}', '\u{2014}', '\u{201c}', '\u{201d}',
'\u{2018}', '\u{2019}', '\u{00f7}', '\u{25ca}', '\u{00ff}', '\u{0178}', '\u{2018}', '\u{2019}', '\u{00f7}', '\u{25ca}', '\u{00ff}', '\u{0178}',
'\u{2044}', '\u{20ac}', '\u{2039}', '\u{203a}', '\u{fb01}', '\u{fb02}', '\u{2044}', '\u{20ac}', '\u{2039}', '\u{203a}', '\u{fb01}', '\u{fb02}',
'\u{2021}', '\u{00b7}', '\u{201a}', '\u{201e}', '\u{2030}', '\u{00c2}', '\u{2021}', '\u{00b7}', '\u{201a}', '\u{201e}', '\u{2030}', '\u{00c2}',
'\u{00ca}', '\u{00c1}', '\u{00cb}', '\u{00c8}', '\u{00cd}', '\u{00ce}', '\u{00ca}', '\u{00c1}', '\u{00cb}', '\u{00c8}', '\u{00cd}', '\u{00ce}',
'\u{00cf}', '\u{00cc}', '\u{00d3}', '\u{00d4}', '\u{f8ff}', '\u{00d2}', '\u{00cf}', '\u{00cc}', '\u{00d3}', '\u{00d4}', '\u{f8ff}', '\u{00d2}',
'\u{00da}', '\u{00db}', '\u{00d9}', '\u{0131}', '\u{02c6}', '\u{02dc}', '\u{00da}', '\u{00db}', '\u{00d9}', '\u{0131}', '\u{02c6}', '\u{02dc}',
'\u{00af}', '\u{02d8}', '\u{02d9}', '\u{02da}', '\u{00b8}', '\u{02dd}', '\u{00af}', '\u{02d8}', '\u{02d9}', '\u{02da}', '\u{00b8}', '\u{02dd}',
'\u{02db}', '\u{02c7}']; '\u{02db}', '\u{02c7}'];
#[test] #[test]
fn to_binsize_integrals() fn to_binsize_integrals()
{ {
assert_eq!(to_binsize(0), "empty"); assert_eq!(to_binsize(0), "empty");
assert_eq!(to_binsize(1), "1 byte"); assert_eq!(to_binsize(1), "1 byte");
assert_eq!(to_binsize(2), "2 bytes"); assert_eq!(to_binsize(2), "2 bytes");
assert_eq!(to_binsize(999), "999 bytes"); assert_eq!(to_binsize(999), "999 bytes");
assert_eq!(to_binsize(1000), "1kB"); assert_eq!(to_binsize(1000), "1kB");
assert_eq!(to_binsize(1000 * 7), "7kB"); assert_eq!(to_binsize(1000 * 7), "7kB");
assert_eq!(to_binsize(1000 * 1000), "1MB"); assert_eq!(to_binsize(1000 * 1000), "1MB");
assert_eq!(to_binsize(1000 * 1000 * 7), "7MB"); assert_eq!(to_binsize(1000 * 1000 * 7), "7MB");
assert_eq!(to_binsize(1000 * 1000 * 1000), "1GB"); assert_eq!(to_binsize(1000 * 1000 * 1000), "1GB");
assert_eq!(to_binsize(1000 * 1000 * 1000 * 7), "7GB"); assert_eq!(to_binsize(1000 * 1000 * 1000 * 7), "7GB");
assert_eq!(to_binsize(1000 * 1000 * 1000 * 1000), "1TB"); assert_eq!(to_binsize(1000 * 1000 * 1000 * 1000), "1TB");
assert_eq!(to_binsize(1000 * 1000 * 1000 * 1000 * 7), "7TB"); assert_eq!(to_binsize(1000 * 1000 * 1000 * 1000 * 7), "7TB");
} }
// EOF // EOF

View File

@ -2,37 +2,37 @@
impl Default for TransferMode impl Default for TransferMode
{ {
fn default() -> Self {TransferMode::Normal} fn default() -> Self {TransferMode::Normal}
} }
c_enum! { c_enum! {
/// A rendering style for many things. /// A rendering style for many things.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
pub enum TransferMode: u16 { pub enum TransferMode: u16 {
Normal = 0, Normal = 0,
FadeBlack = 1, FadeBlack = 1,
Invisibility = 2, Invisibility = 2,
Invisibility2 = 3, Invisibility2 = 3,
Pulsate = 4, Pulsate = 4,
Wobble = 5, Wobble = 5,
Wobble2 = 6, Wobble2 = 6,
Static = 7, Static = 7,
Static2 = 8, Static2 = 8,
Sky = 9, Sky = 9,
Smear = 10, Smear = 10,
StaticFade = 11, StaticFade = 11,
StaticPulse = 12, StaticPulse = 12,
FoldIn = 13, FoldIn = 13,
FoldOut = 14, FoldOut = 14,
SlideHorz = 15, SlideHorz = 15,
SlideHorz2 = 16, SlideHorz2 = 16,
SlideVert = 17, SlideVert = 17,
SlideVert2 = 18, SlideVert2 = 18,
Wander = 19, Wander = 19,
Wander2 = 20, Wander2 = 20,
BigSky = 21, BigSky = 21,
None = 0xFFFF, None = 0xFFFF,
} }
} }
// EOF // EOF

View File

@ -1,56 +1,56 @@
[ [
map::pnts::Point{x: Unit::from_bits(5120), y: Unit::from_bits(4096)}, map::pnts::Point{x: Unit::from_bits(5120), y: Unit::from_bits(4096)},
map::pnts::Point{x: Unit::from_bits(6144), y: Unit::from_bits(4096)}, map::pnts::Point{x: Unit::from_bits(6144), y: Unit::from_bits(4096)},
map::pnts::Point{x: Unit::from_bits(7168), y: Unit::from_bits(5120)}, map::pnts::Point{x: Unit::from_bits(7168), y: Unit::from_bits(5120)},
map::pnts::Point{x: Unit::from_bits(7168), y: Unit::from_bits(6144)}, map::pnts::Point{x: Unit::from_bits(7168), y: Unit::from_bits(6144)},
map::pnts::Point{x: Unit::from_bits(6144), y: Unit::from_bits(7168)}, map::pnts::Point{x: Unit::from_bits(6144), y: Unit::from_bits(7168)},
map::pnts::Point{x: Unit::from_bits(5120), y: Unit::from_bits(7168)}, map::pnts::Point{x: Unit::from_bits(5120), y: Unit::from_bits(7168)},
map::pnts::Point{x: Unit::from_bits(4096), y: Unit::from_bits(6144)}, map::pnts::Point{x: Unit::from_bits(4096), y: Unit::from_bits(6144)},
map::pnts::Point{x: Unit::from_bits(4096), y: Unit::from_bits(5120)}, map::pnts::Point{x: Unit::from_bits(4096), y: Unit::from_bits(5120)},
map::pnts::Point{x: Unit::from_bits(4608), y: Unit::from_bits(3072)}, map::pnts::Point{x: Unit::from_bits(4608), y: Unit::from_bits(3072)},
map::pnts::Point{x: Unit::from_bits(3072), y: Unit::from_bits(4608)}, map::pnts::Point{x: Unit::from_bits(3072), y: Unit::from_bits(4608)},
map::pnts::Point{x: Unit::from_bits(6656), y: Unit::from_bits(3072)}, map::pnts::Point{x: Unit::from_bits(6656), y: Unit::from_bits(3072)},
map::pnts::Point{x: Unit::from_bits(8192), y: Unit::from_bits(4608)}, map::pnts::Point{x: Unit::from_bits(8192), y: Unit::from_bits(4608)},
map::pnts::Point{x: Unit::from_bits(8192), y: Unit::from_bits(6656)}, map::pnts::Point{x: Unit::from_bits(8192), y: Unit::from_bits(6656)},
map::pnts::Point{x: Unit::from_bits(6656), y: Unit::from_bits(8192)}, map::pnts::Point{x: Unit::from_bits(6656), y: Unit::from_bits(8192)},
map::pnts::Point{x: Unit::from_bits(4608), y: Unit::from_bits(8192)}, map::pnts::Point{x: Unit::from_bits(4608), y: Unit::from_bits(8192)},
map::pnts::Point{x: Unit::from_bits(3072), y: Unit::from_bits(6656)}, map::pnts::Point{x: Unit::from_bits(3072), y: Unit::from_bits(6656)},
map::pnts::Point{x: Unit::from_bits(1536), y: Unit::from_bits(13312)}, map::pnts::Point{x: Unit::from_bits(1536), y: Unit::from_bits(13312)},
map::pnts::Point{x: Unit::from_bits(9728), y: Unit::from_bits(13312)}, map::pnts::Point{x: Unit::from_bits(9728), y: Unit::from_bits(13312)},
map::pnts::Point{x: Unit::from_bits(1536), y: Unit::from_bits(63488)}, map::pnts::Point{x: Unit::from_bits(1536), y: Unit::from_bits(63488)},
map::pnts::Point{x: Unit::from_bits(9728), y: Unit::from_bits(63488)}, map::pnts::Point{x: Unit::from_bits(9728), y: Unit::from_bits(63488)},
map::pnts::Point{x: Unit::from_bits(13312), y: Unit::from_bits(1536)}, map::pnts::Point{x: Unit::from_bits(13312), y: Unit::from_bits(1536)},
map::pnts::Point{x: Unit::from_bits(13312), y: Unit::from_bits(9728)}, map::pnts::Point{x: Unit::from_bits(13312), y: Unit::from_bits(9728)},
map::pnts::Point{x: Unit::from_bits(63488), y: Unit::from_bits(1536)}, map::pnts::Point{x: Unit::from_bits(63488), y: Unit::from_bits(1536)},
map::pnts::Point{x: Unit::from_bits(63488), y: Unit::from_bits(9728)}, map::pnts::Point{x: Unit::from_bits(63488), y: Unit::from_bits(9728)},
map::pnts::Point{x: Unit::from_bits(5120), y: Unit::from_bits(13312)}, map::pnts::Point{x: Unit::from_bits(5120), y: Unit::from_bits(13312)},
map::pnts::Point{x: Unit::from_bits(5120), y: Unit::from_bits(14336)}, map::pnts::Point{x: Unit::from_bits(5120), y: Unit::from_bits(14336)},
map::pnts::Point{x: Unit::from_bits(6144), y: Unit::from_bits(13312)}, map::pnts::Point{x: Unit::from_bits(6144), y: Unit::from_bits(13312)},
map::pnts::Point{x: Unit::from_bits(6144), y: Unit::from_bits(14336)}, map::pnts::Point{x: Unit::from_bits(6144), y: Unit::from_bits(14336)},
map::pnts::Point{x: Unit::from_bits(5120), y: Unit::from_bits(63488)}, map::pnts::Point{x: Unit::from_bits(5120), y: Unit::from_bits(63488)},
map::pnts::Point{x: Unit::from_bits(5120), y: Unit::from_bits(62464)}, map::pnts::Point{x: Unit::from_bits(5120), y: Unit::from_bits(62464)},
map::pnts::Point{x: Unit::from_bits(4096), y: Unit::from_bits(62464)}, map::pnts::Point{x: Unit::from_bits(4096), y: Unit::from_bits(62464)},
map::pnts::Point{x: Unit::from_bits(4096), y: Unit::from_bits(61440)}, map::pnts::Point{x: Unit::from_bits(4096), y: Unit::from_bits(61440)},
map::pnts::Point{x: Unit::from_bits(7168), y: Unit::from_bits(61440)}, map::pnts::Point{x: Unit::from_bits(7168), y: Unit::from_bits(61440)},
map::pnts::Point{x: Unit::from_bits(7168), y: Unit::from_bits(62464)}, map::pnts::Point{x: Unit::from_bits(7168), y: Unit::from_bits(62464)},
map::pnts::Point{x: Unit::from_bits(6144), y: Unit::from_bits(62464)}, map::pnts::Point{x: Unit::from_bits(6144), y: Unit::from_bits(62464)},
map::pnts::Point{x: Unit::from_bits(6144), y: Unit::from_bits(63488)}, map::pnts::Point{x: Unit::from_bits(6144), y: Unit::from_bits(63488)},
map::pnts::Point{x: Unit::from_bits(13312), y: Unit::from_bits(5120)}, map::pnts::Point{x: Unit::from_bits(13312), y: Unit::from_bits(5120)},
map::pnts::Point{x: Unit::from_bits(14336), y: Unit::from_bits(5120)}, map::pnts::Point{x: Unit::from_bits(14336), y: Unit::from_bits(5120)},
map::pnts::Point{x: Unit::from_bits(14336), y: Unit::from_bits(6144)}, map::pnts::Point{x: Unit::from_bits(14336), y: Unit::from_bits(6144)},
map::pnts::Point{x: Unit::from_bits(13312), y: Unit::from_bits(6144)}, map::pnts::Point{x: Unit::from_bits(13312), y: Unit::from_bits(6144)},
map::pnts::Point{x: Unit::from_bits(63488), y: Unit::from_bits(5120)}, map::pnts::Point{x: Unit::from_bits(63488), y: Unit::from_bits(5120)},
map::pnts::Point{x: Unit::from_bits(62464), y: Unit::from_bits(5120)}, map::pnts::Point{x: Unit::from_bits(62464), y: Unit::from_bits(5120)},
map::pnts::Point{x: Unit::from_bits(62464), y: Unit::from_bits(4096)}, map::pnts::Point{x: Unit::from_bits(62464), y: Unit::from_bits(4096)},
map::pnts::Point{x: Unit::from_bits(61440), y: Unit::from_bits(4096)}, map::pnts::Point{x: Unit::from_bits(61440), y: Unit::from_bits(4096)},
map::pnts::Point{x: Unit::from_bits(61440), y: Unit::from_bits(7168)}, map::pnts::Point{x: Unit::from_bits(61440), y: Unit::from_bits(7168)},
map::pnts::Point{x: Unit::from_bits(62464), y: Unit::from_bits(7168)}, map::pnts::Point{x: Unit::from_bits(62464), y: Unit::from_bits(7168)},
map::pnts::Point{x: Unit::from_bits(62464), y: Unit::from_bits(6144)}, map::pnts::Point{x: Unit::from_bits(62464), y: Unit::from_bits(6144)},
map::pnts::Point{x: Unit::from_bits(63488), y: Unit::from_bits(6144)}, map::pnts::Point{x: Unit::from_bits(63488), y: Unit::from_bits(6144)},
map::pnts::Point{x: Unit::from_bits(61440), y: Unit::from_bits(7680)}, map::pnts::Point{x: Unit::from_bits(61440), y: Unit::from_bits(7680)},
map::pnts::Point{x: Unit::from_bits(62464), y: Unit::from_bits(7680)}, map::pnts::Point{x: Unit::from_bits(62464), y: Unit::from_bits(7680)},
map::pnts::Point{x: Unit::from_bits(62464), y: Unit::from_bits(13312)}, map::pnts::Point{x: Unit::from_bits(62464), y: Unit::from_bits(13312)},
map::pnts::Point{x: Unit::from_bits(61440), y: Unit::from_bits(8704)}, map::pnts::Point{x: Unit::from_bits(61440), y: Unit::from_bits(8704)},
map::pnts::Point{x: Unit::from_bits(57344), y: Unit::from_bits(8704)}, map::pnts::Point{x: Unit::from_bits(57344), y: Unit::from_bits(8704)},
map::pnts::Point{x: Unit::from_bits(57344), y: Unit::from_bits(13312)} map::pnts::Point{x: Unit::from_bits(57344), y: Unit::from_bits(13312)}
] ]

View File

@ -1,434 +1,434 @@
[ [
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SAME_HEIGHT | flags: map::epnt::EndpointFlags::SAME_HEIGHT |
map::epnt::EndpointFlags::TRANSPARENT, map::epnt::EndpointFlags::TRANSPARENT,
hei_hi: Unit::from_bits(0), hei_hi: Unit::from_bits(0),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(5120), y: Unit::from_bits(4096)}, pos: map::pnts::Point{x: Unit::from_bits(5120), y: Unit::from_bits(4096)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SAME_HEIGHT | flags: map::epnt::EndpointFlags::SAME_HEIGHT |
map::epnt::EndpointFlags::TRANSPARENT, map::epnt::EndpointFlags::TRANSPARENT,
hei_hi: Unit::from_bits(0), hei_hi: Unit::from_bits(0),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(6144), y: Unit::from_bits(4096)}, pos: map::pnts::Point{x: Unit::from_bits(6144), y: Unit::from_bits(4096)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SAME_HEIGHT | flags: map::epnt::EndpointFlags::SAME_HEIGHT |
map::epnt::EndpointFlags::TRANSPARENT, map::epnt::EndpointFlags::TRANSPARENT,
hei_hi: Unit::from_bits(0), hei_hi: Unit::from_bits(0),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(7168), y: Unit::from_bits(5120)}, pos: map::pnts::Point{x: Unit::from_bits(7168), y: Unit::from_bits(5120)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SAME_HEIGHT | flags: map::epnt::EndpointFlags::SAME_HEIGHT |
map::epnt::EndpointFlags::TRANSPARENT, map::epnt::EndpointFlags::TRANSPARENT,
hei_hi: Unit::from_bits(0), hei_hi: Unit::from_bits(0),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(7168), y: Unit::from_bits(6144)}, pos: map::pnts::Point{x: Unit::from_bits(7168), y: Unit::from_bits(6144)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SAME_HEIGHT | flags: map::epnt::EndpointFlags::SAME_HEIGHT |
map::epnt::EndpointFlags::TRANSPARENT, map::epnt::EndpointFlags::TRANSPARENT,
hei_hi: Unit::from_bits(0), hei_hi: Unit::from_bits(0),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(6144), y: Unit::from_bits(7168)}, pos: map::pnts::Point{x: Unit::from_bits(6144), y: Unit::from_bits(7168)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SAME_HEIGHT | flags: map::epnt::EndpointFlags::SAME_HEIGHT |
map::epnt::EndpointFlags::TRANSPARENT, map::epnt::EndpointFlags::TRANSPARENT,
hei_hi: Unit::from_bits(0), hei_hi: Unit::from_bits(0),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(5120), y: Unit::from_bits(7168)}, pos: map::pnts::Point{x: Unit::from_bits(5120), y: Unit::from_bits(7168)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SAME_HEIGHT | flags: map::epnt::EndpointFlags::SAME_HEIGHT |
map::epnt::EndpointFlags::TRANSPARENT, map::epnt::EndpointFlags::TRANSPARENT,
hei_hi: Unit::from_bits(0), hei_hi: Unit::from_bits(0),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(4096), y: Unit::from_bits(6144)}, pos: map::pnts::Point{x: Unit::from_bits(4096), y: Unit::from_bits(6144)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SAME_HEIGHT | flags: map::epnt::EndpointFlags::SAME_HEIGHT |
map::epnt::EndpointFlags::TRANSPARENT, map::epnt::EndpointFlags::TRANSPARENT,
hei_hi: Unit::from_bits(0), hei_hi: Unit::from_bits(0),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(4096), y: Unit::from_bits(5120)}, pos: map::pnts::Point{x: Unit::from_bits(4096), y: Unit::from_bits(5120)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SAME_HEIGHT | flags: map::epnt::EndpointFlags::SAME_HEIGHT |
map::epnt::EndpointFlags::TRANSPARENT, map::epnt::EndpointFlags::TRANSPARENT,
hei_hi: Unit::from_bits(0), hei_hi: Unit::from_bits(0),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(4608), y: Unit::from_bits(3072)}, pos: map::pnts::Point{x: Unit::from_bits(4608), y: Unit::from_bits(3072)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SAME_HEIGHT | flags: map::epnt::EndpointFlags::SAME_HEIGHT |
map::epnt::EndpointFlags::TRANSPARENT, map::epnt::EndpointFlags::TRANSPARENT,
hei_hi: Unit::from_bits(0), hei_hi: Unit::from_bits(0),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(3072), y: Unit::from_bits(4608)}, pos: map::pnts::Point{x: Unit::from_bits(3072), y: Unit::from_bits(4608)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SAME_HEIGHT | flags: map::epnt::EndpointFlags::SAME_HEIGHT |
map::epnt::EndpointFlags::TRANSPARENT, map::epnt::EndpointFlags::TRANSPARENT,
hei_hi: Unit::from_bits(0), hei_hi: Unit::from_bits(0),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(6656), y: Unit::from_bits(3072)}, pos: map::pnts::Point{x: Unit::from_bits(6656), y: Unit::from_bits(3072)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SAME_HEIGHT | flags: map::epnt::EndpointFlags::SAME_HEIGHT |
map::epnt::EndpointFlags::TRANSPARENT, map::epnt::EndpointFlags::TRANSPARENT,
hei_hi: Unit::from_bits(0), hei_hi: Unit::from_bits(0),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(8192), y: Unit::from_bits(4608)}, pos: map::pnts::Point{x: Unit::from_bits(8192), y: Unit::from_bits(4608)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SAME_HEIGHT | flags: map::epnt::EndpointFlags::SAME_HEIGHT |
map::epnt::EndpointFlags::TRANSPARENT, map::epnt::EndpointFlags::TRANSPARENT,
hei_hi: Unit::from_bits(0), hei_hi: Unit::from_bits(0),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(8192), y: Unit::from_bits(6656)}, pos: map::pnts::Point{x: Unit::from_bits(8192), y: Unit::from_bits(6656)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SAME_HEIGHT | flags: map::epnt::EndpointFlags::SAME_HEIGHT |
map::epnt::EndpointFlags::TRANSPARENT, map::epnt::EndpointFlags::TRANSPARENT,
hei_hi: Unit::from_bits(0), hei_hi: Unit::from_bits(0),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(6656), y: Unit::from_bits(8192)}, pos: map::pnts::Point{x: Unit::from_bits(6656), y: Unit::from_bits(8192)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SAME_HEIGHT | flags: map::epnt::EndpointFlags::SAME_HEIGHT |
map::epnt::EndpointFlags::TRANSPARENT, map::epnt::EndpointFlags::TRANSPARENT,
hei_hi: Unit::from_bits(0), hei_hi: Unit::from_bits(0),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(4608), y: Unit::from_bits(8192)}, pos: map::pnts::Point{x: Unit::from_bits(4608), y: Unit::from_bits(8192)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SAME_HEIGHT | flags: map::epnt::EndpointFlags::SAME_HEIGHT |
map::epnt::EndpointFlags::TRANSPARENT, map::epnt::EndpointFlags::TRANSPARENT,
hei_hi: Unit::from_bits(0), hei_hi: Unit::from_bits(0),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(3072), y: Unit::from_bits(6656)}, pos: map::pnts::Point{x: Unit::from_bits(3072), y: Unit::from_bits(6656)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: -Unit::from_bits(9216), hei_hi: -Unit::from_bits(9216),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(1536), y: Unit::from_bits(13312)}, pos: map::pnts::Point{x: Unit::from_bits(1536), y: Unit::from_bits(13312)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: -Unit::from_bits(9216), hei_hi: -Unit::from_bits(9216),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(9728), y: Unit::from_bits(13312)}, pos: map::pnts::Point{x: Unit::from_bits(9728), y: Unit::from_bits(13312)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: -Unit::from_bits(9216), hei_hi: -Unit::from_bits(9216),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(1536), y: -Unit::from_bits(2048)}, pos: map::pnts::Point{x: Unit::from_bits(1536), y: -Unit::from_bits(2048)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: -Unit::from_bits(9216), hei_hi: -Unit::from_bits(9216),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(9728), y: -Unit::from_bits(2048)}, pos: map::pnts::Point{x: Unit::from_bits(9728), y: -Unit::from_bits(2048)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: -Unit::from_bits(9216), hei_hi: -Unit::from_bits(9216),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(13312), y: Unit::from_bits(1536)}, pos: map::pnts::Point{x: Unit::from_bits(13312), y: Unit::from_bits(1536)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: -Unit::from_bits(9216), hei_hi: -Unit::from_bits(9216),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: Unit::from_bits(13312), y: Unit::from_bits(9728)}, pos: map::pnts::Point{x: Unit::from_bits(13312), y: Unit::from_bits(9728)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: -Unit::from_bits(9216), hei_hi: -Unit::from_bits(9216),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: -Unit::from_bits(2048), y: Unit::from_bits(1536)}, pos: map::pnts::Point{x: -Unit::from_bits(2048), y: Unit::from_bits(1536)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: -Unit::from_bits(9216), hei_hi: -Unit::from_bits(9216),
hei_lo: Unit::from_bits(9216), hei_lo: Unit::from_bits(9216),
pos: map::pnts::Point{x: -Unit::from_bits(2048), y: Unit::from_bits(9728)}, pos: map::pnts::Point{x: -Unit::from_bits(2048), y: Unit::from_bits(9728)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: -Unit::from_bits(9216), hei_hi: -Unit::from_bits(9216),
hei_lo: -Unit::from_bits(8192), hei_lo: -Unit::from_bits(8192),
pos: map::pnts::Point{x: Unit::from_bits(5120), y: Unit::from_bits(13312)}, pos: map::pnts::Point{x: Unit::from_bits(5120), y: Unit::from_bits(13312)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: -Unit::from_bits(9216), hei_hi: -Unit::from_bits(9216),
hei_lo: -Unit::from_bits(8192), hei_lo: -Unit::from_bits(8192),
pos: map::pnts::Point{x: Unit::from_bits(5120), y: Unit::from_bits(14336)}, pos: map::pnts::Point{x: Unit::from_bits(5120), y: Unit::from_bits(14336)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: -Unit::from_bits(9216), hei_hi: -Unit::from_bits(9216),
hei_lo: -Unit::from_bits(8192), hei_lo: -Unit::from_bits(8192),
pos: map::pnts::Point{x: Unit::from_bits(6144), y: Unit::from_bits(13312)}, pos: map::pnts::Point{x: Unit::from_bits(6144), y: Unit::from_bits(13312)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: -Unit::from_bits(9216), hei_hi: -Unit::from_bits(9216),
hei_lo: -Unit::from_bits(8192), hei_lo: -Unit::from_bits(8192),
pos: map::pnts::Point{x: Unit::from_bits(6144), y: Unit::from_bits(14336)}, pos: map::pnts::Point{x: Unit::from_bits(6144), y: Unit::from_bits(14336)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(2047), hei_lo: Unit::from_bits(2047),
pos: map::pnts::Point{x: Unit::from_bits(5120), y: -Unit::from_bits(2048)}, pos: map::pnts::Point{x: Unit::from_bits(5120), y: -Unit::from_bits(2048)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(2047), hei_lo: Unit::from_bits(2047),
pos: map::pnts::Point{x: Unit::from_bits(5120), y: -Unit::from_bits(3072)}, pos: map::pnts::Point{x: Unit::from_bits(5120), y: -Unit::from_bits(3072)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(2047), hei_lo: Unit::from_bits(2047),
pos: map::pnts::Point{x: Unit::from_bits(4096), y: -Unit::from_bits(3072)}, pos: map::pnts::Point{x: Unit::from_bits(4096), y: -Unit::from_bits(3072)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(2047), hei_lo: Unit::from_bits(2047),
pos: map::pnts::Point{x: Unit::from_bits(4096), y: -Unit::from_bits(4096)}, pos: map::pnts::Point{x: Unit::from_bits(4096), y: -Unit::from_bits(4096)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(2047), hei_lo: Unit::from_bits(2047),
pos: map::pnts::Point{x: Unit::from_bits(7168), y: -Unit::from_bits(4096)}, pos: map::pnts::Point{x: Unit::from_bits(7168), y: -Unit::from_bits(4096)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(2047), hei_lo: Unit::from_bits(2047),
pos: map::pnts::Point{x: Unit::from_bits(7168), y: -Unit::from_bits(3072)}, pos: map::pnts::Point{x: Unit::from_bits(7168), y: -Unit::from_bits(3072)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(2047), hei_lo: Unit::from_bits(2047),
pos: map::pnts::Point{x: Unit::from_bits(6144), y: -Unit::from_bits(3072)}, pos: map::pnts::Point{x: Unit::from_bits(6144), y: -Unit::from_bits(3072)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(2047), hei_lo: Unit::from_bits(2047),
pos: map::pnts::Point{x: Unit::from_bits(6144), y: -Unit::from_bits(2048)}, pos: map::pnts::Point{x: Unit::from_bits(6144), y: -Unit::from_bits(2048)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: -Unit::from_bits(9216), hei_hi: -Unit::from_bits(9216),
hei_lo: -Unit::from_bits(8192), hei_lo: -Unit::from_bits(8192),
pos: map::pnts::Point{x: Unit::from_bits(13312), y: Unit::from_bits(5120)}, pos: map::pnts::Point{x: Unit::from_bits(13312), y: Unit::from_bits(5120)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: -Unit::from_bits(9216), hei_hi: -Unit::from_bits(9216),
hei_lo: -Unit::from_bits(8192), hei_lo: -Unit::from_bits(8192),
pos: map::pnts::Point{x: Unit::from_bits(14336), y: Unit::from_bits(5120)}, pos: map::pnts::Point{x: Unit::from_bits(14336), y: Unit::from_bits(5120)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: -Unit::from_bits(9216), hei_hi: -Unit::from_bits(9216),
hei_lo: -Unit::from_bits(8192), hei_lo: -Unit::from_bits(8192),
pos: map::pnts::Point{x: Unit::from_bits(14336), y: Unit::from_bits(6144)}, pos: map::pnts::Point{x: Unit::from_bits(14336), y: Unit::from_bits(6144)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: -Unit::from_bits(9216), hei_hi: -Unit::from_bits(9216),
hei_lo: -Unit::from_bits(8192), hei_lo: -Unit::from_bits(8192),
pos: map::pnts::Point{x: Unit::from_bits(13312), y: Unit::from_bits(6144)}, pos: map::pnts::Point{x: Unit::from_bits(13312), y: Unit::from_bits(6144)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(2047), hei_lo: Unit::from_bits(2047),
pos: map::pnts::Point{x: -Unit::from_bits(2048), y: Unit::from_bits(5120)}, pos: map::pnts::Point{x: -Unit::from_bits(2048), y: Unit::from_bits(5120)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(2047), hei_lo: Unit::from_bits(2047),
pos: map::pnts::Point{x: -Unit::from_bits(3072), y: Unit::from_bits(5120)}, pos: map::pnts::Point{x: -Unit::from_bits(3072), y: Unit::from_bits(5120)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(2047), hei_lo: Unit::from_bits(2047),
pos: map::pnts::Point{x: -Unit::from_bits(3072), y: Unit::from_bits(4096)}, pos: map::pnts::Point{x: -Unit::from_bits(3072), y: Unit::from_bits(4096)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(2047), hei_lo: Unit::from_bits(2047),
pos: map::pnts::Point{x: -Unit::from_bits(4096), y: Unit::from_bits(4096)}, pos: map::pnts::Point{x: -Unit::from_bits(4096), y: Unit::from_bits(4096)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(1024), hei_lo: Unit::from_bits(1024),
pos: map::pnts::Point{x: -Unit::from_bits(4096), y: Unit::from_bits(7168)}, pos: map::pnts::Point{x: -Unit::from_bits(4096), y: Unit::from_bits(7168)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(1024), hei_lo: Unit::from_bits(1024),
pos: map::pnts::Point{x: -Unit::from_bits(3072), y: Unit::from_bits(7168)}, pos: map::pnts::Point{x: -Unit::from_bits(3072), y: Unit::from_bits(7168)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(2047), hei_lo: Unit::from_bits(2047),
pos: map::pnts::Point{x: -Unit::from_bits(3072), y: Unit::from_bits(6144)}, pos: map::pnts::Point{x: -Unit::from_bits(3072), y: Unit::from_bits(6144)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(2047), hei_lo: Unit::from_bits(2047),
pos: map::pnts::Point{x: -Unit::from_bits(2048), y: Unit::from_bits(6144)}, pos: map::pnts::Point{x: -Unit::from_bits(2048), y: Unit::from_bits(6144)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(1024), hei_lo: Unit::from_bits(1024),
pos: map::pnts::Point{x: -Unit::from_bits(4096), y: Unit::from_bits(7680)}, pos: map::pnts::Point{x: -Unit::from_bits(4096), y: Unit::from_bits(7680)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(1024), hei_lo: Unit::from_bits(1024),
pos: map::pnts::Point{x: -Unit::from_bits(3072), y: Unit::from_bits(7680)}, pos: map::pnts::Point{x: -Unit::from_bits(3072), y: Unit::from_bits(7680)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(2047), hei_lo: Unit::from_bits(2047),
pos: map::pnts::Point{x: -Unit::from_bits(3072), y: Unit::from_bits(13312)}, pos: map::pnts::Point{x: -Unit::from_bits(3072), y: Unit::from_bits(13312)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(2047), hei_lo: Unit::from_bits(2047),
pos: map::pnts::Point{x: -Unit::from_bits(4096), y: Unit::from_bits(8704)}, pos: map::pnts::Point{x: -Unit::from_bits(4096), y: Unit::from_bits(8704)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(2047), hei_lo: Unit::from_bits(2047),
pos: map::pnts::Point{x: -Unit::from_bits(8192), y: Unit::from_bits(8704)}, pos: map::pnts::Point{x: -Unit::from_bits(8192), y: Unit::from_bits(8704)},
support: 0 support: 0
}, },
map::epnt::Endpoint{ map::epnt::Endpoint{
flags: map::epnt::EndpointFlags::SOLID | flags: map::epnt::EndpointFlags::SOLID |
map::epnt::EndpointFlags::SAME_HEIGHT, map::epnt::EndpointFlags::SAME_HEIGHT,
hei_hi: Unit::from_bits(1024), hei_hi: Unit::from_bits(1024),
hei_lo: Unit::from_bits(2047), hei_lo: Unit::from_bits(2047),
pos: map::pnts::Point{x: -Unit::from_bits(8192), y: Unit::from_bits(13312)}, pos: map::pnts::Point{x: -Unit::from_bits(8192), y: Unit::from_bits(13312)},
support: 0 support: 0
}, },
] ]

View File

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

View File

@ -1,146 +1,146 @@
vec![ vec![
map::term::Terminal { map::term::Terminal {
lines: 22, lines: 22,
groups: vec![ groups: vec![
map::trmg::Group { map::trmg::Group {
flags: map::trmg::GroupFlags::empty(), flags: map::trmg::GroupFlags::empty(),
ttype: map::trmg::GroupType::Unfinished, ttype: map::trmg::GroupType::Unfinished,
lines: 0, lines: 0,
text: "".to_owned() text: "".to_owned()
}, },
map::trmg::Group { map::trmg::Group {
flags: map::trmg::GroupFlags::empty(), flags: map::trmg::GroupFlags::empty(),
ttype: map::trmg::GroupType::Logon(1600), ttype: map::trmg::GroupType::Logon(1600),
lines: 1, lines: 1,
text: "\n".to_owned() text: "\n".to_owned()
}, },
map::trmg::Group { map::trmg::Group {
flags: map::trmg::GroupFlags::empty(), flags: map::trmg::GroupFlags::empty(),
ttype: map::trmg::GroupType::Pict(10011), ttype: map::trmg::GroupType::Pict(10011),
lines: 22, lines: 22,
text: "~text interface terminal malfunction error ~2992dud\n\nThings have gone terribly awry. Until now, I thought myself immortal, but now I know that is not true. There are things that can destroy me with the ease that I slaughtered the Pfhor naval garrison and the Western Arm of their Battle Group Seven. But in their final gasp they used a weapon that I thought they had retired, even Tycho tried to keep them from using it.\n\nNow I fear what that weapon has unleashed will destroy us. I once boasted to be able to count the atoms in a cloud, to understand them all, predict them, and so did I predict you, but this new chaos is entirely terrible, mindless, obeying rules that I don\'t comprehend. And it is hungry.\n\n".to_owned() text: "~text interface terminal malfunction error ~2992dud\n\nThings have gone terribly awry. Until now, I thought myself immortal, but now I know that is not true. There are things that can destroy me with the ease that I slaughtered the Pfhor naval garrison and the Western Arm of their Battle Group Seven. But in their final gasp they used a weapon that I thought they had retired, even Tycho tried to keep them from using it.\n\nNow I fear what that weapon has unleashed will destroy us. I once boasted to be able to count the atoms in a cloud, to understand them all, predict them, and so did I predict you, but this new chaos is entirely terrible, mindless, obeying rules that I don\'t comprehend. And it is hungry.\n\n".to_owned()
}, },
map::trmg::Group { map::trmg::Group {
flags: map::trmg::GroupFlags::empty(), flags: map::trmg::GroupFlags::empty(),
ttype: map::trmg::GroupType::Pict(10005), ttype: map::trmg::GroupType::Pict(10005),
lines: 21, lines: 21,
text: "~text interface terminal malfunction error ~2992dud\n\nIt\'s too bad, perhaps if I could have delayed the Pfhor from using their weapon, I could have sent you to explore the ruins of Lh\'owon, perhaps what you found would give us the answers that we now need so desparately: how to stop this chaos, the purpose of the station on which you\'re currently standing, and why the chaos hasn\'t come here yet.\n\nBut with each moment the chaos grows, I am doomed to die here, after so many triumphs. I have detected one ship nearby, which I can only guess is being commanded by Tycho. The Pfhor have entered the station, and if you can find a way onto their ship, you may be able to escape. To escape. To escape.\n\n".to_owned() text: "~text interface terminal malfunction error ~2992dud\n\nIt\'s too bad, perhaps if I could have delayed the Pfhor from using their weapon, I could have sent you to explore the ruins of Lh\'owon, perhaps what you found would give us the answers that we now need so desparately: how to stop this chaos, the purpose of the station on which you\'re currently standing, and why the chaos hasn\'t come here yet.\n\nBut with each moment the chaos grows, I am doomed to die here, after so many triumphs. I have detected one ship nearby, which I can only guess is being commanded by Tycho. The Pfhor have entered the station, and if you can find a way onto their ship, you may be able to escape. To escape. To escape.\n\n".to_owned()
}, },
map::trmg::Group { map::trmg::Group {
flags: map::trmg::GroupFlags::empty(), flags: map::trmg::GroupFlags::empty(),
ttype: map::trmg::GroupType::Pict(10006), ttype: map::trmg::GroupType::Pict(10006),
lines: 21, lines: 21,
text: "~text interface terminal malfunction error ~2992dud\n\nIt\'s too bad, perhaps if I could have delayed the Pfhor from using their weapon, I could have sent you to explore the ruins of Lh\'owon, perhaps what you found would give us the answers that we now need so desparately: how to stop this chaos, the purpose of the station on which you\'re currently standing, and why the chaos hasn\'t come here yet.\n\nBut with each moment the chaos grows, I am doomed to die here, after so many triumphs. I have detected one ship nearby, which I can only guess is being commanded by Tycho. The Pfhor have entered the station, and if you can find a way onto their ship, you may be able to escape. To escape. To escape.\n\n".to_owned() text: "~text interface terminal malfunction error ~2992dud\n\nIt\'s too bad, perhaps if I could have delayed the Pfhor from using their weapon, I could have sent you to explore the ruins of Lh\'owon, perhaps what you found would give us the answers that we now need so desparately: how to stop this chaos, the purpose of the station on which you\'re currently standing, and why the chaos hasn\'t come here yet.\n\nBut with each moment the chaos grows, I am doomed to die here, after so many triumphs. I have detected one ship nearby, which I can only guess is being commanded by Tycho. The Pfhor have entered the station, and if you can find a way onto their ship, you may be able to escape. To escape. To escape.\n\n".to_owned()
}, },
map::trmg::Group { map::trmg::Group {
flags: map::trmg::GroupFlags::empty(), flags: map::trmg::GroupFlags::empty(),
ttype: map::trmg::GroupType::Logoff(1600), ttype: map::trmg::GroupType::Logoff(1600),
lines: 1, lines: 1,
text: "\n".to_owned() text: "\n".to_owned()
} }
], ],
faces: vec![] faces: vec![]
}, },
map::term::Terminal { map::term::Terminal {
lines: 22, lines: 22,
groups: vec![ groups: vec![
map::trmg::Group { map::trmg::Group {
flags: map::trmg::GroupFlags::empty(), flags: map::trmg::GroupFlags::empty(),
ttype: map::trmg::GroupType::Unfinished, ttype: map::trmg::GroupType::Unfinished,
lines: 0, lines: 0,
text: "".to_owned() text: "".to_owned()
}, },
map::trmg::Group { map::trmg::Group {
flags: map::trmg::GroupFlags::empty(), flags: map::trmg::GroupFlags::empty(),
ttype: map::trmg::GroupType::Logon(1610), ttype: map::trmg::GroupType::Logon(1610),
lines: 1, lines: 1,
text: "\n".to_owned() text: "\n".to_owned()
}, },
map::trmg::Group { map::trmg::Group {
flags: map::trmg::GroupFlags::empty(), flags: map::trmg::GroupFlags::empty(),
ttype: map::trmg::GroupType::Pict(10008), ttype: map::trmg::GroupType::Pict(10008),
lines: 14, lines: 14,
text: "\n\n\nspurious interrupt\nunauthorized access\ninformation contained\n\n<header>\ninformation retrieval aspect 30-f\n<body>\n~eibat weapo` 3941\nsiklicar 21`perie1ces\nclwaa\n\n".to_owned() text: "\n\n\nspurious interrupt\nunauthorized access\ninformation contained\n\n<header>\ninformation retrieval aspect 30-f\n<body>\n~eibat weapo` 3941\nsiklicar 21`perie1ces\nclwaa\n\n".to_owned()
}, },
map::trmg::Group { map::trmg::Group {
flags: map::trmg::GroupFlags::empty(), flags: map::trmg::GroupFlags::empty(),
ttype: map::trmg::GroupType::Logoff(1610), ttype: map::trmg::GroupType::Logoff(1610),
lines: 1, lines: 1,
text: "\n".to_owned() text: "\n".to_owned()
} }
], ],
faces: vec![] faces: vec![]
}, },
map::term::Terminal { map::term::Terminal {
lines: 22, lines: 22,
groups: vec![ groups: vec![
map::trmg::Group { map::trmg::Group {
flags: map::trmg::GroupFlags::empty(), flags: map::trmg::GroupFlags::empty(),
ttype: map::trmg::GroupType::Unfinished, ttype: map::trmg::GroupType::Unfinished,
lines: 0, lines: 0,
text: "".to_owned() text: "".to_owned()
}, },
map::trmg::Group { map::trmg::Group {
flags: map::trmg::GroupFlags::empty(), flags: map::trmg::GroupFlags::empty(),
ttype: map::trmg::GroupType::Logon(1619), ttype: map::trmg::GroupType::Logon(1619),
lines: 1, lines: 1,
text: "".to_owned() text: "".to_owned()
}, },
map::trmg::Group { map::trmg::Group {
flags: map::trmg::GroupFlags::empty(), flags: map::trmg::GroupFlags::empty(),
ttype: map::trmg::GroupType::Pict(10007), ttype: map::trmg::GroupType::Pict(10007),
lines: 16, lines: 16,
text: "\n\n\nthousands are sailing\nthe same self\t\tthe only self\n\nself willed the peril of a thousand fates\n\na line of infinite ends\t\tfinite finishing\nthe one remains oblique and pure\n\narching to the single point of consciousness\n\nfind yourself\nstarting back\n".to_owned() text: "\n\n\nthousands are sailing\nthe same self\t\tthe only self\n\nself willed the peril of a thousand fates\n\na line of infinite ends\t\tfinite finishing\nthe one remains oblique and pure\n\narching to the single point of consciousness\n\nfind yourself\nstarting back\n".to_owned()
}, },
map::trmg::Group { map::trmg::Group {
flags: map::trmg::GroupFlags::empty(), flags: map::trmg::GroupFlags::empty(),
ttype: map::trmg::GroupType::Logoff(1619), ttype: map::trmg::GroupType::Logoff(1619),
lines: 1, lines: 1,
text: "".to_owned() text: "".to_owned()
}, },
map::trmg::Group { map::trmg::Group {
flags: map::trmg::GroupFlags::empty(), flags: map::trmg::GroupFlags::empty(),
ttype: map::trmg::GroupType::TeleInter(1), ttype: map::trmg::GroupType::TeleInter(1),
lines: 1, lines: 1,
text: "".to_owned() text: "".to_owned()
} }
], ],
faces: vec![ faces: vec![
map::trmf::Face { map::trmf::Face {
start: 6, start: 6,
face: 0, face: 0,
color: 1 color: 1
} }
] ]
}, },
map::term::Terminal { map::term::Terminal {
lines: 22, lines: 22,
groups: vec![ groups: vec![
map::trmg::Group { map::trmg::Group {
flags: map::trmg::GroupFlags::empty(), flags: map::trmg::GroupFlags::empty(),
ttype: map::trmg::GroupType::Unfinished, ttype: map::trmg::GroupType::Unfinished,
lines: 0, lines: 0,
text: "".to_owned() text: "".to_owned()
}, },
map::trmg::Group { map::trmg::Group {
flags: map::trmg::GroupFlags::empty(), flags: map::trmg::GroupFlags::empty(),
ttype: map::trmg::GroupType::Logon(1619), ttype: map::trmg::GroupType::Logon(1619),
lines: 1, lines: 1,
text: "".to_owned() text: "".to_owned()
}, },
map::trmg::Group { map::trmg::Group {
flags: map::trmg::GroupFlags::empty(), flags: map::trmg::GroupFlags::empty(),
ttype: map::trmg::GroupType::Pict(10007), ttype: map::trmg::GroupType::Pict(10007),
lines: 84, lines: 84,
text: "534954210001000034EE724C6175020000000016\n000000001E48617473204F666620746F20456967\n6874204E696E657465656E2E736974946AAA0000\n0000000000000000000000000000000000000000\n00000000FFFFFFFF53495444534954210100AE1A\nCAD4AE1ACAD40000000000003468000000000000\n34680000CAF90000000000004A21534954210001\n00003468724C617502000000001600000D0D1A48\n617473204F666620746F204569676874204E696E\n657465656E0001537E94897D0000000000000000\n000000000000000000000000000000000000FFFF\nFFFF7363653232362EB00100AE1AA710AE1ACAC4\n0000087A0000738C0000057100002E7177DCF747\n000000000000EFB60B005D796C65E775CA8EB023\n47B984114E5646B8114E5847B8E498849F479E93\nE347FBB5EC08CB8F30B24A23C7098B3CCBC31B2D\nC2093D4EB81EDE2897F09530326087377E86279C\n3C7BF192A31CCFC988BFD7D993A747669C1C2313\n4638E164CA927072FC24CF8F1CA79EFC0566A33C\n2F3D0302A02F3BC28D3C2748648403AF029F2380\n95318331965FC5D8227C99FD62F78617DE1918ED\n6EC311B368530FEB69375AA82C5BBDE3E0F0D1E2\n5ECE8BC343C5DE23CEC07071CF91417BD8B60737\n984CFF8E1EB2BBBB376DF816BA3E622FCFCBF867\nBE5EFD7981B1A3A7A0FA3DAD4BF36516D4BEC4DA\nD8BC5A8D6A79F00A6B79A051D916AA871D7F88CA\nB550178D9602E760B7F656A37A1EA1CC05D4968B\nFA92BD9CBD3C775FCD6EB0E566B38335535C772C\n7C5B483D065BF2E01E1DF71E61F53CE46C03D782\n7D0BD3B7FB1B6CCB186BCE0D33B66EBD7061EB56\n6676754D4E7675B14CA170FD7AA1A0592727B52D\n8C9D3E8D1DC61E3BA6DD626CDF3E1D55C6D6AFC7\nBE9831B031B6249F1F1FC7A53D9FBF74097BC7DA\nB5E3E31B37B2A55D5DE3E36082E207D3F26A6E5F\n7785162791F485EF70EEA6BC5D702E70EAAF5A9C\nD7852983F8477AFE2AAD4824485C7000FBAE552A\nF5F6F6CFF2BCE3F2332072DC599E8A8CE74BF50B\n6DFE8DCC64CC4F85E13A759E87206765BF55DADD\nE086CB1B22C7CFF4734780516B7D63A565F5BEEE\nC9F857DA3C45AB7C40AC534F5B1677B8F0A4544A\nCAC86BA8BB6424718366556724DCF727AC7269DB\n9A0B57AF5E11DEEFF4DC1F944D7CB75CEA4D4BF9\n4FAC7E47F3C63F532101BBEF9E7FEBFC9713BB4A\n80C5093D798D96D4606319167881FA9E96A8C817\nE270A9F48113FE454FDCA045896F5B5C48F51DE5\n93C83F6B95B78BF03AADBC05915120643C818374\nB917DCA4A5B7B42D5FC16E15DFA2A76628839400\n6746524E53A62665FCC3DC1A4E5353B1B84EEBC0\n51B3ACBE9B9419EEB7635CA7AC72052453963508\n12C1BC3A59292D4BA4904122EC3EA29AF0827BD4\n069B284A258B53481076384B591548DF8B6F6A43\n8413C4B78981A02326AA0A518107C20B536A438E\n02901E32404F2912149CDC1F92CEB3C4AAE2FB64\nAA44A594F347A9CA4F860D3482F48240A9C80BEE\n5247E272217C8E8C925233C492BA326A32A54EE4\n0BCD61EF97440B1A77995507C664AAC2818C5C22\n83D0E7FBEF50CE75C22A17C09830AC8E8008EF1E\n99AE13DCD7668AF00EA2E387C10CE5A41825DF1B\nADD336734CC4B364F8DE0C3543D3771DE8483CAF\nE679506A26521BE78B789A0C11CE472F441EE3DA\n3465234908629D4A06C9FBD494334801B232709B\nB2BE47910F01C6949AA5B6314A22A450ABD1C954\n3AC74604658BC67C71B2A21444EC324F5AA3B364\n9E295590B9B1FEC191F2765871B6B473AA54AEC0\n8A2A4768D9899433F860564B7D9052E5BC729BCC\nDAE13E6839B3DDB62B2E1FA8D3818E1AAA432176\n2AB2079087D5480252C703A2041F643751A2DC1F\nD6ECDE4A83323E0A2745E452758F3223659D1778\n3EFA37B52591EB8EDEA7BCF47C118E090FED78D0\nA4C44F79DEE64E00FF7D81B60852CAD704BA5404\n88BFC8A0BE3D585673454366E74A20BC49CC6FF0\n9C00A1A4A82EDB43D48737D7F60E0CCDF91201A5\n5A1D622C58825E4182337050071011C751C94821\nC94910016AA8F8FA5C13E5E228503034554D6A9F\nE24E8522FDD210A10E3DEAA5011715083ACFE9C6\n10217AA136E25CA3FCA748915D215A760E084D37\n7F2E802781D35AFD090751297CA1DBDC918A6A3E\nDAE51A757C464CA602C522FF243CB2F0CA393EFF\nD27A9CC3C08349FCF4145971B9D17A3EE2F8F1C2\nEB10A7FFF6C73FF806E3FEFD53C0287F38D1A91F\n9B6BD83E66BCB6735B19042B766EDBBB07986773\n65EDDBFC3C5368368B2C7760EE8800E21DFB933E\nAD280D8DBCF9B65DDC32A2FF317875C8191AFC1F\n000E00EB37EAB4CECBEBECBC0CCF06793DBD2EB3\n".to_owned() text: "534954210001000034EE724C6175020000000016\n000000001E48617473204F666620746F20456967\n6874204E696E657465656E2E736974946AAA0000\n0000000000000000000000000000000000000000\n00000000FFFFFFFF53495444534954210100AE1A\nCAD4AE1ACAD40000000000003468000000000000\n34680000CAF90000000000004A21534954210001\n00003468724C617502000000001600000D0D1A48\n617473204F666620746F204569676874204E696E\n657465656E0001537E94897D0000000000000000\n000000000000000000000000000000000000FFFF\nFFFF7363653232362EB00100AE1AA710AE1ACAC4\n0000087A0000738C0000057100002E7177DCF747\n000000000000EFB60B005D796C65E775CA8EB023\n47B984114E5646B8114E5847B8E498849F479E93\nE347FBB5EC08CB8F30B24A23C7098B3CCBC31B2D\nC2093D4EB81EDE2897F09530326087377E86279C\n3C7BF192A31CCFC988BFD7D993A747669C1C2313\n4638E164CA927072FC24CF8F1CA79EFC0566A33C\n2F3D0302A02F3BC28D3C2748648403AF029F2380\n95318331965FC5D8227C99FD62F78617DE1918ED\n6EC311B368530FEB69375AA82C5BBDE3E0F0D1E2\n5ECE8BC343C5DE23CEC07071CF91417BD8B60737\n984CFF8E1EB2BBBB376DF816BA3E622FCFCBF867\nBE5EFD7981B1A3A7A0FA3DAD4BF36516D4BEC4DA\nD8BC5A8D6A79F00A6B79A051D916AA871D7F88CA\nB550178D9602E760B7F656A37A1EA1CC05D4968B\nFA92BD9CBD3C775FCD6EB0E566B38335535C772C\n7C5B483D065BF2E01E1DF71E61F53CE46C03D782\n7D0BD3B7FB1B6CCB186BCE0D33B66EBD7061EB56\n6676754D4E7675B14CA170FD7AA1A0592727B52D\n8C9D3E8D1DC61E3BA6DD626CDF3E1D55C6D6AFC7\nBE9831B031B6249F1F1FC7A53D9FBF74097BC7DA\nB5E3E31B37B2A55D5DE3E36082E207D3F26A6E5F\n7785162791F485EF70EEA6BC5D702E70EAAF5A9C\nD7852983F8477AFE2AAD4824485C7000FBAE552A\nF5F6F6CFF2BCE3F2332072DC599E8A8CE74BF50B\n6DFE8DCC64CC4F85E13A759E87206765BF55DADD\nE086CB1B22C7CFF4734780516B7D63A565F5BEEE\nC9F857DA3C45AB7C40AC534F5B1677B8F0A4544A\nCAC86BA8BB6424718366556724DCF727AC7269DB\n9A0B57AF5E11DEEFF4DC1F944D7CB75CEA4D4BF9\n4FAC7E47F3C63F532101BBEF9E7FEBFC9713BB4A\n80C5093D798D96D4606319167881FA9E96A8C817\nE270A9F48113FE454FDCA045896F5B5C48F51DE5\n93C83F6B95B78BF03AADBC05915120643C818374\nB917DCA4A5B7B42D5FC16E15DFA2A76628839400\n6746524E53A62665FCC3DC1A4E5353B1B84EEBC0\n51B3ACBE9B9419EEB7635CA7AC72052453963508\n12C1BC3A59292D4BA4904122EC3EA29AF0827BD4\n069B284A258B53481076384B591548DF8B6F6A43\n8413C4B78981A02326AA0A518107C20B536A438E\n02901E32404F2912149CDC1F92CEB3C4AAE2FB64\nAA44A594F347A9CA4F860D3482F48240A9C80BEE\n5247E272217C8E8C925233C492BA326A32A54EE4\n0BCD61EF97440B1A77995507C664AAC2818C5C22\n83D0E7FBEF50CE75C22A17C09830AC8E8008EF1E\n99AE13DCD7668AF00EA2E387C10CE5A41825DF1B\nADD336734CC4B364F8DE0C3543D3771DE8483CAF\nE679506A26521BE78B789A0C11CE472F441EE3DA\n3465234908629D4A06C9FBD494334801B232709B\nB2BE47910F01C6949AA5B6314A22A450ABD1C954\n3AC74604658BC67C71B2A21444EC324F5AA3B364\n9E295590B9B1FEC191F2765871B6B473AA54AEC0\n8A2A4768D9899433F860564B7D9052E5BC729BCC\nDAE13E6839B3DDB62B2E1FA8D3818E1AAA432176\n2AB2079087D5480252C703A2041F643751A2DC1F\nD6ECDE4A83323E0A2745E452758F3223659D1778\n3EFA37B52591EB8EDEA7BCF47C118E090FED78D0\nA4C44F79DEE64E00FF7D81B60852CAD704BA5404\n88BFC8A0BE3D585673454366E74A20BC49CC6FF0\n9C00A1A4A82EDB43D48737D7F60E0CCDF91201A5\n5A1D622C58825E4182337050071011C751C94821\nC94910016AA8F8FA5C13E5E228503034554D6A9F\nE24E8522FDD210A10E3DEAA5011715083ACFE9C6\n10217AA136E25CA3FCA748915D215A760E084D37\n7F2E802781D35AFD090751297CA1DBDC918A6A3E\nDAE51A757C464CA602C522FF243CB2F0CA393EFF\nD27A9CC3C08349FCF4145971B9D17A3EE2F8F1C2\nEB10A7FFF6C73FF806E3FEFD53C0287F38D1A91F\n9B6BD83E66BCB6735B19042B766EDBBB07986773\n65EDDBFC3C5368368B2C7760EE8800E21DFB933E\nAD280D8DBCF9B65DDC32A2FF317875C8191AFC1F\n000E00EB37EAB4CECBEBECBC0CCF06793DBD2EB3\n".to_owned()
}, },
map::trmg::Group { map::trmg::Group {
flags: map::trmg::GroupFlags::empty(), flags: map::trmg::GroupFlags::empty(),
ttype: map::trmg::GroupType::Logoff(1619), ttype: map::trmg::GroupType::Logoff(1619),
lines: 1, lines: 1,
text: "".to_owned() text: "".to_owned()
} }
], ],
faces: vec![] faces: vec![]
} }
] ]

File diff suppressed because it is too large Load Diff

View File

@ -1,258 +1,258 @@
[ [
Color8::new(255, 255, 255), Color8::new(255, 255, 255),
Color8::new(7, 9, 19 ), Color8::new(7, 9, 19 ),
Color8::new(7, 18, 42 ), Color8::new(7, 18, 42 ),
Color8::new(61, 66, 20 ), Color8::new(61, 66, 20 ),
Color8::new(39, 12, 18 ), Color8::new(39, 12, 18 ),
Color8::new(28, 35, 47 ), Color8::new(28, 35, 47 ),
Color8::new(52, 52, 62 ), Color8::new(52, 52, 62 ),
Color8::new(14, 5, 6 ), Color8::new(14, 5, 6 ),
Color8::new(48, 61, 79 ), Color8::new(48, 61, 79 ),
Color8::new(44, 21, 32 ), Color8::new(44, 21, 32 ),
Color8::new(220, 220, 1 ), Color8::new(220, 220, 1 ),
Color8::new(16, 19, 28 ), Color8::new(16, 19, 28 ),
Color8::new(29, 41, 59 ), Color8::new(29, 41, 59 ),
Color8::new(70, 82, 94 ), Color8::new(70, 82, 94 ),
Color8::new(240, 241, 242), Color8::new(240, 241, 242),
Color8::new(138, 141, 149), Color8::new(138, 141, 149),
Color8::new(211, 212, 213), Color8::new(211, 212, 213),
Color8::new(130, 129, 132), Color8::new(130, 129, 132),
Color8::new(73, 74, 82 ), Color8::new(73, 74, 82 ),
Color8::new(94, 97, 102), Color8::new(94, 97, 102),
Color8::new(28, 23, 40 ), Color8::new(28, 23, 40 ),
Color8::new(72, 52, 61 ), Color8::new(72, 52, 61 ),
Color8::new(149, 151, 156), Color8::new(149, 151, 156),
Color8::new(85, 83, 2 ), Color8::new(85, 83, 2 ),
Color8::new(111, 111, 3 ), Color8::new(111, 111, 3 ),
Color8::new(224, 225, 225), Color8::new(224, 225, 225),
Color8::new(52, 26, 39 ), Color8::new(52, 26, 39 ),
Color8::new(57, 18, 19 ), Color8::new(57, 18, 19 ),
Color8::new(97, 98, 3 ), Color8::new(97, 98, 3 ),
Color8::new(23, 10, 17 ), Color8::new(23, 10, 17 ),
Color8::new(137, 137, 1 ), Color8::new(137, 137, 1 ),
Color8::new(56, 55, 1 ), Color8::new(56, 55, 1 ),
Color8::new(194, 193, 3 ), Color8::new(194, 193, 3 ),
Color8::new(160, 160, 160), Color8::new(160, 160, 160),
Color8::new(173, 172, 11 ), Color8::new(173, 172, 11 ),
Color8::new(151, 155, 24 ), Color8::new(151, 155, 24 ),
Color8::new(195, 193, 194), Color8::new(195, 193, 194),
Color8::new(41, 49, 73 ), Color8::new(41, 49, 73 ),
Color8::new(202, 203, 205), Color8::new(202, 203, 205),
Color8::new(137, 126, 21 ), Color8::new(137, 126, 21 ),
Color8::new(123, 122, 17 ), Color8::new(123, 122, 17 ),
Color8::new(71, 75, 28 ), Color8::new(71, 75, 28 ),
Color8::new(66, 63, 64 ), Color8::new(66, 63, 64 ),
Color8::new(30, 30, 6 ), Color8::new(30, 30, 6 ),
Color8::new(166, 166, 6 ), Color8::new(166, 166, 6 ),
Color8::new(64, 39, 48 ), Color8::new(64, 39, 48 ),
Color8::new(46, 33, 41 ), Color8::new(46, 33, 41 ),
Color8::new(56, 37, 77 ), Color8::new(56, 37, 77 ),
Color8::new(50, 41, 51 ), Color8::new(50, 41, 51 ),
Color8::new(111, 112, 116), Color8::new(111, 112, 116),
Color8::new(110, 117, 63 ), Color8::new(110, 117, 63 ),
Color8::new(72, 25, 29 ), Color8::new(72, 25, 29 ),
Color8::new(98, 105, 85 ), Color8::new(98, 105, 85 ),
Color8::new(71, 60, 5 ), Color8::new(71, 60, 5 ),
Color8::new(185, 183, 6 ), Color8::new(185, 183, 6 ),
Color8::new(31, 15, 24 ), Color8::new(31, 15, 24 ),
Color8::new(150, 154, 48 ), Color8::new(150, 154, 48 ),
Color8::new(45, 41, 7 ), Color8::new(45, 41, 7 ),
Color8::new(84, 92, 103), Color8::new(84, 92, 103),
Color8::new(124, 129, 26 ), Color8::new(124, 129, 26 ),
Color8::new(35, 29, 61 ), Color8::new(35, 29, 61 ),
Color8::new(57, 70, 87 ), Color8::new(57, 70, 87 ),
Color8::new(116, 119, 130), Color8::new(116, 119, 130),
Color8::new(51, 45, 26 ), Color8::new(51, 45, 26 ),
Color8::new(69, 62, 95 ), Color8::new(69, 62, 95 ),
Color8::new(86, 90, 43 ), Color8::new(86, 90, 43 ),
Color8::new(125, 119, 5 ), Color8::new(125, 119, 5 ),
Color8::new(95, 99, 25 ), Color8::new(95, 99, 25 ),
Color8::new(135, 135, 139), Color8::new(135, 135, 139),
Color8::new(54, 61, 34 ), Color8::new(54, 61, 34 ),
Color8::new(66, 71, 36 ), Color8::new(66, 71, 36 ),
Color8::new(144, 145, 12 ), Color8::new(144, 145, 12 ),
Color8::new(87, 71, 23 ), Color8::new(87, 71, 23 ),
Color8::new(163, 168, 35 ), Color8::new(163, 168, 35 ),
Color8::new(206, 207, 3 ), Color8::new(206, 207, 3 ),
Color8::new(186, 189, 23 ), Color8::new(186, 189, 23 ),
Color8::new(97, 96, 49 ), Color8::new(97, 96, 49 ),
Color8::new(29, 42, 32 ), Color8::new(29, 42, 32 ),
Color8::new(136, 141, 36 ), Color8::new(136, 141, 36 ),
Color8::new(96, 104, 115), Color8::new(96, 104, 115),
Color8::new(110, 115, 26 ), Color8::new(110, 115, 26 ),
Color8::new(113, 81, 82 ), Color8::new(113, 81, 82 ),
Color8::new(88, 71, 71 ), Color8::new(88, 71, 71 ),
Color8::new(83, 46, 47 ), Color8::new(83, 46, 47 ),
Color8::new(87, 89, 15 ), Color8::new(87, 89, 15 ),
Color8::new(172, 176, 181), Color8::new(172, 176, 181),
Color8::new(91, 77, 84 ), Color8::new(91, 77, 84 ),
Color8::new(231, 232, 235), Color8::new(231, 232, 235),
Color8::new(255, 127, 255), Color8::new(255, 127, 255),
Color8::new(4, 3, 4 ), Color8::new(4, 3, 4 ),
Color8::new(4, 9, 21 ), Color8::new(4, 9, 21 ),
Color8::new(1, 4, 10 ), Color8::new(1, 4, 10 ),
Color8::new(1, 2, 3 ), Color8::new(1, 2, 3 ),
Color8::new(141, 144, 16 ), Color8::new(141, 144, 16 ),
Color8::new(1, 0, 0 ), Color8::new(1, 0, 0 ),
Color8::new(25, 30, 40 ), Color8::new(25, 30, 40 ),
Color8::new(14, 17, 27 ), Color8::new(14, 17, 27 ),
Color8::new(152, 155, 162), Color8::new(152, 155, 162),
Color8::new(0, 3, 7 ), Color8::new(0, 3, 7 ),
Color8::new(27, 33, 43 ), Color8::new(27, 33, 43 ),
Color8::new(4, 4, 7 ), Color8::new(4, 4, 7 ),
Color8::new(5, 1, 2 ), Color8::new(5, 1, 2 ),
Color8::new(3, 12, 32 ), Color8::new(3, 12, 32 ),
Color8::new(0, 0, 1 ), Color8::new(0, 0, 1 ),
Color8::new(17, 17, 19 ), Color8::new(17, 17, 19 ),
Color8::new(69, 66, 71 ), Color8::new(69, 66, 71 ),
Color8::new(0, 1, 5 ), Color8::new(0, 1, 5 ),
Color8::new(6, 7, 15 ), Color8::new(6, 7, 15 ),
Color8::new(1, 0, 2 ), Color8::new(1, 0, 2 ),
Color8::new(3, 2, 8 ), Color8::new(3, 2, 8 ),
Color8::new(0, 1, 1 ), Color8::new(0, 1, 1 ),
Color8::new(20, 25, 36 ), Color8::new(20, 25, 36 ),
Color8::new(24, 7, 10 ), Color8::new(24, 7, 10 ),
Color8::new(7, 8, 18 ), Color8::new(7, 8, 18 ),
Color8::new(32, 46, 65 ), Color8::new(32, 46, 65 ),
Color8::new(17, 15, 29 ), Color8::new(17, 15, 29 ),
Color8::new(10, 12, 23 ), Color8::new(10, 12, 23 ),
Color8::new(6, 10, 23 ), Color8::new(6, 10, 23 ),
Color8::new(23, 16, 25 ), Color8::new(23, 16, 25 ),
Color8::new(0, 1, 2 ), Color8::new(0, 1, 2 ),
Color8::new(1, 6, 15 ), Color8::new(1, 6, 15 ),
Color8::new(3, 4, 12 ), Color8::new(3, 4, 12 ),
Color8::new(1, 1, 2 ), Color8::new(1, 1, 2 ),
Color8::new(66, 75, 87 ), Color8::new(66, 75, 87 ),
Color8::new(161, 163, 170), Color8::new(161, 163, 170),
Color8::new(20, 6, 6 ), Color8::new(20, 6, 6 ),
Color8::new(1, 2, 8 ), Color8::new(1, 2, 8 ),
Color8::new(2, 4, 8 ), Color8::new(2, 4, 8 ),
Color8::new(6, 7, 16 ), Color8::new(6, 7, 16 ),
Color8::new(2, 5, 13 ), Color8::new(2, 5, 13 ),
Color8::new(1, 13, 32 ), Color8::new(1, 13, 32 ),
Color8::new(17, 22, 35 ), Color8::new(17, 22, 35 ),
Color8::new(0, 0, 4 ), Color8::new(0, 0, 4 ),
Color8::new(39, 24, 37 ), Color8::new(39, 24, 37 ),
Color8::new(24, 35, 56 ), Color8::new(24, 35, 56 ),
Color8::new(5, 4, 11 ), Color8::new(5, 4, 11 ),
Color8::new(5, 6, 15 ), Color8::new(5, 6, 15 ),
Color8::new(5, 10, 27 ), Color8::new(5, 10, 27 ),
Color8::new(2, 5, 10 ), Color8::new(2, 5, 10 ),
Color8::new(37, 50, 69 ), Color8::new(37, 50, 69 ),
Color8::new(1, 4, 14 ), Color8::new(1, 4, 14 ),
Color8::new(1, 1, 1 ), Color8::new(1, 1, 1 ),
Color8::new(16, 24, 48 ), Color8::new(16, 24, 48 ),
Color8::new(2, 1, 4 ), Color8::new(2, 1, 4 ),
Color8::new(14, 19, 40 ), Color8::new(14, 19, 40 ),
Color8::new(0, 5, 12 ), Color8::new(0, 5, 12 ),
Color8::new(0, 1, 4 ), Color8::new(0, 1, 4 ),
Color8::new(7, 3, 3 ), Color8::new(7, 3, 3 ),
Color8::new(41, 55, 71 ), Color8::new(41, 55, 71 ),
Color8::new(2, 0, 0 ), Color8::new(2, 0, 0 ),
Color8::new(35, 11, 11 ), Color8::new(35, 11, 11 ),
Color8::new(11, 14, 27 ), Color8::new(11, 14, 27 ),
Color8::new(0, 1, 3 ), Color8::new(0, 1, 3 ),
Color8::new(1, 13, 30 ), Color8::new(1, 13, 30 ),
Color8::new(6, 18, 39 ), Color8::new(6, 18, 39 ),
Color8::new(196, 196, 7 ), Color8::new(196, 196, 7 ),
Color8::new(1, 1, 7 ), Color8::new(1, 1, 7 ),
Color8::new(2, 11, 28 ), Color8::new(2, 11, 28 ),
Color8::new(3, 1, 3 ), Color8::new(3, 1, 3 ),
Color8::new(5, 17, 39 ), Color8::new(5, 17, 39 ),
Color8::new(4, 6, 14 ), Color8::new(4, 6, 14 ),
Color8::new(19, 17, 36 ), Color8::new(19, 17, 36 ),
Color8::new(2, 7, 15 ), Color8::new(2, 7, 15 ),
Color8::new(0, 3, 8 ), Color8::new(0, 3, 8 ),
Color8::new(13, 10, 19 ), Color8::new(13, 10, 19 ),
Color8::new(143, 149, 157), Color8::new(143, 149, 157),
Color8::new(10, 4, 5 ), Color8::new(10, 4, 5 ),
Color8::new(8, 6, 14 ), Color8::new(8, 6, 14 ),
Color8::new(32, 21, 35 ), Color8::new(32, 21, 35 ),
Color8::new(17, 7, 13 ), Color8::new(17, 7, 13 ),
Color8::new(45, 56, 79 ), Color8::new(45, 56, 79 ),
Color8::new(3, 10, 25 ), Color8::new(3, 10, 25 ),
Color8::new(2, 3, 6 ), Color8::new(2, 3, 6 ),
Color8::new(34, 42, 68 ), Color8::new(34, 42, 68 ),
Color8::new(2, 15, 34 ), Color8::new(2, 15, 34 ),
Color8::new(10, 21, 43 ), Color8::new(10, 21, 43 ),
Color8::new(0, 2, 5 ), Color8::new(0, 2, 5 ),
Color8::new(15, 17, 27 ), Color8::new(15, 17, 27 ),
Color8::new(7, 3, 6 ), Color8::new(7, 3, 6 ),
Color8::new(2, 10, 23 ), Color8::new(2, 10, 23 ),
Color8::new(22, 19, 32 ), Color8::new(22, 19, 32 ),
Color8::new(58, 59, 7 ), Color8::new(58, 59, 7 ),
Color8::new(8, 3, 9 ), Color8::new(8, 3, 9 ),
Color8::new(6, 3, 8 ), Color8::new(6, 3, 8 ),
Color8::new(4, 14, 30 ), Color8::new(4, 14, 30 ),
Color8::new(2, 2, 4 ), Color8::new(2, 2, 4 ),
Color8::new(0, 3, 9 ), Color8::new(0, 3, 9 ),
Color8::new(51, 64, 82 ), Color8::new(51, 64, 82 ),
Color8::new(2, 3, 10 ), Color8::new(2, 3, 10 ),
Color8::new(4, 12, 29 ), Color8::new(4, 12, 29 ),
Color8::new(18, 22, 31 ), Color8::new(18, 22, 31 ),
Color8::new(2, 4, 13 ), Color8::new(2, 4, 13 ),
Color8::new(192, 192, 193), Color8::new(192, 192, 193),
Color8::new(3, 0, 0 ), Color8::new(3, 0, 0 ),
Color8::new(5, 6, 14 ), Color8::new(5, 6, 14 ),
Color8::new(2, 2, 9 ), Color8::new(2, 2, 9 ),
Color8::new(51, 63, 74 ), Color8::new(51, 63, 74 ),
Color8::new(13, 16, 33 ), Color8::new(13, 16, 33 ),
Color8::new(5, 8, 19 ), Color8::new(5, 8, 19 ),
Color8::new(23, 27, 38 ), Color8::new(23, 27, 38 ),
Color8::new(23, 28, 54 ), Color8::new(23, 28, 54 ),
Color8::new(1, 4, 11 ), Color8::new(1, 4, 11 ),
Color8::new(33, 40, 49 ), Color8::new(33, 40, 49 ),
Color8::new(48, 59, 71 ), Color8::new(48, 59, 71 ),
Color8::new(64, 26, 36 ), Color8::new(64, 26, 36 ),
Color8::new(116, 121, 19 ), Color8::new(116, 121, 19 ),
Color8::new(13, 16, 26 ), Color8::new(13, 16, 26 ),
Color8::new(3, 6, 11 ), Color8::new(3, 6, 11 ),
Color8::new(5, 2, 2 ), Color8::new(5, 2, 2 ),
Color8::new(7, 9, 18 ), Color8::new(7, 9, 18 ),
Color8::new(11, 7, 16 ), Color8::new(11, 7, 16 ),
Color8::new(0, 2, 6 ), Color8::new(0, 2, 6 ),
Color8::new(3, 3, 3 ), Color8::new(3, 3, 3 ),
Color8::new(2, 6, 16 ), Color8::new(2, 6, 16 ),
Color8::new(13, 12, 13 ), Color8::new(13, 12, 13 ),
Color8::new(6, 8, 18 ), Color8::new(6, 8, 18 ),
Color8::new(1, 11, 25 ), Color8::new(1, 11, 25 ),
Color8::new(18, 13, 24 ), Color8::new(18, 13, 24 ),
Color8::new(1, 0, 1 ), Color8::new(1, 0, 1 ),
Color8::new(0, 0, 3 ), Color8::new(0, 0, 3 ),
Color8::new(20, 27, 41 ), Color8::new(20, 27, 41 ),
Color8::new(7, 15, 35 ), Color8::new(7, 15, 35 ),
Color8::new(129, 135, 145), Color8::new(129, 135, 145),
Color8::new(1, 11, 26 ), Color8::new(1, 11, 26 ),
Color8::new(9, 10, 20 ), Color8::new(9, 10, 20 ),
Color8::new(1, 2, 4 ), Color8::new(1, 2, 4 ),
Color8::new(5, 5, 15 ), Color8::new(5, 5, 15 ),
Color8::new(8, 9, 9 ), Color8::new(8, 9, 9 ),
Color8::new(16, 6, 10 ), Color8::new(16, 6, 10 ),
Color8::new(7, 6, 17 ), Color8::new(7, 6, 17 ),
Color8::new(33, 41, 28 ), Color8::new(33, 41, 28 ),
Color8::new(15, 19, 31 ), Color8::new(15, 19, 31 ),
Color8::new(2, 1, 1 ), Color8::new(2, 1, 1 ),
Color8::new(13, 13, 24 ), Color8::new(13, 13, 24 ),
Color8::new(59, 70, 81 ), Color8::new(59, 70, 81 ),
Color8::new(33, 33, 39 ), Color8::new(33, 33, 39 ),
Color8::new(1, 8, 18 ), Color8::new(1, 8, 18 ),
Color8::new(8, 10, 20 ), Color8::new(8, 10, 20 ),
Color8::new(3, 5, 16 ), Color8::new(3, 5, 16 ),
Color8::new(114, 116, 10 ), Color8::new(114, 116, 10 ),
Color8::new(23, 32, 47 ), Color8::new(23, 32, 47 ),
Color8::new(147, 145, 150), Color8::new(147, 145, 150),
Color8::new(2, 8, 20 ), Color8::new(2, 8, 20 ),
Color8::new(1, 5, 11 ), Color8::new(1, 5, 11 ),
Color8::new(42, 52, 63 ), Color8::new(42, 52, 63 ),
Color8::new(13, 6, 11 ), Color8::new(13, 6, 11 ),
Color8::new(79, 83, 93 ), Color8::new(79, 83, 93 ),
Color8::new(195, 195, 198), Color8::new(195, 195, 198),
Color8::new(66, 21, 24 ), Color8::new(66, 21, 24 ),
Color8::new(7, 13, 29 ), Color8::new(7, 13, 29 ),
Color8::new(11, 14, 23 ), Color8::new(11, 14, 23 ),
Color8::new(12, 5, 8 ), Color8::new(12, 5, 8 ),
Color8::new(39, 47, 58 ), Color8::new(39, 47, 58 ),
Color8::new(1, 9, 22 ), Color8::new(1, 9, 22 ),
Color8::new(7, 6, 10 ), Color8::new(7, 6, 10 ),
Color8::new(0, 0, 0 ) Color8::new(0, 0, 0 )
] ]

View File

@ -1,11 +1,11 @@
const RANDOM: [&[u8]; 7] = [ const RANDOM: [&[u8]; 7] = [
include_bytes!("rand/random1.in"), include_bytes!("rand/random1.in"),
include_bytes!("rand/random2.in"), include_bytes!("rand/random2.in"),
include_bytes!("rand/random3.in"), include_bytes!("rand/random3.in"),
include_bytes!("rand/random4.in"), include_bytes!("rand/random4.in"),
include_bytes!("rand/random5.in"), include_bytes!("rand/random5.in"),
include_bytes!("rand/random6.in"), include_bytes!("rand/random6.in"),
include_bytes!("rand/random7.in") include_bytes!("rand/random7.in")
]; ];
// EOF // EOF

View File

@ -4,74 +4,74 @@ include!("data/rand.rs");
fn defl_gzip(inp: &[u8], out: &[u8]) fn defl_gzip(inp: &[u8], out: &[u8])
{ {
let b = &inp[defl::load_gzip_header(inp).unwrap()..]; let b = &inp[defl::load_gzip_header(inp).unwrap()..];
assert_eq!(defl::load_deflate(b).unwrap().1, out.to_vec()); assert_eq!(defl::load_deflate(b).unwrap().1, out.to_vec());
} }
fn defl_alice(inp: &[u8]) fn defl_alice(inp: &[u8])
{ {
const OUTPUT: &[u8] = include_bytes!("data/defl/alice.out"); const OUTPUT: &[u8] = include_bytes!("data/defl/alice.out");
defl_gzip(inp, OUTPUT); defl_gzip(inp, OUTPUT);
} }
#[test] #[test]
fn defl_alice_1() fn defl_alice_1()
{ {
const INPUT: &[u8] = include_bytes!("data/defl/alice1.in"); const INPUT: &[u8] = include_bytes!("data/defl/alice1.in");
defl_alice(INPUT); defl_alice(INPUT);
} }
#[test] #[test]
fn defl_alice_2() fn defl_alice_2()
{ {
const INPUT: &[u8] = include_bytes!("data/defl/alice2.in"); const INPUT: &[u8] = include_bytes!("data/defl/alice2.in");
defl_alice(INPUT); defl_alice(INPUT);
} }
#[test] #[test]
#[ignore] #[ignore]
fn defl_shapes() fn defl_shapes()
{ {
const INPUT: &[u8] = include_bytes!("data/defl/Shapes.in"); const INPUT: &[u8] = include_bytes!("data/defl/Shapes.in");
const OUTPUT: &[u8] = include_bytes!("data/m2/Shapes"); const OUTPUT: &[u8] = include_bytes!("data/m2/Shapes");
defl_gzip(INPUT, OUTPUT); defl_gzip(INPUT, OUTPUT);
} }
#[test] #[test]
fn defl_good_gzip_headers() fn defl_good_gzip_headers()
{ {
defl::load_gzip_header(include_bytes!("data/gz/ok1.in")).unwrap(); defl::load_gzip_header(include_bytes!("data/gz/ok1.in")).unwrap();
defl::load_gzip_header(include_bytes!("data/gz/ok2.in")).unwrap(); defl::load_gzip_header(include_bytes!("data/gz/ok2.in")).unwrap();
defl::load_gzip_header(include_bytes!("data/gz/ok3.in")).unwrap(); defl::load_gzip_header(include_bytes!("data/gz/ok3.in")).unwrap();
} }
#[test] #[test]
fn defl_bad_gzip_headers() fn defl_bad_gzip_headers()
{ {
for inp in &RANDOM { for inp in &RANDOM {
assert!(defl::load_gzip_header(inp).is_err()); assert!(defl::load_gzip_header(inp).is_err());
} }
assert!(defl::load_gzip_header(include_bytes!("data/gz/bad1.in")).is_err()); assert!(defl::load_gzip_header(include_bytes!("data/gz/bad1.in")).is_err());
assert!(defl::load_gzip_header(include_bytes!("data/gz/bad2.in")).is_err()); assert!(defl::load_gzip_header(include_bytes!("data/gz/bad2.in")).is_err());
assert!(defl::load_gzip_header(include_bytes!("data/gz/bad3.in")).is_err()); assert!(defl::load_gzip_header(include_bytes!("data/gz/bad3.in")).is_err());
assert!(defl::load_gzip_header(include_bytes!("data/gz/bad4.in")).is_err()); assert!(defl::load_gzip_header(include_bytes!("data/gz/bad4.in")).is_err());
assert!(defl::load_gzip_header(include_bytes!("data/gz/bad5.in")).is_err()); assert!(defl::load_gzip_header(include_bytes!("data/gz/bad5.in")).is_err());
assert!(defl::load_gzip_header(include_bytes!("data/gz/bad6.in")).is_err()); assert!(defl::load_gzip_header(include_bytes!("data/gz/bad6.in")).is_err());
assert!(defl::load_gzip_header(include_bytes!("data/gz/bad7.in")).is_err()); assert!(defl::load_gzip_header(include_bytes!("data/gz/bad7.in")).is_err());
} }
#[test] #[test]
#[allow(unused_must_use)] #[allow(unused_must_use)]
fn defl_must_not_panic() fn defl_must_not_panic()
{ {
for inp in &RANDOM { for inp in &RANDOM {
defl::load_deflate(inp); defl::load_deflate(inp);
} }
} }
// EOF // EOF

View File

@ -5,126 +5,126 @@ include!("data/rand.rs");
#[test] #[test]
fn read_minf_must_process() fn read_minf_must_process()
{ {
let inp = include_bytes!("data/map/minf.in"); let inp = include_bytes!("data/map/minf.in");
let out = include!("data/map/minf.out"); let out = include!("data/map/minf.out");
assert_eq!(map::minf::read(inp).unwrap(), out); assert_eq!(map::minf::read(inp).unwrap(), out);
} }
#[test] #[test]
fn read_epnt_must_process() fn read_epnt_must_process()
{ {
let inp = include_bytes!("data/map/epnt.in"); let inp = include_bytes!("data/map/epnt.in");
let inp = bin::rd_array(inp, map::epnt::read).unwrap(); let inp = bin::rd_array(inp, map::epnt::read).unwrap();
let out = include!("data/map/epnt.out.2").to_vec(); let out = include!("data/map/epnt.out.2").to_vec();
assert_eq!(inp, out); assert_eq!(inp, out);
let inp = map::epnt::to_pnts(&inp); let inp = map::epnt::to_pnts(&inp);
let out = include!("data/map/epnt.out.1").to_vec(); let out = include!("data/map/epnt.out.1").to_vec();
assert_eq!(inp, out); assert_eq!(inp, out);
} }
#[test] #[test]
fn read_term_must_process() fn read_term_must_process()
{ {
let inp = include_bytes!("data/map/term.in"); let inp = include_bytes!("data/map/term.in");
let out = include!("data/map/term.out"); let out = include!("data/map/term.out");
let inp = bin::rd_array(inp, map::term::read).unwrap(); let inp = bin::rd_array(inp, map::term::read).unwrap();
// for better debug output, we iterate over each item // for better debug output, we iterate over each item
assert_eq!(inp.len(), out.len()); assert_eq!(inp.len(), out.len());
for (itrm, otrm) in inp.iter().zip(&out) { for (itrm, otrm) in inp.iter().zip(&out) {
assert_eq!(itrm.groups.len(), otrm.groups.len()); assert_eq!(itrm.groups.len(), otrm.groups.len());
for (igrp, ogrp) in itrm.groups.iter().zip(&otrm.groups) { for (igrp, ogrp) in itrm.groups.iter().zip(&otrm.groups) {
assert_eq!(igrp, ogrp); assert_eq!(igrp, ogrp);
} }
assert_eq!(itrm.faces.len(), otrm.faces.len()); assert_eq!(itrm.faces.len(), otrm.faces.len());
for (ifac, ofac) in itrm.faces.iter().zip(&otrm.faces) { for (ifac, ofac) in itrm.faces.iter().zip(&otrm.faces) {
assert_eq!(ifac, ofac); assert_eq!(ifac, ofac);
} }
} }
} }
#[test] #[test]
fn map_m2() fn map_m2()
{ {
let inp = include_bytes!("data/m2/Map"); let inp = include_bytes!("data/m2/Map");
let mut rd = std::io::BufReader::new(&inp[..]); let mut rd = std::io::BufReader::new(&inp[..]);
let mp = map::head::read(&mut rd).unwrap(); let mp = map::head::read(&mut rd).unwrap();
let en = map::entr::read_all(&mp).unwrap(); let en = map::entr::read_all(&mp).unwrap();
assert!(map::data::read_all(mp.head(), &en).is_ok()); assert!(map::data::read_all(mp.head(), &en).is_ok());
} }
#[test] #[test]
#[ignore] #[ignore]
fn map_full_check() fn map_full_check()
{ {
use maraiah::{bin::OptU16, use maraiah::{bin::OptU16,
map::{data::*, lins::*, lite::*, ltfn::*, minf::*, objs::*, map::{data::*, lins::*, lite::*, ltfn::*, minf::*, objs::*,
plac::*, pnts::*, poly::*}, plac::*, pnts::*, poly::*},
xfer::TransferMode}; xfer::TransferMode};
use std::collections::BTreeMap; use std::collections::BTreeMap;
let inp = include_bytes!("data/map/testmap.in"); let inp = include_bytes!("data/map/testmap.in");
let mut rd = std::io::BufReader::new(&inp[..]); let mut rd = std::io::BufReader::new(&inp[..]);
let mp = map::head::read(&mut rd).unwrap(); let mp = map::head::read(&mut rd).unwrap();
let en = map::entr::read_all(&mp).unwrap(); let en = map::entr::read_all(&mp).unwrap();
let ed = map::data::read_all(mp.head(), &en).unwrap(); let ed = map::data::read_all(mp.head(), &en).unwrap();
let mut out = BTreeMap::new(); let mut out = BTreeMap::new();
out.insert(0, include!("data/map/testmap.out")); out.insert(0, include!("data/map/testmap.out"));
assert_eq!(out, ed); assert_eq!(out, ed);
} }
#[test] #[test]
fn map_must_not_process() fn map_must_not_process()
{ {
for inp in &RANDOM { for inp in &RANDOM {
bin::rd_array(inp, map::fxpx::read).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::lins::read).err().unwrap();
bin::rd_array(inp, map::lite::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::lite::read_old).err().unwrap();
bin::rd_array(inp, map::medi::read).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::mnpx::read).err().unwrap();
bin::rd_array(inp, map::note::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::objs::read).err().unwrap();
bin::rd_array(inp, map::plat::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).err().unwrap();
bin::rd_array(inp, map::poly::read_old).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::prpx::read).err().unwrap();
bin::rd_array(inp, map::sids::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::sids::read_old).err().unwrap();
bin::rd_array(inp, map::term::read).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::trmg::read).err().unwrap();
bin::rd_array(inp, map::wppx::read).err().unwrap(); bin::rd_array(inp, map::wppx::read).err().unwrap();
map::minf::read(inp).err().unwrap(); map::minf::read(inp).err().unwrap();
map::minf::read_old(inp).err().unwrap(); map::minf::read_old(inp).err().unwrap();
} }
} }
#[test] #[test]
fn map_must_not_panic() fn map_must_not_panic()
{ {
for inp in &RANDOM { for inp in &RANDOM {
drop(bin::rd_array(inp, map::ambi::read)); drop(bin::rd_array(inp, map::ambi::read));
drop(bin::rd_array(inp, map::bonk::read)); drop(bin::rd_array(inp, map::bonk::read));
drop(bin::rd_array(inp, map::epnt::read)); drop(bin::rd_array(inp, map::epnt::read));
drop(bin::rd_array(inp, map::iidx::read)); drop(bin::rd_array(inp, map::iidx::read));
drop(bin::rd_array(inp, map::plac::read)); drop(bin::rd_array(inp, map::plac::read));
drop(bin::rd_array(inp, map::pxpx::read)); drop(bin::rd_array(inp, map::pxpx::read));
drop(bin::rd_array(inp, map::trmf::read)); drop(bin::rd_array(inp, map::trmf::read));
} }
} }
// EOF // EOF

View File

@ -5,25 +5,25 @@ include!("data/rand.rs");
#[test] #[test]
fn machdr_must_process() fn machdr_must_process()
{ {
const INPUT: &[u8] = include_bytes!("data/misc/macbin.in"); const INPUT: &[u8] = include_bytes!("data/misc/macbin.in");
let mut inp = std::io::Cursor::new(INPUT); let mut inp = std::io::Cursor::new(INPUT);
assert_eq!(machdr::skip_macbin(&mut inp), true); assert_eq!(machdr::skip_macbin(&mut inp), true);
assert_eq!(machdr::skip_mac_header(&mut inp), true); assert_eq!(machdr::skip_mac_header(&mut inp), true);
// FIXME: missing test data for applesingle // FIXME: missing test data for applesingle
} }
#[test] #[test]
fn machdr_must_not_process() fn machdr_must_not_process()
{ {
for rinp in &RANDOM { for rinp in &RANDOM {
let mut inp = std::io::Cursor::new(rinp); let mut inp = std::io::Cursor::new(rinp);
assert_eq!(machdr::skip_macbin(&mut inp), false); assert_eq!(machdr::skip_macbin(&mut inp), false);
assert_eq!(machdr::skip_apple_single(&mut inp), false); assert_eq!(machdr::skip_apple_single(&mut inp), false);
assert_eq!(machdr::skip_mac_header(&mut inp), false); assert_eq!(machdr::skip_mac_header(&mut inp), false);
} }
} }
// EOF // EOF

View File

@ -5,19 +5,19 @@ include!("data/rand.rs");
#[test] #[test]
fn get_clut_must_process() fn get_clut_must_process()
{ {
const INPUT: &[u8] = include_bytes!("data/pict/clut.in"); const INPUT: &[u8] = include_bytes!("data/pict/clut.in");
const OUTPUT: [Color8; 256] = include!("data/pict/clut.out"); const OUTPUT: [Color8; 256] = include!("data/pict/clut.out");
assert_eq!(pict::clut::read(INPUT).unwrap(), (OUTPUT.to_vec(), 2056)); assert_eq!(pict::clut::read(INPUT).unwrap(), (OUTPUT.to_vec(), 2056));
} }
#[test] #[test]
fn pict_must_not_process() fn pict_must_not_process()
{ {
for inp in &RANDOM { for inp in &RANDOM {
assert!(pict::clut::read(inp).is_err()); assert!(pict::clut::read(inp).is_err());
assert!(pict::read(inp).is_err()); assert!(pict::read(inp).is_err());
} }
} }
// EOF // EOF

View File

@ -5,15 +5,15 @@ include!("data/rand.rs");
#[test] #[test]
fn shp_must_not_process() fn shp_must_not_process()
{ {
for inp in &RANDOM { for inp in &RANDOM {
assert!(shp::bmap::read(inp).is_err()); assert!(shp::bmap::read(inp).is_err());
assert!(shp::coll::read(inp).is_err()); assert!(shp::coll::read(inp).is_err());
assert!(shp::fram::read(inp).is_err()); assert!(shp::fram::read(inp).is_err());
assert!(shp::sequ::read(inp).is_err()); assert!(shp::sequ::read(inp).is_err());
let mut inp = std::io::BufReader::new(&inp[..]); let mut inp = std::io::BufReader::new(&inp[..]);
assert!(shp::read(&mut inp).is_err()); assert!(shp::read(&mut inp).is_err());
} }
} }
// EOF // EOF

View File

@ -5,13 +5,13 @@ include!("data/rand.rs");
#[test] #[test]
fn snd_must_not_process() fn snd_must_not_process()
{ {
for inp in &RANDOM { for inp in &RANDOM {
assert!(snd::defs::read(inp).is_err()); assert!(snd::defs::read(inp).is_err());
assert!(snd::snds::read(inp).is_err()); assert!(snd::snds::read(inp).is_err());
let mut inp = std::io::BufReader::new(&inp[..]); let mut inp = std::io::BufReader::new(&inp[..]);
assert!(snd::read(&mut inp).is_err()); assert!(snd::read(&mut inp).is_err());
} }
} }
// EOF // EOF

View File

@ -11,72 +11,72 @@ set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_INCLUDE_CURRENT_DIR ON)
if(NOT MSVC) if(NOT MSVC)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Werror") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Werror")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
endif() endif()
find_package( find_package(
Qt5 5.6.0 Qt5 5.6.0
CONFIG CONFIG
REQUIRED REQUIRED
COMPONENTS Core Widgets COMPONENTS Core Widgets
) )
add_library( add_library(
maraiah-tycho-hermes maraiah-tycho-hermes
STATIC STATIC
$ENV{OUT_DIR}/bindings.cc $ENV{OUT_DIR}/bindings.cc
$ENV{OUT_DIR}/bindings.h $ENV{OUT_DIR}/bindings.h
cc/interface.h cc/interface.h
cc/main.cc cc/main.cc
cc/mapmodel.cc cc/mapmodel.cc
cc/mapprops.cc cc/mapprops.cc
cc/mapview.cc cc/mapview.cc
cc/menu.cc cc/menu.cc
cc/project.cc cc/project.cc
cc/tycho.h cc/tycho.h
resources/resources.qrc resources/resources.qrc
ui/about.ui ui/about.ui
ui/license.ui ui/license.ui
ui/mapprops.ui ui/mapprops.ui
ui/mapview.ui ui/mapview.ui
ui/menu.ui ui/menu.ui
ui/points.ui ui/points.ui
ui/project.ui ui/project.ui
) )
set_target_properties( set_target_properties(
maraiah-tycho-hermes maraiah-tycho-hermes
PROPERTIES PROPERTIES
CXX_STANDARD 17 CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON CXX_STANDARD_REQUIRED ON
) )
target_include_directories( target_include_directories(
maraiah-tycho-hermes maraiah-tycho-hermes
PUBLIC PUBLIC
$ENV{OUT_DIR} $ENV{OUT_DIR}
cc cc
) )
target_link_libraries( target_link_libraries(
maraiah-tycho-hermes maraiah-tycho-hermes
Qt5::Core Qt5::Core
Qt5::Widgets Qt5::Widgets
) )
target_compile_definitions( target_compile_definitions(
maraiah-tycho-hermes maraiah-tycho-hermes
PUBLIC PUBLIC
-DQT_DEPRECATED_WARNINGS -DQT_DEPRECATED_WARNINGS
-DQT_STRICT_ITERATORS -DQT_STRICT_ITERATORS
-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT -DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT
) )
file( file(
GENERATE GENERATE
OUTPUT link.txt OUTPUT link.txt
CONTENT CONTENT
"$<TARGET_PROPERTY:Qt5::Core,IMPORTED_LOCATION_RELEASE> "$<TARGET_PROPERTY:Qt5::Core,IMPORTED_LOCATION_RELEASE>
$<TARGET_PROPERTY:Qt5::Widgets,IMPORTED_LOCATION_RELEASE> $<TARGET_PROPERTY:Qt5::Widgets,IMPORTED_LOCATION_RELEASE>
$<TARGET_PROPERTY:Qt5::Gui,IMPORTED_LOCATION_RELEASE>" $<TARGET_PROPERTY:Qt5::Gui,IMPORTED_LOCATION_RELEASE>"

View File

@ -1,69 +1,69 @@
{ {
"beforeHeader": "interface.h", "beforeHeader": "interface.h",
"cppFile": "", "cppFile": "",
"rust": { "rust": {
"dir": "", "dir": "",
"interfaceModule": "ffi", "interfaceModule": "ffi",
"implementationModule": "gui" "implementationModule": "gui"
}, },
"objects": { "objects": {
"IMapModel": { "IMapModel": {
"type": "List", "type": "List",
"baseClass": "IProjectModel", "baseClass": "IProjectModel",
"functions": { "functions": {
"open": { "open": {
"return": "bool", "return": "bool",
"mut": true, "mut": true,
"arguments": [ "arguments": [
{"name": "path", "type": "QString"} {"name": "path", "type": "QString"}
] ]
}, },
"save": { "save": {
"return": "bool", "return": "bool",
"mut": false "mut": false
}, },
"saveAs": { "saveAs": {
"return": "bool", "return": "bool",
"mut": false, "mut": false,
"arguments": [ "arguments": [
{"name": "path", "type": "QString"} {"name": "path", "type": "QString"}
] ]
}, },
"propIcon": { "propIcon": {
"return": "QString", "return": "QString",
"mut": false, "mut": false,
"arguments": [ "arguments": [
{"name": "index", "type": "quint16"} {"name": "index", "type": "quint16"}
] ]
}, },
"deselect": { "deselect": {
"return": "void", "return": "void",
"mut": true "mut": true
}, },
"select": { "select": {
"return": "void", "return": "void",
"mut": true, "mut": true,
"arguments": [ "arguments": [
{"name": "index", "type": "quint16"} {"name": "index", "type": "quint16"}
] ]
} }
}, },
"properties": { "properties": {
"dirty": {"type": "bool", "write": true} "dirty": {"type": "bool", "write": true}
}, },
"itemProperties": { "itemProperties": {
"propIndex": {"type": "quint64", "roles": [["display"]]} "propIndex": {"type": "quint64", "roles": [["display"]]}
} }
}, },
"IMapView": { "IMapView": {
"type": "Object", "type": "Object",
"baseClass": "IProjectView", "baseClass": "IProjectView",
"functions": { "functions": {
}, },
"properties": { "properties": {
}, },
"itemProperties": { "itemProperties": {
} }
} }
} }
} }

View File

@ -2,81 +2,81 @@ use std::{io::prelude::*, path::{Path, PathBuf}};
fn gen_bindings(out_dir: &Path) fn gen_bindings(out_dir: &Path)
{ {
use rust_qt_binding_generator::{configuration, generate_bindings}; use rust_qt_binding_generator::{configuration, generate_bindings};
let mut config = configuration::parse("bindings.json").unwrap(); let mut config = configuration::parse("bindings.json").unwrap();
config.overwrite_implementation = true; config.overwrite_implementation = true;
config.cpp_file = out_dir.join("bindings.cc"); config.cpp_file = out_dir.join("bindings.cc");
config.rust.dir = out_dir.to_path_buf(); config.rust.dir = out_dir.to_path_buf();
generate_bindings(&config).unwrap(); generate_bindings(&config).unwrap();
} }
fn cxx_build() -> PathBuf fn cxx_build() -> PathBuf
{ {
let mut config = cmake::Config::new("."); let mut config = cmake::Config::new(".");
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
config.cxxflag("-DTYCHO_DEBUG_ASSERTIONS"); config.cxxflag("-DTYCHO_DEBUG_ASSERTIONS");
} }
config.build() config.build()
} }
fn get_link_dirs(lnk: &Path) -> Vec<PathBuf> fn get_link_dirs(lnk: &Path) -> Vec<PathBuf>
{ {
let mut dirs = Vec::new(); let mut dirs = Vec::new();
let lnk = std::fs::File::open(lnk).unwrap(); let lnk = std::fs::File::open(lnk).unwrap();
let lnk = std::io::BufReader::new(lnk); let lnk = std::io::BufReader::new(lnk);
for path in lnk.lines() { for path in lnk.lines() {
let path = PathBuf::from(path.unwrap()); let path = PathBuf::from(path.unwrap());
let path = path.parent().unwrap(); let path = path.parent().unwrap();
let path = if cfg!(target_os = "macos") { let path = if cfg!(target_os = "macos") {
path.parent().unwrap() path.parent().unwrap()
} else { } else {
path path
}; };
dirs.push(path.to_path_buf()); dirs.push(path.to_path_buf());
} }
dirs dirs
} }
fn main() fn main()
{ {
let (lty, dty, qtpre, cxx) = if cfg!(target_os = "macos") { let (lty, dty, qtpre, cxx) = if cfg!(target_os = "macos") {
("framework", "framework", "Qt", "c++") ("framework", "framework", "Qt", "c++")
} else { } else {
("dylib", "native", "Qt5", "stdc++") ("dylib", "native", "Qt5", "stdc++")
}; };
let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
gen_bindings(&out_dir); gen_bindings(&out_dir);
let cxx_dir = cxx_build(); let cxx_dir = cxx_build();
let lib_dir = cxx_dir.join("lib"); let lib_dir = cxx_dir.join("lib");
let etc_dir = cxx_dir.join("etc"); let etc_dir = cxx_dir.join("etc");
println!("cargo:rustc-link-search=native={}", lib_dir.display()); println!("cargo:rustc-link-search=native={}", lib_dir.display());
println!("cargo:rustc-link-lib=static=maraiah-tycho-hermes"); println!("cargo:rustc-link-lib=static=maraiah-tycho-hermes");
let dirs = get_link_dirs(&etc_dir.join("link.txt")); let dirs = get_link_dirs(&etc_dir.join("link.txt"));
for path in dirs { for path in dirs {
println!("cargo:rustc-link-search={}={}", dty, path.display()); println!("cargo:rustc-link-search={}={}", dty, path.display());
} }
println!("cargo:rustc-link-lib={}={}Core", lty, qtpre); println!("cargo:rustc-link-lib={}={}Core", lty, qtpre);
println!("cargo:rustc-link-lib={}={}Widgets", lty, qtpre); println!("cargo:rustc-link-lib={}={}Widgets", lty, qtpre);
println!("cargo:rustc-link-lib={}={}Gui", lty, qtpre); println!("cargo:rustc-link-lib={}={}Gui", lty, qtpre);
println!("cargo:rustc-link-lib=dylib={}", cxx); println!("cargo:rustc-link-lib=dylib={}", cxx);
} }
// EOF // EOF

View File

@ -7,41 +7,41 @@
class IProjectModel : public QAbstractItemModel class IProjectModel : public QAbstractItemModel
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(bool dirty READ dirty WRITE setDirty NOTIFY dirtyChanged) Q_PROPERTY(bool dirty READ dirty WRITE setDirty NOTIFY dirtyChanged)
public: public:
using QAbstractItemModel::QAbstractItemModel; using QAbstractItemModel::QAbstractItemModel;
virtual ~IProjectModel() {} virtual ~IProjectModel() {}
virtual bool dirty() const = 0; virtual bool dirty() const = 0;
virtual void setDirty(bool dirty) = 0; virtual void setDirty(bool dirty) = 0;
virtual bool open(QString const &path) = 0; virtual bool open(QString const &path) = 0;
virtual bool save() const = 0; virtual bool save() const = 0;
virtual bool saveAs(QString const &path) const = 0; virtual bool saveAs(QString const &path) const = 0;
public slots: public slots:
virtual void deselect() = 0; virtual void deselect() = 0;
virtual void select(QModelIndex const &index) = 0; virtual void select(QModelIndex const &index) = 0;
signals: signals:
void dirtyChanged(bool dirty); void dirtyChanged(bool dirty);
void deselected(); void deselected();
void selected(std::uint16_t index); void selected(std::uint16_t index);
}; };
class IProjectView : public QObject class IProjectView : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
using QObject::QObject; using QObject::QObject;
virtual ~IProjectView() {} virtual ~IProjectView() {}
virtual QWidget *widget() = 0; virtual QWidget *widget() = 0;
}; };
// EOF // EOF

View File

@ -1,23 +1,23 @@
#include "tycho.h" #include "tycho.h"
extern "C" { extern "C" {
void critical_msg(char const *title, char const *msg) void critical_msg(char const *title, char const *msg)
{ {
QMessageBox::critical(nullptr, QObject::tr(title), QObject::tr(msg)); QMessageBox::critical(nullptr, QObject::tr(title), QObject::tr(msg));
} }
int main_cc(char *app_path) int main_cc(char *app_path)
{ {
dbgPrint("cc entry"); dbgPrint("cc entry");
int argc = 1; int argc = 1;
char *argv[] = {app_path, nullptr}; char *argv[] = {app_path, nullptr};
QApplication a(argc, argv); QApplication a(argc, argv);
Menu w; Menu w;
w.show(); w.show();
return a.exec(); return a.exec();
} }
} }
// EOF // EOF

View File

@ -1,44 +1,44 @@
#include "tycho.h" #include "tycho.h"
MapModel::MapModel(Project *parent) : MapModel::MapModel(Project *parent) :
IMapModel(parent) IMapModel(parent)
{ {
dbgPrintFunc(); dbgPrintFunc();
} }
MapModel::~MapModel() MapModel::~MapModel()
{ {
dbgPrintFunc(); dbgPrintFunc();
} }
void MapModel::deselect() void MapModel::deselect()
{ {
IMapModel::deselect(); IMapModel::deselect();
emit deselected(); emit deselected();
} }
void MapModel::select(QModelIndex const &index) void MapModel::select(QModelIndex const &index)
{ {
auto idx = index.internalId(); auto idx = index.internalId();
IMapModel::select(idx); IMapModel::select(idx);
emit selected(idx); emit selected(idx);
} }
QVariant MapModel::data(const QModelIndex &index, int role) const QVariant MapModel::data(const QModelIndex &index, int role) const
{ {
switch(role) { switch(role) {
case Qt::DecorationRole: { case Qt::DecorationRole: {
auto name = propIcon(index.row()); auto name = propIcon(index.row());
auto icon = name.front() == ':' ? QIcon(name) auto icon = name.front() == ':' ? QIcon(name)
: QIcon::fromTheme(name); : QIcon::fromTheme(name);
return QVariant::fromValue(icon); return QVariant::fromValue(icon);
} }
default: default:
return IMapModel::data(index, role); return IMapModel::data(index, role);
} }
} }
// EOF // EOF

View File

@ -1,31 +1,31 @@
#include "tycho.h" #include "tycho.h"
MapProps::MapProps(Project *parent) : MapProps::MapProps(Project *parent) :
QDialog(parent), QDialog(parent),
m_mapModel(parent->mapModel()) m_mapModel(parent->mapModel())
{ {
setupUi(this); setupUi(this);
setModal(true); setModal(true);
auto bbox = new QDialogButtonBox(this); auto bbox = new QDialogButtonBox(this);
bbox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok); bbox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
verticalLayout->addWidget(bbox); verticalLayout->addWidget(bbox);
connect(bbox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(bbox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(bbox, &QDialogButtonBox::rejected, this, &QDialog::reject); connect(bbox, &QDialogButtonBox::rejected, this, &QDialog::reject);
dbgPrintFunc(); dbgPrintFunc();
} }
MapProps::~MapProps() MapProps::~MapProps()
{ {
dbgPrintFunc(); dbgPrintFunc();
} }
void MapProps::accept() void MapProps::accept()
{ {
done(QDialog::Accepted); done(QDialog::Accepted);
} }
// EOF // EOF

View File

@ -1,23 +1,23 @@
#include "tycho.h" #include "tycho.h"
MapView::MapView(Project *parent) : MapView::MapView(Project *parent) :
IMapView(parent), IMapView(parent),
m_internal(parent), m_internal(parent),
m_mapModel(parent->mapModel()) m_mapModel(parent->mapModel())
{ {
setupUi(&m_internal); setupUi(&m_internal);
dbgPrintFunc(); dbgPrintFunc();
} }
MapView::~MapView() MapView::~MapView()
{ {
dbgPrintFunc(); dbgPrintFunc();
} }
QWidget *MapView::widget() QWidget *MapView::widget()
{ {
return &m_internal; return &m_internal;
} }
// EOF // EOF

View File

@ -1,148 +1,148 @@
#include "tycho.h" #include "tycho.h"
Menu::Menu(QWidget *parent) : Menu::Menu(QWidget *parent) :
QMainWindow(parent) QMainWindow(parent)
{ {
setupUi(this); setupUi(this);
actionAbout->setShortcut(QKeySequence(QKeySequence::HelpContents)); actionAbout->setShortcut(QKeySequence(QKeySequence::HelpContents));
actionClose->setShortcut(QKeySequence(QKeySequence::Close)); actionClose->setShortcut(QKeySequence(QKeySequence::Close));
actionMapProps->setShortcut(QKeySequence(tr("Ctrl+P"))); actionMapProps->setShortcut(QKeySequence(tr("Ctrl+P")));
actionNew->setShortcut(QKeySequence(QKeySequence::New)); actionNew->setShortcut(QKeySequence(QKeySequence::New));
actionOpen->setShortcut(QKeySequence(QKeySequence::Open)); actionOpen->setShortcut(QKeySequence(QKeySequence::Open));
actionQuit->setShortcut(QKeySequence(QKeySequence::Quit)); actionQuit->setShortcut(QKeySequence(QKeySequence::Quit));
dbgPrintFunc(); dbgPrintFunc();
} }
Menu::~Menu() Menu::~Menu()
{ {
dbgPrintFunc(); dbgPrintFunc();
} }
void Menu::mapNew() void Menu::mapNew()
{ {
QScopedPointer proj{new Project(Project::Map)}; QScopedPointer proj{new Project(Project::Map)};
addProject(proj.take()); addProject(proj.take());
} }
void Menu::mapOpen() void Menu::mapOpen()
{ {
auto fname = auto fname =
QFileDialog::getOpenFileName( QFileDialog::getOpenFileName(
this, this,
tr("Open Map File"), tr("Open Map File"),
QString(), QString(),
tr("Marathon Map files (*.scen *.sceA Map);;" tr("Marathon Map files (*.scen *.sceA Map);;"
"Marathon Physics files (*.phys *.phyA Physics);;" "Marathon Physics files (*.phys *.phyA Physics);;"
"Aleph One Image files (*.imgA);;" "Aleph One Image files (*.imgA);;"
"All files (*)")); "All files (*)"));
if(!fname.isEmpty()) { if(!fname.isEmpty()) {
QScopedPointer proj{new Project(Project::Map)}; QScopedPointer proj{new Project(Project::Map)};
if(proj->model()->open(fname)) { if(proj->model()->open(fname)) {
addProject(proj.take()); addProject(proj.take());
} }
} }
} }
void Menu::openAbout() void Menu::openAbout()
{ {
QDialog dlg{this}; QDialog dlg{this};
Ui::About ui{}; Ui::About ui{};
ui.setupUi(&dlg); ui.setupUi(&dlg);
auto text = ui.labelText->text(); auto text = ui.labelText->text();
text.replace("AUTHORS", text.replace("AUTHORS",
tr(tychoAuthors()).replace(':', ", ").toHtmlEscaped()); tr(tychoAuthors()).replace(':', ", ").toHtmlEscaped());
text.replace("HOMEPAGE", tr(tychoHomepage())); text.replace("HOMEPAGE", tr(tychoHomepage()));
text.replace("REPOSITORY", tr(tychoRepository())); text.replace("REPOSITORY", tr(tychoRepository()));
text.replace("VERSION", tr(tychoVersion())); text.replace("VERSION", tr(tychoVersion()));
ui.labelText->setText(text); ui.labelText->setText(text);
connect(ui.btnLicense, &QPushButton::clicked, this, [&](){ connect(ui.btnLicense, &QPushButton::clicked, this, [&](){
openLicense(&dlg); openLicense(&dlg);
}); });
dlg.exec(); dlg.exec();
} }
void Menu::openAboutQt() void Menu::openAboutQt()
{ {
QMessageBox::aboutQt(this); QMessageBox::aboutQt(this);
} }
void Menu::openLicense(QWidget *parent) void Menu::openLicense(QWidget *parent)
{ {
QDialog dlg{parent}; QDialog dlg{parent};
Ui::License ui{}; Ui::License ui{};
ui.setupUi(&dlg); ui.setupUi(&dlg);
ui.text->setPlainText(tychoLicenseText()); ui.text->setPlainText(tychoLicenseText());
connect(ui.btnCopy, &QPushButton::clicked, this, [&]() { connect(ui.btnCopy, &QPushButton::clicked, this, [&]() {
ui.text->selectAll(); ui.text->selectAll();
ui.text->copy(); ui.text->copy();
}); });
dlg.exec(); dlg.exec();
} }
void Menu::openMapProperties() void Menu::openMapProperties()
{ {
auto proj = activeProject(); auto proj = activeProject();
if(proj && proj->type() == Project::Map) { if(proj && proj->type() == Project::Map) {
MapProps props{proj}; MapProps props{proj};
props.exec(); props.exec();
} }
} }
void Menu::updateActions() void Menu::updateActions()
{ {
std::optional<Project::Type> active; std::optional<Project::Type> active;
if(auto proj = activeProject()) { if(auto proj = activeProject()) {
active = proj->type(); active = proj->type();
} }
actionClose->setEnabled(!!active); actionClose->setEnabled(!!active);
actionMapProps->setEnabled(active == Project::Map); actionMapProps->setEnabled(active == Project::Map);
} }
void Menu::closeEvent(QCloseEvent *event) void Menu::closeEvent(QCloseEvent *event)
{ {
for(auto *win : mdiArea->subWindowList()) { for(auto *win : mdiArea->subWindowList()) {
if(!win->close()) { if(!win->close()) {
event->ignore(); event->ignore();
return; return;
} }
} }
event->accept(); event->accept();
} }
Project *Menu::activeProject() const Project *Menu::activeProject() const
{ {
return qobject_cast<Project *>(activeSubWindow()); return qobject_cast<Project *>(activeSubWindow());
} }
QMdiSubWindow *Menu::activeSubWindow() const QMdiSubWindow *Menu::activeSubWindow() const
{ {
return mdiArea->activeSubWindow(); return mdiArea->activeSubWindow();
} }
void Menu::addProject(Project *proj) void Menu::addProject(Project *proj)
{ {
auto win = mdiArea->addSubWindow(proj); auto win = mdiArea->addSubWindow(proj);
win->showMaximized(); win->showMaximized();
} }
// EOF // EOF

View File

@ -3,89 +3,89 @@
static static
IProjectModel *makeModel(Project *proj) IProjectModel *makeModel(Project *proj)
{ {
switch(proj->type()) { switch(proj->type()) {
case Project::Map: return new MapModel(proj); case Project::Map: return new MapModel(proj);
} }
} }
static static
IProjectView *makeView(Project *proj) IProjectView *makeView(Project *proj)
{ {
switch(proj->type()) { switch(proj->type()) {
case Project::Map: return new MapView(proj); case Project::Map: return new MapView(proj);
} }
} }
Project::Project(Type type) : Project::Project(Type type) :
QMdiSubWindow(), QMdiSubWindow(),
m_type(type), m_type(type),
m_model(makeModel(this)), m_model(makeModel(this)),
m_view(makeView(this)) m_view(makeView(this))
{ {
auto widget = new QWidget(this); auto widget = new QWidget(this);
setupUi(widget); setupUi(widget);
setWidget(widget); setWidget(widget);
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);
listView->setModel(m_model); listView->setModel(m_model);
verticalLayout->insertWidget(0, m_view->widget()); verticalLayout->insertWidget(0, m_view->widget());
connect(listView, connect(listView,
SIGNAL(doubleClicked(QModelIndex const &)), SIGNAL(doubleClicked(QModelIndex const &)),
m_model, m_model,
SLOT(select(QModelIndex const &))); SLOT(select(QModelIndex const &)));
dbgPrintFunc(); dbgPrintFunc();
} }
Project::~Project() Project::~Project()
{ {
dbgPrintFunc(); dbgPrintFunc();
} }
Project::Type Project::type() const Project::Type Project::type() const
{ {
return m_type; return m_type;
} }
IProjectModel *Project::model() const IProjectModel *Project::model() const
{ {
return m_model; return m_model;
} }
MapModel *Project::mapModel() const MapModel *Project::mapModel() const
{ {
return qobject_cast<MapModel *>(m_model); return qobject_cast<MapModel *>(m_model);
} }
void Project::closeEvent(QCloseEvent *event) void Project::closeEvent(QCloseEvent *event)
{ {
if(m_model->dirty()) { if(m_model->dirty()) {
QMessageBox msg; QMessageBox msg;
msg.setText(tr("Do you want to save your changes to this project before closing it?")); msg.setText(tr("Do you want to save your changes to this project before closing it?"));
msg.setInformativeText(tr("Unsaved changes will be lost unless you save.")); msg.setInformativeText(tr("Unsaved changes will be lost unless you save."));
msg.setStandardButtons(QMessageBox::Save | msg.setStandardButtons(QMessageBox::Save |
QMessageBox::Discard | QMessageBox::Discard |
QMessageBox::Cancel); QMessageBox::Cancel);
msg.setDefaultButton(QMessageBox::Save); msg.setDefaultButton(QMessageBox::Save);
switch(msg.exec()) { switch(msg.exec()) {
case QMessageBox::Save: case QMessageBox::Save:
m_model->save(); m_model->save();
break; break;
case QMessageBox::Discard: case QMessageBox::Discard:
break; break;
case QMessageBox::Cancel: case QMessageBox::Cancel:
event->ignore(); event->ignore();
return; return;
default: default:
Q_UNREACHABLE(); Q_UNREACHABLE();
} }
} }
event->accept(); event->accept();
} }
// EOF // EOF

View File

@ -33,105 +33,105 @@ using byte = std::uint8_t;
class MapModel final : public IMapModel class MapModel final : public IMapModel
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit MapModel(Project *parent); explicit MapModel(Project *parent);
~MapModel() override; ~MapModel() override;
public slots: public slots:
void deselect() override; void deselect() override;
void select(QModelIndex const &index) override; void select(QModelIndex const &index) override;
private: private:
QVariant data(const QModelIndex &index, int role) const override; QVariant data(const QModelIndex &index, int role) const override;
}; };
class MapView final : public IMapView, class MapView final : public IMapView,
private Ui::MapView private Ui::MapView
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit MapView(Project *parent); explicit MapView(Project *parent);
~MapView(); ~MapView();
QWidget *widget(); QWidget *widget();
private: private:
QWidget m_internal; QWidget m_internal;
MapModel *const m_mapModel; MapModel *const m_mapModel;
}; };
class MapProps final : public QDialog, class MapProps final : public QDialog,
private Ui::MapProps private Ui::MapProps
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit MapProps(Project *parent); explicit MapProps(Project *parent);
~MapProps(); ~MapProps();
void accept() override; void accept() override;
private: private:
MapModel *const m_mapModel; MapModel *const m_mapModel;
}; };
class Menu final : public QMainWindow, class Menu final : public QMainWindow,
private Ui::Menu private Ui::Menu
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit Menu(QWidget *parent = nullptr); explicit Menu(QWidget *parent = nullptr);
~Menu(); ~Menu();
public slots: public slots:
void mapNew(); void mapNew();
void mapOpen(); void mapOpen();
void openAbout(); void openAbout();
void openAboutQt(); void openAboutQt();
void openMapProperties(); void openMapProperties();
void updateActions(); void updateActions();
protected: protected:
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void openLicense(QWidget *parent); void openLicense(QWidget *parent);
private: private:
Project *activeProject() const; Project *activeProject() const;
QMdiSubWindow *activeSubWindow() const; QMdiSubWindow *activeSubWindow() const;
void addProject(Project *proj); void addProject(Project *proj);
}; };
class Project final : public QMdiSubWindow, class Project final : public QMdiSubWindow,
private Ui::Project private Ui::Project
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(Type type READ type CONSTANT) Q_PROPERTY(Type type READ type CONSTANT)
Q_PROPERTY(IProjectModel *model READ model CONSTANT) Q_PROPERTY(IProjectModel *model READ model CONSTANT)
Q_PROPERTY(MapModel *mapModel READ mapModel CONSTANT) Q_PROPERTY(MapModel *mapModel READ mapModel CONSTANT)
public: public:
enum Type {Map}; enum Type {Map};
Q_ENUM(Type) Q_ENUM(Type)
explicit Project(Type type); explicit Project(Type type);
~Project(); ~Project();
Type type() const; Type type() const;
IProjectModel *model() const; IProjectModel *model() const;
MapModel *mapModel() const; MapModel *mapModel() const;
protected: protected:
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
private: private:
Type const m_type; Type const m_type;
IProjectModel *const m_model; IProjectModel *const m_model;
IProjectView *const m_view; IProjectView *const m_view;
}; };
#pragma clang diagnostic push #pragma clang diagnostic push
@ -141,9 +141,9 @@ template<typename... VA>
static inline static inline
void dbgPrint([[maybe_unused]] char const *fmt, [[maybe_unused]] VA &&...va) void dbgPrint([[maybe_unused]] char const *fmt, [[maybe_unused]] VA &&...va)
{ {
#ifdef TYCHO_DEBUG_ASSERTIONS #ifdef TYCHO_DEBUG_ASSERTIONS
qDebug(fmt, std::forward<VA>(va)...); qDebug(fmt, std::forward<VA>(va)...);
#endif #endif
} }
#pragma clang diagnostic pop #pragma clang diagnostic pop
@ -153,18 +153,18 @@ void dbgPrint([[maybe_unused]] char const *fmt, [[maybe_unused]] VA &&...va)
constexpr constexpr
std::uint32_t fourCC(byte a, byte b, byte c, byte d) std::uint32_t fourCC(byte a, byte b, byte c, byte d)
{ {
return (static_cast<std::uint32_t>(a) << 24) | return (static_cast<std::uint32_t>(a) << 24) |
(static_cast<std::uint32_t>(b) << 16) | (static_cast<std::uint32_t>(b) << 16) |
(static_cast<std::uint32_t>(c) << 8) | (static_cast<std::uint32_t>(c) << 8) |
static_cast<std::uint32_t>(d); static_cast<std::uint32_t>(d);
} }
extern "C" { extern "C" {
char const *tychoAuthors(); char const *tychoAuthors();
char const *tychoHomepage(); char const *tychoHomepage();
char const *tychoLicenseText(); char const *tychoLicenseText();
char const *tychoRepository(); char const *tychoRepository();
char const *tychoVersion(); char const *tychoVersion();
} }
// EOF // EOF

View File

@ -1,21 +1,21 @@
//! C++ functions. //! C++ functions.
mod ffi { mod ffi {
extern "C" { extern "C" {
pub fn critical_msg(title: maraiah::ffi::NT, msg: maraiah::ffi::NT); pub fn critical_msg(title: maraiah::ffi::NT, msg: maraiah::ffi::NT);
} }
} }
pub fn critical_msg<T, U>(title: T, msg: U) pub fn critical_msg<T, U>(title: T, msg: U)
where T: ToString, where T: ToString,
U: ToString U: ToString
{ {
let title = std::ffi::CString::new(title.to_string()).unwrap(); let title = std::ffi::CString::new(title.to_string()).unwrap();
let msg = std::ffi::CString::new(msg.to_string()).unwrap(); let msg = std::ffi::CString::new(msg.to_string()).unwrap();
unsafe { unsafe {
ffi::critical_msg(title.as_ptr(), msg.as_ptr()); ffi::critical_msg(title.as_ptr(), msg.as_ptr());
} }
} }
// EOF // EOF

View File

@ -6,130 +6,130 @@ use crate::cc;
impl IMapModel impl IMapModel
{ {
pub fn open_map(path: String) -> ResultS<EntryDataMap> pub fn open_map(path: String) -> ResultS<EntryDataMap>
{ {
let mut fp = maraiah::file::open_mac(path)?; let mut fp = maraiah::file::open_mac(path)?;
let map = map::head::read(&mut fp)?; let map = map::head::read(&mut fp)?;
let ent = map::entr::read_all(&map)?; let ent = map::entr::read_all(&map)?;
map::data::read_all(map.head(), &ent) map::data::read_all(map.head(), &ent)
} }
pub fn get(&self, index: usize) -> (&u16, &EntryData) pub fn get(&self, index: usize) -> (&u16, &EntryData)
{ {
self.map.iter().nth(index).unwrap() self.map.iter().nth(index).unwrap()
} }
/* /*
pub fn get_mut(&mut self, index: usize) -> (&u16, &mut EntryData) pub fn get_mut(&mut self, index: usize) -> (&u16, &mut EntryData)
{ {
self.map.iter_mut().nth(index).unwrap() self.map.iter_mut().nth(index).unwrap()
} }
*/ */
} }
impl IMapModelTrait for IMapModel impl IMapModelTrait for IMapModel
{ {
/// Returns a new `IMapModel` instance. /// Returns a new `IMapModel` instance.
fn new(emit: IMapModelEmitter, _: IMapModelList) -> Self fn new(emit: IMapModelEmitter, _: IMapModelList) -> Self
{ {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
eprintln!("new IMapModel"); eprintln!("new IMapModel");
} }
Self{emit, map: EntryDataMap::default(), selected: None, dirty: false} Self{emit, map: EntryDataMap::default(), selected: None, dirty: false}
} }
/// Returns the emitter of `self`. /// Returns the emitter of `self`.
fn emit(&mut self) -> &mut IMapModelEmitter {&mut self.emit} fn emit(&mut self) -> &mut IMapModelEmitter {&mut self.emit}
fn row_count(&self) -> usize {self.map.len()} fn row_count(&self) -> usize {self.map.len()}
fn prop_index(&self, index: usize) -> u64 {(*self.get(index).0).into()} fn prop_index(&self, index: usize) -> u64 {(*self.get(index).0).into()}
fn prop_icon(&self, index: u16) -> String fn prop_icon(&self, index: u16) -> String
{ {
match self.get(index.into()).1.get_type() { match self.get(index.into()).1.get_type() {
EntryType::Image => "image-x-generic".to_string(), EntryType::Image => "image-x-generic".to_string(),
EntryType::Map => ":/tycho/color/map.png".to_string(), EntryType::Map => ":/tycho/color/map.png".to_string(),
EntryType::Other => "image-missing".to_string(), EntryType::Other => "image-missing".to_string(),
EntryType::Physics => "applications-system".to_string(), EntryType::Physics => "applications-system".to_string(),
} }
} }
/// Opens the map file at `path`. /// Opens the map file at `path`.
fn open(&mut self, path: String) -> bool fn open(&mut self, path: String) -> bool
{ {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
eprintln!("opening project: {}", &path); eprintln!("opening project: {}", &path);
} }
match Self::open_map(path) { match Self::open_map(path) {
Ok(map) => { Ok(map) => {
self.map = map; self.map = map;
true true
} }
Err(e) => { Err(e) => {
backtrace!(e); backtrace!(e);
cc::critical_msg("Error opening map", e); cc::critical_msg("Error opening map", e);
false false
} }
} }
} }
/// Saves the project into the original file. /// Saves the project into the original file.
fn save(&self) -> bool fn save(&self) -> bool
{ {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
eprintln!("saving project"); eprintln!("saving project");
} }
false false
} }
/// Saves the project into `path`. /// Saves the project into `path`.
fn save_as(&self, path: String) -> bool fn save_as(&self, path: String) -> bool
{ {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
eprintln!("saving project as {}", path); eprintln!("saving project as {}", path);
} }
false false
} }
/// Returns `true` if the file has been modified from its original state. /// Returns `true` if the file has been modified from its original state.
fn dirty(&self) -> bool {self.dirty} fn dirty(&self) -> bool {self.dirty}
fn set_dirty(&mut self, dirty: bool) {self.dirty = dirty;} fn set_dirty(&mut self, dirty: bool) {self.dirty = dirty;}
fn deselect(&mut self) {self.selected = None;} fn deselect(&mut self) {self.selected = None;}
fn select(&mut self, index: u16) fn select(&mut self, index: u16)
{ {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
eprintln!("selecting map {}", index); eprintln!("selecting map {}", index);
} }
self.selected = Some(index); self.selected = Some(index);
} }
} }
impl Drop for IMapModel impl Drop for IMapModel
{ {
fn drop(&mut self) fn drop(&mut self)
{ {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
eprintln!("drop IMapModel"); eprintln!("drop IMapModel");
} }
} }
} }
pub struct IMapModel { pub struct IMapModel {
emit: IMapModelEmitter, emit: IMapModelEmitter,
map: EntryDataMap, map: EntryDataMap,
selected: Option<u16>, selected: Option<u16>,
dirty: bool, dirty: bool,
} }
// EOF // EOF

View File

@ -4,32 +4,32 @@ use super::qobj::*;
impl IMapViewTrait for IMapView impl IMapViewTrait for IMapView
{ {
/// Returns a new `IMapView` instance. /// Returns a new `IMapView` instance.
fn new(emit: IMapViewEmitter) -> Self fn new(emit: IMapViewEmitter) -> Self
{ {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
eprintln!("new IMapView"); eprintln!("new IMapView");
} }
Self{emit} Self{emit}
} }
/// Returns the emitter of `self`. /// Returns the emitter of `self`.
fn emit(&mut self) -> &mut IMapViewEmitter {&mut self.emit} fn emit(&mut self) -> &mut IMapViewEmitter {&mut self.emit}
} }
impl Drop for IMapView impl Drop for IMapView
{ {
fn drop(&mut self) fn drop(&mut self)
{ {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
eprintln!("drop IMapView"); eprintln!("drop IMapView");
} }
} }
} }
pub struct IMapView { pub struct IMapView {
emit: IMapViewEmitter, emit: IMapViewEmitter,
} }
// EOF // EOF

View File

@ -5,24 +5,24 @@ mod gui;
mod meta; mod meta;
extern "C" { extern "C" {
fn main_cc(app_name: *mut ffi::c_char); fn main_cc(app_name: *mut ffi::c_char);
} }
fn main() -> ResultS<()> fn main() -> ResultS<()>
{ {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
eprintln!("rust entry"); eprintln!("rust entry");
} }
let mut args = std::env::args(); let mut args = std::env::args();
let app_name = args.next().ok_or(err_msg("bad launch name"))?; let app_name = args.next().ok_or(err_msg("bad launch name"))?;
let app_name = ffi::CString::new(app_name)?; let app_name = ffi::CString::new(app_name)?;
unsafe { unsafe {
main_cc(app_name.into_raw()); main_cc(app_name.into_raw());
} }
Ok(()) Ok(())
} }
// EOF // EOF

View File

@ -3,23 +3,23 @@
use maraiah::{ffi, meta}; use maraiah::{ffi, meta};
macro_rules! meta_str { macro_rules! meta_str {
($($name:ident = $e:expr;)*) => { ($($name:ident = $e:expr;)*) => {
$( $(
#[no_mangle] #[no_mangle]
pub extern "C" fn $name() -> ffi::NT pub extern "C" fn $name() -> ffi::NT
{ {
$e $e
} }
)* )*
} }
} }
meta_str! { meta_str! {
tychoAuthors = meta::ffi::authors(); tychoAuthors = meta::ffi::authors();
tychoHomepage = meta::ffi::homepage(); tychoHomepage = meta::ffi::homepage();
tychoLicenseText = meta::ffi::license_text(); tychoLicenseText = meta::ffi::license_text();
tychoRepository = meta::ffi::repository(); tychoRepository = meta::ffi::repository();
tychoVersion = meta::ffi::version(); tychoVersion = meta::ffi::version();
} }
// EOF // EOF