add Unit and Angle types

png-branch
an 2019-02-16 13:08:50 -05:00
parent c258ee2558
commit 5e2ad524b0
6 changed files with 240 additions and 205 deletions

View File

@ -431,7 +431,7 @@ The type "`fixed`" refers to a 32-bit fixed point number with the format 15.16s
sign.)
The type "`angle`" refers to a 16-bit fixed point number with the format 0.9s.
This is used for angles.
This is used for all angles.
The type "`unit`" refers to a 16-bit fixed point number with the format 5.10s.
This is used for all world coordinates.

200
src/durandal/fixed.rs Normal file
View File

@ -0,0 +1,200 @@
//! Fixed point numbers.
use serde::Serialize;
use std::{fmt::{self, Write},
ops};
macro_rules! define_fixed_type {
(
$Type:ident : $IT:ident, $UT:ident, $LT:ident, $FracBits:expr
) => {
#[derive(Serialize)]
pub struct $Type($IT);
impl $Type
{
const FRACBITS: $UT = $FracBits;
const FRACMASK: $UT = (1 << Self::FRACBITS) - 1;
const ONE: $IT = 1 << Self::FRACBITS;
pub fn to_bits(&self) -> $UT
{
self.0 as $UT
}
pub fn set_bits(&mut self, bits: $UT)
{
self.0 = bits as $IT
}
pub fn from_bits(bits: $UT) -> Self
{
$Type(bits as $IT)
}
pub fn integ(&self) -> $LT
{
(self.0 >> Self::FRACBITS) as $LT
}
pub fn fract(&self) -> u16
{
(self.0 as $UT & Self::FRACMASK) as u16
}
pub fn mul_i(&self, n: $LT) -> Self
{
$Type(self.0 * $IT::from(n))
}
pub fn div_i(&self, n: $LT) -> Self
{
$Type(self.0 / $IT::from(n))
}
#[inline]
fn fx_div(x: $IT, y: $IT) -> $IT
{
(i64::from(x) * i64::from(Self::ONE) / i64::from(y)) as $IT
}
#[inline]
fn fx_mul(x: $IT, y: $IT) -> $IT
{
(i64::from(x) * i64::from(y) / i64::from(Self::ONE)) as $IT
}
}
impl From<$LT> for $Type
{
fn from(n: $LT) -> Self
{
$Type($IT::from(n) << Self::FRACBITS)
}
}
impl ops::Add for $Type
{
type Output = Self;
fn add(self, o: Self) -> Self
{
$Type(self.0 + o.0)
}
}
impl ops::Sub for $Type
{
type Output = Self;
fn sub(self, o: Self) -> Self
{
$Type(self.0 - o.0)
}
}
impl ops::Mul for $Type
{
type Output = Self;
fn mul(self, o: Self) -> Self
{
$Type(Self::fx_mul(self.0, o.0))
}
}
impl ops::Div for $Type
{
type Output = Self;
fn div(self, o: Self) -> Self
{
$Type(Self::fx_div(self.0, o.0))
}
}
impl ops::Neg for $Type
{
type Output = Self;
fn neg(self) -> Self
{
$Type(-self.0)
}
}
impl ops::Not for $Type
{
type Output = Self;
fn not(self) -> Self
{
$Type(!self.0)
}
}
impl fmt::Display for $Type
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
{
let prec = f.precision().unwrap_or(1);
let widt = f.width().unwrap_or(0);
write!(f, "{:widt$}.", self.integ(), widt = widt)?;
let mut k = self.to_bits();
for _ in 0..prec {
k &= Self::FRACMASK;
k *= 10;
let d = k >> Self::FRACBITS;
let d = d % 10;
f.write_char((d as u8 + b'0') as char)?;
}
Ok(())
}
}
impl fmt::Debug for $Type
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
{
fmt::Display::fmt(self, f)
}
}
};
}
define_fixed_type!(Fixed: i32, u32, i16, 16);
define_fixed_type!(Unit: i16, u16, i8, 10);
define_fixed_type!(Angle: i16, u16, i8, 9);
#[test]
fn fixed_basic_ops()
{
let seven_div_2 = 3 << Fixed::FRACBITS | Fixed::FRACMASK / 2 + 1;
assert_eq!((Fixed::from(1) + 1.into()).to_bits(), 2 << Fixed::FRACBITS);
assert_eq!((Fixed::from(2) - 1.into()).to_bits(), 1 << Fixed::FRACBITS);
assert_eq!((Fixed::from(6) * 2.into()).to_bits(), 12 << Fixed::FRACBITS);
assert_eq!((Fixed::from(6).mul_i(2)).to_bits(), 12 << Fixed::FRACBITS);
assert_eq!((Fixed::from(7) / 2.into()).to_bits(), seven_div_2);
assert_eq!((Fixed::from(7).div_i(2)).to_bits(), seven_div_2);
}
#[test]
#[should_panic]
#[allow(unused_must_use)]
fn fixed_overflow()
{
Fixed::from(i16::max_value()) + 1.into();
}
#[test]
fn fixed_printing()
{
assert_eq!(format!("{}", Fixed::from(6)), "6.0");
assert_eq!(format!("{}", Fixed::from(7).div_i(2)), "3.5");
assert_eq!(format!("{:7.7}", Fixed::from_bits(0xDEAD_BEEF)),
" -8531.7458343");
}
// EOF

