1use std::path::Path;
4use bytemuck;
5use derive_more::{From, TryInto};
6use gltf;
7use num_traits::NumCast;
8use strum;
9use crate::{math, math::geometry, util, vertex};
10
11pub mod capsule;
12pub mod cube;
13pub mod cylinder;
14pub mod grid;
15pub mod hemisphere;
16pub mod sphere;
17
18#[derive(Clone, Debug, PartialEq, From, TryInto)]
19pub enum Mesh {
20 Points3d (Points3d),
21 Lines3d (Lines3d),
22 Triangles3d (Triangles3d)
23}
24
25#[derive(Clone, Debug, PartialEq, From)]
27pub struct Points3d {
28 pub vertices : Vec <vertex::Vert3dInstanced>,
29 pub indices : Vec <u32>
30}
31
32#[derive(Clone, Debug, PartialEq, From)]
34pub struct Lines3d {
35 pub vertices : Vec <vertex::Vert3dInstanced>,
36 pub indices : Vec <u32>
37}
38
39#[derive(Clone, Debug, PartialEq, From)]
41pub struct Triangles3d {
42 pub vertices : Vec <vertex::Vert3dInstanced>,
43 pub indices : Vec <u32>
44}
45
46pub struct Points3dBuilder {
48 points : Points3d
49}
50
51pub struct Lines3dBuilder {
53 lines : Lines3d
54}
55
56pub struct Triangles3dBuilder {
58 triangles : Triangles3d
59}
60
61impl Mesh {
62 pub fn load_gltf <P : AsRef <Path>> (path : P) -> Self {
64 let (document, buffers, _images) = gltf::import (path).unwrap();
65 let mut meshes = document.meshes();
66 let mesh = meshes.next().unwrap();
67 debug_assert!(meshes.peekable().next().is_none());
68 let mut primitives = mesh.primitives();
69 let primitive = primitives.next().unwrap();
70 debug_assert!(primitives.peekable().next().is_none());
71 let reader = primitive.reader (|buffer| Some (&buffers[buffer.index()]));
72 let vertices = reader.read_positions().unwrap()
73 .map (|inst_position| vertex::Vert3dInstanced { inst_position }).collect();
74 let indices = reader.read_indices().unwrap().into_u32().collect();
75 match primitive.mode() {
76 gltf::mesh::Mode::Points => Points3d { vertices, indices }.into(),
77 gltf::mesh::Mode::Lines => Lines3d { vertices, indices }.into(),
78 _ => unimplemented!()
79 }
80 }
81
82 pub fn write_gltf <P : AsRef <Path>> (&self, path : P) {
84 fn bounding_coords (points: &[vertex::Vert3dInstanced])
85 -> ([f32; 3], [f32; 3])
86 {
87 let mut min = [f32::MAX, f32::MAX, f32::MAX];
88 let mut max = [f32::MIN, f32::MIN, f32::MIN];
89 for point in points {
90 let p = point.inst_position;
91 for i in 0..3 {
92 min[i] = f32::min (min[i], p[i]);
93 max[i] = f32::max (max[i], p[i]);
94 }
95 }
96 (min, max)
97 }
98 let (vertices, indices, mode) = match self {
99 Mesh::Points3d (Points3d { vertices, indices }) =>
100 (vertices, indices, gltf::mesh::Mode::Points),
101 Mesh::Lines3d (Lines3d { vertices, indices }) =>
102 (vertices, indices, gltf::mesh::Mode::Lines),
103 Mesh::Triangles3d (Triangles3d { vertices, indices }) =>
104 (vertices, indices, gltf::mesh::Mode::Triangles)
105 };
106 let (min, max) = bounding_coords (&vertices[..]);
107 let vertices_bytes = bytemuck::cast_slice (vertices);
108 let indices_bytes = bytemuck::cast_slice (indices);
109 let (buffer, views) =
110 util::gltf::json_buffer_views (0, &[vertices_bytes, indices_bytes]);
111 let position_accessor = util::gltf::json_accessor (0, vertices.len() as u32,
112 gltf::json::accessor::Type::Vec3,
113 gltf::json::accessor::ComponentType::F32, Some ([min, max]));
114 let index_accessor = util::gltf::json_accessor (1, indices.len() as u32,
115 gltf::json::accessor::Type::Scalar,
116 gltf::json::accessor::ComponentType::U32, None);
117 let lines_primitive = util::gltf::json_primitive (
118 gltf::json::mesh::Semantic::Positions, mode, 1);
119 let mesh = util::gltf::json_mesh (vec![lines_primitive]);
120 let node = util::gltf::json_node (0);
121 let root = util::gltf::json_root (
122 vec![node], vec![mesh], vec![buffer], views,
123 vec![position_accessor, index_accessor]);
124 let writer = std::fs::File::create (path).unwrap();
125 gltf::json::serialize::to_writer_pretty (writer, &root).unwrap();
126 }
127}
128
129impl Points3d {
130 pub const fn empty() -> Self {
131 Points3d { vertices: vec![], indices: vec![] }
132 }
133}
134
135impl Lines3d {
136 pub const fn empty() -> Self {
137 Lines3d { vertices: vec![], indices: vec![] }
138 }
139}
140
141impl From <geometry::Aabb3 <f32>> for Lines3d {
142 fn from (aabb : geometry::Aabb3 <f32>) -> Self {
143 use strum::IntoEnumIterator;
144 let vertices = math::Octant::iter().map (|octant| vertex::Vert3dInstanced {
145 inst_position: aabb.corner (octant).0.into_array()
146 }).collect();
147 let indices = vec![
148 0, 1, 0, 2, 0, 4,
149 7, 6, 7, 5, 7, 3,
150 1, 3, 1, 5,
151 2, 3, 2, 6,
152 4, 5, 4, 6
153 ];
154 Lines3d { vertices, indices }
155 }
156}
157
158impl Triangles3d {
159 pub const fn empty() -> Self {
160 Triangles3d { vertices: vec![], indices: vec![] }
161 }
162}
163
164impl Points3dBuilder {
165 pub const fn empty() -> Self {
166 Points3dBuilder {
167 points: Points3d::empty()
168 }
169 }
170
171 pub fn push_point <T : NumCast> (&mut self, point : math::Point3 <T>) -> &mut Self {
172 let vertex = |p : math::Point3 <T>|
173 vertex::Vert3dInstanced { inst_position: p.0.numcast().unwrap().into_array() };
174 self.points.indices.push (self.points.vertices.len() as u32);
175 self.points.vertices.push (vertex (point));
176 self
177 }
178
179 pub fn build (self) -> Points3d {
180 self.points
181 }
182}
183
184impl Lines3dBuilder {
185 pub const fn empty() -> Self {
186 Lines3dBuilder {
187 lines: Lines3d::empty()
188 }
189 }
190
191 pub fn push_edge <T : NumCast> (&mut self, edge : [math::Point3 <T>; 2]) -> &mut Self {
192 let [a, b] : [math::Point3 <f32>; 2] = edge.map (|p| p.numcast().unwrap());
196 let vertex = |p : math::Point3 <f32>|
197 vertex::Vert3dInstanced { inst_position: p.0.into_array() };
198 let mut add_vertex = |v|
199 if let Some(i) = self.lines.vertices.iter().position (|x| *x == v) {
200 self.lines.indices.push (i as u32)
201 } else {
202 self.lines.indices.push (self.lines.vertices.len() as u32);
203 self.lines.vertices.push (v);
204 };
205 add_vertex (vertex (a));
206 add_vertex (vertex (b));
207 self
208 }
209
210 pub fn build (self) -> Lines3d {
211 self.lines
212 }
213}
214
215impl Triangles3dBuilder {
216 pub const fn empty() -> Self {
217 Triangles3dBuilder {
218 triangles: Triangles3d::empty()
219 }
220 }
221
222 pub fn push_face <T : NumCast> (&mut self, face : [math::Point3 <T>; 3]) -> &mut Self {
223 let [a, b, c] : [math::Point3 <f32>; 3] = face.map (|p| p.numcast().unwrap());
227 let vertex = |p : math::Point3 <f32>|
228 vertex::Vert3dInstanced { inst_position: p.0.into_array() };
229 let mut add_vertex = |v|
230 if let Some(i) = self.triangles.vertices.iter().position (|x| *x == v) {
231 self.triangles.indices.push (i as u32)
232 } else {
233 self.triangles.indices.push (self.triangles.vertices.len() as u32);
234 self.triangles.vertices.push (v);
235 };
236 add_vertex (vertex (a));
237 add_vertex (vertex (b));
238 add_vertex (vertex (c));
239 self
240 }
241
242 pub fn build (self) -> Triangles3d {
243 self.triangles
244 }
245}