summaryrefslogtreecommitdiff
path: root/engine/src/projection.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/projection.rs')
-rw-r--r--engine/src/projection.rs201
1 files changed, 177 insertions, 24 deletions
diff --git a/engine/src/projection.rs b/engine/src/projection.rs
index aa84a9f..b3bfa00 100644
--- a/engine/src/projection.rs
+++ b/engine/src/projection.rs
@@ -1,57 +1,210 @@
-use crate::matrix::Matrix;
+use crate::builder;
+use crate::data_types::dimens::Dimens;
+use crate::matrix::{CellPos as MatrixCellPos, Matrix};
+use crate::reflection::Reflection;
+use crate::vector::Vec2;
+use crate::windowing::dpi::PhysicalSize;
-#[derive(Debug)]
+#[derive(Debug, Clone, Reflection)]
#[non_exhaustive]
pub enum Projection
{
Perspective(Perspective),
+ Orthographic(Orthographic),
+}
+
+impl Projection
+{
+ pub fn to_matrix_rh(
+ &self,
+ window_size: PhysicalSize<u32>,
+ clip_volume: ClipVolume,
+ ) -> Matrix<f32, 4, 4>
+ {
+ match self {
+ Projection::Perspective(perspective_proj) => perspective_proj.to_matrix_rh(
+ window_size.width as f32 / window_size.height as f32,
+ clip_volume,
+ ),
+ Projection::Orthographic(orthographic_proj) => {
+ orthographic_proj.to_matrix_rh(window_size, clip_volume)
+ }
+ }
+ }
}
/// Perspective projection parameters.
-#[derive(Debug)]
+#[derive(Debug, Clone, Reflection)]
pub struct Perspective
{
- pub fov_radians: f32,
+ /// Field-of-view in degrees
+ pub fov_degs: f32,
pub far: f32,
pub near: f32,
}
+impl Perspective
+{
+ /// Creates a perspective projection matrix using right-handed coordinates.
+ #[inline]
+ pub fn to_matrix_rh(&self, aspect: f32, clip_volume: ClipVolume)
+ -> Matrix<f32, 4, 4>
+ {
+ let mut out = Matrix::new();
+
+ let fov_rads = self.fov_degs.to_radians();
+
+ match clip_volume {
+ ClipVolume::NegOneToOne => {
+ out[MatrixCellPos { row: 0, col: 0 }] =
+ (1.0 / (fov_rads / 2.0).tan()) / aspect;
+ out[MatrixCellPos { row: 1, col: 1 }] = 1.0 / (fov_rads / 2.0).tan();
+ out[MatrixCellPos { row: 2, col: 2 }] =
+ (self.near + self.far) / (self.near - self.far);
+ out[MatrixCellPos { row: 2, col: 3 }] =
+ (2.0 * self.near * self.far) / (self.near - self.far);
+ out[MatrixCellPos { row: 3, col: 2 }] = -1.0;
+ }
+ }
+
+ out
+ }
+}
+
impl Default for Perspective
{
fn default() -> Self
{
Self {
- fov_radians: 80.0f32.to_radians(),
+ fov_degs: 80.0,
far: 100.0,
near: 0.1,
}
}
}
-pub(crate) fn new_perspective_matrix(
- perspective: &Perspective,
- aspect: f32,
-) -> Matrix<f32, 4, 4>
+#[derive(Debug, Default, Clone, Reflection)]
+pub enum OrthographicSize
+{
+ FixedSize(Dimens<f32>),
+
+ #[default]
+ WindowSize,
+}
+
+builder! {
+#[builder(name = OrthographicBuilder, derives=(Debug, Clone))]
+#[derive(Debug, Clone, Reflection)]
+#[non_exhaustive]
+pub struct Orthographic
+{
+ pub near: f32,
+ pub far: f32,
+ pub viewport_origin: Vec2<f32>,
+ pub size: OrthographicSize,
+}
+}
+
+impl Orthographic
+{
+ pub fn builder() -> OrthographicBuilder
+ {
+ OrthographicBuilder::default()
+ }
+
+ /// Creates a orthographic projection matrix using right-handed coordinates.
+ pub fn to_matrix_rh(
+ &self,
+ window_size: PhysicalSize<u32>,
+ clip_volume: ClipVolume,
+ ) -> Matrix<f32, 4, 4>
+ {
+ let size = match self.size {
+ OrthographicSize::FixedSize(fixed_size) => fixed_size,
+ OrthographicSize::WindowSize => Dimens {
+ width: window_size.width as f32,
+ height: window_size.height as f32,
+ },
+ };
+
+ let origin_x = size.width * self.viewport_origin.x;
+ let origin_y = size.height * self.viewport_origin.y;
+
+ let left = -origin_x;
+ let right = size.width - origin_x;
+
+ let bottom = -origin_y;
+ let top = size.height - origin_y;
+
+ let near = self.near;
+ let far = self.far;
+
+ orthographic_rh(
+ OrthographicParams { left, right, bottom, top, near, far },
+ clip_volume,
+ )
+ }
+}
+
+impl Default for Orthographic
{
- let mut out = Matrix::new();
+ fn default() -> Self
+ {
+ Self::builder().build()
+ }
+}
- out.set_cell(0, 0, (1.0 / (perspective.fov_radians / 2.0).tan()) / aspect);
+impl Default for OrthographicBuilder
+{
+ fn default() -> Self
+ {
+ Self {
+ near: 0.0,
+ far: 1000.0,
+ viewport_origin: Vec2 { x: 0.5, y: 0.5 },
+ size: OrthographicSize::WindowSize,
+ }
+ }
+}
- out.set_cell(1, 1, 1.0 / (perspective.fov_radians / 2.0).tan());
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[non_exhaustive]
+pub enum ClipVolume
+{
+ /// -1 to +1. This is the OpenGL clip volume definition.
+ NegOneToOne,
+}
- out.set_cell(
- 2,
- 2,
- (perspective.near + perspective.far) / (perspective.near - perspective.far),
- );
+#[derive(Debug, Clone)]
+pub struct OrthographicParams
+{
+ pub left: f32,
+ pub right: f32,
+ pub bottom: f32,
+ pub top: f32,
+ pub near: f32,
+ pub far: f32,
+}
- out.set_cell(
- 2,
- 3,
- (2.0 * perspective.near * perspective.far) / (perspective.near - perspective.far),
- );
+/// Creates a orthographic projection matrix using right-handed coordinates.
+pub fn orthographic_rh(
+ OrthographicParams { left, right, bottom, top, near, far }: OrthographicParams,
+ clip_volume: ClipVolume,
+) -> Matrix<f32, 4, 4>
+{
+ let mut result = Matrix::<f32, 4, 4>::new();
- out.set_cell(3, 2, -1.0);
+ match clip_volume {
+ ClipVolume::NegOneToOne => {
+ result[MatrixCellPos { row: 0, col: 0 }] = 2.0 / (right - left);
+ result[MatrixCellPos { row: 1, col: 1 }] = 2.0 / (top - bottom);
+ result[MatrixCellPos { row: 2, col: 2 }] = -2.0 / (far - near);
+ result[MatrixCellPos { row: 0, col: 3 }] = -(right + left) / (right - left);
+ result[MatrixCellPos { row: 1, col: 3 }] = -(top + bottom) / (top - bottom);
+ result[MatrixCellPos { row: 2, col: 3 }] = -(far + near) / (far - near);
+ result[MatrixCellPos { row: 3, col: 3 }] = 1.0;
+ }
+ }
- out
+ result
}