roast2d_internal 0.4.0

Roast2D internal crate
Documentation
use glam::Vec4;

#[derive(Debug, Default, Clone, Copy, PartialEq, PartialOrd)]
pub struct Color {
    pub r: f32,
    pub g: f32,
    pub b: f32,
    pub a: f32,
}

impl Color {
    pub const fn rgba(r: f32, g: f32, b: f32, a: f32) -> Self {
        Self { r, g, b, a }
    }

    pub const fn rgb(r: f32, g: f32, b: f32) -> Self {
        Self::rgba(r, g, b, 1.0)
    }

    pub fn with_a(mut self, a: f32) -> Self {
        self.a = a.clamp(0.0, 1.0);
        self
    }

    pub fn to_rgba(&self) -> (f32, f32, f32, f32) {
        (self.r, self.g, self.b, self.a)
    }

    pub const fn rgba_u8(r: u8, g: u8, b: u8, a: u8) -> Self {
        Self {
            r: r as f32 / 255.0,
            g: g as f32 / 255.0,
            b: b as f32 / 255.0,
            a: a as f32 / 255.0,
        }
    }

    pub const fn rgb_u8(r: u8, g: u8, b: u8) -> Self {
        Self::rgba_u8(r, g, b, 0xff)
    }

    pub fn with_a_u8(mut self, a: u8) -> Self {
        self.a = a as f32 / 255.0;
        self
    }

    pub fn to_rgba_u8(&self) -> (u8, u8, u8, u8) {
        (
            (self.r * 255.0).round() as u8,
            (self.g * 255.0).round() as u8,
            (self.b * 255.0).round() as u8,
            (self.a * 255.0).round() as u8,
        )
    }

    pub fn to_vec4(&self) -> Vec4 {
        Vec4::new(self.r, self.g, self.b, self.a)
    }

    pub fn is_transparent(&self) -> bool {
        self.a < 1.0
    }
}

