gl_utils/mesh/
mod.rs

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