use crate::geom::Point3;
use crate::glam::{EulerRot, Mat4, Quat, Vec3};
use crate::math::{deg_to_rad, turns_to_rad};
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Properties {
Axes(Vec3),
LookAt(Point3),
Quat(Quat),
}
impl Properties {
pub fn transform(&self) -> Mat4 {
match *self {
Properties::Axes(v) => Mat4::from_euler(EulerRot::XYZ, v.x, v.y, v.z),
Properties::LookAt(p) => {
let eye = Vec3::ZERO;
let up = Vec3::Y;
Mat4::look_at_rh(eye, p, up)
}
Properties::Quat(q) => Mat4::from_quat(q),
}
}
pub fn switch_to_axes(&mut self) {
if let Properties::LookAt(_) = *self {
*self = Properties::Axes(Vec3::ZERO);
}
}
}
pub trait SetOrientation: Sized {
fn properties(&mut self) -> &mut Properties;
fn look_at(mut self, target: Point3) -> Self {
*self.properties() = Properties::LookAt(target);
self
}
fn x_radians(mut self, x: f32) -> Self {
self.properties().switch_to_axes();
expect_axes(self.properties()).x = x;
self
}
fn y_radians(mut self, y: f32) -> Self {
self.properties().switch_to_axes();
expect_axes(self.properties()).y = y;
self
}
fn z_radians(mut self, z: f32) -> Self {
self.properties().switch_to_axes();
expect_axes(self.properties()).z = z;
self
}
fn x_degrees(self, x: f32) -> Self {
self.x_radians(deg_to_rad(x))
}
fn y_degrees(self, y: f32) -> Self {
self.y_radians(deg_to_rad(y))
}
fn z_degrees(self, z: f32) -> Self {
self.z_radians(deg_to_rad(z))
}
fn x_turns(self, x: f32) -> Self {
self.x_radians(turns_to_rad(x))
}
fn y_turns(self, y: f32) -> Self {
self.y_radians(turns_to_rad(y))
}
fn z_turns(self, z: f32) -> Self {
self.z_radians(turns_to_rad(z))
}
fn radians(self, v: Vec3) -> Self {
self.x_radians(v.x).y_radians(v.y).z_radians(v.z)
}
fn degrees(self, v: Vec3) -> Self {
self.x_degrees(v.x).y_degrees(v.y).z_degrees(v.z)
}
fn turns(self, v: Vec3) -> Self {
self.x_turns(v.x).y_turns(v.y).z_turns(v.z)
}
fn euler(self, e: Vec3) -> Self {
self.radians(e)
}
fn quaternion(mut self, q: Quat) -> Self {
*self.properties() = Properties::Quat(q);
self
}
fn pitch(self, pitch: f32) -> Self {
self.x_radians(pitch)
}
fn yaw(self, yaw: f32) -> Self {
self.y_radians(yaw)
}
fn roll(self, roll: f32) -> Self {
self.z_radians(roll)
}
fn rotate(self, radians: f32) -> Self {
self.z_radians(radians)
}
}
impl SetOrientation for Properties {
fn properties(&mut self) -> &mut Properties {
self
}
}
impl Default for Properties {
fn default() -> Self {
Properties::Axes(Vec3::ZERO)
}
}
fn expect_axes(p: &mut Properties) -> &mut Vec3 {
match *p {
Properties::Axes(ref mut axes) => axes,
Properties::LookAt(_) => panic!("expected `Axes`, found `LookAt`"),
Properties::Quat(_) => panic!("expected `Axes`, found `Quat`"),
}
}