1use crate::*;
26
27use std::{
28 fmt,
29 io::{BufRead, Error as ioError},
30};
31
32use super::{types::*, utils::*};
33
34pub fn load_obj_mesh<EM, P, R>(read: &mut R, mesh: &mut EM) -> ObjResult<()>
38where
39 EM: IsFaceEditableMesh<P, Face3> + IsVertexEditableMesh<P, Face3>,
40 P: IsBuildable3D + Clone,
41 R: BufRead,
42{
43 let mut line_buffer = Vec::new();
44 let mut i_line = 0;
45
46 while let Ok(line) = fetch_line(read, &mut line_buffer) {
47 i_line += 1;
48
49 if line.starts_with(b"v ") {
50 let mut words = to_words_skip_empty(line);
51
52 words.next().ok_or(ObjError::Vertex).line(i_line, line)?;
54
55 let x = words
56 .next()
57 .and_then(|w| from_ascii(w))
58 .ok_or(ObjError::Vertex)
59 .line(i_line, line)?;
60
61 let y = words
62 .next()
63 .and_then(|w| from_ascii(w))
64 .ok_or(ObjError::Vertex)
65 .line(i_line, line)?;
66
67 let z = words
68 .next()
69 .and_then(|w| from_ascii(w))
70 .ok_or(ObjError::Vertex)
71 .line(i_line, line)?;
72
73 mesh.add_vertex(P::new(x, y, z));
74 } else if line.starts_with(b"f ") {
75 let mut words = to_words_skip_empty(line);
76
77 words.next().ok_or(ObjError::Face).line(i_line, line)?;
79
80 let mut tmp = words.next().ok_or(ObjError::Face).line(i_line, line)?;
81 let a: usize = from_ascii(until_bytes(tmp, b'/'))
82 .ok_or(ObjError::Face)
83 .line(i_line, line)?;
84
85 tmp = words.next().ok_or(ObjError::Face).line(i_line, line)?;
86 let b: usize = from_ascii(until_bytes(tmp, b'/'))
87 .ok_or(ObjError::Face)
88 .line(i_line, line)?;
89
90 tmp = words.next().ok_or(ObjError::Face).line(i_line, line)?;
91 let c: usize = from_ascii(until_bytes(tmp, b'/'))
92 .ok_or(ObjError::Face)
93 .line(i_line, line)?;
94
95 mesh.try_add_connection(VId { val: a - 1 }, VId { val: b - 1 }, VId { val: c - 1 })
97 .or(Err(ObjError::InvalidMeshIndices))
98 .line(i_line, line)?;
99 }
100 }
101
102 Ok(())
103}
104
105pub fn load_obj_points<IP, P, R>(read: &mut R, ip: &mut IP) -> ObjResult<()>
107where
108 IP: IsPushable<P>,
109 P: IsBuildable3D,
110 R: BufRead,
111{
112 let mut line_buffer = Vec::new();
113 let mut i_line = 0;
114
115 while let Ok(line) = fetch_line(read, &mut line_buffer) {
116 i_line += 1;
117
118 if line.starts_with(b"v ") {
119 let mut words = to_words_skip_empty(line);
120
121 words.next().ok_or(ObjError::Vertex).line(i_line, line)?;
123
124 let x = words
125 .next()
126 .and_then(|w| from_ascii(w))
127 .ok_or(ObjError::Vertex)
128 .line(i_line, line)?;
129
130 let y = words
131 .next()
132 .and_then(|w| from_ascii(w))
133 .ok_or(ObjError::Vertex)
134 .line(i_line, line)?;
135
136 let z = words
137 .next()
138 .and_then(|w| from_ascii(w))
139 .ok_or(ObjError::Vertex)
140 .line(i_line, line)?;
141
142 ip.push(P::new(x, y, z));
143 }
144 }
145
146 Ok(())
147}
148
149pub enum ObjError {
153 AccessFile,
154 InvalidMeshIndices,
155 Face,
156 Vertex,
157}
158
159pub type ObjResult<T> = IOResult<T, ObjError>;
161
162impl fmt::Debug for ObjError {
163 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164 match self {
165 Self::AccessFile => write!(f, "Unable to access file"),
166 Self::Face => write!(f, "Unable to parse face"),
167 Self::Vertex => write!(f, "Unable to parse vertex"),
168 Self::InvalidMeshIndices => write!(f, "File contains invalid mesh indices"),
169 }
170 }
171}
172
173impl fmt::Display for ObjError {
174 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
175 write!(f, "{:?}", self)
176 }
177}
178
179impl From<ioError> for ObjError {
180 fn from(_error: ioError) -> Self {
181 ObjError::AccessFile
182 }
183}