Skip to main content

jag_draw/
color.rs

1use palette::{FromColor, LinSrgba, Srgba};
2
3use crate::scene::ColorLinPremul;
4
5// sRGB → Linear premultiplied conversions, kept out of scene.rs for separation of concerns.
6impl ColorLinPremul {
7    /// Convenience alias matching Color::rgba(...) widely used in UI code.
8    #[inline]
9    pub fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
10        Self::from_srgba_u8([r, g, b, a])
11    }
12
13    /// Create from sRGB u8 RGBA array (premultiplied in linear space).
14    #[inline]
15    pub fn from_srgba_u8(c: [u8; 4]) -> Self {
16        let s = Srgba::new(
17            c[0] as f32 / 255.0,
18            c[1] as f32 / 255.0,
19            c[2] as f32 / 255.0,
20            c[3] as f32 / 255.0,
21        );
22        let lin: LinSrgba = LinSrgba::from_color(s);
23        Self {
24            r: lin.red * lin.alpha,
25            g: lin.green * lin.alpha,
26            b: lin.blue * lin.alpha,
27            a: lin.alpha,
28        }
29    }
30
31    /// Create from sRGB u8 RGB with float alpha (CSS-like rgba).
32    #[inline]
33    pub fn from_srgba(r: u8, g: u8, b: u8, a: f32) -> Self {
34        let s = Srgba::new(r as f32 / 255.0, g as f32 / 255.0, b as f32 / 255.0, a);
35        let lin: LinSrgba = LinSrgba::from_color(s);
36        Self {
37            r: lin.red * lin.alpha,
38            g: lin.green * lin.alpha,
39            b: lin.blue * lin.alpha,
40            a: lin.alpha,
41        }
42    }
43
44    /// Create directly from linear RGBA floats and premultiply.
45    #[inline]
46    pub fn from_lin_rgba(r: f32, g: f32, b: f32, a: f32) -> Self {
47        Self {
48            r: r * a,
49            g: g * a,
50            b: b * a,
51            a,
52        }
53    }
54
55    /// Convert back to sRGB u8 RGBA array (unpremultiplied).
56    #[inline]
57    pub fn to_srgba_u8(&self) -> [u8; 4] {
58        // Unpremultiply
59        let (r, g, b) = if self.a > 0.0001 {
60            (self.r / self.a, self.g / self.a, self.b / self.a)
61        } else {
62            (0.0, 0.0, 0.0)
63        };
64
65        // Convert linear to sRGB
66        let lin = LinSrgba::new(r, g, b, self.a);
67        let srgb: Srgba = Srgba::from_color(lin);
68
69        [
70            (srgb.red * 255.0).round().clamp(0.0, 255.0) as u8,
71            (srgb.green * 255.0).round().clamp(0.0, 255.0) as u8,
72            (srgb.blue * 255.0).round().clamp(0.0, 255.0) as u8,
73            (srgb.alpha * 255.0).round().clamp(0.0, 255.0) as u8,
74        ]
75    }
76}