use crate::std::{Vec2f, Vec4f, vec2f, vec4f};
pub fn pack4x8snorm(e: Vec4f) -> u32 {
fn to_snorm8(v: f32) -> u8 {
let clamped = v.clamp(-1.0, 1.0);
let scaled = (0.5 + 127.0 * clamped).floor() as i8;
scaled as u8
}
let b0 = to_snorm8(e.x()) as u32;
let b1 = to_snorm8(e.y()) as u32;
let b2 = to_snorm8(e.z()) as u32;
let b3 = to_snorm8(e.w()) as u32;
b0 | (b1 << 8) | (b2 << 16) | (b3 << 24)
}
pub fn pack4x8unorm(e: Vec4f) -> u32 {
fn to_unorm8(v: f32) -> u8 {
let clamped = v.clamp(0.0, 1.0);
(0.5 + 255.0 * clamped).floor() as u8
}
let b0 = to_unorm8(e.x()) as u32;
let b1 = to_unorm8(e.y()) as u32;
let b2 = to_unorm8(e.z()) as u32;
let b3 = to_unorm8(e.w()) as u32;
b0 | (b1 << 8) | (b2 << 16) | (b3 << 24)
}
pub fn pack2x16snorm(e: Vec2f) -> u32 {
fn to_snorm16(v: f32) -> u16 {
let clamped = v.clamp(-1.0, 1.0);
let scaled = (0.5 + 32767.0 * clamped).floor() as i16;
scaled as u16
}
let lo = to_snorm16(e.x()) as u32;
let hi = to_snorm16(e.y()) as u32;
lo | (hi << 16)
}
pub fn pack2x16unorm(e: Vec2f) -> u32 {
fn to_unorm16(v: f32) -> u16 {
let clamped = v.clamp(0.0, 1.0);
(0.5 + 65535.0 * clamped).floor() as u16
}
let lo = to_unorm16(e.x()) as u32;
let hi = to_unorm16(e.y()) as u32;
lo | (hi << 16)
}
pub fn pack2x16float(e: Vec2f) -> u32 {
let lo = half::f16::from_f32(e.x()).to_bits() as u32;
let hi = half::f16::from_f32(e.y()).to_bits() as u32;
lo | (hi << 16)
}
pub fn unpack4x8snorm(e: u32) -> Vec4f {
fn from_snorm8(bits: u8) -> f32 {
let v = bits as i8;
(v as f32 / 127.0).max(-1.0)
}
vec4f(
from_snorm8(e as u8),
from_snorm8((e >> 8) as u8),
from_snorm8((e >> 16) as u8),
from_snorm8((e >> 24) as u8),
)
}
pub fn unpack4x8unorm(e: u32) -> Vec4f {
fn from_unorm8(bits: u8) -> f32 {
bits as f32 / 255.0
}
vec4f(
from_unorm8(e as u8),
from_unorm8((e >> 8) as u8),
from_unorm8((e >> 16) as u8),
from_unorm8((e >> 24) as u8),
)
}
pub fn unpack2x16snorm(e: u32) -> Vec2f {
fn from_snorm16(bits: u16) -> f32 {
let v = bits as i16;
(v as f32 / 32767.0).max(-1.0)
}
vec2f(from_snorm16(e as u16), from_snorm16((e >> 16) as u16))
}
pub fn unpack2x16unorm(e: u32) -> Vec2f {
fn from_unorm16(bits: u16) -> f32 {
bits as f32 / 65535.0
}
vec2f(from_unorm16(e as u16), from_unorm16((e >> 16) as u16))
}
pub fn unpack2x16float(e: u32) -> Vec2f {
let lo = half::f16::from_bits(e as u16).to_f32();
let hi = half::f16::from_bits((e >> 16) as u16).to_f32();
vec2f(lo, hi)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn pack4x8snorm_known_values() {
assert_eq!(pack4x8snorm(vec4f(0.0, 0.0, 0.0, 0.0)), 0);
assert_eq!(pack4x8snorm(vec4f(1.0, 1.0, 1.0, 1.0)), 0x7F7F7F7F);
assert_eq!(pack4x8snorm(vec4f(-1.0, -1.0, -1.0, -1.0)), 0x81818181);
}
#[test]
fn pack4x8snorm_clamps_out_of_range() {
assert_eq!(
pack4x8snorm(vec4f(2.0, -2.0, 0.0, 0.0)),
pack4x8snorm(vec4f(1.0, -1.0, 0.0, 0.0))
);
}
#[test]
fn pack4x8snorm_roundtrip() {
let original = vec4f(0.5, -0.5, 0.25, -0.75);
let packed = pack4x8snorm(original);
let unpacked = unpack4x8snorm(packed);
assert!((unpacked.x() - 0.5).abs() < 0.01);
assert!((unpacked.y() - (-0.5)).abs() < 0.01);
assert!((unpacked.z() - 0.25).abs() < 0.01);
assert!((unpacked.w() - (-0.75)).abs() < 0.01);
}
#[test]
fn unpack4x8snorm_known_values() {
let v = unpack4x8snorm(0);
assert_eq!(v, vec4f(0.0, 0.0, 0.0, 0.0));
let v = unpack4x8snorm(0x7F7F7F7F);
assert!((v.x() - 1.0).abs() < 1e-6);
assert!((v.y() - 1.0).abs() < 1e-6);
let v = unpack4x8snorm(0x80808080);
assert!((v.x() - (-1.0)).abs() < 1e-6);
}
#[test]
fn pack4x8unorm_known_values() {
assert_eq!(pack4x8unorm(vec4f(0.0, 0.0, 0.0, 0.0)), 0);
assert_eq!(pack4x8unorm(vec4f(1.0, 1.0, 1.0, 1.0)), 0xFFFFFFFF);
}
#[test]
fn pack4x8unorm_clamps_out_of_range() {
assert_eq!(
pack4x8unorm(vec4f(2.0, -1.0, 0.0, 0.0)),
pack4x8unorm(vec4f(1.0, 0.0, 0.0, 0.0))
);
}
#[test]
fn pack4x8unorm_roundtrip() {
let original = vec4f(0.0, 0.25, 0.5, 1.0);
let packed = pack4x8unorm(original);
let unpacked = unpack4x8unorm(packed);
assert!((unpacked.x() - 0.0).abs() < 0.005);
assert!((unpacked.y() - 0.25).abs() < 0.005);
assert!((unpacked.z() - 0.5).abs() < 0.005);
assert!((unpacked.w() - 1.0).abs() < 0.005);
}
#[test]
fn unpack4x8unorm_known_values() {
let v = unpack4x8unorm(0);
assert_eq!(v, vec4f(0.0, 0.0, 0.0, 0.0));
let v = unpack4x8unorm(0xFFFFFFFF);
assert!((v.x() - 1.0).abs() < 1e-6);
assert!((v.y() - 1.0).abs() < 1e-6);
assert!((v.z() - 1.0).abs() < 1e-6);
assert!((v.w() - 1.0).abs() < 1e-6);
}
#[test]
fn pack2x16snorm_known_values() {
assert_eq!(pack2x16snorm(vec2f(0.0, 0.0)), 0);
assert_eq!(pack2x16snorm(vec2f(1.0, 1.0)), 0x7FFF7FFF);
assert_eq!(pack2x16snorm(vec2f(-1.0, -1.0)), 0x80018001);
}
#[test]
fn pack2x16snorm_clamps_out_of_range() {
assert_eq!(
pack2x16snorm(vec2f(5.0, -5.0)),
pack2x16snorm(vec2f(1.0, -1.0))
);
}
#[test]
fn pack2x16snorm_roundtrip() {
let original = vec2f(0.5, -0.75);
let packed = pack2x16snorm(original);
let unpacked = unpack2x16snorm(packed);
assert!((unpacked.x() - 0.5).abs() < 0.0001);
assert!((unpacked.y() - (-0.75)).abs() < 0.0001);
}
#[test]
fn unpack2x16snorm_known_values() {
let v = unpack2x16snorm(0);
assert_eq!(v, vec2f(0.0, 0.0));
let v = unpack2x16snorm(0x7FFF7FFF);
assert!((v.x() - 1.0).abs() < 1e-6);
assert!((v.y() - 1.0).abs() < 1e-6);
let v = unpack2x16snorm(0x80008000);
assert!((v.x() - (-1.0)).abs() < 1e-6);
assert!((v.y() - (-1.0)).abs() < 1e-6);
}
#[test]
fn pack2x16unorm_known_values() {
assert_eq!(pack2x16unorm(vec2f(0.0, 0.0)), 0);
assert_eq!(pack2x16unorm(vec2f(1.0, 1.0)), 0xFFFFFFFF);
}
#[test]
fn pack2x16unorm_clamps_out_of_range() {
assert_eq!(
pack2x16unorm(vec2f(2.0, -1.0)),
pack2x16unorm(vec2f(1.0, 0.0))
);
}
#[test]
fn pack2x16unorm_roundtrip() {
let original = vec2f(0.25, 0.75);
let packed = pack2x16unorm(original);
let unpacked = unpack2x16unorm(packed);
assert!((unpacked.x() - 0.25).abs() < 0.0001);
assert!((unpacked.y() - 0.75).abs() < 0.0001);
}
#[test]
fn unpack2x16unorm_known_values() {
let v = unpack2x16unorm(0);
assert_eq!(v, vec2f(0.0, 0.0));
let v = unpack2x16unorm(0xFFFFFFFF);
assert!((v.x() - 1.0).abs() < 1e-6);
assert!((v.y() - 1.0).abs() < 1e-6);
}
#[test]
fn pack2x16float_known_values() {
let packed = pack2x16float(vec2f(0.0, 1.0));
assert_eq!(packed & 0xFFFF, 0x0000); assert_eq!(packed >> 16, 0x3C00); }
#[test]
fn pack2x16float_roundtrip() {
let original = vec2f(1.5, -0.25);
let packed = pack2x16float(original);
let unpacked = unpack2x16float(packed);
assert!((unpacked.x() - 1.5).abs() < 0.001);
assert!((unpacked.y() - (-0.25)).abs() < 0.001);
}
#[test]
fn unpack2x16float_known_values() {
let packed = 0x3C00 | (0xC000 << 16);
let v = unpack2x16float(packed);
assert!((v.x() - 1.0).abs() < 1e-6);
assert!((v.y() - (-2.0)).abs() < 1e-6);
}
#[test]
fn pack2x16float_roundtrip_special() {
let v = vec2f(0.0, 0.0);
assert_eq!(unpack2x16float(pack2x16float(v)), v);
let packed = pack2x16float(vec2f(-0.0, -0.0));
let unpacked = unpack2x16float(packed);
assert!(unpacked.x().is_sign_negative() || unpacked.x() == 0.0);
}
}