gemini_engine/mesh3d/
mesh3d_presets.rs

1//! This file contains the presets available when spawning a [`Mesh3D`]
2
3use crate::core::{ColChar, Modifier};
4use std::f64::consts::TAU;
5
6use super::{Face, Mesh3D, Transform3D, Vec3D};
7
8impl Mesh3D {
9    /// The `gemini_engine` equivalent of Blender's default cube. Has sides of length 2
10    #[must_use]
11    pub fn default_cube() -> Self {
12        Self::new(
13            vec![
14                Vec3D::new(1.0, 1.0, -1.0),
15                Vec3D::new(1.0, 1.0, 1.0),
16                Vec3D::new(1.0, -1.0, -1.0),
17                Vec3D::new(1.0, -1.0, 1.0),
18                Vec3D::new(-1.0, 1.0, -1.0),
19                Vec3D::new(-1.0, 1.0, 1.0),
20                Vec3D::new(-1.0, -1.0, -1.0),
21                Vec3D::new(-1.0, -1.0, 1.0),
22            ],
23            vec![
24                Face::new(vec![2, 3, 1, 0], ColChar::SOLID.with_mod(Modifier::BLUE)),
25                Face::new(vec![4, 5, 7, 6], ColChar::SOLID.with_mod(Modifier::BLUE)),
26                Face::new(vec![1, 3, 7, 5], ColChar::SOLID.with_mod(Modifier::None)),
27                Face::new(vec![4, 6, 2, 0], ColChar::SOLID.with_mod(Modifier::None)),
28                Face::new(vec![6, 7, 3, 2], ColChar::SOLID.with_mod(Modifier::RED)),
29                Face::new(vec![0, 1, 5, 4], ColChar::SOLID.with_mod(Modifier::RED)),
30            ],
31        )
32    }
33
34    /// Create a torus (donut shape)
35    #[must_use]
36    pub fn torus(
37        outer_radius: f64,
38        inner_radius: f64,
39        outer_segments: usize,
40        inner_segments: usize,
41    ) -> Self {
42        let mut vertices = vec![];
43        let mut faces = vec![];
44
45        for outer_i in 0..outer_segments {
46            let outer_angle = (outer_i as f64 / outer_segments as f64) * TAU;
47            let outer_transform = Transform3D::from_rotation_y(-outer_angle);
48            let outer_point = Vec3D::new(
49                outer_angle.cos() * outer_radius,
50                0.0,
51                outer_angle.sin() * outer_radius,
52            );
53
54            for inner_i in 0..inner_segments {
55                let inner_angle = (inner_i as f64 / inner_segments as f64) * TAU;
56                let inner_point = Vec3D::new(
57                    inner_angle.cos() * inner_radius,
58                    inner_angle.sin() * inner_radius,
59                    0.0,
60                );
61                vertices.push(outer_point + outer_transform.transform_vector3(inner_point));
62
63                let inc_outer_i = (outer_i + 1) % outer_segments;
64                let inc_inner_i = (inner_i + 1) % inner_segments;
65                faces.push(Face::new(
66                    vec![
67                        inc_outer_i * inner_segments + inner_i,
68                        inc_outer_i * inner_segments + inc_inner_i,
69                        outer_i * inner_segments + inc_inner_i,
70                        outer_i * inner_segments + inner_i,
71                    ],
72                    ColChar::SOLID,
73                ));
74            }
75        }
76
77        Self::new(vertices, faces)
78    }
79
80    /// A gimbal to help you orient in `gemini_engine`'s 3D space. The orientation is as follows (from the default [`Viewport`](crate::view3d::Viewport))
81    /// - X (red) increases as you move to the right
82    /// - Y (green) increases as you move up
83    /// - Z (blue) increases as you move away from the viewport
84    ///
85    /// Think of it like Blender's axes but with Y and Z swapped.
86    /// Since this Mesh does not have a real triangle mesh, it is only visible in [`DisplayMode::Wireframe`](crate::view3d::DisplayMode)
87    #[must_use]
88    pub fn gimbal() -> Self {
89        Self::new(
90            vec![
91                Vec3D::ZERO,
92                Vec3D::new(1.0, 0.0, 0.0),
93                Vec3D::new(0.0, 1.0, 0.0),
94                Vec3D::new(0.0, 0.0, 1.0),
95            ],
96            vec![
97                Face::new(vec![0, 1], ColChar::SOLID.with_mod(Modifier::RED)),
98                Face::new(vec![0, 2], ColChar::SOLID.with_mod(Modifier::GREEN)),
99                Face::new(vec![0, 3], ColChar::SOLID.with_mod(Modifier::BLUE)),
100            ],
101        )
102    }
103}