use std::fmt;
#[derive(Copy, Clone)]
#[repr(C, packed)]
pub struct Vector {
data: u32,
}
impl Vector {
pub fn new(x: f32, y: f32, z: f32, w: f32) -> Vector {
let x = (clamp(x) * 1023f32).round() as u32;
let y = (clamp(y) * 1023f32).round() as u32;
let z = (clamp(z) * 1023f32).round() as u32;
let w = (clamp(w) * 3f32).round() as u32;
let mut c: u32 = 0;
c |= w << 30;
c |= z << 20;
c |= y << 10;
c |= x << 0;
Vector {
data: c
}
}
pub fn from_raw(data: u32) -> Vector {
Vector {
data: data
}
}
pub fn x(&self) -> f32 {
(1023 & self.data) as f32 / 1023f32
}
pub fn y(&self) -> f32 {
((1023 << 10 & self.data) >> 10) as f32 / 1023f32
}
pub fn z(&self) -> f32 {
((1023 << 20 & self.data) >> 20) as f32 / 1023f32
}
pub fn w(&self) -> f32 {
((0b11 << 30 & self.data) >> 30) as f32 / 3f32
}
pub fn set_x(&mut self, x: f32) {
let x = (clamp(x) * 1023f32).round() as u32;
let mut c: u32 =
(
3 << 30 | 1023 << 20 | 1023 << 10
) & self.data;
c |= x;
self.data = c;
}
pub fn set_y(&mut self, y: f32) {
let y = (clamp(y) * 1023f32).round() as u32;
let mut c: u32 =
(
3 << 30 | 1023 << 20 | 1023
) & self.data;
c |= y << 10;
self.data = c;
}
pub fn set_z(&mut self, z: f32) {
let z = (clamp(z) * 1023f32).round() as u32;
let mut c: u32 =
(
3 << 30 | 1023 << 10 | 1023
) & self.data;
c |= z << 20;
self.data = c;
}
pub fn set_xyz(&mut self, x: f32, y: f32, z: f32) {
let x = (clamp(x) * 1023f32).round() as u32;
let y = (clamp(y) * 1023f32).round() as u32;
let z = (clamp(z) * 1023f32).round() as u32;
let mut c: u32 =
(
3 << 30
) & self.data;
c |= z << 20;
c |= y << 10;
c |= x << 0;
self.data = c;
}
pub fn set_w(&mut self, w: f32) {
let w = (clamp(w) * 3f32).round() as u32;
let mut c: u32 =
(
1023 << 20 | 1023 << 10 | 1023
) & self.data;
c |= w << 30;
self.data = c;
}
pub fn raw_value(&self) -> &u32 {
&self.data
}
}
impl fmt::Debug for Vector {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_set()
.entry(&self.x())
.entry(&self.y())
.entry(&self.z())
.entry(&self.w())
.finish()
}
}
#[inline]
fn clamp(c: f32) -> f32 {
if c < 0.0 {
return 0.0;
}
if c > 1.0 {
return 1.0;
}
c
}