use bevy::prelude::*;
use crate::draw::{Draw, drawing};
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Properties {
Axes(Vec3),
LookAt(Vec3),
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: Vec3) -> 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(x.to_radians())
}
fn y_degrees(self, y: f32) -> Self {
self.y_radians(y.to_radians())
}
fn z_degrees(self, z: f32) -> Self {
self.z_radians(z.to_radians())
}
fn x_turns(self, x: f32) -> Self {
self.x_radians(x * std::f32::consts::TAU)
}
fn y_turns(self, y: f32) -> Self {
self.y_radians(y * std::f32::consts::TAU)
}
fn z_turns(self, z: f32) -> Self {
self.z_radians(z * std::f32::consts::TAU)
}
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`"),
}
}
pub(crate) enum Update {
LookAt(Vec3),
XRadians(f32),
YRadians(f32),
ZRadians(f32),
Radians(Vec3),
Quat(Quat),
}
pub(crate) fn set_orientation(draw: &Draw, index: usize, update: Update) {
drawing::with_primitive(draw, index, |prim| match prim.orientation_mut() {
Some(props) => apply_update(props, update),
None => bevy::log::warn_once!("drawing primitive does not support `orientation`"),
})
}
fn apply_update(props: &mut Properties, update: Update) {
match update {
Update::LookAt(target) => *props = Properties::LookAt(target),
Update::XRadians(x) => *props = SetOrientation::x_radians(*props, x),
Update::YRadians(y) => *props = SetOrientation::y_radians(*props, y),
Update::ZRadians(z) => *props = SetOrientation::z_radians(*props, z),
Update::Radians(v) => *props = SetOrientation::radians(*props, v),
Update::Quat(q) => *props = Properties::Quat(q),
}
}