use crate::util::{DivOr, impl_op}; use std::{hash::Hash, ops::*}; #[repr(C)] #[derive(Clone, Copy, PartialEq, Default, bytemuck::Pod, bytemuck::Zeroable)] pub struct Vec2 { pub x: f32, pub y: f32, } impl Eq for Vec2 {} impl Hash for Vec2 { fn hash(&self, state: &mut H) { state.write_u32(self.x.to_bits()); state.write_u32(self.y.to_bits()); } } impl Vec2 { pub const ZERO: Self = Self::new(0.0, 0.0); pub const ONE: Self = Self::new(1.0, 1.0); pub const fn new(x: f32, y: f32) -> Self { Self { x, y } } pub const fn round(self) -> Self { Self { x: self.x.round(), y: self.y.round(), } } pub const fn floor(self) -> Self { Self { x: self.x.floor(), y: self.y.floor(), } } pub const fn ceil(self) -> Self { Self { x: self.x.ceil(), y: self.y.ceil(), } } pub const fn tuple(&self) -> (f32, f32) { (self.x, self.y) } pub const fn with_x(mut self, x: f32) -> Self { self.x = x; self } pub const fn with_y(mut self, y: f32) -> Self { self.y = y; self } } // this version looks kinda cool... is it more readable? more annoying to copy and change though impl_op!(impl Add for Vec2: add x y); impl_op!(Vec2 Sub sub; x y); impl_op!(Vec2 Mul mul; x y); impl_op!(Vec2 Div div; x y); impl const DivOr for Vec2 { fn div_or(self, rhs: Self, other: Self) -> Self { Self { x: self.x.div_or(rhs.x, other.x), y: self.y.div_or(rhs.y, other.y), } } } impl Neg for Vec2 { type Output = Self; fn neg(mut self) -> Self::Output { self.x = -self.x; self.y = -self.y; self } } impl std::fmt::Debug for Vec2 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "({}, {})", self.x, self.y) } } impl std::fmt::Display for Vec2 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "({}, {})", self.x, self.y) } }