1#[derive(Copy, Clone, Debug, Default, PartialEq)]
13pub struct Color {
14 pub r: f32,
15 pub g: f32,
16 pub b: f32,
17 pub a: f32,
18}
19
20impl Color {
21 pub const TRANSPARENT: Self = Self::rgba(0.0, 0.0, 0.0, 0.0);
22 pub const BLACK: Self = Self::rgb(0.0, 0.0, 0.0);
23 pub const WHITE: Self = Self::rgb(1.0, 1.0, 1.0);
24 pub const GRAY: Self = Self::rgb(0.5, 0.5, 0.5);
25 pub const RED: Self = Self::rgb(1.0, 0.0, 0.0);
26 pub const GREEN: Self = Self::rgb(0.0, 1.0, 0.0);
27 pub const BLUE: Self = Self::rgb(0.0, 0.0, 1.0);
28 pub const YELLOW: Self = Self::rgb(1.0, 1.0, 0.0);
29 pub const CYAN: Self = Self::rgb(0.0, 1.0, 1.0);
30 pub const MAGENTA: Self = Self::rgb(1.0, 0.0, 1.0);
31 pub const ORANGE: Self = Self::rgb(1.0, 0.5, 0.0);
32 pub const GOLD: Self = Self::rgb(1.0, 0.84, 0.0);
33
34 pub const fn rgb(r: f32, g: f32, b: f32) -> Self {
36 Self::rgba(r, g, b, 1.0)
37 }
38
39 pub const fn rgba(r: f32, g: f32, b: f32, a: f32) -> Self {
41 Self { r, g, b, a }
42 }
43
44 pub const fn rgb8(r: u8, g: u8, b: u8) -> Self {
46 Self::rgba8(r, g, b, 255)
47 }
48
49 pub const fn rgba8(r: u8, g: u8, b: u8, a: u8) -> Self {
51 Self::rgba(
52 r as f32 / 255.0,
53 g as f32 / 255.0,
54 b as f32 / 255.0,
55 a as f32 / 255.0,
56 )
57 }
58
59 pub const fn hex(rgb: u32) -> Self {
61 Self::rgb8((rgb >> 16) as u8, (rgb >> 8) as u8, rgb as u8)
62 }
63
64 pub const fn hex_rgba(rgba: u32) -> Self {
66 Self::rgba8(
67 (rgba >> 24) as u8,
68 (rgba >> 16) as u8,
69 (rgba >> 8) as u8,
70 rgba as u8,
71 )
72 }
73
74 pub const fn with_alpha(self, a: f32) -> Self {
76 Self { a, ..self }
77 }
78
79 pub fn lerp(self, other: Self, t: f32) -> Self {
81 let mix = |a: f32, b: f32| a + (b - a) * t;
82 Self::rgba(
83 mix(self.r, other.r),
84 mix(self.g, other.g),
85 mix(self.b, other.b),
86 mix(self.a, other.a),
87 )
88 }
89
90 pub const fn to_array(self) -> [f32; 4] {
92 [self.r, self.g, self.b, self.a]
93 }
94}
95
96impl From<[f32; 4]> for Color {
97 fn from([r, g, b, a]: [f32; 4]) -> Self {
98 Self { r, g, b, a }
99 }
100}
101
102impl From<[f32; 3]> for Color {
103 fn from([r, g, b]: [f32; 3]) -> Self {
104 Self::rgb(r, g, b)
105 }
106}
107
108impl From<Color> for [f32; 4] {
109 fn from(c: Color) -> Self {
110 c.to_array()
111 }
112}
113
114#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
119pub struct Layer(pub i16);
120
121impl Layer {
122 pub const DEFAULT: Self = Self(0);
124 pub const BOTTOM: Self = Self(i16::MIN);
126 pub const TOP: Self = Self(i16::MAX);
128}
129
130impl From<i16> for Layer {
131 fn from(layer: i16) -> Self {
132 Self(layer)
133 }
134}
135
136impl From<Layer> for i16 {
137 fn from(layer: Layer) -> Self {
138 layer.0
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn hex_and_rgba8() {
148 assert_eq!(Color::hex(0xff0000), Color::RED);
149 assert_eq!(
150 Color::hex_rgba(0x00ff0080),
151 Color::GREEN.with_alpha(128.0 / 255.0)
152 );
153 assert_eq!(Color::rgb8(0, 0, 255), Color::BLUE);
154 }
155
156 #[test]
157 fn array_conversions_roundtrip() {
158 let c: Color = [0.1, 0.2, 0.3, 0.4].into();
159 assert_eq!(<[f32; 4]>::from(c), [0.1, 0.2, 0.3, 0.4]);
160 assert_eq!(Color::from([0.1, 0.2, 0.3]).a, 1.0);
161 }
162
163 #[test]
164 fn lerp_endpoints() {
165 assert_eq!(Color::BLACK.lerp(Color::WHITE, 0.0), Color::BLACK);
166 assert_eq!(Color::BLACK.lerp(Color::WHITE, 1.0), Color::WHITE);
167 assert_eq!(Color::BLACK.lerp(Color::WHITE, 0.5), Color::GRAY);
168 }
169
170 #[test]
171 fn layer_from_literal() {
172 fn take(l: impl Into<Layer>) -> Layer {
173 l.into()
174 }
175 assert_eq!(take(3), Layer(3));
176 assert!(Layer::BOTTOM < Layer::DEFAULT && Layer::DEFAULT < Layer::TOP);
177 }
178}