rust_raylib/
color.rs

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/// Color, 4 components, R8G8B8A8 (32bit)
9#[repr(C)]
10#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub struct Color {
13    /// Color red value
14    pub r: u8,
15    /// Color green value
16    pub g: u8,
17    /// Color blue value
18    pub b: u8,
19    /// Color alpha value
20    pub a: u8,
21}
22
23assert_eq_size!(Color, ffi::Color);
24assert_eq_align!(Color, ffi::Color);
25
26impl Color {
27    /// Light gray color
28    pub const LIGHTGRAY: Color = Color {
29        r: 200,
30        g: 200,
31        b: 200,
32        a: 255,
33    };
34
35    /// Gray color
36    pub const GRAY: Color = Color {
37        r: 130,
38        g: 130,
39        b: 130,
40        a: 255,
41    };
42
43    /// Dark gray color
44    pub const DARKGRAY: Color = Color {
45        r: 80,
46        g: 80,
47        b: 80,
48        a: 255,
49    };
50
51    /// Yellow color
52    pub const YELLOW: Color = Color {
53        r: 253,
54        g: 249,
55        b: 0,
56        a: 255,
57    };
58
59    /// Gold color
60    pub const GOLD: Color = Color {
61        r: 255,
62        g: 203,
63        b: 0,
64        a: 255,
65    };
66
67    /// Orange color
68    pub const ORANGE: Color = Color {
69        r: 255,
70        g: 161,
71        b: 0,
72        a: 255,
73    };
74
75    /// Pink color
76    pub const PINK: Color = Color {
77        r: 255,
78        g: 109,
79        b: 194,
80        a: 255,
81    };
82
83    /// Red color
84    pub const RED: Color = Color {
85        r: 230,
86        g: 41,
87        b: 55,
88        a: 255,
89    };
90
91    /// Maroon color
92    pub const MAROON: Color = Color {
93        r: 190,
94        g: 33,
95        b: 55,
96        a: 255,
97    };
98
99    /// Green color
100    pub const GREEN: Color = Color {
101        r: 0,
102        g: 228,
103        b: 48,
104        a: 255,
105    };
106
107    /// Lime color
108    pub const LIME: Color = Color {
109        r: 0,
110        g: 158,
111        b: 47,
112        a: 255,
113    };
114
115    /// Dark green color
116    pub const DARKGREEN: Color = Color {
117        r: 0,
118        g: 117,
119        b: 44,
120        a: 255,
121    };
122
123    /// Sky blue color
124    pub const SKYBLUE: Color = Color {
125        r: 102,
126        g: 191,
127        b: 255,
128        a: 255,
129    };
130
131    /// Blue color
132    pub const BLUE: Color = Color {
133        r: 0,
134        g: 121,
135        b: 241,
136        a: 255,
137    };
138
139    /// Dark blue color
140    pub const DARKBLUE: Color = Color {
141        r: 0,
142        g: 82,
143        b: 172,
144        a: 255,
145    };
146
147    /// Purple color
148    pub const PURPLE: Color = Color {
149        r: 200,
150        g: 122,
151        b: 255,
152        a: 255,
153    };
154
155    /// Violet color
156    pub const VIOLET: Color = Color {
157        r: 135,
158        g: 60,
159        b: 190,
160        a: 255,
161    };
162
163    /// Dark purple color
164    pub const DARKPURPLE: Color = Color {
165        r: 112,
166        g: 31,
167        b: 126,
168        a: 255,
169    };
170
171    /// Beige color
172    pub const BEIGE: Color = Color {
173        r: 211,
174        g: 176,
175        b: 131,
176        a: 255,
177    };
178
179    /// Brown color
180    pub const BROWN: Color = Color {
181        r: 127,
182        g: 106,
183        b: 79,
184        a: 255,
185    };
186
187    /// Dark brown color
188    pub const DARKBROWN: Color = Color {
189        r: 76,
190        g: 63,
191        b: 47,
192        a: 255,
193    };
194
195    /// White color
196    pub const WHITE: Color = Color {
197        r: 255,
198        g: 255,
199        b: 255,
200        a: 255,
201    };
202
203    /// Black color
204    pub const BLACK: Color = Color {
205        r: 0,
206        g: 0,
207        b: 0,
208        a: 255,
209    };
210
211    /// Blank color (alpha = 0)
212    pub const BLANK: Color = Color {
213        r: 0,
214        g: 0,
215        b: 0,
216        a: 0,
217    };
218
219    /// Magenta color
220    pub const MAGENTA: Color = Color {
221        r: 255,
222        g: 0,
223        b: 255,
224        a: 255,
225    };
226
227    /// Raylib white color
228    pub const RAYWHITE: Color = Color {
229        r: 245,
230        g: 245,
231        b: 245,
232        a: 255,
233    };
234
235    /// Convenience function for creating a new color
236    #[inline]
237    pub const fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
238        Self { r, g, b, a }
239    }
240
241    /// Get color with alpha applied, alpha goes from 0.0f to 1.0f
242    #[inline]
243    pub fn fade(self, alpha: f32) -> Self {
244        unsafe { ffi::Fade(self.into(), alpha).into() }
245    }
246
247    /// Get hexadecimal value for a Color
248    #[inline]
249    pub fn to_hex(self) -> u32 {
250        // no real need to use ffi here
251        ((self.r as u32) << 24) | ((self.g as u32) << 16) | ((self.b as u32) << 8) | (self.a as u32)
252    }
253
254    /// Get Color structure from hexadecimal value
255    #[inline]
256    pub fn from_hex(val: u32) -> Self {
257        // no real need to use ffi here
258        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    /// Get Color normalized as float [0..1]
267    #[inline]
268    pub fn normalize(self) -> Vector4 {
269        // no real need to use ffi here
270        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    /// Get Color from normalized values [0..1]
279    #[inline]
280    pub fn from_normalized(normalized: Vector4) -> Self {
281        // no real need to use ffi here
282        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    /// Get HSV values for a Color, hue [0..360], saturation/value [0..1]
291    #[inline]
292    pub fn to_hsv(self) -> Vector3 {
293        unsafe { ffi::ColorToHSV(self.into()).into() }
294    }
295
296    /// Get a Color from HSV values, hue [0..360], saturation/value [0..1]
297    #[inline]
298    pub fn from_hsv(hue: f32, saturation: f32, value: f32) -> Self {
299        unsafe { ffi::ColorFromHSV(hue, saturation, value).into() }
300    }
301
302    /// Get color multiplied with another color
303    #[inline]
304    pub fn tint(self, tint: Self) -> Self {
305        unsafe { ffi::ColorTint(self.into(), tint.into()).into() }
306    }
307
308    /// Get color with brightness correction, brightness factor goes from -1.0f to 1.0f
309    #[inline]
310    pub fn brightness(self, factor: f32) -> Self {
311        unsafe { ffi::ColorBrightness(self.into(), factor).into() }
312    }
313
314    /// Get color with contrast correction, contrast values between -1.0f and 1.0f
315    #[inline]
316    pub fn contrast(self, contrast: f32) -> Self {
317        unsafe { ffi::ColorContrast(self.into(), contrast).into() }
318    }
319
320    /// Get color with alpha applied, alpha goes from 0.0f to 1.0f
321    #[inline]
322    pub fn alpha(self, alpha: f32) -> Self {
323        unsafe { ffi::ColorAlpha(self.into(), alpha).into() }
324    }
325
326    /// Get src alpha-blended into dst color with tint
327    #[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    /// Get Color from a source pixel pointer of certain format (uncompressed formats only)
333    ///
334    /// Returns `None` if buffer isn't large enough
335    #[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    /// Set color formatted into destination pixel pointer (uncompressed formats only)
350    ///
351    /// Returns `true` on success, `false` if buffer isn't large enough
352    #[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}