View File

@ -1,176 +0,0 @@
use serde::Serialize;
use std::{fmt::{self, Write},
ops};
#[derive(Serialize)]
pub struct Fx32(i32);
impl Fx32
{
const FRACBITS: u32 = 16;
const FRACMASK: u32 = 0xFFFF;
const ONE: i32 = 1 << Fx32::FRACBITS;
pub fn to_bits(&self) -> u32
{
self.0 as u32
}
pub fn set_bits(&mut self, bits: u32)
{
self.0 = bits as i32
}
pub fn from_bits(bits: u32) -> Fx32
{
Fx32(bits as i32)
}
pub fn integ(&self) -> i16
{
(self.0 >> Fx32::FRACBITS) as i16
}
pub fn fract(&self) -> u16
{
(self.0 as u32 & Fx32::FRACMASK) as u16
}
pub fn mul_i(&self, n: i32) -> Fx32
{
Fx32(self.0 * n)
}
pub fn div_i(&self, n: i32) -> Fx32
{
Fx32(self.0 / n)
}
}
impl From<i32> for Fx32
{
fn from(n: i32) -> Fx32
{
Fx32(n << Fx32::FRACBITS)
}
}
impl ops::Add for Fx32
{
type Output = Fx32;
fn add(self, o: Fx32) -> Fx32
{
Fx32(self.0 + o.0)
}
}
impl ops::Sub for Fx32
{
type Output = Fx32;
fn sub(self, o: Fx32) -> Fx32
{
Fx32(self.0 - o.0)
}
}
impl ops::Mul for Fx32
{
type Output = Fx32;
fn mul(self, o: Fx32) -> Fx32
{
Fx32((i64::from(self.0) * i64::from(o.0) / i64::from(Fx32::ONE)) as i32)
}
}
impl ops::Div for Fx32
{
type Output = Fx32;
fn div(self, o: Fx32) -> Fx32
{
Fx32((i64::from(self.0) * i64::from(Fx32::ONE) / i64::from(o.0)) as i32)
}
}
impl ops::Neg for Fx32
{
type Output = Fx32;
fn neg(self) -> Fx32
{
Fx32(-self.0)
}
}
impl ops::Not for Fx32
{
type Output = Fx32;
fn not(self) -> Fx32
{
Fx32(!self.0)
}
}
impl fmt::Display for Fx32
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
{
let prec = f.precision().unwrap_or(1);
let widt = f.width().unwrap_or(0);
write!(f, "{:widt$}.", self.integ(), widt = widt)?;
let mut k = self.to_bits();
for _ in 0..prec {
k &= Fx32::FRACMASK;
k *= 10;
let d = k >> Fx32::FRACBITS;
let d = d % 10;
f.write_char((d as u8 + b'0') as char)?;
}
Ok(())
}
}
impl fmt::Debug for Fx32
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
{
fmt::Display::fmt(self, f)
}
}
#[test]
fn fx32_basic_ops()
{
let seven_div_2 = 3 << Fx32::FRACBITS | Fx32::FRACMASK / 2 + 1;
assert_eq!((Fx32::from(1) + 1.into()).to_bits(), 2 << Fx32::FRACBITS);
assert_eq!((Fx32::from(2) - 1.into()).to_bits(), 1 << Fx32::FRACBITS);
assert_eq!((Fx32::from(6) * 2.into()).to_bits(), 12 << Fx32::FRACBITS);
assert_eq!((Fx32::from(6).mul_i(2)).to_bits(), 12 << Fx32::FRACBITS);
assert_eq!((Fx32::from(7) / 2.into()).to_bits(), seven_div_2);
assert_eq!((Fx32::from(7).div_i(2)).to_bits(), seven_div_2);
}
#[test]
#[should_panic]
#[allow(unused_must_use)]
fn fx32_overflow()
{
Fx32::from(32767) + 1.into();
}
#[test]
fn fx32_printing()
{
assert_eq!(format!("{}", Fx32::from(6)), "6.0");
assert_eq!(format!("{}", Fx32::from(7).div_i(2)), "3.5");
assert_eq!(format!("{:7.7}", Fx32::from_bits(0xDEAD_BEEF)),
" -8531.7458343");
}
// EOF

