summaryrefslogtreecommitdiff
path: root/src/camera.rs
diff options
context:
space:
mode:
authorMicha White <botahamec@outlook.com>2022-09-24 18:20:46 -0400
committerMicha White <botahamec@outlook.com>2022-09-24 18:20:46 -0400
commitc29555bddac1c0027bf6e15d91e219adaa088065 (patch)
tree59e671e4ded20b58027987053e207e4fe6a51307 /src/camera.rs
parent7f364d2642784fcffea730b1f168270ce907a27c (diff)
Implemented a camera
Diffstat (limited to 'src/camera.rs')
-rw-r--r--src/camera.rs95
1 files changed, 95 insertions, 0 deletions
diff --git a/src/camera.rs b/src/camera.rs
new file mode 100644
index 0000000..2eb1730
--- /dev/null
+++ b/src/camera.rs
@@ -0,0 +1,95 @@
+use cgmath::{Matrix4, Vector3};
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub struct Camera {
+ position: (f32, f32),
+ zoom: f32,
+ rotation: f32,
+ inverse_aspect_ratio: f32,
+}
+
+pub(crate) type CameraUniform = [[f32; 4]; 4];
+
+#[allow(clippy::cast_precision_loss)]
+fn inverse_aspect_ratio(width: u32, height: u32) -> f32 {
+ (height as f32) / (width as f32)
+}
+
+impl Camera {
+ /// Create a new camera, with a position of (0, 0), and a zoom of 1.0
+ pub(crate) fn from_size(width: u32, height: u32) -> Self {
+ Self {
+ position: (0.0, 0.0),
+ zoom: 1.0,
+ rotation: 0.0,
+ inverse_aspect_ratio: inverse_aspect_ratio(width, height),
+ }
+ }
+
+ /// Get the camera's current x position
+ #[must_use]
+ pub const fn x(&self) -> f32 {
+ self.position.0
+ }
+
+ /// Get the camera's current y position
+ #[must_use]
+ pub const fn y(&self) -> f32 {
+ self.position.1
+ }
+
+ /// Get the camera's current zoom
+ #[must_use]
+ pub const fn zoom(&self) -> f32 {
+ self.zoom
+ }
+
+ /// Set the position of the camera
+ pub fn set_position(&mut self, x: f32, y: f32) {
+ self.position = (x, y);
+ }
+
+ /// Set the aspect ratio of the camera
+ pub fn set_zoom(&mut self, zoom: f32) {
+ self.zoom = zoom;
+ }
+
+ /// Set the aspect ratio of the camera
+ pub(crate) fn set_size(&mut self, width: u32, height: u32) {
+ self.inverse_aspect_ratio = inverse_aspect_ratio(width, height);
+ }
+
+ #[allow(clippy::wrong_self_convention)]
+ pub(crate) fn to_matrix(&mut self) -> [[f32; 4]; 4] {
+ let cos_theta = self.rotation.cos();
+ let sin_theta = self.rotation.sin();
+
+ let x_axis = Vector3::new(cos_theta, -sin_theta, 0.0);
+ let y_axis = Vector3::new(sin_theta, cos_theta, 0.0);
+ let z_axis = Vector3::new(0.0, 0.0, 1.0);
+
+ let eye = Vector3::new(self.position.0, self.position.1, 0.0);
+ let x_dot = -cgmath::dot(x_axis, eye);
+ let y_dot = -cgmath::dot(y_axis, eye);
+ let z_dot = -cgmath::dot(z_axis, eye);
+
+ #[rustfmt::skip]
+ let view_matrix = Matrix4::new(
+ x_axis.x, y_axis.x, z_axis.x, 0.0,
+ x_axis.y, y_axis.y, z_axis.y, 0.0,
+ x_axis.x, y_axis.y, z_axis.z, 0.0,
+ x_dot, y_dot, z_dot, 1.0
+ );
+
+ #[rustfmt::skip]
+ // TODO implement more scaling coordinate systems
+ let projection_matrix = Matrix4::new(
+ self.inverse_aspect_ratio, 0.0, 0.0, 0.0,
+ 0.0, self.zoom, 0.0, 0.0,
+ 0.0, 0.0, 0.0, 0.0,
+ 0.0, 0.0, 0.0, 1.0
+ );
+
+ (projection_matrix * view_matrix).into()
+ }
+}