block_mesh/geometry/
face.rs

1use crate::{Axis, AxisPermutation, SignedAxis, UnorientedQuad};
2
3use ilattice::glam::{IVec3, UVec3};
4
5/// Metadata that's used to aid in the geometric calculations for one of the 6 possible cube faces.
6#[derive(Clone, Copy, Debug, Eq, PartialEq)]
7pub struct OrientedBlockFace {
8    /// Determines the orientation of the plane.
9    pub(crate) n_sign: i32,
10
11    /// Determines the {N, U, V} <--> {X, Y, Z} relation.
12    pub(crate) permutation: AxisPermutation,
13
14    /// First in the `permutation` of +X, +Y, and +Z.
15    pub(crate) n: UVec3,
16    /// Second in the `permutation` of +X, +Y, and +Z.
17    pub(crate) u: UVec3,
18    /// Third in the `permutation` of +X, +Y, and +Z.
19    pub(crate) v: UVec3,
20}
21
22impl OrientedBlockFace {
23    pub const fn new(n_sign: i32, permutation: AxisPermutation) -> Self {
24        let [n_axis, u_axis, v_axis] = permutation.axes();
25
26        Self {
27            n_sign,
28            permutation,
29            n: n_axis.get_unit_vector(),
30            u: u_axis.get_unit_vector(),
31            v: v_axis.get_unit_vector(),
32        }
33    }
34
35    /// A cube face, using axes with an even permutation.
36    pub fn canonical(normal: SignedAxis) -> Self {
37        Self::new(
38            normal.signum(),
39            AxisPermutation::even_with_normal_axis(normal.unsigned_axis()),
40        )
41    }
42
43    #[inline]
44    pub fn signed_normal(&self) -> IVec3 {
45        self.n.as_ivec3() * self.n_sign
46    }
47
48    /// Returns the 4 corners of the quad in this order:
49    ///
50    /// ```text
51    ///         2 ----> 3
52    ///           ^
53    ///     ^       \
54    ///     |         \
55    ///  +V |   0 ----> 1
56    ///     |
57    ///      -------->
58    ///        +U
59    ///
60    /// (+N pointing out of the screen)
61    /// ```
62    ///
63    /// Note that this is natural when UV coordinates have (0,0) at the bottom
64    /// left, but when (0,0) is at the top left, V must be flipped.
65    #[inline]
66    pub fn quad_corners(&self, quad: &UnorientedQuad) -> [UVec3; 4] {
67        let w_vec = self.u * quad.width;
68        let h_vec = self.v * quad.height;
69
70        let minu_minv = if self.n_sign > 0 {
71            UVec3::from(quad.minimum) + self.n
72        } else {
73            UVec3::from(quad.minimum)
74        };
75        let maxu_minv = minu_minv + w_vec;
76        let minu_maxv = minu_minv + h_vec;
77        let maxu_maxv = minu_minv + w_vec + h_vec;
78
79        [minu_minv, maxu_minv, minu_maxv, maxu_maxv]
80    }
81
82    #[inline]
83    pub fn quad_mesh_positions(&self, quad: &UnorientedQuad, voxel_size: f32) -> [[f32; 3]; 4] {
84        self.quad_corners(quad)
85            .map(|c| (voxel_size * c.as_vec3()).to_array())
86    }
87
88    #[inline]
89    pub fn quad_mesh_normals(&self) -> [[f32; 3]; 4] {
90        [self.signed_normal().as_vec3().to_array(); 4]
91    }
92
93    /// Returns the 6 vertex indices for the quad in order to make two triangles
94    /// in a mesh. Winding order depends on both the sign of the surface normal
95    /// and the permutation of the UVs.
96    ///
97    /// Front faces will be wound counterclockwise, and back faces clockwise, as
98    /// per convention.
99    #[inline]
100    pub fn quad_mesh_indices(&self, start: u32) -> [u32; 6] {
101        quad_indices(start, self.n_sign * self.permutation.sign() > 0)
102    }
103
104    /// Returns the UV coordinates of the 4 corners of the quad. Returns
105    /// vertices in the same order as [`OrientedBlockFace::quad_corners`].
106    ///
107    /// `u_flip_face` should correspond to the field on
108    /// [`QuadCoordinateConfig`](crate::QuadCoordinateConfig). See the docs
109    /// there for more info.
110    ///
111    /// This is just one way of assigning UVs to voxel quads. It assumes that
112    /// each material has a single tile texture with wrapping coordinates, and
113    /// each voxel face should show the entire texture. It also assumes a
114    /// particular orientation for the texture. This should be sufficient for
115    /// minecraft-style meshing.
116    ///
117    /// If you need to use a texture atlas, you must calculate your own
118    /// coordinates from the `Quad`.
119    #[inline]
120    pub fn tex_coords(
121        &self,
122        u_flip_face: Axis,
123        flip_v: bool,
124        quad: &UnorientedQuad,
125    ) -> [[f32; 2]; 4] {
126        let face_normal_axis = self.permutation.axes()[0];
127        let flip_u = if self.n_sign < 0 {
128            u_flip_face != face_normal_axis
129        } else {
130            u_flip_face == face_normal_axis
131        };
132
133        match (flip_u, flip_v) {
134            (false, false) => [
135                [0.0, 0.0],
136                [quad.width as f32, 0.0],
137                [0.0, quad.height as f32],
138                [quad.width as f32, quad.height as f32],
139            ],
140            (true, false) => [
141                [quad.width as f32, 0.0],
142                [0.0, 0.0],
143                [quad.width as f32, quad.height as f32],
144                [0.0, quad.height as f32],
145            ],
146            (false, true) => [
147                [0.0, quad.height as f32],
148                [quad.width as f32, quad.height as f32],
149                [0.0, 0.0],
150                [quad.width as f32, 0.0],
151            ],
152            (true, true) => [
153                [quad.width as f32, quad.height as f32],
154                [0.0, quad.height as f32],
155                [quad.width as f32, 0.0],
156                [0.0, 0.0],
157            ],
158        }
159    }
160}
161
162/// Returns the vertex indices for a single quad (two triangles). The triangles
163/// may have either clockwise or counter-clockwise winding. `start` is the first
164/// index.
165fn quad_indices(start: u32, counter_clockwise: bool) -> [u32; 6] {
166    if counter_clockwise {
167        [start, start + 1, start + 2, start + 1, start + 3, start + 2]
168    } else {
169        [start, start + 2, start + 1, start + 1, start + 2, start + 3]
170    }
171}