renderling/
color.rs

1//! Color utils.
2
3use glam::Vec4;
4#[cfg(target_arch = "spirv")]
5use spirv_std::num_traits::Float;
6
7/// Applies a linear transfer function to an 8-bit unsigned integer color component.
8///
9/// This function simulates the gamma correction process by raising the component
10/// to the power of 2.2.
11///
12/// Converts from sRGB to linear color space.
13pub fn linear_xfer_u8(c: &mut u8) {
14    *c = ((*c as f32 / 255.0).powf(2.2) * 255.0) as u8;
15}
16
17/// Applies an optical transfer function to an 8-bit unsigned integer color component.
18///
19/// This function simulates the inverse gamma correction process by raising the component
20/// to the power of 1/2.2.
21///
22/// Converts from linear to sRGB color space.
23pub fn opto_xfer_u8(c: &mut u8) {
24    *c = ((*c as f32 / 255.0).powf(1.0 / 2.2) * 255.0) as u8;
25}
26
27/// Applies a linear transfer function to a 16-bit unsigned integer color component.
28///
29/// This function simulates the gamma correction process by raising the component
30/// to the power of 2.2.
31///
32/// Converts from sRGB to linear color space.
33pub fn linear_xfer_u16(c: &mut u16) {
34    *c = ((*c as f32 / 65535.0).powf(2.2) * 65535.0) as u16;
35}
36
37#[cfg(not(target_arch = "spirv"))]
38mod cpu {
39    use super::*;
40    use glam::Vec3;
41
42    /// Applies a linear transfer function to a 16-bit floating-point color component.
43    ///
44    /// This function simulates the gamma correction process by raising the component
45    /// to the power of 2.2.
46    ///
47    /// Converts from sRGB to linear color space.
48    pub fn linear_xfer_f16(c: &mut u16) {
49        let mut f = half::f16::from_bits(*c).to_f32();
50        super::linear_xfer_f32(&mut f);
51        *c = half::f16::from_f32(f).to_bits();
52    }
53
54    pub fn u16_to_u8(c: u16) -> u8 {
55        ((c as f32 / 65535.0) * 255.0) as u8
56    }
57
58    pub fn f32_to_u8(c: f32) -> u8 {
59        (c / 255.0) as u8
60    }
61
62    pub fn u8_to_f32(c: u8) -> f32 {
63        c as f32 / 255.0
64    }
65
66    /// Converts a CSS style sRGB color into a `Vec4`.
67    ///
68    /// This applies the linear transfer function to the input color,
69    /// returning a color in linear color space.
70    pub fn css_srgb_color_to_linear(r: u8, g: u8, b: u8) -> Vec4 {
71        let rgb = [r, g, b].map(u8_to_f32);
72        let mut color = Vec3::from_array(rgb).extend(1.0);
73        linear_xfer_vec4(&mut color);
74        color
75    }
76}
77#[cfg(not(target_arch = "spirv"))]
78pub use cpu::*;
79
80/// Applies a linear transfer function to a 32-bit floating-point color component.
81///
82/// This function simulates the gamma correction process by raising the component
83/// to the power of 2.2.
84///
85/// Converts from sRGB to linear color space.
86pub fn linear_xfer_f32(c: &mut f32) {
87    *c = c.powf(2.2);
88}
89
90/// Applies a linear transfer function to each component of a `Vec4`.
91///
92/// This function simulates the gamma correction process by raising each component
93/// to the power of 2.2.
94///
95/// Converts from sRGB to linear color space for each component.
96pub fn linear_xfer_vec4(v: &mut Vec4) {
97    linear_xfer_f32(&mut v.x);
98    linear_xfer_f32(&mut v.y);
99    linear_xfer_f32(&mut v.z);
100}
101
102/// Converts an RGB hex color.
103///
104/// Converts a hex code like `0x6DC5D1` to a Vec4 with
105/// RGB components in the range `0.0` to `1.0` and an alpha of `1.0`.
106///
107/// ## Note
108/// This does **not** apply the linear transfer.
109pub fn rgb_hex_color(hex: u32) -> Vec4 {
110    let r = ((hex >> 16) & 0xFF) as f32 / 255.0;
111    let g = ((hex >> 8) & 0xFF) as f32 / 255.0;
112    let b = (hex & 0xFF) as f32 / 255.0;
113    Vec4::new(r, g, b, 1.0)
114}
115
116#[cfg(test)]
117mod test {
118    use super::rgb_hex_color;
119
120    #[test]
121    fn can_rgb_hex_color() {
122        let hex = 0x6dc5d1;
123        let color = rgb_hex_color(hex);
124        let r = (color.x * 255.0) as u8;
125        let g = (color.y * 255.0) as u8;
126        let b = (color.z * 255.0) as u8;
127        assert_eq!(109, 0x6d);
128        assert_eq!([109, 197, 209], [r, g, b]);
129    }
130}