1use crate::{
2 ffi,
3 math::{Vector3, Vector4},
4 texture::{get_pixel_data_size, PixelFormat},
5};
6use static_assertions::{assert_eq_align, assert_eq_size};
7
8#[repr(C)]
10#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub struct Color {
13 pub r: u8,
15 pub g: u8,
17 pub b: u8,
19 pub a: u8,
21}
22
23assert_eq_size!(Color, ffi::Color);
24assert_eq_align!(Color, ffi::Color);
25
26impl Color {
27 pub const LIGHTGRAY: Color = Color {
29 r: 200,
30 g: 200,
31 b: 200,
32 a: 255,
33 };
34
35 pub const GRAY: Color = Color {
37 r: 130,
38 g: 130,
39 b: 130,
40 a: 255,
41 };
42
43 pub const DARKGRAY: Color = Color {
45 r: 80,
46 g: 80,
47 b: 80,
48 a: 255,
49 };
50
51 pub const YELLOW: Color = Color {
53 r: 253,
54 g: 249,
55 b: 0,
56 a: 255,
57 };
58
59 pub const GOLD: Color = Color {
61 r: 255,
62 g: 203,
63 b: 0,
64 a: 255,
65 };
66
67 pub const ORANGE: Color = Color {
69 r: 255,
70 g: 161,
71 b: 0,
72 a: 255,
73 };
74
75 pub const PINK: Color = Color {
77 r: 255,
78 g: 109,
79 b: 194,
80 a: 255,
81 };
82
83 pub const RED: Color = Color {
85 r: 230,
86 g: 41,
87 b: 55,
88 a: 255,
89 };
90
91 pub const MAROON: Color = Color {
93 r: 190,
94 g: 33,
95 b: 55,
96 a: 255,
97 };
98
99 pub const GREEN: Color = Color {
101 r: 0,
102 g: 228,
103 b: 48,
104 a: 255,
105 };
106
107 pub const LIME: Color = Color {
109 r: 0,
110 g: 158,
111 b: 47,
112 a: 255,
113 };
114
115 pub const DARKGREEN: Color = Color {
117 r: 0,
118 g: 117,
119 b: 44,
120 a: 255,
121 };
122
123 pub const SKYBLUE: Color = Color {
125 r: 102,
126 g: 191,
127 b: 255,
128 a: 255,
129 };
130
131 pub const BLUE: Color = Color {
133 r: 0,
134 g: 121,
135 b: 241,
136 a: 255,
137 };
138
139 pub const DARKBLUE: Color = Color {
141 r: 0,
142 g: 82,
143 b: 172,
144 a: 255,
145 };
146
147 pub const PURPLE: Color = Color {
149 r: 200,
150 g: 122,
151 b: 255,
152 a: 255,
153 };
154
155 pub const VIOLET: Color = Color {
157 r: 135,
158 g: 60,
159 b: 190,
160 a: 255,
161 };
162
163 pub const DARKPURPLE: Color = Color {
165 r: 112,
166 g: 31,
167 b: 126,
168 a: 255,
169 };
170
171 pub const BEIGE: Color = Color {
173 r: 211,
174 g: 176,
175 b: 131,
176 a: 255,
177 };
178
179 pub const BROWN: Color = Color {
181 r: 127,
182 g: 106,
183 b: 79,
184 a: 255,
185 };
186
187 pub const DARKBROWN: Color = Color {
189 r: 76,
190 g: 63,
191 b: 47,
192 a: 255,
193 };
194
195 pub const WHITE: Color = Color {
197 r: 255,
198 g: 255,
199 b: 255,
200 a: 255,
201 };
202
203 pub const BLACK: Color = Color {
205 r: 0,
206 g: 0,
207 b: 0,
208 a: 255,
209 };
210
211 pub const BLANK: Color = Color {
213 r: 0,
214 g: 0,
215 b: 0,
216 a: 0,
217 };
218
219 pub const MAGENTA: Color = Color {
221 r: 255,
222 g: 0,
223 b: 255,
224 a: 255,
225 };
226
227 pub const RAYWHITE: Color = Color {
229 r: 245,
230 g: 245,
231 b: 245,
232 a: 255,
233 };
234
235 #[inline]
237 pub const fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
238 Self { r, g, b, a }
239 }
240
241 #[inline]
243 pub fn fade(self, alpha: f32) -> Self {
244 unsafe { ffi::Fade(self.into(), alpha).into() }
245 }
246
247 #[inline]
249 pub fn to_hex(self) -> u32 {
250 ((self.r as u32) << 24) | ((self.g as u32) << 16) | ((self.b as u32) << 8) | (self.a as u32)
252 }
253
254 #[inline]
256 pub fn from_hex(val: u32) -> Self {
257 Self {
259 r: (val >> 24 & 0xFF) as u8,
260 g: (val >> 16 & 0xFF) as u8,
261 b: (val >> 8 & 0xFF) as u8,
262 a: (val & 0xFF) as u8,
263 }
264 }
265
266 #[inline]
268 pub fn normalize(self) -> Vector4 {
269 Vector4 {
271 x: self.r as f32 / 255.,
272 y: self.g as f32 / 255.,
273 z: self.b as f32 / 255.,
274 w: self.a as f32 / 255.,
275 }
276 }
277
278 #[inline]
280 pub fn from_normalized(normalized: Vector4) -> Self {
281 Self {
283 r: (normalized.x * 255.) as u8,
284 g: (normalized.y * 255.) as u8,
285 b: (normalized.z * 255.) as u8,
286 a: (normalized.w * 255.) as u8,
287 }
288 }
289
290 #[inline]
292 pub fn to_hsv(self) -> Vector3 {
293 unsafe { ffi::ColorToHSV(self.into()).into() }
294 }
295
296 #[inline]
298 pub fn from_hsv(hue: f32, saturation: f32, value: f32) -> Self {
299 unsafe { ffi::ColorFromHSV(hue, saturation, value).into() }
300 }
301
302 #[inline]
304 pub fn tint(self, tint: Self) -> Self {
305 unsafe { ffi::ColorTint(self.into(), tint.into()).into() }
306 }
307
308 #[inline]
310 pub fn brightness(self, factor: f32) -> Self {
311 unsafe { ffi::ColorBrightness(self.into(), factor).into() }
312 }
313
314 #[inline]
316 pub fn contrast(self, contrast: f32) -> Self {
317 unsafe { ffi::ColorContrast(self.into(), contrast).into() }
318 }
319
320 #[inline]
322 pub fn alpha(self, alpha: f32) -> Self {
323 unsafe { ffi::ColorAlpha(self.into(), alpha).into() }
324 }
325
326 #[inline]
328 pub fn alpha_blend(self, src: Self, tint: Self) -> Self {
329 unsafe { ffi::ColorAlphaBlend(self.into(), src.into(), tint.into()).into() }
330 }
331
332 #[inline]
336 pub fn get_pixel_color(source: &[u8], format: PixelFormat) -> Option<Self> {
337 if source.len() >= get_pixel_data_size(1, 1, format) {
338 unsafe {
339 Some(
340 ffi::GetPixelColor(source.as_ptr() as *mut core::ffi::c_void, format as _)
341 .into(),
342 )
343 }
344 } else {
345 None
346 }
347 }
348
349 #[inline]
353 pub fn set_pixel_color(self, dest: &mut [u8], format: PixelFormat) -> bool {
354 if dest.len() >= get_pixel_data_size(1, 1, format) {
355 unsafe {
356 ffi::SetPixelColor(
357 dest.as_mut_ptr() as *mut core::ffi::c_void,
358 self.into(),
359 format as _,
360 );
361 }
362 true
363 } else {
364 false
365 }
366 }
367}
368
369impl From<Color> for ffi::Color {
370 #[inline]
371 fn from(val: Color) -> Self {
372 unsafe { std::mem::transmute(val) }
373 }
374}
375
376impl From<ffi::Color> for Color {
377 #[inline]
378 fn from(value: ffi::Color) -> Self {
379 unsafe { std::mem::transmute(value) }
380 }
381}