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}