Skip to main content

mraphics_core/geometry/
sphere.rs

1use crate::{
2    CustomIndices, Geometry, GeometryIndices, Material, Mesh, Representable, Transformable,
3    Vertices,
4};
5use std::f32::consts::PI;
6
7#[derive(Clone)]
8pub struct Sphere {
9    pub radius: f32,
10
11    pub phi_start: f32,
12    pub phi_end: f32,
13    pub phi_segments: u16,
14
15    pub theta_start: f32,
16    pub theta_end: f32,
17    pub theta_segments: u16,
18
19    pub vertices: Vertices,
20    pub indices: Vec<u16>,
21}
22
23impl Sphere {
24    pub fn new() -> Self {
25        Self::default()
26    }
27}
28
29impl Default for Sphere {
30    fn default() -> Self {
31        Self {
32            radius: 1.0,
33            phi_start: 0.0,
34            phi_end: PI * 2.0,
35            phi_segments: 32,
36            theta_start: 0.0,
37            theta_end: PI,
38            theta_segments: 16,
39            vertices: Vertices::new(),
40            indices: Vec::new(),
41        }
42    }
43}
44
45impl Geometry for Sphere {
46    fn init_view(&self, view: &mut super::GeometryView) {
47        view.add_attribute(
48            crate::constants::POSITION_ATTR_LABEL,
49            crate::constants::POSITION_ATTR_INDEX,
50            Vec::<u8>::new(),
51        );
52    }
53
54    fn update_view(&self, view: &mut super::GeometryView) {
55        self.vertices.update_geometry_view(view);
56
57        view.get_attribute_mut(crate::constants::POSITION_ATTR_LABEL)
58            .unwrap()
59            .needs_update_buffer = true;
60        view.indices = GeometryIndices::CustomU16(CustomIndices::new((&self.indices).to_owned()));
61    }
62
63    fn update(&mut self) {
64        self.vertices = Vertices::new();
65        self.indices = Vec::new();
66
67        let r = self.radius;
68        let phi_unit = (self.phi_end - self.phi_start) / self.phi_segments as f32;
69        let theta_unit = (self.theta_end - self.theta_start) / self.theta_segments as f32;
70
71        for i in 0..=self.theta_segments {
72            let i = i as f32;
73            for j in 0..self.phi_segments {
74                let j = j as f32;
75
76                let phi = self.phi_start + j * phi_unit;
77                let theta = self.theta_start + i * theta_unit;
78
79                self.vertices.data.push([
80                    r * phi.cos() * theta.sin(),
81                    r * theta.cos(),
82                    r * phi.sin() * theta.sin(),
83                    1.0,
84                ]);
85            }
86        }
87
88        let mut add_plane = |a: u16, b: u16, c: u16, d: u16| {
89            self.indices.push(a);
90            self.indices.push(b);
91            self.indices.push(d);
92
93            self.indices.push(b);
94            self.indices.push(c);
95            self.indices.push(d);
96        };
97
98        for i in 0..self.theta_segments {
99            for j in 0..self.phi_segments {
100                let next = if j + 1 == self.phi_segments { 0 } else { j + 1 };
101
102                if (self.phi_start > 0.0 || self.phi_end < PI * 2.0) && next == 0 {
103                    continue;
104                }
105
106                let offset = i * self.phi_segments;
107                let a = offset + j;
108                let b = offset + self.phi_segments + j;
109                let c = offset + self.phi_segments + next;
110                let d = offset + next;
111
112                add_plane(a, b, c, d);
113            }
114        }
115    }
116}
117
118impl<M: Material> Representable for Mesh<Sphere, M> {
119    type Intermediate = Vertices;
120
121    fn as_intermediate(&self) -> Self::Intermediate {
122        self.geometry.vertices.clone()
123    }
124
125    fn update_from_intermediate(&mut self, repr: &Self::Intermediate) {
126        self.geometry.vertices = repr.clone();
127    }
128}
129
130impl<M: Material> Transformable for Mesh<Sphere, M> {
131    fn apply_transform<Trans: Fn(&[f32; 3]) -> [f32; 3]>(
132        &self,
133        transform: Trans,
134    ) -> Self::Intermediate {
135        self.geometry.vertices.apply_transform(|vertex| {
136            let transformed = transform(&[vertex[0], vertex[1], vertex[2]]);
137            [transformed[0], transformed[1], transformed[2], 1.0]
138        })
139    }
140}