1use crate::*;
26
27use std::{
28 fmt,
29 io::{BufRead, Error as ioError},
30};
31
32use super::{types::*, utils::*};
33
34pub fn load_ptx<IP, P, R>(read: &mut R, ip: &mut IP) -> PtxResult<()>
38where
39 IP: IsPushable<P>,
40 P: IsBuildable3D + IsMatrix4Transformable,
41 R: BufRead,
42{
43 let mut i_line = 0;
44 let mut line_buffer = Vec::new();
45
46 let mut line: &[u8];
47
48 loop {
49 let columns: usize;
50 {
51 let first_line = fetch_line(read, &mut line_buffer);
52 if first_line.is_err() {
53 break;
54 }
55 i_line += 1;
56
57 columns = from_ascii(first_line.as_ref().unwrap())
58 .ok_or(PtxError::Columns)
59 .index(i_line)?;
60 }
62
63 line = fetch_line(read, &mut line_buffer).index(i_line)?;
64 i_line += 1;
65
66 let rows: usize = from_ascii(line).ok_or(PtxError::Rows).line(i_line, line)?;
67
68 fetch_line(read, &mut line_buffer).index(i_line)?;
70 i_line += 1;
71
72 fetch_line(read, &mut line_buffer).index(i_line)?;
74 i_line += 1;
75
76 fetch_line(read, &mut line_buffer).index(i_line)?;
78 i_line += 1;
79
80 fetch_line(read, &mut line_buffer).index(i_line)?;
82 i_line += 1;
83
84 line = fetch_line(read, &mut line_buffer).index(i_line)?;
85 i_line += 1;
86 let [m11, m12, m13, m14] = read_matrix_row(line)
87 .ok_or(PtxError::Matrix)
88 .line(i_line, line)?;
89
90 line = fetch_line(read, &mut line_buffer).index(i_line)?;
91 i_line += 1;
92 let [m21, m22, m23, m24] = read_matrix_row(line)
93 .ok_or(PtxError::Matrix)
94 .line(i_line, line)?;
95
96 line = fetch_line(read, &mut line_buffer).index(i_line)?;
97 i_line += 1;
98 let [m31, m32, m33, m34] = read_matrix_row(line)
99 .ok_or(PtxError::Matrix)
100 .line(i_line, line)?;
101
102 line = fetch_line(read, &mut line_buffer).index(i_line)?;
103 i_line += 1;
104 let [m41, m42, m43, m44] = read_matrix_row(line)
105 .ok_or(PtxError::Matrix)
106 .line(i_line, line)?;
107
108 let m = Matrix4 {
109 data: [
110 [m11, m12, m13, m14],
111 [m21, m22, m23, m24],
112 [m31, m32, m33, m34],
113 [m41, m42, m43, m44],
114 ],
115 };
116
117 let must_transform = m != Matrix4::identity();
118
119 let n = columns * rows;
120
121 ip.reserve(n);
122
123 for _ in 0..n {
124 line = fetch_line(read, &mut line_buffer).index(i_line)?;
125 i_line += 1;
126
127 let mut words = to_words_skip_empty(line);
128
129 let x = words
130 .next()
131 .and_then(|w| from_ascii(w))
132 .ok_or(PtxError::Point)
133 .line(i_line, line)?;
134 let y = words
135 .next()
136 .and_then(|w| from_ascii(w))
137 .ok_or(PtxError::Point)
138 .line(i_line, line)?;
139 let z = words
140 .next()
141 .and_then(|w| from_ascii(w))
142 .ok_or(PtxError::Point)
143 .line(i_line, line)?;
144
145 let mut p = P::new(x, y, z);
146
147 if must_transform {
148 p.transform(&m)
149 }
150 ip.push(p)
151 }
152 }
153
154 Ok(())
155}
156
157#[inline(always)]
160fn read_matrix_row(line: &[u8]) -> Option<[f64; 4]> {
161 let mut words = to_words_skip_empty(line);
162
163 let a = from_ascii(words.next()?)?;
164 let b = from_ascii(words.next()?)?;
165 let c = from_ascii(words.next()?)?;
166 let d = from_ascii(words.next()?)?;
167
168 Some([a, b, c, d])
169}
170
171pub enum PtxError {
175 LoadFileEndReached,
176 AccessFile,
177 Columns,
178 Rows,
179 Matrix,
180 Point,
181}
182
183pub type PtxResult<T> = IOResult<T, PtxError>;
185
186impl fmt::Debug for PtxError {
187 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
188 match self {
189 Self::LoadFileEndReached => write!(f, "Unexpected reach of .ptx file end"),
190 Self::AccessFile => write!(f, "Unable to access file"),
191 Self::Columns => write!(f, "Columns could not be parsed"),
192 Self::Rows => write!(f, "Rows could not be parsed"),
193 Self::Matrix => write!(f, "Transformation matrix could not be parsed"),
194 Self::Point => write!(f, "Point could not be parsed"),
195 }
196 }
197}
198
199impl fmt::Display for PtxError {
200 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
201 write!(f, "{:?}", self)
202 }
203}
204
205impl From<ioError> for PtxError {
206 fn from(_error: ioError) -> Self {
207 PtxError::AccessFile
208 }
209}
210
211impl From<FetchLineError> for PtxError {
212 fn from(_error: FetchLineError) -> Self {
213 PtxError::LoadFileEndReached
214 }
215}
216
217impl From<WithLineInfo<FetchLineError>> for WithLineInfo<PtxError> {
218 fn from(other: WithLineInfo<FetchLineError>) -> Self {
219 match other {
220 WithLineInfo::<FetchLineError>::None(x) => WithLineInfo::None(PtxError::from(x)),
221 WithLineInfo::<FetchLineError>::Index(i, x) => {
222 WithLineInfo::Index(i, PtxError::from(x))
223 }
224 WithLineInfo::<FetchLineError>::Line(i, l, x) => {
225 WithLineInfo::Line(i, l, PtxError::from(x))
226 }
227 }
228 }
229}