use crate::read_extension::ReadExt;
use crate::unaligned_rw::{UnalignedRWMode, UnalignedReader, UnalignedWriter};
use crate::TMFImportError;
use crate::MAX_SEG_SIZE;
use crate::{FloatType, IndexType, Vector3};
use std::io::{Read, Write};
#[derive(Clone, Copy, PartialEq)]
pub struct VertexPrecisionMode(pub FloatType);
impl Default for VertexPrecisionMode {
fn default() -> Self {
Self(0.1)
}
}
pub fn save_tmf_vertices<W: Write>(
vertices: &[Vector3],
precision: VertexPrecisionMode,
writer: &mut W,
shortest_edge: FloatType,
) -> std::io::Result<()> {
let mut min_x = vertices[0].0;
let mut max_x = vertices[0].0;
let mut min_y = vertices[0].1;
let mut max_y = vertices[0].1;
let mut min_z = vertices[0].2;
let mut max_z = vertices[0].2;
writer.write_all(&(vertices.len() as u64).to_le_bytes())?;
for vertex in vertices {
min_x = min_x.min(vertex.0);
max_x = max_y.max(vertex.1);
min_y = min_z.min(vertex.2);
max_y = max_x.max(vertex.0);
min_z = min_y.min(vertex.1);
max_z = max_z.max(vertex.2);
}
writer.write_all(&(min_x as f64).to_le_bytes())?;
writer.write_all(&(max_x as f64).to_le_bytes())?;
writer.write_all(&(min_y as f64).to_le_bytes())?;
writer.write_all(&(max_y as f64).to_le_bytes())?;
writer.write_all(&(min_z as f64).to_le_bytes())?;
writer.write_all(&(max_z as f64).to_le_bytes())?;
let sx = max_x - min_x;
let sy = max_y - min_y;
let sz = max_z - min_z;
let sx = sx.max(0.000_001);
let sy = sy.max(0.000_001);
let sz = sz.max(0.000_001);
let inc_x = (shortest_edge / sx) * precision.0;
let inc_y = (shortest_edge / sy) * precision.0;
let inc_z = (shortest_edge / sy) * precision.0;
let prec_x = (1.0 / inc_x).log2().ceil() as u8;
let prec_y = (1.0 / inc_y).log2().ceil() as u8;
let prec_z = (1.0 / inc_z).log2().ceil() as u8;
let prec_x = prec_x.max(1);
let prec_y = prec_y.max(1);
let prec_z = prec_z.max(1);
writer.write_all(&[prec_x])?;
writer.write_all(&[prec_y])?;
writer.write_all(&[prec_z])?;
let mul_x = ((1 << prec_x) - 1) as FloatType;
let mul_y = ((1 << prec_y) - 1) as FloatType;
let mul_z = ((1 << prec_z) - 1) as FloatType;
let prec_x = UnalignedRWMode::precision_bits(prec_x);
let prec_y = UnalignedRWMode::precision_bits(prec_y);
let prec_z = UnalignedRWMode::precision_bits(prec_z);
let mut writer = UnalignedWriter::new(writer);
for vertex in vertices {
let x = (((vertex.0 - min_x) / sx) * mul_x) as u64;
let y = (((vertex.1 - min_y) / sy) * mul_y) as u64;
let z = (((vertex.2 - min_z) / sz) * mul_z) as u64;
writer.write_unaligned(prec_x, x)?;
writer.write_unaligned(prec_y, y)?;
writer.write_unaligned(prec_z, z)?;
}
writer.flush()?;
Ok(())
}
pub fn read_tmf_vertices<R: Read>(reader: &mut R) -> Result<Box<[Vector3]>, TMFImportError> {
let vertex_count = reader.read_u64()? as usize;
let min_x = reader.read_f64()? as FloatType;
let max_x = reader.read_f64()? as FloatType;
let min_y = reader.read_f64()? as FloatType;
let max_y = reader.read_f64()? as FloatType;
let min_z = reader.read_f64()? as FloatType;
let max_z = reader.read_f64()? as FloatType;
let prec_x = reader.read_u8()?;
if prec_x >= u64::BITS as u8 {
return Err(TMFImportError::InvalidPrecision(prec_x));
}
let prec_y = reader.read_u8()?;
if prec_y >= u64::BITS as u8 {
return Err(TMFImportError::InvalidPrecision(prec_y));
}
let prec_z = reader.read_u8()?;
if prec_z >= u64::BITS as u8 {
return Err(TMFImportError::InvalidPrecision(prec_z));
}
let div_x = ((1_u64 << prec_x) - 1) as FloatType;
let div_y = ((1_u64 << prec_y) - 1) as FloatType;
let div_z = ((1_u64 << prec_z) - 1) as FloatType;
let prec_x = UnalignedRWMode::precision_bits(prec_x);
let prec_y = UnalignedRWMode::precision_bits(prec_y);
let prec_z = UnalignedRWMode::precision_bits(prec_z);
let sx = max_x - min_x;
let sy = max_y - min_y;
let sz = max_z - min_z;
if vertex_count > MAX_SEG_SIZE {
return Err(TMFImportError::SegmentTooLong);
}
let mut vertices = Vec::with_capacity(vertex_count);
let mut reader = UnalignedReader::new(reader);
for _ in 0..vertex_count {
let x = reader.read_unaligned(prec_x)?;
let y = reader.read_unaligned(prec_y)?;
let z = reader.read_unaligned(prec_z)?;
let x = (x as FloatType) / div_x;
let y = (y as FloatType) / div_y;
let z = (z as FloatType) / div_z;
let x = x * sx + min_x;
let y = y * sy + min_y;
let z = z * sz + min_z;
vertices.push((x, y, z));
}
Ok(vertices.into())
}
#[allow(clippy::cast_possible_truncation)]
pub(crate) fn calc_prec(max: usize) -> u8 {
if max == usize::MAX {
return 64;
}
let max1 = max + 1;
let offset_of_first_1 = (usize::BITS - 1 - max1.leading_zeros()) as u8;
let round_up = max1.count_ones() > 1;
offset_of_first_1 + if round_up { 1 } else { 0 }
}
pub fn save_triangles<W: Write>(
triangles: &[IndexType],
max_index: usize,
writer: &mut W,
) -> std::io::Result<()> {
let min = *triangles.iter().min().unwrap_or(&0);
let precision = calc_prec(max_index);
writer.write_all(&precision.to_le_bytes())?;
writer.write_all(&(triangles.len() as u64).to_le_bytes())?;
writer.write_all(&u64::from(min).to_le_bytes())?;
let precision = UnalignedRWMode::precision_bits(precision);
let mut writer = UnalignedWriter::new(writer);
for index in triangles {
writer.write_unaligned(precision, u64::from(index - min))?;
}
writer.flush()
}
pub(crate) fn read_triangles<R: Read>(
reader: &mut R,
ctx: &crate::tmf_importer::TMFImportContext,
) -> Result<Box<[IndexType]>, TMFImportError> {
let precision = reader.read_u8()?;
let length = reader.read_u64()?;
let min = ctx.read_traingle_min(reader)?;
if length > MAX_SEG_SIZE as u64 {
return Err(TMFImportError::SegmentTooLong);
}
let mut res = Vec::with_capacity(length as usize);
let precision = UnalignedRWMode::precision_bits(precision);
let mut reader = UnalignedReader::new(reader);
for _ in 0..(length / 2) {
let (i1, i2) = reader.read2_unaligned(precision)?;
res.push((i1 + min) as IndexType);
res.push((i2 + min) as IndexType);
}
for _i in 0..length % 2 {
res.push((reader.read_unaligned(precision)? + min) as IndexType);
}
Ok(res.into())
}
#[cfg(test)]
mod testing {
fn dst(a: Vector3, b: Vector3) -> FloatType {
let dx = a.0 - b.0;
let dy = a.1 - b.1;
let dz = a.2 - b.2;
(dx * dx + dy * dy + dz * dz).sqrt()
}
use super::*;
#[test]
fn rw_vertices() {
use rand::{thread_rng, Rng};
let mut rng = thread_rng();
let vertex_count = (rng.gen::<IndexType>() % 0x800) + 0x800;
let mut vertices = Vec::with_capacity(vertex_count as usize);
for _ in 0..vertex_count {
let x = (rng.gen::<FloatType>() - 0.5) * 2.0;
let y = (rng.gen::<FloatType>() - 0.5) * 2.0;
let z = (rng.gen::<FloatType>() - 0.5) * 2.0;
vertices.push((x, y, z));
}
let mut res = Vec::with_capacity(vertex_count as usize);
{
save_tmf_vertices(&vertices, VertexPrecisionMode(0.01), &mut res, 0.1).unwrap();
}
let r_vertices = read_tmf_vertices(&mut (&res as &[u8])).unwrap();
assert!(r_vertices.len() == vertices.len());
for i in 0..vertices.len() {
assert!(
dst(r_vertices[i], vertices[i]) < 0.01,
"{:?} {:?} {}",
r_vertices[i],
vertices[i],
dst(r_vertices[i], vertices[i])
);
}
}
}