View File

@ -9,7 +9,7 @@ pub mod bin;
pub mod chunk;
pub mod crc;
pub mod file;
pub mod fx32;
pub mod fixed;
pub mod image;
pub mod text;

View File

@ -1,4 +1,4 @@
use crate::{durandal::{bin::*, chunk::*, err::*, fx32::*,
use crate::{durandal::{bin::*, chunk::*, err::*, fixed::*,
text::mac_roman_conv},
marathon::xfer::TransferMode};
use bitflags::bitflags;
@ -11,8 +11,10 @@ impl Chunked<Point> for Point
fn read(b: &[u8]) -> ResultS<Self>
{
let x = c_i16b(b, 0)?;
let y = c_i16b(b, 2)?;
let x = c_u16b(b, 0)?;
let y = c_u16b(b, 2)?;
let x = Unit::from_bits(x);
let y = Unit::from_bits(y);
Ok(Point{x, y})
}
}
@ -24,11 +26,13 @@ impl Chunked<Endpoint> for Endpoint
fn read(b: &[u8]) -> ResultS<Self>
{
let flags = c_u16b(b, 0)?;
let adj_hi = c_i16b(b, 2)?;
let adj_lo = c_i16b(b, 4)?;
let adj_hi = c_u16b(b, 2)?;
let adj_lo = c_u16b(b, 4)?;
let pos = Point::read(c_data(b, 6..10)?)?;
let support = c_u16b(b, 14)?;
let flags = ok!(EndpFlags::from_bits(flags), "bad EndpFlags")?;
let adj_hi = Unit::from_bits(adj_hi);
let adj_lo = Unit::from_bits(adj_lo);
Ok(Endpoint{flags, adj_hi, adj_lo, pos, support})
}
}
@ -42,14 +46,17 @@ impl Chunked<Line> for Line
let epnt_f = c_u16b(b, 0)?;
let epnt_b = c_u16b(b, 2)?;
let flags = c_u16b(b, 4)?;
let length = c_i16b(b, 6)?;
let adj_hi = c_i16b(b, 8)?;
let adj_lo = c_i16b(b, 10)?;
let length = c_u16b(b, 6)?;
let adj_hi = c_u16b(b, 8)?;
let adj_lo = c_u16b(b, 10)?;
let side_f = c_u16b(b, 12)?;
let side_b = c_u16b(b, 14)?;
let poly_f = c_u16b(b, 16)?;
let poly_b = c_u16b(b, 18)?;
let flags = ok!(LineFlags::from_bits(flags), "bad LineFlags")?;
let length = Unit::from_bits(length);
let adj_hi = Unit::from_bits(adj_hi);
let adj_lo = Unit::from_bits(adj_lo);
Ok(Line{flags, length, adj_hi, adj_lo, epnt_f, epnt_b, side_f, side_b,
poly_f, poly_b})
}
@ -91,7 +98,7 @@ impl Chunked<Side> for Side
let xfer_pri = TransferMode::from_repr(xfer_pri)?;
let xfer_sec = TransferMode::from_repr(xfer_sec)?;
let xfer_tra = TransferMode::from_repr(xfer_tra)?;
let shade = Fx32::from_bits(shade);
let shade = Fixed::from_bits(shade);
Ok(Side{stype, flags, tex_pri, tex_sec, tex_tra, ex_tleft, ex_trigh,
ex_bleft, ex_brigh, paneltyp, paneldat, xfer_pri, xfer_sec,
xfer_tra, shade})
@ -117,8 +124,6 @@ impl Chunker<Minf> for Minf
}
}
type Unit = i16;
#[derive(Serialize)]
pub struct Point
{
@ -175,7 +180,7 @@ pub struct Side
xfer_pri: TransferMode,
xfer_sec: TransferMode,
xfer_tra: TransferMode,
shade: Fx32,
shade: Fixed,
}
#[derive(Debug, Serialize)]

