use std::f32::consts::PI;
use glam::{Vec2, Vec3, Vec3Swizzles};
use crate::types::Rect;
impl From<Vec3> for Transform {
fn from(pos: Vec3) -> Self {
Self::new(pos, Vec2::ONE)
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct Transform {
pub pos: Vec3,
pub scale: Vec2,
pub angle: f32,
pub size: Vec2,
}
impl Transform {
pub fn new(pos: Vec3, size: Vec2) -> Self {
Self {
pos,
size,
scale: Vec2::ONE,
angle: 0.0,
}
}
pub fn set_xy(&mut self, Vec2 { x, y }: Vec2) {
self.pos.x = x;
self.pos.y = y;
}
pub fn with_scale(mut self, scale: Vec2) -> Self {
self.scale = scale;
self
}
pub fn with_angle(mut self, angle: f32) -> Self {
self.angle = angle;
self
}
pub fn with_size(mut self, size: Vec2) -> Self {
self.size = size;
self
}
pub fn with_pos(mut self, pos: Vec3) -> Self {
self.pos = pos;
self
}
pub fn with_xy(mut self, xy: Vec2) -> Self {
self.set_xy(xy);
self
}
pub fn scaled_size(&self) -> Vec2 {
self.size * self.scale
}
pub fn bounds(&self) -> Rect {
self.bounds_with_anchor(Vec2::splat(0.5))
}
pub fn bounds_with_anchor(&self, anchor: Vec2) -> Rect {
calc_bounds(self.pos.xy(), self.scaled_size(), anchor, self.angle)
}
}
fn calc_bounds(pos: Vec2, size: Vec2, anchor: Vec2, angle: f32) -> Rect {
const HF_PI: f32 = PI * 0.5;
let lb = anchor;
let rt = Vec2::ONE - anchor;
if angle == 0.0 || angle.abs() == PI {
let min = pos - (size * lb);
let max = pos + (size * rt);
Rect { min, max }
} else if angle.abs() == HF_PI {
let size = Vec2 {
x: size.y,
y: size.x,
};
let min = pos - (size * lb);
let max = pos + (size * rt);
Rect { min, max }
} else {
let rot = Vec2::from_angle(angle);
let p_rt = size * rt;
let p_lb = -size * lb;
let p_rb = Vec2::new(p_rt.x, p_lb.y);
let p_lt = Vec2::new(p_lb.x, p_rt.y);
if angle > 0. && angle < HF_PI {
let max_x = rot.rotate(p_rb).x;
let min_x = rot.rotate(p_lt).x;
let max_y = rot.rotate(p_rt).y;
let min_y = rot.rotate(p_lb).y;
Rect {
min: pos + Vec2::new(min_x, min_y),
max: pos + Vec2::new(max_x, max_y),
}
} else if angle > HF_PI && angle < PI {
let max_x = rot.rotate(p_lb).x;
let min_x = rot.rotate(p_rt).x;
let max_y = rot.rotate(p_rb).y;
let min_y = rot.rotate(p_lt).y;
Rect {
min: pos + Vec2::new(min_x, min_y),
max: pos + Vec2::new(max_x, max_y),
}
} else if angle > -PI && angle < -HF_PI {
let max_x = rot.rotate(p_lt).x;
let min_x = rot.rotate(p_rb).x;
let max_y = rot.rotate(p_lb).y;
let min_y = rot.rotate(p_rt).y;
Rect {
min: pos + Vec2::new(min_x, min_y),
max: pos + Vec2::new(max_x, max_y),
}
} else if angle > -HF_PI && angle < 0.0 {
let max_x = rot.rotate(p_rt).x;
let min_x = rot.rotate(p_lb).x;
let max_y = rot.rotate(p_lt).y;
let min_y = rot.rotate(p_rb).y;
Rect {
min: pos + Vec2::new(min_x, min_y),
max: pos + Vec2::new(max_x, max_y),
}
} else {
panic!("Unnormalized angle {angle}")
}
}
}