1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
//! Voxel geometry and coordinate systems.
//!
//! `block-mesh` is designed to work for any 3-dimensional coordinate system.
//! Doing this requires a somewhat complicated interplay between the types in
//! this module. This documentation attempts to clarify what's going on.
//!
//! # Quads and Faces
//!
//! As most will know, a cube is composed of six **faces**.
//!
//! ```text
//!     O--------O
//!   / |      / |
//! O--------O   |
//! |   |    |   |
//! |   O----|---O
//! | /      | /
//! O--------O
//!
//! Fig 1: Cube
//! ```
//!
//! When rendering a cube to the screen, this will involve rendering six
//! **quads**. A quad has four **vertices**, each with a unique **UV** texture
//! coordinate and the same **normal** vector. The quad is rendered as two
//! triangles, typically as four vertices and six **indices**.
//!
//! ```text
//!            (U, V)                                         3    
//!              3                    3------> N            / ^     
//!            / |                  / |                   /   |     
//!  (U, V)  /   |                /   |                 2     |     
//!        2     |              2------> N                \   |     
//!        | \   |              | \   |                 2   \ |     
//!        |   \ |              |   \ |                 | \   1     
//!        |     1              |     1------> N        |   \       
//!        |   /   (U, V)       |   /                   |     1     
//!        | /                  | /                     |   /       
//!        0                    0------> N              V /         
//!     (U, V)                                          0           
//!
//! Fig 2: Quad with vertices [A, B, C, D].
//! - (left) UVs.
//! - (middle) Normals.
//! - (right) Two triangles rendered using indices [0, 1, 2, 3, 2, 1].
//! ```
//!
//! # Coordinate System
//!
//! Different domains (e.g., your game engine or 3D modeling application) use
//! different coordinate systems. Generating correct vertex positions, normals,
//! and UV coordinates requires knowing the specifics of the coordinate system.
//!
//! ```text
//!       +Y                 +Y                 -Y      
//!       | +Z               | -Z               | -Z    
//! -X____|/____+X     -X____|/____+X     +X____|/____-X
//!      /|                 /|                 /|       
//!    -Z |               +Z |               +Z |       
//!       -Y                 -Y                 +Y      
//!
//! Fig 3: Various coordinate systems.
//! - (left) Left-handed coordinate system with Y up.
//! - (middle) Right-handed coordinate system with Y up.
//! - (right) Right-handed coordinate system with Y down.
//! ```
//!
//! ## Handedness
//!
//! **Handedness** (also called chirality) is this weird property of 3D things.
//! If two 3D things have different handedness, then it is impossible to rotate
//! or translate one to look like the other; it's only possible if you mirror
//! it.
//!
//! Most often, in games and 3D modeling, this corresponds to which way the Z
//! axis grows. Often, +X is right, +Y is up, and the handedness determines
//! whether +Z is into or out of the screen.
//!
//! See wikipedia for more information on handedness:
//! - <https://en.wikipedia.org/wiki/Right-hand_rule>
//! - <https://en.wikipedia.org/wiki/Orientation_(vector_space)>
//!
//! ## Orientation
//!
//! The **orientation** of the coordinate system determines which way textures
//! are displayed on cube faces. Most often, the orientation is "Y up", meaning
//! that textures are displayed with the top of the image toward the +Y axis.
//!
//! # `{N, U, V}` Space
//!
//! "`{N, U, V}` space" is basically the **face-local coordinate space**
//! (**N**ormal, **U**, **V**).
//!
//! The notion of an `{N, U, V}` space is convenient because we can return
//! vertices, UVs, and indices in a consistent order regardless of the face. See
//! [`OrientedBlockFace::quad_corners`].
//!
//! # Putting It All Together
//!
//! The output of the `block-mesh` algorithms are [`UnorientedQuad`]s. These
//! simply specify the size and minimum `{X, Y, Z}` coordinate of the cube they
//! are a part of.
//!
//! In order to get vertex positions, UV coordinates, normals, and mesh indices
//! for an [`UnorientedQuad`], it must be paired with an [`OrientedBlockFace`],
//! which specifies the `{N, U, V}` --> `{X, Y, Z}` mapping and the sign of the
//! normal vector.
//!
//! Six [`OrientedBlockFace`] definitions combine to form a
//! [`QuadCoordinateConfig`], which also implicitly defines the coordinate
//! system.

mod axis;
mod face;
mod quad;

pub use axis::*;
pub use face::*;
pub use quad::*;

/// A configuration of XYZ --> NUV axis mappings and orientations of the cube
/// faces for a given coordinate system.
///
/// See the [`geometry` module documentation][crate::geometry] for more
/// information on `{N, U, V}` space.
#[derive(Clone)]
pub struct QuadCoordinateConfig {
    pub faces: [OrientedBlockFace; 6],

    /// For a given coordinate system, one of the two axes that isn't UP must be
    /// flipped in the U texel coordinate direction to avoid incorrect texture
    /// mirroring. For example, in a right-handed coordinate system with +Y
    /// pointing up, you should set `u_flip_face` to [`Axis::X`], because those
    /// faces need their U coordinates to be flipped relative to the other
    /// faces:
    ///
    /// ```text
    ///                         +X face  O           
    ///         +Z face                / |           
    ///     ^  O--------O          ^ O   |           
    ///     |  |        |          | |   |           
    ///  +V |  |        |       +V | |   O  ^        
    ///     |  |        |          | | /  /          
    ///     |  O--------O          | O  /                 
    ///      ------------ >        |  /  +U
    ///           +U                
    ///
    ///                    +Y      
    ///                    | -Z    
    ///              -X____|/____+X
    ///                   /|       
    ///                 +Z |       
    ///                    -Y      
    /// ```
    ///
    /// As you can see, for the +Z face, +U is toward positive X. But for the +X
    /// face, +U is towards **negative** Z.
    pub u_flip_face: Axis,
}

/// Coordinate configuration for a right-handed coordinate system with Y up.
///
/// ```text
///       +Y      
///       | -Z    
/// -X____|/____+X
///      /|       
///    +Z |       
///       -Y      
/// ```
pub const RIGHT_HANDED_Y_UP_CONFIG: QuadCoordinateConfig = QuadCoordinateConfig {
    // Y is always in the V direction when it's not the normal. When Y is the
    // normal, right-handedness determines that we must use Yzx permutations.
    faces: [
        OrientedBlockFace::new(-1, AxisPermutation::Xzy),
        OrientedBlockFace::new(-1, AxisPermutation::Yzx),
        OrientedBlockFace::new(-1, AxisPermutation::Zxy),
        OrientedBlockFace::new(1, AxisPermutation::Xzy),
        OrientedBlockFace::new(1, AxisPermutation::Yzx),
        OrientedBlockFace::new(1, AxisPermutation::Zxy),
    ],
    u_flip_face: Axis::X,
};