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 184 185 186 187 188 189
use crate::geom::Point3;
use crate::glam::{EulerRot, Mat4, Quat, Vec3};
use crate::math::{deg_to_rad, turns_to_rad};
/// Orientation properties for **Drawing** a **Primitive**.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Properties {
/// The orientation described by an angle along each axis.
Axes(Vec3),
/// The orientation described by looking at some other point.
LookAt(Point3),
/// Angle described by quarternion.
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),
}
}
/// If the `Properties` was set to the `LookAt` variant, this method switches to the `Axes`
/// variant.
///
/// If the `Properties` is already `Axes`, nothing changes.
pub fn switch_to_axes(&mut self) {
if let Properties::LookAt(_) = *self {
*self = Properties::Axes(Vec3::ZERO);
}
}
}
/// An API for setting the **orientation::Properties**.
pub trait SetOrientation: Sized {
/// Provide a mutable reference to the **orientation::Properties** for updating.
fn properties(&mut self) -> &mut Properties;
// Describing orientation via a target.
/// Describe orientation via the vector that points to the given target.
fn look_at(mut self, target: Point3) -> Self {
*self.properties() = Properties::LookAt(target);
self
}
// Absolute orientation.
/// Specify the orientation around the *x* axis as an absolute value in radians.
fn x_radians(mut self, x: f32) -> Self {
self.properties().switch_to_axes();
expect_axes(self.properties()).x = x;
self
}
/// Specify the orientation around the *y* axis as an absolute value in radians.
fn y_radians(mut self, y: f32) -> Self {
self.properties().switch_to_axes();
expect_axes(self.properties()).y = y;
self
}
/// Specify the orientation around the *z* axis as an absolute value in radians.
fn z_radians(mut self, z: f32) -> Self {
self.properties().switch_to_axes();
expect_axes(self.properties()).z = z;
self
}
/// Specify the orientation around the *x* axis as an absolute value in degrees.
fn x_degrees(self, x: f32) -> Self {
self.x_radians(deg_to_rad(x))
}
/// Specify the orientation around the *y* axis as an absolute value in degrees.
fn y_degrees(self, y: f32) -> Self {
self.y_radians(deg_to_rad(y))
}
/// Specify the orientation around the *z* axis as an absolute value in degrees.
fn z_degrees(self, z: f32) -> Self {
self.z_radians(deg_to_rad(z))
}
/// Specify the orientation around the *x* axis as a number of turns around the axis.
fn x_turns(self, x: f32) -> Self {
self.x_radians(turns_to_rad(x))
}
/// Specify the orientation around the *y* axis as a number of turns around the axis.
fn y_turns(self, y: f32) -> Self {
self.y_radians(turns_to_rad(y))
}
/// Specify the orientation around the *z* axis as a number of turns around the axis.
fn z_turns(self, z: f32) -> Self {
self.z_radians(turns_to_rad(z))
}
/// Specify the orientation along each axis with the given **Vector** of radians.
///
/// This has the same affect as calling `self.x_radians(v.x).y_radians(v.y).z_radians(v.z)`.
fn radians(self, v: Vec3) -> Self {
self.x_radians(v.x).y_radians(v.y).z_radians(v.z)
}
/// Specify the orientation along each axis with the given **Vector** of degrees.
///
/// This has the same affect as calling `self.x_degrees(v.x).y_degrees(v.y).z_degrees(v.z)`.
fn degrees(self, v: Vec3) -> Self {
self.x_degrees(v.x).y_degrees(v.y).z_degrees(v.z)
}
/// Specify the orientation along each axis with the given **Vector** of "turns".
///
/// This has the same affect as calling `self.x_turns(v.x).y_turns(v.y).z_turns(v.z)`.
fn turns(self, v: Vec3) -> Self {
self.x_turns(v.x).y_turns(v.y).z_turns(v.z)
}
/// Specify the orientation with the given euler orientation in radians.
fn euler(self, e: Vec3) -> Self {
self.radians(e)
}
/// Specify the orientation with the given **Quaternion**.
fn quaternion(mut self, q: Quat) -> Self {
*self.properties() = Properties::Quat(q);
self
}
// Higher level methods.
/// Specify the "pitch" of the orientation in radians.
///
/// This has the same effect as calling `x_radians`.
fn pitch(self, pitch: f32) -> Self {
self.x_radians(pitch)
}
/// Specify the "yaw" of the orientation in radians.
///
/// This has the same effect as calling `y_radians`.
fn yaw(self, yaw: f32) -> Self {
self.y_radians(yaw)
}
/// Specify the "roll" of the orientation in radians.
///
/// This has the same effect as calling `z_radians`.
fn roll(self, roll: f32) -> Self {
self.z_radians(roll)
}
/// Assuming we're looking at a 2D plane, positive values cause a clockwise rotation where the
/// given value is specified in radians.
///
/// This is equivalent to calling the `z_radians` or `roll` methods.
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)
}
}
// Expects the `Axes` variant from the given properties.
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`"),
}
}