1use crate::math::{Vec2, Vec3};
2use crate::mesh::{Mesh, MeshData, Vertex};
3use crate::{Assets, Catalog};
4
5const HALF: f32 = 0.5;
6
7const QUAD_INDICES: [u32; 6] = [0, 1, 2, 0, 2, 3];
8
9#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
11pub struct Cube;
12
13impl Catalog for Cube {
14 fn catalog() -> Vec<Self> {
15 vec![Self]
16 }
17}
18
19impl Mesh for Cube {
20 fn build(&self, _assets: &Assets) -> MeshData {
21 let faces = [
22 (Vec3::X, Vec3::NEG_Z, Vec3::Y),
23 (Vec3::NEG_X, Vec3::Z, Vec3::Y),
24 (Vec3::Y, Vec3::X, Vec3::NEG_Z),
25 (Vec3::NEG_Y, Vec3::X, Vec3::Z),
26 (Vec3::Z, Vec3::X, Vec3::Y),
27 (Vec3::NEG_Z, Vec3::NEG_X, Vec3::Y),
28 ];
29
30 let vertices = faces
31 .iter()
32 .flat_map(|&(normal, right, up)| square(normal * HALF, normal, right, up))
33 .collect();
34 let indices = (0..faces.len() as u32)
35 .flat_map(|face| QUAD_INDICES.map(|index| face * 4 + index))
36 .collect();
37
38 MeshData::new(vertices, indices)
39 }
40}
41
42#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
44pub struct Plane;
45
46impl Catalog for Plane {
47 fn catalog() -> Vec<Self> {
48 vec![Self]
49 }
50}
51
52impl Mesh for Plane {
53 fn build(&self, _assets: &Assets) -> MeshData {
54 square_mesh(Vec3::Y, Vec3::X, Vec3::NEG_Z)
55 }
56}
57
58#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
60pub struct Quad;
61
62impl Catalog for Quad {
63 fn catalog() -> Vec<Self> {
64 vec![Self]
65 }
66}
67
68impl Mesh for Quad {
69 fn build(&self, _assets: &Assets) -> MeshData {
70 square_mesh(Vec3::Z, Vec3::X, Vec3::Y)
71 }
72}
73
74#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
76pub struct Sphere {
77 pub subdivisions: u32,
80}
81
82impl Catalog for Sphere {
83 fn catalog() -> Vec<Self> {
87 (0..=3).map(|subdivisions| Self { subdivisions }).collect()
88 }
89}
90
91impl Mesh for Sphere {
92 fn build(&self, _assets: &Assets) -> MeshData {
93 let segments = 4 * (self.subdivisions + 1);
94 let rings = 2 * (self.subdivisions + 1);
95
96 let mut vertices = Vec::with_capacity(((rings + 1) * (segments + 1)) as usize);
97 for ring in 0..=rings {
98 let latitude = core::f32::consts::PI * ring as f32 / rings as f32;
99 let (radius, height) = latitude.sin_cos();
100 for segment in 0..=segments {
101 let longitude = core::f32::consts::TAU * segment as f32 / segments as f32;
102 let (ahead, right) = longitude.sin_cos();
103 let normal = Vec3::new(radius * right, height, radius * ahead);
104 vertices.push(Vertex::new(
105 normal * HALF,
106 normal,
107 Vec2::new(segment as f32 / segments as f32, ring as f32 / rings as f32),
108 ));
109 }
110 }
111
112 let corner = |ring: u32, segment: u32| ring * (segments + 1) + segment;
113 let mut indices = Vec::with_capacity((rings * segments * 6) as usize);
114 for ring in 0..rings {
115 for segment in 0..segments {
116 let (here, next) = (corner(ring, segment), corner(ring, segment + 1));
117 let (under, under_next) =
118 (corner(ring + 1, segment), corner(ring + 1, segment + 1));
119
120 let touches_north_pole = ring == 0;
121 let touches_south_pole = ring + 1 == rings;
122 if !touches_north_pole {
123 indices.extend([here, next, under_next]);
124 }
125 if !touches_south_pole {
126 indices.extend([here, under_next, under]);
127 }
128 }
129 }
130
131 MeshData::new(vertices, indices)
132 }
133}
134
135fn square(center: Vec3, normal: Vec3, right: Vec3, up: Vec3) -> [Vertex; 4] {
138 let (right, up) = (right * HALF, up * HALF);
139 [
140 Vertex::new(center - right - up, normal, Vec2::new(0.0, 1.0)),
141 Vertex::new(center + right - up, normal, Vec2::new(1.0, 1.0)),
142 Vertex::new(center + right + up, normal, Vec2::new(1.0, 0.0)),
143 Vertex::new(center - right + up, normal, Vec2::new(0.0, 0.0)),
144 ]
145}
146
147fn square_mesh(normal: Vec3, right: Vec3, up: Vec3) -> MeshData {
148 MeshData::new(
149 square(Vec3::ZERO, normal, right, up).to_vec(),
150 QUAD_INDICES.to_vec(),
151 )
152}