speedy2d/color.rs
1/*
2 * Copyright 2021 QuantumBadger
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/// A struct representing a color with red, green, blue, and alpha components.
18/// Each component is stored as a float.
19#[derive(Debug, PartialEq, Clone, Copy)]
20pub struct Color
21{
22 r: f32,
23 g: f32,
24 b: f32,
25 a: f32
26}
27
28impl Color
29{
30 /// Color constant for transparency, with the alpha value set to zero.
31 pub const TRANSPARENT: Color = Color::from_rgba(0.0, 0.0, 0.0, 0.0);
32
33 /// Constant for the color black.
34 pub const BLACK: Color = Color::from_rgb(0.0, 0.0, 0.0);
35
36 /// Constant for the color white.
37 pub const WHITE: Color = Color::from_rgb(1.0, 1.0, 1.0);
38
39 /// Constant for the color red.
40 pub const RED: Color = Color::from_rgb(1.0, 0.0, 0.0);
41
42 /// Constant for the color green.
43 pub const GREEN: Color = Color::from_rgb(0.0, 1.0, 0.0);
44
45 /// Constant for the color blue.
46 pub const BLUE: Color = Color::from_rgb(0.0, 0.0, 1.0);
47
48 /// Constant for the color yellow.
49 pub const YELLOW: Color = Color::from_rgb(1.0, 1.0, 0.0);
50
51 /// Constant for the color cyan.
52 pub const CYAN: Color = Color::from_rgb(0.0, 1.0, 1.0);
53
54 /// Constant for the color magenta.
55 pub const MAGENTA: Color = Color::from_rgb(1.0, 0.0, 1.0);
56
57 /// Constant for the color gray.
58 pub const GRAY: Color = Color::from_rgb(0.5, 0.5, 0.5);
59
60 /// Constant for the color light gray.
61 pub const LIGHT_GRAY: Color = Color::from_rgb(0.75, 0.75, 0.75);
62
63 /// Constant for the color dark gray.
64 pub const DARK_GRAY: Color = Color::from_rgb(0.25, 0.25, 0.25);
65
66 /// Creates a color with the specified components, including an alpha
67 /// component. Each component should be in the range `0.0` to `1.0`.
68 #[inline]
69 pub const fn from_rgba(r: f32, g: f32, b: f32, a: f32) -> Self
70 {
71 Color { r, g, b, a }
72 }
73
74 /// Creates a color with the specified components. The alpha component will
75 /// be set to 1.0 (full opacity). Each component should be in the range
76 /// `0.0` to `1.0`.
77 #[inline]
78 pub const fn from_rgb(r: f32, g: f32, b: f32) -> Self
79 {
80 Color { r, g, b, a: 1.0 }
81 }
82
83 /// Creates a color with the specified components, including an alpha
84 /// component. Each component should be in the range `0` to `255`.
85 #[inline]
86 pub fn from_int_rgba(r: u8, g: u8, b: u8, a: u8) -> Self
87 {
88 Color {
89 r: r as f32 / 255.0,
90 g: g as f32 / 255.0,
91 b: b as f32 / 255.0,
92 a: a as f32 / 255.0
93 }
94 }
95
96 /// Creates a color with the specified components. The alpha component will
97 /// be set to 255 (full opacity). Each component should be in the range
98 /// `0` to `255`.
99 #[inline]
100 pub fn from_int_rgb(r: u8, g: u8, b: u8) -> Self
101 {
102 Color {
103 r: r as f32 / 255.0,
104 g: g as f32 / 255.0,
105 b: b as f32 / 255.0,
106 a: 1.0
107 }
108 }
109
110 /// Creates a color from the specified integer value, including an alpha
111 /// component.
112 ///
113 /// For example, the input value `0xAABBCCDD` will result in a color with:
114 ///
115 /// * Alpha = `0xAA`
116 /// * Red = `0xBB`
117 /// * Green = `0xCC`
118 /// * Blue = `0xDD`
119 ///
120 /// Note: If you don't specify the alpha component, the color will be
121 /// transparent.
122 #[inline]
123 pub fn from_hex_argb(argb: u32) -> Self
124 {
125 Color::from_int_rgba(
126 (argb >> 16) as u8,
127 (argb >> 8) as u8,
128 argb as u8,
129 (argb >> 24) as u8
130 )
131 }
132
133 /// Creates a color from the specified integer value, with the alpha
134 /// component set to `255` (full opacity).
135 ///
136 /// For example, the input value `0xAABBCC` will result in a color with:
137 ///
138 /// * Alpha = `0xFF`
139 /// * Red = `0xAA`
140 /// * Green = `0xBB`
141 /// * Blue = `0xCC`
142 ///
143 /// Note: if an alpha component is specified in the high bits of the
144 /// integer, it will be ignored. See [Color::from_hex_argb] if you wish to
145 /// specify the alpha component.
146 #[inline]
147 pub fn from_hex_rgb(rgb: u32) -> Self
148 {
149 Color::from_int_rgb((rgb >> 16) as u8, (rgb >> 8) as u8, rgb as u8)
150 }
151
152 /// Creates a shade of gray from the specified float value, between `0.0`
153 /// and `1.0`. All three RGB components will be set to this value.
154 #[inline]
155 pub const fn from_gray(brightness: f32) -> Self
156 {
157 Self::from_rgb(brightness, brightness, brightness)
158 }
159
160 /// Returns the red component of the color, as a value in the range `0.0` to
161 /// `1.0`.
162 #[inline]
163 pub const fn r(&self) -> f32
164 {
165 self.r
166 }
167
168 /// Returns the green component of the color, as a value in the range `0.0`
169 /// to `1.0`.
170 #[inline]
171 pub const fn g(&self) -> f32
172 {
173 self.g
174 }
175
176 /// Returns the blue component of the color, as a value in the range `0.0`
177 /// to `1.0`.
178 #[inline]
179 pub const fn b(&self) -> f32
180 {
181 self.b
182 }
183
184 /// Returns the alpha component of the color, as a value in the range `0.0`
185 /// to `1.0`. The value `0.0` is fully transparent, and the value `1.0`
186 /// is fully opaque.
187 #[inline]
188 pub const fn a(&self) -> f32
189 {
190 self.a
191 }
192
193 /// Returns the brightness of the color as perceived by a human, as a value
194 /// in the range `0.0` to `1.0`.
195 ///
196 /// This is calculated using the following formula:
197 ///
198 /// ```
199 /// # let red = 0.0;
200 /// # let green = 0.0;
201 /// # let blue = 0.0;
202 /// # let result =
203 /// red * 0.299 + green * 0.587 + blue * 0.114
204 /// # ;
205 /// ```
206 pub fn subjective_brightness(&self) -> f32
207 {
208 self.r * 0.299 + self.g * 0.587 + self.b * 0.114
209 }
210}
211
212#[cfg(test)]
213mod tests
214{
215 use super::*;
216
217 #[test]
218 fn test_from_hex()
219 {
220 // We're comparing floats for equality here, which is normally a bad idea, but
221 // here the result should be deterministic as it's computed the same way both
222 // times.
223
224 assert_eq!(
225 Color::from_hex_rgb(0xFF5511),
226 Color::from_int_rgb(0xFF, 0x55, 0x11)
227 );
228
229 assert_eq!(
230 Color::from_hex_argb(0xAAFF5511),
231 Color::from_int_rgba(0xFF, 0x55, 0x11, 0xAA)
232 );
233 }
234}