use crate::*;
use std::{
fmt,
io::{BufRead, Error as ioError},
};
use super::{types::*, utils::*};
pub fn load_ptx<IP, P, R>(read: &mut R, ip: &mut IP) -> PtxResult<()>
where
IP: IsPushable<P>,
P: IsBuildable3D + IsMatrix4Transformable,
R: BufRead,
{
let mut i_line = 0;
let mut line_buffer = Vec::new();
let mut line: &[u8];
loop {
let columns: usize;
{
let first_line = fetch_line(read, &mut line_buffer);
if first_line.is_err() {
break;
}
i_line += 1;
columns = from_ascii(first_line.as_ref().unwrap())
.ok_or(PtxError::Columns)
.index(i_line)?;
}
line = fetch_line(read, &mut line_buffer).index(i_line)?;
i_line += 1;
let rows: usize = from_ascii(line).ok_or(PtxError::Rows).line(i_line, line)?;
fetch_line(read, &mut line_buffer).index(i_line)?;
i_line += 1;
fetch_line(read, &mut line_buffer).index(i_line)?;
i_line += 1;
fetch_line(read, &mut line_buffer).index(i_line)?;
i_line += 1;
fetch_line(read, &mut line_buffer).index(i_line)?;
i_line += 1;
line = fetch_line(read, &mut line_buffer).index(i_line)?;
i_line += 1;
let [m11, m12, m13, m14] = read_matrix_row(line)
.ok_or(PtxError::Matrix)
.line(i_line, line)?;
line = fetch_line(read, &mut line_buffer).index(i_line)?;
i_line += 1;
let [m21, m22, m23, m24] = read_matrix_row(line)
.ok_or(PtxError::Matrix)
.line(i_line, line)?;
line = fetch_line(read, &mut line_buffer).index(i_line)?;
i_line += 1;
let [m31, m32, m33, m34] = read_matrix_row(line)
.ok_or(PtxError::Matrix)
.line(i_line, line)?;
line = fetch_line(read, &mut line_buffer).index(i_line)?;
i_line += 1;
let [m41, m42, m43, m44] = read_matrix_row(line)
.ok_or(PtxError::Matrix)
.line(i_line, line)?;
let m = Matrix4 {
data: [
[m11, m12, m13, m14],
[m21, m22, m23, m24],
[m31, m32, m33, m34],
[m41, m42, m43, m44],
],
};
let must_transform = m != Matrix4::identity();
let n = columns * rows;
ip.reserve(n);
for _ in 0..n {
line = fetch_line(read, &mut line_buffer).index(i_line)?;
i_line += 1;
let mut words = to_words_skip_empty(line);
let x = words
.next()
.and_then(|w| from_ascii(w))
.ok_or(PtxError::Point)
.line(i_line, line)?;
let y = words
.next()
.and_then(|w| from_ascii(w))
.ok_or(PtxError::Point)
.line(i_line, line)?;
let z = words
.next()
.and_then(|w| from_ascii(w))
.ok_or(PtxError::Point)
.line(i_line, line)?;
let mut p = P::new(x, y, z);
if must_transform {
p.transform(&m)
}
ip.push(p)
}
}
Ok(())
}
#[inline(always)]
fn read_matrix_row(line: &[u8]) -> Option<[f64; 4]> {
let mut words = to_words_skip_empty(line);
let a = from_ascii(words.next()?)?;
let b = from_ascii(words.next()?)?;
let c = from_ascii(words.next()?)?;
let d = from_ascii(words.next()?)?;
Some([a, b, c, d])
}
pub enum PtxError {
LoadFileEndReached,
AccessFile,
Columns,
Rows,
Matrix,
Point,
}
pub type PtxResult<T> = IOResult<T, PtxError>;
impl fmt::Debug for PtxError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::LoadFileEndReached => write!(f, "Unexpected reach of .ptx file end"),
Self::AccessFile => write!(f, "Unable to access file"),
Self::Columns => write!(f, "Columns could not be parsed"),
Self::Rows => write!(f, "Rows could not be parsed"),
Self::Matrix => write!(f, "Transformation matrix could not be parsed"),
Self::Point => write!(f, "Point could not be parsed"),
}
}
}
impl fmt::Display for PtxError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl From<ioError> for PtxError {
fn from(_error: ioError) -> Self {
PtxError::AccessFile
}
}
impl From<FetchLineError> for PtxError {
fn from(_error: FetchLineError) -> Self {
PtxError::LoadFileEndReached
}
}
impl From<WithLineInfo<FetchLineError>> for WithLineInfo<PtxError> {
fn from(other: WithLineInfo<FetchLineError>) -> Self {
match other {
WithLineInfo::<FetchLineError>::None(x) => WithLineInfo::None(PtxError::from(x)),
WithLineInfo::<FetchLineError>::Index(i, x) => {
WithLineInfo::Index(i, PtxError::from(x))
}
WithLineInfo::<FetchLineError>::Line(i, l, x) => {
WithLineInfo::Line(i, l, PtxError::from(x))
}
}
}
}