pub const WHITE: Color = Color::rgb_u8(0xff, 0xff, 0xff);
pub const BLACK: Color = Color::rgb_u8(0, 0, 0);
pub const BLUE: Color = Color::rgb_u8(0, 0, 0xff);
pub const GRAY: Color = Color::rgb_u8(0x80, 0x80, 0x80);
pub const GREEN: Color = Color::rgb_u8(0, 0x80, 0);
pub const PURPLE: Color = Color::rgb_u8(0x80, 0, 0x80);
pub const RED: Color = Color::rgb_u8(0xff, 0, 0);
pub const SILVER: Color = Color::rgb_u8(0xc0, 0xc0, 0xc0);
pub const YELLOW: Color = Color::rgb_u8(0xff, 0xff, 0);
pub const NAVY: Color = Color::rgb_u8(0x00, 0x00, 0x80);
pub const DARK_BLUE: Color = Color::rgb_u8(0x00, 0x00, 0x8b);
pub const MEDIUM_BLUE: Color = Color::rgb_u8(0x00, 0x00, 0xcd);
pub const DARK_GREEN: Color = Color::rgb_u8(0x00, 0x64, 0x00);
pub const TEAL: Color = Color::rgb_u8(0x00, 0x80, 0x80);
pub const DARK_CYAN: Color = Color::rgb_u8(0x00, 0x8B, 0x8B);
pub const DEEP_SKY_BLUE: Color = Color::rgb_u8(0x00, 0xBF, 0xFF);
pub const DARK_TURQUOISE: Color = Color::rgb_u8(0x00, 0xce, 0xd1);
pub const MEDIUM_SPRING_GREEN: Color = Color::rgb_u8(0x00, 0xfa, 0x9a);
pub const LIME: Color = Color::rgb_u8(0x00, 0xff, 0x00);
pub const SPRING_GREEN: Color = Color::rgb_u8(0x00, 0xff, 0x7f);
pub const AQUA: Color = Color::rgb_u8(0x00, 0xff, 0xff);
pub const MIDNIGHT_BLUE: Color = Color::rgb_u8(0x19, 0x19, 0x70);
pub const DODGER_BLUE: Color = Color::rgb_u8(0x1e, 0x90, 0xff);
pub const LIGHT_SEA_GREEN: Color = Color::rgb_u8(0x20, 0xb2, 0xaa);
pub const FOREST_GREEN: Color = Color::rgb_u8(0x22, 0x8b, 0x22);
pub const SEA_GREEN: Color = Color::rgb_u8(0x2e, 0x8b, 0x57);
pub const DARK_SLATE_GRAY: Color = Color::rgb_u8(0x2f, 0x4f, 0x4f);
pub const LIME_GREEN: Color = Color::rgb_u8(0x32, 0xcd, 0x32);
pub const MEDIUM_SEA_GREEN: Color = Color::rgb_u8(0x3c, 0xb3, 0x71);
pub const TURQUOISE: Color = Color::rgb_u8(0x40, 0xe0, 0xd0);
pub const ROYAL_BLUE: Color = Color::rgb_u8(0x41, 0x69, 0xe1);
pub const STEEL_BLUE: Color = Color::rgb_u8(0x46, 0x82, 0xb4);
pub const DARK_SLATE_BLUE: Color = Color::rgb_u8(0x48, 0x3d, 0x8b);
pub const MEDIUM_TORQUOISE: Color = Color::rgb_u8(0x48, 0xd1, 0xcc);
pub const INDIGO: Color = Color::rgb_u8(0x4b, 0x00, 0x82);
pub const DARK_OLIVE_GREEN: Color = Color::rgb_u8(0x55, 0x6b, 0x2f);
pub const CADET_BLUE: Color = Color::rgb_u8(0x5f, 0x9e, 0xa0);
pub const CORN_FLOWER_BLUE: Color = Color::rgb_u8(0x64, 0x95, 0xed);
pub const REBECCA_PURPLE: Color = Color::rgb_u8(0x66, 0x33, 0x99);
pub const MEDIUM_AQUA_MARINE: Color = Color::rgb_u8(0x66, 0xcd, 0xaa);
pub const DIM_GRAY: Color = Color::rgb_u8(0x69, 0x69, 0x69);
pub const SLATE_BLUE: Color = Color::rgb_u8(0x6a, 0x5a, 0xcd);
pub const OLIVE_DRAB: Color = Color::rgb_u8(0x6b, 0x8e, 0x23);
pub const SLATE_GRAY: Color = Color::rgb_u8(0x70, 0x80, 0x90);
pub const LIGHT_SLATE_GRAY: Color = Color::rgb_u8(0x77, 0x88, 0x99);
pub const MEDIUM_SLATE_BLUE: Color = Color::rgb_u8(0x7b, 0x68, 0xee);
pub const LAWN_GREEN: Color = Color::rgb_u8(0x7c, 0xfc, 0x00);
pub const CHARTREUSE: Color = Color::rgb_u8(0x7f, 0xff, 0x00);
pub const AUQAMARINE: Color = Color::rgb_u8(0x7f, 0xff, 0xd4);
pub const MAROON: Color = Color::rgb_u8(0x80, 0x00, 0x00);
pub const OLIVE: Color = Color::rgb_u8(0x80, 0x80, 0x00);
pub const SKY_BLUE: Color = Color::rgb_u8(0x87, 0xce, 0xeb);
pub const LIGHT_SKY_BLUE: Color = Color::rgb_u8(0x87, 0xce, 0xfa);
pub const BLUE_VIOLET: Color = Color::rgb_u8(0x8a, 0x2b, 0xe2);
pub const DARK_RED: Color = Color::rgb_u8(0x8b, 0x00, 0x00);
pub const DARK_MAGENTA: Color = Color::rgb_u8(0x8b, 0x00, 0x8b);
pub const SADDLE_BROWN: Color = Color::rgb_u8(0x8b, 0x45, 0x13);
pub const DARK_SEA_GREEN: Color = Color::rgb_u8(0x8f, 0xbc, 0x8f);
pub const LIGHT_GREEN: Color = Color::rgb_u8(0x90, 0xee, 0x90);
pub const MEDIUM_PURPLE: Color = Color::rgb_u8(0x93, 0x70, 0xdb);
pub const DARK_VIOLET: Color = Color::rgb_u8(0x94, 0x00, 0xd3);
pub const PALE_GREEN: Color = Color::rgb_u8(0x98, 0xfb, 0x98);
pub const DARK_ORCHID: Color = Color::rgb_u8(0x99, 0x32, 0xcc);
pub const YELLOW_GREEN: Color = Color::rgb_u8(0x9a, 0xcd, 0x32);
pub const SIENNA: Color = Color::rgb_u8(0xa0, 0x52, 0x2d);
pub const BROWN: Color = Color::rgb_u8(0xa5, 0x2a, 0x2a);
pub const DARK_GRAY: Color = Color::rgb_u8(0xa9, 0xa9, 0xa9);
pub const LIGHT_BLUE: Color = Color::rgb_u8(0xad, 0xd8, 0xe6);
pub const PALE_TURQUOISE: Color = Color::rgb_u8(0xaf, 0xee, 0xee);
pub const FIRE_BRICK: Color = Color::rgb_u8(0xb2, 0x22, 0x22);
pub const DARK_GOLDEN_ROD: Color = Color::rgb_u8(0xb8, 0x86, 0x0b);
pub const MEDIUM_ORCHID: Color = Color::rgb_u8(0xba, 0x55, 0xd3);
pub const ROSY_BROWN: Color = Color::rgb_u8(0xbc, 0x8f, 0x8f);
pub const DARK_KHAKI: Color = Color::rgb_u8(0xbd, 0xb7, 0x6b);
pub const MEDIUM_VIOLET_RED: Color = Color::rgb_u8(0xc7, 0x15, 0x85);
pub const INDIAN_RED: Color = Color::rgb_u8(0xcd, 0x5c, 0x5c);
pub const PERU: Color = Color::rgb_u8(0xcd, 0x85, 0x3f);
pub const CHOCOLATE: Color = Color::rgb_u8(0xd2, 0x69, 0x1e);
pub const TAN: Color = Color::rgb_u8(0xd2, 0xb4, 0x8c);
pub const LIGHT_GRAY: Color = Color::rgb_u8(0xd3, 0xd3, 0xd3);
pub const THISTLE: Color = Color::rgb_u8(0xd8, 0xbf, 0xd8);
pub const ORCHID: Color = Color::rgb_u8(0xda, 0x70, 0xd6);
pub const GOLDEN_ROD: Color = Color::rgb_u8(0xda, 0xa5, 0x20);
pub const PALE_VIOLET_RED: Color = Color::rgb_u8(0xdb, 0x70, 0x93);
pub const CRIMSON: Color = Color::rgb_u8(0xdc, 0x14, 0x3c);
pub const GAINSBORO: Color = Color::rgb_u8(0xdc, 0xdc, 0xdc);
pub const PLUM: Color = Color::rgb_u8(0xdd, 0xa0, 0xdd);
pub const BURLY_WOOD: Color = Color::rgb_u8(0xde, 0xb8, 0x87);
pub const LIGHT_CYAN: Color = Color::rgb_u8(0xe0, 0xff, 0xff);
pub const LAVENDER: Color = Color::rgb_u8(0xe6, 0xe6, 0xfa);
pub const DARK_SALMON: Color = Color::rgb_u8(0xe9, 0x96, 0x7a);
pub const VIOLET: Color = Color::rgb_u8(0xee, 0x82, 0xee);
pub const PALE_GOLDEN_ROD: Color = Color::rgb_u8(0xee, 0xe8, 0xaa);
pub const LIGHT_CORAL: Color = Color::rgb_u8(0xf0, 0x80, 0x80);
pub const KHAKI: Color = Color::rgb_u8(0xf0, 0xe6, 0x8c);
pub const ALICE_BLUE: Color = Color::rgb_u8(0xf0, 0xf8, 0xff);
pub const HONEY_DEW: Color = Color::rgb_u8(0xf0, 0xff, 0xf0);
pub const AZURE: Color = Color::rgb_u8(0xf0, 0xff, 0xff);
pub const SANDY_BROWN: Color = Color::rgb_u8(0xf4, 0xa4, 0x60);
pub const WHEAT: Color = Color::rgb_u8(0xf5, 0xde, 0xb3);
pub const BEIGE: Color = Color::rgb_u8(0xf5, 0xf5, 0xdc);
pub const WHITE_SMOKE: Color = Color::rgb_u8(0xf5, 0xf5, 0xf5);
pub const MINT_CREAM: Color = Color::rgb_u8(0xf5, 0xff, 0xfa);
pub const GHOST_WHITE: Color = Color::rgb_u8(0xf8, 0xf8, 0xff);
pub const SALMON: Color = Color::rgb_u8(0xfa, 0x80, 0x72);
pub const ANTIQUE_WHITE: Color = Color::rgb_u8(0xfa, 0xeb, 0xd7);
pub const LINEN: Color = Color::rgb_u8(0xfa, 0xf0, 0xe6);
pub const LIGHT_GOLDEN_ROD_YELLOW: Color = Color::rgb_u8(0xfa, 0xfa, 0xd2);
pub const OLD_LACE: Color = Color::rgb_u8(0xfd, 0xf5, 0xe6);
pub const FUCHSIA: Color = Color::rgb_u8(0xff, 0x00, 0xff);
pub const DEEP_PINK: Color = Color::rgb_u8(0xff, 0x14, 0x93);
pub const ORANGE_RED: Color = Color::rgb_u8(0xff, 0x45, 0x00);
pub const TOMATO: Color = Color::rgb_u8(0xff, 0x63, 0x47);
pub const HOT_PINK: Color = Color::rgb_u8(0xff, 0x69, 0xb4);
pub const CORAL: Color = Color::rgb_u8(0xff, 0x7f, 0x50);
pub const DARK_ORANGE: Color = Color::rgb_u8(0xff, 0x8c, 0x00);
pub const LIGHT_SALMON: Color = Color::rgb_u8(0xff, 0xa0, 0x7a);
pub const ORANGE: Color = Color::rgb_u8(0xff, 0xa5, 0x00);
pub const LIGHT_PINK: Color = Color::rgb_u8(0xff, 0xb6, 0xc1);
pub const PINK: Color = Color::rgb_u8(0xff, 0xc0, 0xcb);
pub const GOLD: Color = Color::rgb_u8(0xff, 0xd7, 0x00);
pub const PEACH_PUFF: Color = Color::rgb_u8(0xff, 0xda, 0xb9);
pub const NAVAJO_WHITE: Color = Color::rgb_u8(0xff, 0xde, 0xad);
pub const MOCCASIN: Color = Color::rgb_u8(0xff, 0xe4, 0xb5);
pub const BISQUE: Color = Color::rgb_u8(0xff, 0xe4, 0xc4);
pub const MISTY_ROSE: Color = Color::rgb_u8(0xff, 0xe4, 0xe1);
pub const BLANCHED_ALMOND: Color = Color::rgb_u8(0xff, 0xeb, 0xcd);
pub const PAPAYA_WHIP: Color = Color::rgb_u8(0xff, 0xef, 0xd5);
pub const LAVENDER_BLUSH: Color = Color::rgb_u8(0xff, 0xf0, 0xf5);
pub const SEA_SHELL: Color = Color::rgb_u8(0xff, 0xf5, 0xee);
pub const CORNSILK: Color = Color::rgb_u8(0xff, 0xf8, 0xdc);
pub const LEMON_CHIFFON: Color = Color::rgb_u8(0xff, 0xfa, 0xcd);
pub const FLORAL_WHITE: Color = Color::rgb_u8(0xff, 0xfa, 0xf0);
pub const SNOW: Color = Color::rgb_u8(0xff, 0xfa, 0xfa);
pub const LIGHT_YELLOW: Color = Color::rgb_u8(0xff, 0xff, 0xe0);
pub const IVORY: Color = Color::rgb_u8(0xff, 0xff, 0xf0);

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_color_rgba() {
        let c = Color::rgba(0.5, 0.25, 0.75, 0.8);
        assert_eq!(c.r, 0.5);
        assert_eq!(c.g, 0.25);
        assert_eq!(c.b, 0.75);
        assert_eq!(c.a, 0.8);
    }

    #[test]
    fn test_color_rgb() {
        let c = Color::rgb(0.5, 0.25, 0.75);
        assert_eq!(c.r, 0.5);
        assert_eq!(c.g, 0.25);
        assert_eq!(c.b, 0.75);
        assert_eq!(c.a, 1.0); // default alpha
    }

    #[test]
    fn test_color_rgba_u8() {
        let c = Color::rgba_u8(127, 255, 64, 200);
        assert!((c.r - 127.0 / 255.0).abs() < 0.001);
        assert!((c.g - 1.0).abs() < 0.001);
        assert!((c.b - 64.0 / 255.0).abs() < 0.001);
        assert!((c.a - 200.0 / 255.0).abs() < 0.001);
    }

    #[test]
    fn test_color_rgb_u8() {
        let c = Color::rgb_u8(127, 255, 64);
        assert!((c.r - 127.0 / 255.0).abs() < 0.001);
        assert_eq!(c.a, 1.0);
    }

    #[test]
    fn test_color_with_a_clamp() {
        let c = Color::rgb(0.5, 0.5, 0.5);

        // Normal case
        let c1 = c.with_a(0.5);
        assert_eq!(c1.a, 0.5);

        // Clamp above 1.0
        let c2 = c.with_a(1.5);
        assert_eq!(c2.a, 1.0);

        // Clamp below 0.0
        let c3 = c.with_a(-0.5);
        assert_eq!(c3.a, 0.0);
    }

    #[test]
    fn test_color_with_a_u8() {
        let c = Color::rgb(0.5, 0.5, 0.5).with_a_u8(128);
        assert!((c.a - 128.0 / 255.0).abs() < 0.001);
    }

    #[test]
    fn test_color_to_rgba() {
        let c = Color::rgba(0.1, 0.2, 0.3, 0.4);
        let (r, g, b, a) = c.to_rgba();
        assert_eq!(r, 0.1);
        assert_eq!(g, 0.2);
        assert_eq!(b, 0.3);
        assert_eq!(a, 0.4);
    }

    #[test]
    fn test_color_roundtrip_u8() {
        // Test u8 -> f32 -> u8 roundtrip
        let original = Color::rgba_u8(127, 255, 64, 200);
        let (r, g, b, a) = original.to_rgba_u8();
        assert_eq!(r, 127);
        assert_eq!(g, 255);
        assert_eq!(b, 64);
        assert_eq!(a, 200);
    }

    #[test]
    fn test_color_boundary_values_u8() {
        // Minimum values
        let min = Color::rgba_u8(0, 0, 0, 0);
        assert_eq!(min.r, 0.0);
        assert_eq!(min.a, 0.0);

        // Maximum values
        let max = Color::rgba_u8(255, 255, 255, 255);
        assert_eq!(max.r, 1.0);
        assert_eq!(max.a, 1.0);
    }

    #[test]
    fn test_color_to_vec4() {
        let c = Color::rgba(0.1, 0.2, 0.3, 0.4);
        let v = c.to_vec4();
        assert_eq!(v.x, 0.1);
        assert_eq!(v.y, 0.2);
        assert_eq!(v.z, 0.3);
        assert_eq!(v.w, 0.4);
    }

    #[test]
    fn test_color_is_transparent() {
        let opaque = Color::rgb(0.5, 0.5, 0.5);
        assert!(!opaque.is_transparent());

        let transparent = Color::rgba(0.5, 0.5, 0.5, 0.5);
        assert!(transparent.is_transparent());

        let fully_transparent = Color::rgba(0.5, 0.5, 0.5, 0.0);
        assert!(fully_transparent.is_transparent());
    }

    #[test]
    fn test_color_constants() {
        // Verify some common color constants
        assert_eq!(WHITE.r, 1.0);
        assert_eq!(WHITE.g, 1.0);
        assert_eq!(WHITE.b, 1.0);
        assert_eq!(WHITE.a, 1.0);

        assert_eq!(BLACK.r, 0.0);
        assert_eq!(BLACK.g, 0.0);
        assert_eq!(BLACK.b, 0.0);

        assert_eq!(RED.r, 1.0);
        assert_eq!(RED.g, 0.0);
        assert_eq!(RED.b, 0.0);

        assert_eq!(GREEN.r, 0.0);
        assert!((GREEN.g - 128.0 / 255.0).abs() < 0.01);
        assert_eq!(GREEN.b, 0.0);
    }
}