add Unit and Angle types
parent
c258ee2558
commit
5e2ad524b0
|
@ -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.
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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)]
|
||||
|
|
Loading…
Reference in New Issue