#![allow(dead_code)]
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PackedVec3 {
pub x: u16,
pub y: u16,
pub z: u16,
}
#[allow(dead_code)]
#[derive(Debug, Clone, Copy)]
pub struct PackedVec3Config {
pub min: f32,
pub max: f32,
}
impl Default for PackedVec3Config {
fn default() -> Self {
PackedVec3Config {
min: -1.0,
max: 1.0,
}
}
}
#[allow(dead_code)]
pub fn default_packed_config() -> PackedVec3Config {
PackedVec3Config::default()
}
#[allow(dead_code)]
pub fn packed_config(min: f32, max: f32) -> PackedVec3Config {
PackedVec3Config { min, max }
}
#[allow(dead_code)]
pub fn encode_f32_to_u16(val: f32, cfg: &PackedVec3Config) -> u16 {
let range = cfg.max - cfg.min;
if range < 1e-10 {
return 0;
}
let normalized = ((val - cfg.min) / range).clamp(0.0, 1.0);
(normalized * u16::MAX as f32).round() as u16
}
#[allow(dead_code)]
pub fn decode_u16_to_f32(val: u16, cfg: &PackedVec3Config) -> f32 {
let normalized = val as f32 / u16::MAX as f32;
cfg.min + normalized * (cfg.max - cfg.min)
}
#[allow(dead_code)]
pub fn pack_vec3(v: [f32; 3], cfg: &PackedVec3Config) -> PackedVec3 {
PackedVec3 {
x: encode_f32_to_u16(v[0], cfg),
y: encode_f32_to_u16(v[1], cfg),
z: encode_f32_to_u16(v[2], cfg),
}
}
#[allow(dead_code)]
pub fn unpack_vec3(pv: &PackedVec3, cfg: &PackedVec3Config) -> [f32; 3] {
[
decode_u16_to_f32(pv.x, cfg),
decode_u16_to_f32(pv.y, cfg),
decode_u16_to_f32(pv.z, cfg),
]
}
#[allow(dead_code)]
#[derive(Debug, Clone, Default)]
pub struct PackedVec3Buffer {
data: Vec<PackedVec3>,
config: PackedVec3Config,
}
#[allow(dead_code)]
pub fn new_packed_buffer(cfg: PackedVec3Config) -> PackedVec3Buffer {
PackedVec3Buffer {
data: Vec::new(),
config: cfg,
}
}
#[allow(dead_code)]
pub fn pvbuf_push(buf: &mut PackedVec3Buffer, v: [f32; 3]) {
buf.data.push(pack_vec3(v, &buf.config));
}
#[allow(dead_code)]
pub fn pvbuf_get(buf: &PackedVec3Buffer, idx: usize) -> Option<[f32; 3]> {
buf.data.get(idx).map(|pv| unpack_vec3(pv, &buf.config))
}
#[allow(dead_code)]
pub fn pvbuf_len(buf: &PackedVec3Buffer) -> usize {
buf.data.len()
}
#[allow(dead_code)]
pub fn pvbuf_is_empty(buf: &PackedVec3Buffer) -> bool {
buf.data.is_empty()
}
#[allow(dead_code)]
pub fn pvbuf_clear(buf: &mut PackedVec3Buffer) {
buf.data.clear();
}
#[allow(dead_code)]
pub fn pvbuf_bytes(buf: &PackedVec3Buffer) -> usize {
buf.data.len() * 6
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_encode_decode_roundtrip() {
let cfg = default_packed_config();
let val = 0.5f32;
let encoded = encode_f32_to_u16(val, &cfg);
let decoded = decode_u16_to_f32(encoded, &cfg);
assert!((decoded - val).abs() < 0.0001);
}
#[test]
fn test_pack_unpack_zero() {
let cfg = default_packed_config();
let v = [0.0f32, 0.0, 0.0];
let packed = pack_vec3(v, &cfg);
let unpacked = unpack_vec3(&packed, &cfg);
assert!((unpacked[0]).abs() < 0.0001);
}
#[test]
fn test_pack_unpack_max() {
let cfg = default_packed_config();
let v = [1.0f32, 1.0, 1.0];
let packed = pack_vec3(v, &cfg);
let unpacked = unpack_vec3(&packed, &cfg);
assert!((unpacked[0] - 1.0).abs() < 0.0001);
}
#[test]
fn test_pack_unpack_min() {
let cfg = default_packed_config();
let v = [-1.0f32, -1.0, -1.0];
let packed = pack_vec3(v, &cfg);
let unpacked = unpack_vec3(&packed, &cfg);
assert!((unpacked[0] + 1.0).abs() < 0.0001);
}
#[test]
fn test_buffer_push_and_get() {
let cfg = default_packed_config();
let mut buf = new_packed_buffer(cfg);
pvbuf_push(&mut buf, [0.5, -0.5, 0.0]);
assert_eq!(pvbuf_len(&buf), 1);
let got = pvbuf_get(&buf, 0).expect("should succeed");
assert!((got[0] - 0.5).abs() < 0.0001);
}
#[test]
fn test_buffer_is_empty() {
let cfg = default_packed_config();
let buf = new_packed_buffer(cfg);
assert!(pvbuf_is_empty(&buf));
}
#[test]
fn test_buffer_clear() {
let cfg = default_packed_config();
let mut buf = new_packed_buffer(cfg);
pvbuf_push(&mut buf, [1.0, 0.0, 0.0]);
pvbuf_clear(&mut buf);
assert!(pvbuf_is_empty(&buf));
}
#[test]
fn test_buffer_bytes() {
let cfg = default_packed_config();
let mut buf = new_packed_buffer(cfg);
pvbuf_push(&mut buf, [0.0, 0.0, 0.0]);
assert_eq!(pvbuf_bytes(&buf), 6);
}
#[test]
fn test_get_out_of_bounds() {
let cfg = default_packed_config();
let buf = new_packed_buffer(cfg);
assert!(pvbuf_get(&buf, 0).is_none());
}
#[test]
fn test_custom_range() {
let cfg = packed_config(0.0, 100.0);
let val = 50.0f32;
let encoded = encode_f32_to_u16(val, &cfg);
let decoded = decode_u16_to_f32(encoded, &cfg);
assert!((decoded - val).abs() < 0.01);
}
}