catgirl_engine_client/render/
mod.rs

1#[cfg(feature = "serde")]
2use serde::{Deserialize, Serialize};
3
4/// Struct used for storing colors (usually in linear srgb)
5#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
7pub(crate) struct Color {
8    /// The color red
9    /// 0 (no red) to 1 (fully red)
10    red: f64,
11
12    /// The color green
13    /// 0 (no green) to 1 (fully green)
14    green: f64,
15
16    /// The color blue
17    /// 0 (no blue) to 1 (fully blue)
18    blue: f64,
19
20    /// The transparency
21    /// 0 (fully transparent) to 1 (fullly opaque)
22    alpha: f64,
23
24    /// The color space
25    /// Linear is more accurate
26    space: ColorSpace,
27}
28
29/// The color space a color is in
30#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
31#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default, Hash, Eq, Ord)]
32enum ColorSpace {
33    /// Linear Color Space
34    #[default]
35    Linear,
36}
37
38// https://www.colorspaceconverter.com/converter/rgb-to-srgb-linear
39// https://en.wikipedia.org/wiki/SRGB
40// https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_sRGB_decode.txt
41/// Converts Standard RGB Color Space to Linear Standard RGB Color Space
42///
43/// Outputs f64 instead of f32 for use in `wgpu::Color`
44/// TODO: Research Wide Gamut
45pub(crate) fn srgb_to_linear_srgb(red: u8, green: u8, blue: u8) -> Color {
46    let r: f64 = f64::from(red) / 255.0;
47    let g: f64 = f64::from(green) / 255.0;
48    let b: f64 = f64::from(blue) / 255.0;
49
50    let convert_color = |value: f64| -> f64 {
51        if 0.04045 >= value {
52            value / 12.92
53        } else {
54            ((value + 0.055) / 1.055).powf(2.4)
55        }
56    };
57
58    Color {
59        red: convert_color(r),
60        green: convert_color(g),
61        blue: convert_color(b),
62        alpha: 1.0,
63        space: ColorSpace::Linear,
64    }
65}
66
67/// Converts out color struct to WGPU's color struct
68pub(crate) fn get_wgpu_color_from_ce_color(color: Color) -> wgpu::Color {
69    wgpu::Color {
70        r: color.red,
71        g: color.green,
72        b: color.blue,
73        a: color.alpha,
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use crate::render::{Color, ColorSpace};
80
81    #[test]
82    fn test_srgb_to_linear_srgb() {
83        // ~(0.14, 0.06, 0.27)
84        let expected_result: Color = Color {
85            red: 0.138_431_615_032_451_83,
86            green: 0.063_010_017_653_167_67,
87            blue: 0.266_355_604_802_862_47,
88            alpha: 1.0,
89            space: ColorSpace::Linear,
90        };
91
92        assert_eq!(super::srgb_to_linear_srgb(104, 71, 141), expected_result);
93    }
94}