View File

@ -1,6 +1,6 @@
//! Marathon Shapes format handling.
use crate::{durandal::{bin::*, err::*, fx32::*, image::*, text::*},
use crate::{durandal::{bin::*, err::*, fixed::*, image::*, text::*},
marathon::xfer::TransferMode};
use bitflags::bitflags;
use serde::Serialize;
@ -114,14 +114,20 @@ fn frame(b: &[u8]) -> ResultS<Frame>
let flags = c_u16b(b, 0)?;
let min_lt = c_u32b(b, 2)?;
let bmp_ind = c_u16b(b, 6)? as usize;
let wrl_l = c_i16b(b, 16)?;
let wrl_r = c_i16b(b, 18)?;
let wrl_t = c_i16b(b, 20)?;
let wrl_b = c_i16b(b, 22)?;
let wrl_x = c_i16b(b, 24)?;
let wrl_y = c_i16b(b, 26)?;
let wrl_l = c_u16b(b, 16)?;
let wrl_r = c_u16b(b, 18)?;
let wrl_t = c_u16b(b, 20)?;
let wrl_b = c_u16b(b, 22)?;
let wrl_x = c_u16b(b, 24)?;
let wrl_y = c_u16b(b, 26)?;
let flags = ok!(FrameFlags::from_bits(flags), "bad flag")?;
let min_lt = Fx32::from_bits(min_lt);
let min_lt = Fixed::from_bits(min_lt);
let wrl_l = Unit::from_bits(wrl_l);
let wrl_r = Unit::from_bits(wrl_r);
let wrl_t = Unit::from_bits(wrl_t);
let wrl_b = Unit::from_bits(wrl_b);
let wrl_x = Unit::from_bits(wrl_x);
let wrl_y = Unit::from_bits(wrl_y);
Ok(Frame{flags, min_lt, bmp_ind, wrl_l, wrl_r, wrl_t, wrl_b, wrl_x, wrl_y})
}
@ -345,14 +351,14 @@ pub struct ImageShp<'a, 'b>
pub struct Frame
{
flags: FrameFlags,
min_lt: Fx32,
min_lt: Fixed,
bmp_ind: usize,
wrl_l: i16,
wrl_r: i16,
wrl_t: i16,
wrl_b: i16,
wrl_x: i16,
wrl_y: i16,
wrl_l: Unit,
wrl_r: Unit,
wrl_t: Unit,
wrl_b: Unit,
wrl_x: Unit,
wrl_y: Unit,
}
#[derive(Debug, Serialize)]