use crate::camera::Camera2d;
use crate::event::WindowEvent;
use crate::window::Canvas;
use glamx::{Mat3, Vec2, Vec3, Vec3Swizzles};
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum CoordinateSystem2d {
#[default]
CenterUp,
TopLeftDown,
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FixedView2d {
proj: Mat3,
inv_proj: Mat3,
coord_system: CoordinateSystem2d,
apply_hidpi: bool,
}
impl Default for FixedView2d {
fn default() -> Self {
Self::new(CoordinateSystem2d::CenterUp, true)
}
}
impl FixedView2d {
pub fn new(coord_system: CoordinateSystem2d, apply_hidpi: bool) -> FixedView2d {
FixedView2d {
proj: Mat3::IDENTITY,
inv_proj: Mat3::IDENTITY,
coord_system,
apply_hidpi,
}
}
}
impl Camera2d for FixedView2d {
fn handle_event(&mut self, canvas: &Canvas, event: &WindowEvent) {
if let WindowEvent::FramebufferSize(w, h) = *event {
let scale = if self.apply_hidpi {
canvas.scale_factor() as f32
} else {
1.0
};
let w = w as f32;
let h = h as f32;
let proj = match self.coord_system {
CoordinateSystem2d::CenterUp => {
let diag = Vec3::new(2.0 * scale / w, 2.0 * scale / h, 1.0);
Mat3::from_diagonal(diag)
}
CoordinateSystem2d::TopLeftDown => Mat3::from_cols(
Vec3::new(2.0 * scale / w, 0.0, 0.0),
Vec3::new(0.0, -2.0 * scale / h, 0.0),
Vec3::new(-1.0, 1.0, 1.0),
),
};
self.proj = proj;
self.inv_proj = proj.inverse();
}
}
#[inline]
fn view_transform_pair(&self) -> (Mat3, Mat3) {
(Mat3::IDENTITY, self.proj)
}
fn update(&mut self, _: &Canvas) {}
fn unproject(&self, window_coord: Vec2, size: Vec2) -> Vec2 {
let normalized_coords = Vec2::new(
2.0 * window_coord.x / size.x - 1.0,
2.0 * -window_coord.y / size.y + 1.0,
);
let normalized_homogeneous = Vec3::new(normalized_coords.x, normalized_coords.y, 1.0);
let unprojected_homogeneous = self.inv_proj * normalized_homogeneous;
unprojected_homogeneous.xy() / unprojected_homogeneous.z
}
}