twsnap 0.9.2

Common snapshot format between TwGpu and TwGame
Documentation
use fixed::traits::Fixed;
use fixed::types::{I24F8, I27F5};
use serde::{Deserialize, Serialize};
use vek::{Rgb, Rgba, Vec2};

pub type PositionPrecision = I27F5;
pub type Position = Vec2<PositionPrecision>;
pub type VelocityPrecision = I24F8;
pub type Velocity = Vec2<VelocityPrecision>;
pub type AnglePrecision = I24F8;

/// Converts the coordinates to i32 by simple cast and interpret as fixed type
pub fn vec2_from_bits<T: Fixed<Bits = i32>>(from: Vec2<f32>) -> Vec2<T> {
    Vec2::new(T::from_bits(from.x as i32), T::from_bits(from.y as i32))
}

/// Similar to HSLA, however, the `l` value is abnormal.
/// The base float value of `l` will always be 0.5 on any color conversion.
/// `l_upper` determines the final `l` value from 0.5 to 1.
#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)]
pub struct SkinColor {
    pub a: u8,
    pub h: u8,
    pub s: u8,
    pub l_upper: u8,
}

impl SkinColor {
    pub fn to_rgba(&self) -> Rgba<f32> {
        let [a, h, s, l_upper] = [self.a, self.h, self.s, self.l_upper].map(|c| c as f32 / 255.);

        // UnclampLighting
        // https://github.com/ddnet/ddnet/blob/a1b603a4244adad21f48039edda5cd9954a11e44/src/base/color.h#L170
        let l = 0.5 + l_upper / 2.;

        // color_cast HSLA -> RGBA
        // https://github.com/ddnet/ddnet/blob/a1b603a4244adad21f48039edda5cd9954a11e44/src/base/color.h#L223
        let h1 = h * 6.;
        let c = (1. - (2. * l - 1.).abs()) * s;
        let x = c * (1. - ((h1 % 2.) - 1.).abs());
        let rgb = match h1 as i32 {
            0 => Rgb::new(c, x, 0.),
            1 => Rgb::new(x, c, 0.),
            2 => Rgb::new(0., c, x),
            3 => Rgb::new(0., x, c),
            4 => Rgb::new(x, 0., c),
            5 | 6 => Rgb::new(c, 0., x),
            _ => Rgb::new(0., 0., 0.),
        };
        let m = l - (c / 2.);
        Rgba::from_translucent(rgb + m, 1. - a)
    }
}