dear_imgui/
colors.rs

1use std::fmt;
2
3/// RGBA color with 32-bit floating point components
4#[repr(C)]
5#[derive(Copy, Clone, Debug, PartialEq)]
6pub struct Color {
7    pub r: f32,
8    pub g: f32,
9    pub b: f32,
10    pub a: f32,
11}
12
13impl Color {
14    pub const fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
15        Self { r, g, b, a }
16    }
17    pub const fn rgb(r: f32, g: f32, b: f32) -> Self {
18        Self::new(r, g, b, 1.0)
19    }
20    pub fn from_rgba_bytes(r: u8, g: u8, b: u8, a: u8) -> Self {
21        Self::new(
22            r as f32 / 255.0,
23            g as f32 / 255.0,
24            b as f32 / 255.0,
25            a as f32 / 255.0,
26        )
27    }
28    pub fn from_rgb_bytes(r: u8, g: u8, b: u8) -> Self {
29        Self::from_rgba_bytes(r, g, b, 255)
30    }
31    /// Construct from an ImGui-packed color (ImU32 ABGR order).
32    ///
33    /// ImGui packs colors with IM_COL32(R,G,B,A) into `(A<<24)|(B<<16)|(G<<8)|R`.
34    /// This converts that ABGR-packed u32 into an RGBA float Color.
35    pub fn from_imgui_u32(abgr: u32) -> Self {
36        let a = ((abgr >> 24) & 0xFF) as u8;
37        let b = ((abgr >> 16) & 0xFF) as u8;
38        let g = ((abgr >> 8) & 0xFF) as u8;
39        let r = (abgr & 0xFF) as u8;
40        Self::from_rgba_bytes(r, g, b, a)
41    }
42
43    /// Construct from an opaque 24-bit RGB value (0xRRGGBB).
44    pub fn from_rgb_u32(rgb: u32) -> Self {
45        Self::from_rgba_bytes(
46            ((rgb >> 16) & 0xFF) as u8,
47            ((rgb >> 8) & 0xFF) as u8,
48            (rgb & 0xFF) as u8,
49            255,
50        )
51    }
52
53    /// Pack to ImGui ImU32 ABGR order `(A<<24)|(B<<16)|(G<<8)|R`.
54    pub fn to_imgui_u32(self) -> u32 {
55        let r = (self.r * 255.0).round() as u32;
56        let g = (self.g * 255.0).round() as u32;
57        let b = (self.b * 255.0).round() as u32;
58        let a = (self.a * 255.0).round() as u32;
59        (a << 24) | (b << 16) | (g << 8) | r
60    }
61    pub fn to_array(self) -> [f32; 4] {
62        [self.r, self.g, self.b, self.a]
63    }
64    pub fn from_array(arr: [f32; 4]) -> Self {
65        Self::new(arr[0], arr[1], arr[2], arr[3])
66    }
67    pub fn with_alpha(mut self, alpha: f32) -> Self {
68        self.a = alpha;
69        self
70    }
71    pub fn lerp(self, other: Self, t: f32) -> Self {
72        let t = t.clamp(0.0, 1.0);
73        Self::new(
74            self.r + (other.r - self.r) * t,
75            self.g + (other.g - self.g) * t,
76            self.b + (other.b - self.b) * t,
77            self.a + (other.a - self.a) * t,
78        )
79    }
80    pub fn to_hsv(self) -> (f32, f32, f32) {
81        let max = self.r.max(self.g).max(self.b);
82        let min = self.r.min(self.g).min(self.b);
83        let delta = max - min;
84        let h = if delta == 0.0 {
85            0.0
86        } else if max == self.r {
87            60.0 * (((self.g - self.b) / delta) % 6.0)
88        } else if max == self.g {
89            60.0 * (((self.b - self.r) / delta) + 2.0)
90        } else {
91            60.0 * (((self.r - self.g) / delta) + 4.0)
92        };
93        let s = if max == 0.0 { 0.0 } else { delta / max };
94        let v = max;
95        (h, s, v)
96    }
97    pub fn from_hsv(h: f32, s: f32, v: f32) -> Self {
98        let h = h % 360.0;
99        let c = v * s;
100        let x = c * (1.0 - ((h / 60.0) % 2.0 - 1.0).abs());
101        let m = v - c;
102        let (r, g, b) = if h < 60.0 {
103            (c, x, 0.0)
104        } else if h < 120.0 {
105            (x, c, 0.0)
106        } else if h < 180.0 {
107            (0.0, c, x)
108        } else if h < 240.0 {
109            (0.0, x, c)
110        } else if h < 300.0 {
111            (x, 0.0, c)
112        } else {
113            (c, 0.0, x)
114        };
115        Self::new(r + m, g + m, b + m, 1.0)
116    }
117}
118
119impl Default for Color {
120    fn default() -> Self {
121        Self::new(1.0, 1.0, 1.0, 1.0)
122    }
123}
124impl From<[f32; 4]> for Color {
125    fn from(arr: [f32; 4]) -> Self {
126        Self::from_array(arr)
127    }
128}
129impl From<Color> for [f32; 4] {
130    fn from(color: Color) -> Self {
131        color.to_array()
132    }
133}
134impl From<(f32, f32, f32, f32)> for Color {
135    fn from((r, g, b, a): (f32, f32, f32, f32)) -> Self {
136        Self::new(r, g, b, a)
137    }
138}
139impl From<Color> for (f32, f32, f32, f32) {
140    fn from(color: Color) -> Self {
141        (color.r, color.g, color.b, color.a)
142    }
143}
144
145impl fmt::Display for Color {
146    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147        write!(
148            f,
149            "rgba({:.3}, {:.3}, {:.3}, {:.3})",
150            self.r, self.g, self.b, self.a
151        )
152    }
153}
154
155/// Common color constants
156impl Color {
157    pub const TRANSPARENT: Color = Color::new(0.0, 0.0, 0.0, 0.0);
158    pub const BLACK: Color = Color::new(0.0, 0.0, 0.0, 1.0);
159    pub const WHITE: Color = Color::new(1.0, 1.0, 1.0, 1.0);
160    pub const RED: Color = Color::new(1.0, 0.0, 0.0, 1.0);
161    pub const GREEN: Color = Color::new(0.0, 1.0, 0.0, 1.0);
162    pub const BLUE: Color = Color::new(0.0, 0.0, 1.0, 1.0);
163    pub const YELLOW: Color = Color::new(1.0, 1.0, 0.0, 1.0);
164    pub const CYAN: Color = Color::new(0.0, 1.0, 1.0, 1.0);
165    pub const MAGENTA: Color = Color::new(1.0, 0.0, 1.0, 1.0);
166}