mirror of
https://codeberg.org/demostf/parser.git
synced 2026-06-03 18:24:05 +02:00
sendprop writing
This commit is contained in:
parent
208ab1240d
commit
bfd6d8caf9
3 changed files with 382 additions and 24 deletions
|
|
@ -34,6 +34,9 @@ impl<'a> BitRead<'a, LittleEndian> for TempEntitiesMessage<'a> {
|
||||||
|
|
||||||
impl BitWrite<LittleEndian> for TempEntitiesMessage<'_> {
|
impl BitWrite<LittleEndian> for TempEntitiesMessage<'_> {
|
||||||
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
|
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
|
||||||
|
if !self.entities.is_empty() {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
self.count.write(stream)?;
|
self.count.write(stream)?;
|
||||||
write_var_int(self.data.bit_len() as u32, stream)?;
|
write_var_int(self.data.bit_len() as u32, stream)?;
|
||||||
self.data.write(stream)
|
self.data.write(stream)
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,8 @@ pub enum MalformedSendPropDefinitionError {
|
||||||
ArrayChangesOften,
|
ArrayChangesOften,
|
||||||
#[error(display = "SendProp value out of range")]
|
#[error(display = "SendProp value out of range")]
|
||||||
OutOfRange,
|
OutOfRange,
|
||||||
|
#[error(display = "Wrong prop value type for definition")]
|
||||||
|
WrongPropType,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
|
|
||||||
|
|
@ -678,6 +678,75 @@ impl SendPropValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn encode(
|
||||||
|
&self,
|
||||||
|
stream: &mut BitWriteStream<LittleEndian>,
|
||||||
|
definition: &SendPropParseDefinition,
|
||||||
|
) -> Result<()> {
|
||||||
|
match definition {
|
||||||
|
SendPropParseDefinition::NormalVarInt { unsigned, .. } => {
|
||||||
|
let val: i64 = self.try_into()?;
|
||||||
|
write_var_int(val as i32, stream, !*unsigned)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
SendPropParseDefinition::UnsignedInt { bit_count, .. } => {
|
||||||
|
let val: i64 = self.try_into()?;
|
||||||
|
(val as u32).write_sized(stream, *bit_count as usize)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
SendPropParseDefinition::Int { bit_count, .. } => {
|
||||||
|
let val: i64 = self.try_into()?;
|
||||||
|
(val as i32).write_sized(stream, *bit_count as usize)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
SendPropParseDefinition::Float {
|
||||||
|
definition: float_definition,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let val: f32 = self.try_into()?;
|
||||||
|
Self::write_float(val, stream, float_definition)
|
||||||
|
}
|
||||||
|
SendPropParseDefinition::String { .. } => {
|
||||||
|
let val: &str = self.try_into()?;
|
||||||
|
(val.len() as u16).write_sized(stream, 9)?;
|
||||||
|
val.write_sized(stream, val.len())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
SendPropParseDefinition::Vector {
|
||||||
|
definition: float_definition,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let val: Vector = self.try_into()?;
|
||||||
|
Self::write_float(val.x, stream, float_definition)?;
|
||||||
|
Self::write_float(val.y, stream, float_definition)?;
|
||||||
|
Self::write_float(val.z, stream, float_definition)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
SendPropParseDefinition::VectorXY {
|
||||||
|
definition: float_definition,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let val: VectorXY = self.try_into()?;
|
||||||
|
Self::write_float(val.x, stream, float_definition)?;
|
||||||
|
Self::write_float(val.y, stream, float_definition)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
SendPropParseDefinition::Array {
|
||||||
|
count_bit_count,
|
||||||
|
inner_definition,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let array: &[SendPropValue] = self.try_into()?;
|
||||||
|
(array.len() as u16).write_sized(stream, *count_bit_count as usize)?;
|
||||||
|
|
||||||
|
for inner in array {
|
||||||
|
inner.encode(stream, inner_definition)?
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn read_float(stream: &mut Stream, definition: &FloatDefinition) -> Result<f32> {
|
fn read_float(stream: &mut Stream, definition: &FloatDefinition) -> Result<f32> {
|
||||||
match definition {
|
match definition {
|
||||||
|
|
@ -706,6 +775,157 @@ impl SendPropValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_float(
|
||||||
|
val: f32,
|
||||||
|
stream: &mut BitWriteStream<LittleEndian>,
|
||||||
|
definition: &FloatDefinition,
|
||||||
|
) -> Result<()> {
|
||||||
|
match definition {
|
||||||
|
FloatDefinition::Coord => write_bit_coord(val, stream).map_err(ParseError::from),
|
||||||
|
FloatDefinition::CoordMP => {
|
||||||
|
write_bit_coord_mp(val, stream, false, false).map_err(ParseError::from)
|
||||||
|
}
|
||||||
|
FloatDefinition::CoordMPLowPrecision => {
|
||||||
|
write_bit_coord_mp(val, stream, false, true).map_err(ParseError::from)
|
||||||
|
}
|
||||||
|
FloatDefinition::CoordMPIntegral => {
|
||||||
|
write_bit_coord_mp(val, stream, true, false).map_err(ParseError::from)
|
||||||
|
}
|
||||||
|
FloatDefinition::FloatNoScale => val.write(stream).map_err(ParseError::from),
|
||||||
|
FloatDefinition::NormalVarFloat => {
|
||||||
|
write_bit_normal(val, stream).map_err(ParseError::from)
|
||||||
|
}
|
||||||
|
FloatDefinition::Scaled {
|
||||||
|
bit_count,
|
||||||
|
low,
|
||||||
|
high,
|
||||||
|
} => {
|
||||||
|
let percentage = (val - low) / (high - low);
|
||||||
|
let raw =
|
||||||
|
(percentage * ((1i32.wrapping_shl(*bit_count as u32)) as f32 - 1.0)) as u32;
|
||||||
|
raw.write_sized(stream, *bit_count as usize)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_send_prop_value_roundtrip() {
|
||||||
|
use bitbuffer::{BitReadBuffer, BitReadStream};
|
||||||
|
|
||||||
|
fn send_prop_value_roundtrip(val: SendPropValue, def: SendPropParseDefinition) {
|
||||||
|
let mut data = Vec::new();
|
||||||
|
let pos = {
|
||||||
|
let mut write = BitWriteStream::new(&mut data, LittleEndian);
|
||||||
|
val.encode(&mut write, &def).unwrap();
|
||||||
|
write.bit_len()
|
||||||
|
};
|
||||||
|
let mut read = BitReadStream::new(BitReadBuffer::new(&data, LittleEndian));
|
||||||
|
assert_eq!(val, SendPropValue::parse(&mut read, &def).unwrap());
|
||||||
|
assert_eq!(pos, read.pos());
|
||||||
|
}
|
||||||
|
send_prop_value_roundtrip(
|
||||||
|
SendPropValue::Integer(0),
|
||||||
|
SendPropParseDefinition::UnsignedInt {
|
||||||
|
changes_often: false,
|
||||||
|
bit_count: 5,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
send_prop_value_roundtrip(
|
||||||
|
SendPropValue::Integer(12),
|
||||||
|
SendPropParseDefinition::NormalVarInt {
|
||||||
|
changes_often: false,
|
||||||
|
unsigned: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
send_prop_value_roundtrip(
|
||||||
|
SendPropValue::Integer(12),
|
||||||
|
SendPropParseDefinition::NormalVarInt {
|
||||||
|
changes_often: false,
|
||||||
|
unsigned: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
send_prop_value_roundtrip(
|
||||||
|
SendPropValue::Integer(-12),
|
||||||
|
SendPropParseDefinition::NormalVarInt {
|
||||||
|
changes_often: false,
|
||||||
|
unsigned: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
send_prop_value_roundtrip(
|
||||||
|
SendPropValue::String("foobar".into()),
|
||||||
|
SendPropParseDefinition::String {
|
||||||
|
changes_often: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
send_prop_value_roundtrip(
|
||||||
|
SendPropValue::Vector(Vector {
|
||||||
|
x: 1.0,
|
||||||
|
y: 0.0,
|
||||||
|
z: 1.125,
|
||||||
|
}),
|
||||||
|
SendPropParseDefinition::Vector {
|
||||||
|
changes_often: false,
|
||||||
|
definition: FloatDefinition::Coord,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
send_prop_value_roundtrip(
|
||||||
|
SendPropValue::VectorXY(VectorXY { x: 1.0, y: 0.0 }),
|
||||||
|
SendPropParseDefinition::VectorXY {
|
||||||
|
changes_often: false,
|
||||||
|
definition: FloatDefinition::FloatNoScale,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
send_prop_value_roundtrip(
|
||||||
|
SendPropValue::Float(12.5),
|
||||||
|
SendPropParseDefinition::Float {
|
||||||
|
changes_often: false,
|
||||||
|
definition: FloatDefinition::CoordMP,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
send_prop_value_roundtrip(
|
||||||
|
SendPropValue::Float(12.0),
|
||||||
|
SendPropParseDefinition::Float {
|
||||||
|
changes_often: false,
|
||||||
|
definition: FloatDefinition::CoordMPIntegral,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
send_prop_value_roundtrip(
|
||||||
|
SendPropValue::Float(12.5),
|
||||||
|
SendPropParseDefinition::Float {
|
||||||
|
changes_often: false,
|
||||||
|
definition: FloatDefinition::CoordMPLowPrecision,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
send_prop_value_roundtrip(
|
||||||
|
SendPropValue::Float(12.498169),
|
||||||
|
SendPropParseDefinition::Float {
|
||||||
|
changes_often: false,
|
||||||
|
definition: FloatDefinition::Scaled {
|
||||||
|
bit_count: 12,
|
||||||
|
high: 25.0,
|
||||||
|
low: 10.0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
send_prop_value_roundtrip(
|
||||||
|
SendPropValue::Array(vec![
|
||||||
|
SendPropValue::Integer(0),
|
||||||
|
SendPropValue::Integer(1),
|
||||||
|
SendPropValue::Integer(2),
|
||||||
|
]),
|
||||||
|
SendPropParseDefinition::Array {
|
||||||
|
changes_often: false,
|
||||||
|
inner_definition: Box::new(SendPropParseDefinition::UnsignedInt {
|
||||||
|
changes_often: false,
|
||||||
|
bit_count: 3,
|
||||||
|
}),
|
||||||
|
count_bit_count: 5,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<i32> for SendPropValue {
|
impl From<i32> for SendPropValue {
|
||||||
|
|
@ -751,61 +971,61 @@ impl From<Vec<SendPropValue>> for SendPropValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&SendPropValue> for i64 {
|
impl TryFrom<&SendPropValue> for i64 {
|
||||||
type Error = ();
|
type Error = MalformedSendPropDefinitionError;
|
||||||
fn try_from(value: &SendPropValue) -> std::result::Result<Self, Self::Error> {
|
fn try_from(value: &SendPropValue) -> std::result::Result<Self, Self::Error> {
|
||||||
match value {
|
match value {
|
||||||
SendPropValue::Integer(val) => Ok(*val),
|
SendPropValue::Integer(val) => Ok(*val),
|
||||||
_ => Err(()),
|
_ => Err(MalformedSendPropDefinitionError::WrongPropType),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&SendPropValue> for Vector {
|
impl TryFrom<&SendPropValue> for Vector {
|
||||||
type Error = ();
|
type Error = MalformedSendPropDefinitionError;
|
||||||
fn try_from(value: &SendPropValue) -> std::result::Result<Self, Self::Error> {
|
fn try_from(value: &SendPropValue) -> std::result::Result<Self, Self::Error> {
|
||||||
match value {
|
match value {
|
||||||
SendPropValue::Vector(val) => Ok(*val),
|
SendPropValue::Vector(val) => Ok(*val),
|
||||||
_ => Err(()),
|
_ => Err(MalformedSendPropDefinitionError::WrongPropType),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&SendPropValue> for VectorXY {
|
impl TryFrom<&SendPropValue> for VectorXY {
|
||||||
type Error = ();
|
type Error = MalformedSendPropDefinitionError;
|
||||||
fn try_from(value: &SendPropValue) -> std::result::Result<Self, Self::Error> {
|
fn try_from(value: &SendPropValue) -> std::result::Result<Self, Self::Error> {
|
||||||
match value {
|
match value {
|
||||||
SendPropValue::VectorXY(val) => Ok(*val),
|
SendPropValue::VectorXY(val) => Ok(*val),
|
||||||
_ => Err(()),
|
_ => Err(MalformedSendPropDefinitionError::WrongPropType),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&SendPropValue> for f32 {
|
impl TryFrom<&SendPropValue> for f32 {
|
||||||
type Error = ();
|
type Error = MalformedSendPropDefinitionError;
|
||||||
fn try_from(value: &SendPropValue) -> std::result::Result<Self, Self::Error> {
|
fn try_from(value: &SendPropValue) -> std::result::Result<Self, Self::Error> {
|
||||||
match value {
|
match value {
|
||||||
SendPropValue::Float(val) => Ok(*val),
|
SendPropValue::Float(val) => Ok(*val),
|
||||||
_ => Err(()),
|
_ => Err(MalformedSendPropDefinitionError::WrongPropType),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TryFrom<&'a SendPropValue> for &'a str {
|
impl<'a> TryFrom<&'a SendPropValue> for &'a str {
|
||||||
type Error = ();
|
type Error = MalformedSendPropDefinitionError;
|
||||||
fn try_from(value: &'a SendPropValue) -> std::result::Result<Self, Self::Error> {
|
fn try_from(value: &'a SendPropValue) -> std::result::Result<Self, Self::Error> {
|
||||||
match value {
|
match value {
|
||||||
SendPropValue::String(val) => Ok(val.as_str()),
|
SendPropValue::String(val) => Ok(val.as_str()),
|
||||||
_ => Err(()),
|
_ => Err(MalformedSendPropDefinitionError::WrongPropType),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TryFrom<&'a SendPropValue> for &'a [SendPropValue] {
|
impl<'a> TryFrom<&'a SendPropValue> for &'a [SendPropValue] {
|
||||||
type Error = ();
|
type Error = MalformedSendPropDefinitionError;
|
||||||
fn try_from(value: &'a SendPropValue) -> std::result::Result<Self, Self::Error> {
|
fn try_from(value: &'a SendPropValue) -> std::result::Result<Self, Self::Error> {
|
||||||
match value {
|
match value {
|
||||||
SendPropValue::Array(val) => Ok(val.as_slice()),
|
SendPropValue::Array(val) => Ok(val.as_slice()),
|
||||||
_ => Err(()),
|
_ => Err(MalformedSendPropDefinitionError::WrongPropType),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -828,24 +1048,62 @@ pub struct SendProp {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_var_int(stream: &mut Stream, signed: bool) -> ReadResult<i32> {
|
pub fn read_var_int(stream: &mut Stream, signed: bool) -> ReadResult<i32> {
|
||||||
let mut result: i32 = 0;
|
let abs_int = crate::demo::message::stringtable::read_var_int(stream)? as i32;
|
||||||
|
|
||||||
for i in (0..35).step_by(7) {
|
|
||||||
let byte: u8 = stream.read()?;
|
|
||||||
result |= ((byte & 0x7F) as i32) << i;
|
|
||||||
|
|
||||||
if (byte >> 7) == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if signed {
|
if signed {
|
||||||
Ok((result >> 1) ^ -(result & 1))
|
Ok((abs_int >> 1) ^ -(abs_int & 1))
|
||||||
} else {
|
} else {
|
||||||
Ok(result)
|
Ok(abs_int)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write_var_int(
|
||||||
|
int: i32,
|
||||||
|
stream: &mut BitWriteStream<LittleEndian>,
|
||||||
|
signed: bool,
|
||||||
|
) -> ReadResult<()> {
|
||||||
|
let abs = if signed {
|
||||||
|
let sign = int < 0;
|
||||||
|
(int.abs() as u32) << 1 | (sign as u32)
|
||||||
|
} else {
|
||||||
|
int as u32
|
||||||
|
};
|
||||||
|
|
||||||
|
crate::demo::message::stringtable::write_var_int(abs, stream)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_var_int_roundtrip() {
|
||||||
|
use bitbuffer::{BitReadBuffer, BitReadStream};
|
||||||
|
|
||||||
|
fn var_int_roundtrip(int: i32, signed: bool) {
|
||||||
|
let mut data = Vec::new();
|
||||||
|
let pos = {
|
||||||
|
let mut write = BitWriteStream::new(&mut data, LittleEndian);
|
||||||
|
write_var_int(int, &mut write, signed).unwrap();
|
||||||
|
write.bit_len()
|
||||||
|
};
|
||||||
|
let mut read = BitReadStream::new(BitReadBuffer::new(&data, LittleEndian));
|
||||||
|
assert_eq!(int, read_var_int(&mut read, signed).unwrap());
|
||||||
|
assert_eq!(pos, read.pos());
|
||||||
|
}
|
||||||
|
var_int_roundtrip(0, false);
|
||||||
|
var_int_roundtrip(1, false);
|
||||||
|
var_int_roundtrip(10, false);
|
||||||
|
var_int_roundtrip(55, false);
|
||||||
|
var_int_roundtrip(355, false);
|
||||||
|
var_int_roundtrip(12354, false);
|
||||||
|
var_int_roundtrip(123125412, false);
|
||||||
|
|
||||||
|
var_int_roundtrip(-0, false);
|
||||||
|
var_int_roundtrip(-1, false);
|
||||||
|
var_int_roundtrip(-10, false);
|
||||||
|
var_int_roundtrip(-55, false);
|
||||||
|
var_int_roundtrip(-355, false);
|
||||||
|
var_int_roundtrip(-12354, false);
|
||||||
|
var_int_roundtrip(-123125412, false);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn read_bit_coord(stream: &mut Stream) -> ReadResult<f32> {
|
pub fn read_bit_coord(stream: &mut Stream) -> ReadResult<f32> {
|
||||||
let has_int = stream.read()?;
|
let has_int = stream.read()?;
|
||||||
let has_frac = stream.read()?;
|
let has_frac = stream.read()?;
|
||||||
|
|
@ -890,7 +1148,7 @@ pub fn write_bit_coord(val: f32, stream: &mut BitWriteStream<LittleEndian>) -> R
|
||||||
fn bit_coord_roundtrip() {
|
fn bit_coord_roundtrip() {
|
||||||
use bitbuffer::BitReadBuffer;
|
use bitbuffer::BitReadBuffer;
|
||||||
|
|
||||||
let mut data = Vec::with_capacity(128);
|
let mut data = Vec::with_capacity(16);
|
||||||
let (pos1, pos2, pos3, pos4) = {
|
let (pos1, pos2, pos3, pos4) = {
|
||||||
let mut write = BitWriteStream::new(&mut data, LittleEndian);
|
let mut write = BitWriteStream::new(&mut data, LittleEndian);
|
||||||
write_bit_coord(0.0, &mut write).unwrap();
|
write_bit_coord(0.0, &mut write).unwrap();
|
||||||
|
|
@ -955,6 +1213,74 @@ pub fn read_bit_coord_mp(
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write_bit_coord_mp(
|
||||||
|
val: f32,
|
||||||
|
stream: &mut BitWriteStream<LittleEndian>,
|
||||||
|
is_integral: bool,
|
||||||
|
low_precision: bool,
|
||||||
|
) -> ReadResult<()> {
|
||||||
|
let abs = val.abs();
|
||||||
|
let in_bounds = (abs as u32) <= 2u32.pow(10);
|
||||||
|
let has_int_val = abs > 1.0;
|
||||||
|
in_bounds.write(stream)?;
|
||||||
|
has_int_val.write(stream)?;
|
||||||
|
|
||||||
|
if is_integral {
|
||||||
|
if has_int_val {
|
||||||
|
val.is_sign_negative().write(stream)?;
|
||||||
|
((abs - 1.0) as u32).write_sized(stream, if in_bounds { 11 } else { 14 })?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val.is_sign_negative().write(stream)?;
|
||||||
|
if has_int_val {
|
||||||
|
((abs - 1.0) as u32).write_sized(stream, if in_bounds { 11 } else { 14 })?;
|
||||||
|
}
|
||||||
|
let frac_bits = if low_precision { 3 } else { 5 };
|
||||||
|
let frac_val = (abs.fract() / get_frac_factor(frac_bits)) as u32;
|
||||||
|
frac_val.write_sized(stream, frac_bits)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bit_coord_mp_roundtrip() {
|
||||||
|
use bitbuffer::{BitReadBuffer, BitReadStream};
|
||||||
|
|
||||||
|
fn bit_coord_mp_normal(val: f32, is_integral: bool, low_precision: bool) {
|
||||||
|
let mut data = Vec::with_capacity(16);
|
||||||
|
let pos = {
|
||||||
|
let mut write = BitWriteStream::new(&mut data, LittleEndian);
|
||||||
|
write_bit_coord_mp(val, &mut write, is_integral, low_precision).unwrap();
|
||||||
|
write.bit_len()
|
||||||
|
};
|
||||||
|
let mut read = BitReadStream::new(BitReadBuffer::new(&data, LittleEndian));
|
||||||
|
assert_eq!(
|
||||||
|
val,
|
||||||
|
read_bit_coord_mp(&mut read, is_integral, low_precision).unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(pos, read.pos());
|
||||||
|
}
|
||||||
|
bit_coord_mp_normal(0.0, false, false);
|
||||||
|
bit_coord_mp_normal(0.5, false, false);
|
||||||
|
bit_coord_mp_normal(-0.5, false, false);
|
||||||
|
bit_coord_mp_normal(1234.5, false, false);
|
||||||
|
bit_coord_mp_normal(-1234.5, false, false);
|
||||||
|
bit_coord_mp_normal(2.0f32.powf(12.0) + 0.125, false, false);
|
||||||
|
|
||||||
|
bit_coord_mp_normal(0.0, false, true);
|
||||||
|
bit_coord_mp_normal(0.5, false, true);
|
||||||
|
bit_coord_mp_normal(-0.5, false, true);
|
||||||
|
bit_coord_mp_normal(1234.5, false, true);
|
||||||
|
bit_coord_mp_normal(-1234.5, false, true);
|
||||||
|
bit_coord_mp_normal(2.0f32.powf(12.0) + 0.125, false, true);
|
||||||
|
|
||||||
|
bit_coord_mp_normal(0.0, true, false);
|
||||||
|
bit_coord_mp_normal(1234.0, true, false);
|
||||||
|
bit_coord_mp_normal(-1234.0, true, false);
|
||||||
|
bit_coord_mp_normal(2.0f32.powf(12.0), true, false);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn read_bit_normal(stream: &mut Stream) -> ReadResult<f32> {
|
pub fn read_bit_normal(stream: &mut Stream) -> ReadResult<f32> {
|
||||||
let is_negative = stream.read()?;
|
let is_negative = stream.read()?;
|
||||||
let frac_val: u16 = stream.read_sized(11)?;
|
let frac_val: u16 = stream.read_sized(11)?;
|
||||||
|
|
@ -965,3 +1291,30 @@ pub fn read_bit_normal(stream: &mut Stream) -> ReadResult<f32> {
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write_bit_normal(val: f32, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
|
||||||
|
val.is_sign_negative().write(stream)?;
|
||||||
|
let frac_val = (val.abs().fract() / get_frac_factor(11)) as u16;
|
||||||
|
frac_val.write_sized(stream, 11)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bit_normal_roundtrip() {
|
||||||
|
use bitbuffer::{BitReadBuffer, BitReadStream};
|
||||||
|
|
||||||
|
fn roundtrip_normal(val: f32) {
|
||||||
|
let mut data = Vec::with_capacity(16);
|
||||||
|
let pos = {
|
||||||
|
let mut write = BitWriteStream::new(&mut data, LittleEndian);
|
||||||
|
write_bit_normal(val, &mut write).unwrap();
|
||||||
|
write.bit_len()
|
||||||
|
};
|
||||||
|
let mut read = BitReadStream::new(BitReadBuffer::new(&data, LittleEndian));
|
||||||
|
assert_eq!(val, read_bit_normal(&mut read).unwrap());
|
||||||
|
assert_eq!(pos, read.pos());
|
||||||
|
}
|
||||||
|
roundtrip_normal(0.0);
|
||||||
|
roundtrip_normal(-0.0);
|
||||||
|
roundtrip_normal(0.5);
|
||||||
|
roundtrip_normal(-0.5);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue