GUI-free half of the cce toolkit: config, input, IPC, spec parsers
git clone https://git.lucas.co/cce-core.git
src/color.rs (2K)
1 //! sRGB/linear conversion and the DE's hex colour strings — the pure half of
2 //! `cce_ui::color`, which re-exports every item here.
3
4 pub fn srgb_to_linear(c: f32) -> f32 {
5 if c <= 0.04045 {
6 c / 12.92
7 } else {
8 ((c + 0.055) / 1.055).powf(2.4)
9 }
10 }
11
12 /// Parse a hex color string into raw RGBA bytes.
13 ///
14 /// Accepts `#RRGGBB` or `#RRGGBBAA`, tolerating surrounding quotes/whitespace and
15 /// an optional leading `#`. 6-digit input yields alpha `255`. Returns `None` for
16 /// any shorter/invalid input. This is the primitive the `[f32;_]` parsers build on.
17 pub fn parse_hex_bytes(s: &str) -> Option<[u8; 4]> {
18 let hex = s
19 .trim_matches(|c| c == '"' || c == '\'' || c == ' ')
20 .trim_start_matches('#');
21 let b = |i: usize| u8::from_str_radix(hex.get(i * 2..i * 2 + 2)?, 16).ok();
22 if hex.len() >= 8 {
23 Some([b(0)?, b(1)?, b(2)?, b(3)?])
24 } else if hex.len() >= 6 {
25 Some([b(0)?, b(1)?, b(2)?, 255])
26 } else {
27 None
28 }
29 }
30
31 /// Parse a hex color string into raw sRGB RGBA in `[0,1]` (no gamma conversion).
32 /// See [`parse_hex_bytes`] for the accepted formats. Apply [`srgb_to_linear`] to
33 /// the RGB channels yourself if your render target expects linear color.
34 pub fn parse_hex_rgba(s: &str) -> Option<[f32; 4]> {
35 parse_hex_bytes(s).map(|[r, g, b, a]| {
36 [r as f32 / 255.0, g as f32 / 255.0, b as f32 / 255.0, a as f32 / 255.0]
37 })
38 }
39
40 /// Like [`parse_hex_rgba`] but drops alpha, returning raw sRGB RGB in `[0,1]`.
41 pub fn parse_hex_rgb(s: &str) -> Option<[f32; 3]> {
42 parse_hex_rgba(s).map(|[r, g, b, _]| [r, g, b])
43 }
44
45 /// Like [`parse_hex_rgba`] but converts RGB from sRGB to linear (alpha kept as-is).
46 /// Use when your render target samples colors in linear space.
47 pub fn parse_hex_rgba_linear(s: &str) -> Option<[f32; 4]> {
48 parse_hex_rgba(s).map(|[r, g, b, a]| {
49 [srgb_to_linear(r), srgb_to_linear(g), srgb_to_linear(b), a]
50 })
51 }
52
53 pub fn linear_to_srgb(c: f32) -> f32 {
54 if c <= 0.0031308 {
55 c * 12.92
56 } else {
57 1.055 * c.powf(1.0 / 2.4) - 0.055
58 }
59 }