1use std::path::Path;
4use bytemuck;
5use derive_more::{From, TryInto};
6use gltf;
7use strum;
8use crate::{math, math::geometry, util, vertex};
9
10pub mod capsule;
11pub mod cube;
12pub mod cylinder;
13pub mod grid;
14pub mod hemisphere;
15pub mod sphere;
16
17#[derive(Clone, Debug, PartialEq, From, TryInto)]
18pub enum Mesh {
19 Lines3d (Lines3d)
20}
21
22#[derive(Clone, Debug, PartialEq, From)]
24pub struct Lines3d {
25 pub vertices : Vec <vertex::Vert3dInstanced>,
26 pub indices : Vec <u32>
27}
28
29impl Mesh {
30 pub fn load_gltf <P : AsRef <Path>> (path : P) -> Self {
32 let (document, buffers, _images) = gltf::import (path).unwrap();
33 let mut meshes = document.meshes();
34 let mesh = meshes.next().unwrap();
35 debug_assert!(meshes.peekable().next().is_none());
36 let mut primitives = mesh.primitives();
37 let primitive = primitives.next().unwrap();
38 debug_assert!(primitives.peekable().next().is_none());
39 let reader = primitive.reader (|buffer| Some (&buffers[buffer.index()]));
40 let vertices = reader.read_positions().unwrap()
41 .map (|inst_position| vertex::Vert3dInstanced { inst_position }).collect();
42 let indices = reader.read_indices().unwrap().into_u32().collect();
43 Lines3d { vertices, indices }.into()
44 }
45
46 pub fn write_gltf <P : AsRef <Path>> (&self, path : P) {
48 fn bounding_coords (points: &[vertex::Vert3dInstanced])
49 -> ([f32; 3], [f32; 3])
50 {
51 let mut min = [f32::MAX, f32::MAX, f32::MAX];
52 let mut max = [f32::MIN, f32::MIN, f32::MIN];
53 for point in points {
54 let p = point.inst_position;
55 for i in 0..3 {
56 min[i] = f32::min (min[i], p[i]);
57 max[i] = f32::max (max[i], p[i]);
58 }
59 }
60 (min, max)
61 }
62 let (vertices, indices) = match self {
63 Mesh::Lines3d (Lines3d { vertices, indices }) => (vertices, indices)
64 };
65 let (min, max) = bounding_coords (&vertices[..]);
66 let vertices_bytes = bytemuck::cast_slice (vertices);
67 let indices_bytes = bytemuck::cast_slice (indices);
68 let (buffer, views) =
69 util::gltf::json_buffer_views (0, &[vertices_bytes, indices_bytes]);
70 let position_accessor = util::gltf::json_accessor (0, vertices.len() as u32,
71 gltf::json::accessor::Type::Vec3,
72 gltf::json::accessor::ComponentType::F32, Some ([min, max]));
73 let index_accessor = util::gltf::json_accessor (1, indices.len() as u32,
74 gltf::json::accessor::Type::Scalar,
75 gltf::json::accessor::ComponentType::U32, None);
76 let lines_primitive = util::gltf::json_primitive (
77 gltf::json::mesh::Semantic::Positions, gltf::json::mesh::Mode::Lines, 1);
78 let mesh = util::gltf::json_mesh (vec![lines_primitive]);
79 let node = util::gltf::json_node (0);
80 let root = util::gltf::json_root (
81 vec![node], vec![mesh], vec![buffer], views,
82 vec![position_accessor, index_accessor]);
83 let writer = std::fs::File::create (path).unwrap();
84 gltf::json::serialize::to_writer_pretty (writer, &root).unwrap();
85 }
86}
87
88impl Lines3d {
89 pub const fn empty() -> Self {
90 Lines3d { vertices: vec![], indices: vec![] }
91 }
92}
93
94impl From <geometry::Aabb3 <f32>> for Lines3d {
95 fn from (aabb : geometry::Aabb3 <f32>) -> Self {
96 use strum::IntoEnumIterator;
97 let vertices = math::Octant::iter().map (|octant| vertex::Vert3dInstanced {
98 inst_position: aabb.corner (octant).0.into_array()
99 }).collect();
100 let indices = vec![
101 0, 1, 0, 2, 0, 4,
102 7, 6, 7, 5, 7, 3,
103 1, 3, 1, 5,
104 2, 3, 2, 6,
105 4, 5, 4, 6
106 ];
107 Lines3d { vertices, indices }
108 }
109}