1use std::io::Write;
2
3use crate::kernel::{fxx, vec2, vec3, Vec2, Vec3};
4
5use crate::{core::PointBased, data::Grid2};
6
7#[derive(Default, Debug)]
8pub struct Mesh {
9 pub verts: Vec<Vec3>,
10 pub uvs: Vec<Vec2>,
11 pub tri: Vec<usize>,
12}
13
14impl Mesh {
15 pub fn new(verts: Vec<Vec3>, tri: Vec<usize>, uvs: Vec<Vec2>) -> Self {
16 Self { verts, tri, uvs }
17 }
18
19 pub fn new_weave(verts: Grid2<Option<(Vec3, Vec2)>>) -> Mesh {
33 let mut mesh = Mesh::default();
34
35 for (i, res) in verts.items.iter().enumerate() {
37 let (x, y) = verts.to_xy(i);
38 match res {
39 Some((pos, uv)) => {
40 mesh.verts.push(pos.clone());
41 mesh.uvs.push(uv.clone());
42 }
43 None => {
44 mesh.verts.push(vec3(0., 0., 0.));
45 mesh.uvs.push(vec2(0., 0.));
46 }
47 }
48 }
49
50 for (i, res) in verts.items.iter().enumerate() {
52 let (x, y) = verts.to_xy(i);
53
54 if x == 0 || y == 0 {
55 continue;
56 }
57
58 let ia = i;
59 let ib = verts.to_index(x - 1, y).unwrap();
60 let ic = verts.to_index(x, y - 1).unwrap();
61 let id = verts.to_index(x - 1, y - 1).unwrap();
62
63 let a = verts.get_unsafe(ia);
64 let b = verts.get_unsafe(ib);
65 let c = verts.get_unsafe(ic);
66 let d = verts.get_unsafe(id);
67
68 if a.is_some() && b.is_some() && c.is_some() && d.is_some() {
72 mesh.tri.append(&mut vec![ia, id, ib]);
73 mesh.tri.append(&mut vec![ia, ic, id]);
74 } else if a.is_some() && b.is_some() && c.is_some() {
75 mesh.tri.append(&mut vec![ia, ic, ib]);
76 } else if a.is_some() && b.is_some() && d.is_some() {
77 mesh.tri.append(&mut vec![ia, id, ib]);
78 } else if a.is_some() && c.is_some() && d.is_some() {
79 mesh.tri.append(&mut vec![ia, ic, id]);
80 } else if b.is_some() && c.is_some() && d.is_some() {
81 mesh.tri.append(&mut vec![ib, ic, id]);
82 }
83 }
84
85 mesh
88 }
89
90 pub fn new_diamonds(points: Vec<Vec3>, size: fxx) -> Mesh {
92 let mut meshes = Vec::new();
93 for point in points {
94 meshes.push(Mesh::new_diamond(point, size))
95 }
96 Mesh::from_join(meshes)
97 }
98
99 pub fn new_diamond(center: Vec3, size: fxx) -> Mesh {
100 let mut mesh = Mesh::default();
101
102 mesh.verts
103 .push(Vec3::new(center.x + size, center.y, center.z));
104 mesh.verts
105 .push(Vec3::new(center.x - size, center.y, center.z));
106 mesh.verts
107 .push(Vec3::new(center.x, center.y + size, center.z));
108 mesh.verts
109 .push(Vec3::new(center.x, center.y - size, center.z));
110 mesh.verts
111 .push(Vec3::new(center.x, center.y, center.z + size));
112 mesh.verts
113 .push(Vec3::new(center.x, center.y, center.z - size));
114
115 mesh.tri.append(&mut vec![
116 4, 0, 2, 4, 2, 1, 4, 1, 3, 4, 3, 0, 5, 2, 0, 5, 1, 2, 5, 3, 1, 5, 0, 3,
117 ]);
118
119 mesh
120 }
121
122 pub fn from_join(meshes: Vec<Mesh>) -> Mesh {
124 let mut mesh = Mesh::default();
125
126 let mut vertcount = 0;
127 for mut other in meshes {
128 let length = other.verts.len();
129 mesh.verts.append(&mut other.verts);
130 mesh.tri
131 .append(&mut other.tri.iter().map(|t| t + vertcount).collect());
132 vertcount += length;
133 }
134
135 mesh
136 }
137
138 pub fn get_triangles(&self) -> Vec<(usize, usize, usize)> {
139 let mut data = Vec::new();
140 assert!(self.tri.len() % 3 == 0);
141 for i in (0..self.tri.len()).step_by(3) {
142 data.push((self.tri[i], self.tri[i + 1], self.tri[i + 2]))
143 }
144 data
145 }
146
147 pub fn get_edges(&self) -> Vec<(usize, usize)> {
148 let tri = self.get_triangles();
149 let mut edges = Vec::new();
150 for (a, b, c) in tri {
151 edges.push((a, b));
152 edges.push((b, c));
153 edges.push((c, a));
154 }
155 edges
156 }
157
158 pub fn to_clean(&self) -> Mesh {
159 todo!();
163 }
164
165 pub fn write_obj(&self, path: &str) -> Result<(), std::io::Error> {
166 let obj = self.gen_obj_buffer("obj generated by Hedron", None, None)?;
167 let mut obj_file = std::fs::File::create(&path)?;
168 obj_file.write_all(&obj)?;
169 Ok(())
170 }
171
172 pub fn write_obj_mtl(
173 &self,
174 path: &str,
175 name_obj: &str,
176 name_mtl: &str,
177 name_texture: &str,
178 ) -> Result<(), std::io::Error> {
179 let mat_name = "Material";
180
181 let mtl = Mesh::gen_mtl_buffer("mtl generated by Hedron", mat_name, Some(name_texture))?;
183 let obj = self.gen_obj_buffer("obj generated by Hedron", Some(mat_name), Some(name_mtl))?;
184
185 let texture_path = path.to_owned() + name_texture;
186 let mtl_path = path.to_owned() + name_mtl;
187 let obj_path = path.to_owned() + name_obj;
188
189 let mut obj_file = std::fs::File::create(obj_path)?;
190 obj_file.write_all(&obj)?;
191 let mut mtl_path = std::fs::File::create(mtl_path)?;
192 mtl_path.write_all(&mtl)?;
193
194 Ok(())
195 }
196
197 pub fn gen_mtl_buffer(
198 header: &str,
199 mat_name: &str,
200 texture_path: Option<&str>,
201 ) -> Result<Vec<u8>, std::io::Error> {
202 let mut mtl = Vec::new();
203 writeln!(&mut mtl, "# {}", header)?;
204 writeln!(&mut mtl, "newmtl {}", mat_name)?;
205 writeln!(&mut mtl, "Ns 250.000000")?;
206 writeln!(&mut mtl, "Ka 1.000000 1.000000 1.000000")?;
207 writeln!(&mut mtl, "Kd 0.000000 0.000000 0.000000")?;
208 writeln!(&mut mtl, "Ks 0.000000 0.000000 0.000000")?;
209 writeln!(&mut mtl, "Ke 0.000000 0.000000 0.000000")?;
210 writeln!(&mut mtl, "Ni 1.450000")?;
211 writeln!(&mut mtl, "d 1.000000")?;
212 writeln!(&mut mtl, "illum 2")?;
213 if let Some(path) = texture_path {
214 writeln!(&mut mtl, "{}", format!("map_Ka {}", texture_path.unwrap()))?;
215 writeln!(&mut mtl, "{}", format!("map_Kd {}", texture_path.unwrap()))?;
216 writeln!(&mut mtl, "{}", format!("map_Ks {}", texture_path.unwrap()))?;
217 }
218 Ok(mtl)
219 }
220
221 pub fn gen_obj_buffer(
222 &self,
223 header: &str,
224 mat_name: Option<&str>,
225 mtl_path: Option<&str>,
226 ) -> Result<Vec<u8>, std::io::Error> {
227 let mut obj = Vec::new();
228 let o = &mut obj;
229
230 writeln!(o, "# {}", header)?;
231
232 if mtl_path.is_some() && mat_name.is_some() {
233 writeln!(o, "mtllib {}", mtl_path.unwrap())?;
234 writeln!(o, "usemtl {}", mat_name.unwrap())?;
235 }
236 for vert in self.verts.iter() {
237 writeln!(o, "v {} {} {}", vert.x, vert.y, vert.z)?;
238 }
239 for uv in self.uvs.iter() {
240 writeln!(o, "vt {} {}", uv.x, uv.y)?;
241 }
242
243 if self.uvs.len() == self.verts.len() {
244 for (a, b, c) in self.get_triangles() {
245 let (a, b, c) = (a + 1, b + 1, c + 1);
246 writeln!(o, "f {a}/{a} {b}/{b} {c}/{c}")?;
247 }
248 } else {
249 for (a, b, c) in self.get_triangles() {
250 let (a, b, c) = (a + 1, b + 1, c + 1);
251 writeln!(o, "f {a} {b} {c}")?;
252 }
253 }
254 Ok(obj)
255 }
256}
257
258impl PointBased for Mesh {
261 fn mutate_points<'a>(&'a mut self) -> Vec<&'a mut Vec3> {
263 self.verts.iter_mut().collect() }
265}
266
267#[cfg(test)]
268mod test {
269 use super::Mesh;
270 use crate::core::Geometry;
271 use crate::kernel::vec3;
272 use std::io::Write;
273
274 #[test]
283 fn write_file() {
284 let mut buffer = Vec::new();
285 writeln!(&mut buffer, "test").unwrap();
286 writeln!(&mut buffer, "formatted {}", "arguments").unwrap();
287
288 let mut file = std::fs::File::create("data.txt").expect("create failed");
289 file.write_all(&buffer).expect("write failed");
290 }
291
292 #[test]
293 fn transform_mesh() {
294 let mut mesh = Mesh::new_diamond(vec3(0.5, 0.5, 0.5), 0.5);
295 mesh = mesh.mv(&-vec3(0.5, 0.5, 0.5));
296 mesh = mesh.scale_u(2.0);
297 assert_eq!(
298 mesh.verts,
299 vec![
300 vec3(1.0, 0.0, 0.0),
301 vec3(-1.0, 0.0, 0.0),
302 vec3(0.0, 1.0, 0.0),
303 vec3(0.0, -1.0, 0.0),
304 vec3(0.0, 0.0, 1.0),
305 vec3(0.0, 0.0, -1.0)
306 ]
307 );
308 }
309}