immense/
mesh.rs

1// Copyright 2018 The immense Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::Tf;
16use genmesh::generators::{IcoSphere, IndexedPolygon, SharedVertex};
17use lazy_static::lazy_static;
18use nalgebra::base::dimension::{U1, U4};
19use std::rc::Rc;
20
21/// A type for custom mesh vertices. Initialize with [vertex][self::vertex].
22pub type Vertex = nalgebra::Matrix<f32, U4, U1, nalgebra::MatrixArray<f32, U4, U1>>;
23
24/// Initializes a vertex for a custom mesh.
25pub fn vertex(x: f32, y: f32, z: f32) -> Vertex {
26    Vertex::new(x, y, z, 1.0)
27}
28
29pub(crate) fn sphere_of_resolution(resolution: usize) -> Mesh {
30    Mesh::new(
31        IcoSphere::subdivide(resolution)
32            .shared_vertex_iter()
33            .map(|v| Tf::s(0.5).apply_to(vertex(v.pos.x, v.pos.y, v.pos.z)))
34            .collect(),
35        Some(
36            IcoSphere::subdivide(resolution)
37                .shared_vertex_iter()
38                .map(|v| vertex(v.normal.x, v.normal.y, v.normal.z))
39                .collect(),
40        ),
41        IcoSphere::subdivide(resolution)
42            .indexed_polygon_iter()
43            .map(|t| vec![t.x + 1, t.y + 1, t.z + 1])
44            .collect(),
45    )
46}
47
48lazy_static! {
49    static ref CUBE_MESH: Mesh = Mesh::new(
50        vec![
51            vertex(-0.5, 0.5, 0.5),
52            vertex(-0.5, -0.5, 0.5),
53            vertex(0.5, -0.5, 0.5),
54            vertex(0.5, 0.5, 0.5),
55            vertex(-0.5, 0.5, -0.5),
56            vertex(-0.5, -0.5, -0.5),
57            vertex(0.5, -0.5, -0.5),
58            vertex(0.5, 0.5, -0.5),
59        ],
60        None,
61        vec![
62            vec![1, 2, 3, 4],
63            vec![8, 7, 6, 5],
64            vec![4, 3, 7, 8],
65            vec![5, 1, 4, 8],
66            vec![5, 6, 2, 1],
67            vec![2, 6, 7, 3],
68        ]
69    );
70    static ref ICO_SPHERE: Mesh = sphere_of_resolution(0);
71}
72
73/// A custom mesh definition described by a set of vertices, normals, and faces.
74///
75/// This is a low-level type and you are expected to know what you are doing in this part of the API.
76///
77/// 1. There should be a normal for each vertex if you provide any normals at all.
78/// 2. Each face is a set of indices to the vertices that the face connects.
79/// 3. Vertex indices start at 1, according to the object file standard.
80#[derive(Debug)]
81pub struct Mesh {
82    vertices: Vec<Vertex>,
83    normals: Option<Vec<Vertex>>,
84    faces: Vec<Vec<usize>>,
85}
86
87impl Mesh {
88    /// Allocates a mesh from the given vertices, normals, and faces, which can invoked as rules.
89    pub fn from(
90        vertices: Vec<Vertex>,
91        normals: Option<Vec<Vertex>>,
92        faces: Vec<Vec<usize>>,
93    ) -> Rc<Self> {
94        Rc::new(Self::new(vertices, normals, faces))
95    }
96
97    pub(crate) fn new(
98        vertices: Vec<Vertex>,
99        normals: Option<Vec<Vertex>>,
100        faces: Vec<Vec<usize>>,
101    ) -> Self {
102        Self {
103            vertices,
104            normals,
105            faces: faces,
106        }
107    }
108
109    pub(crate) fn vertices<'a>(&'a self) -> &'a [Vertex] {
110        self.vertices.as_slice()
111    }
112
113    pub(crate) fn normals<'a>(&'a self) -> Option<&'a [Vertex]> {
114        self.normals.as_ref().map(|ns| ns.as_slice())
115    }
116
117    pub(crate) fn faces<'a>(&'a self) -> impl Iterator<Item = &'a [usize]> {
118        self.faces.iter().map(|f| f.as_slice())
119    }
120}
121
122#[derive(Clone, Debug)]
123pub enum PrimitiveMesh {
124    Cube,
125    IcoSphere,
126}
127
128impl PrimitiveMesh {
129    pub(crate) fn mesh(&self) -> &'static Mesh {
130        match *self {
131            PrimitiveMesh::Cube => &*CUBE_MESH,
132            PrimitiveMesh::IcoSphere => &*ICO_SPHERE,
133        }
134    }
135}