Skip to main content

agg_gui/
color.rs

1//! Color type for agg-gui.
2//!
3//! Colors are stored as f32 RGBA in linear space. Conversion to AGG's `Rgba8`
4//! happens at the rasterizer boundary.
5
6use agg_rust::color::Rgba8;
7
8/// An RGBA color with f32 components in [0.0, 1.0].
9#[derive(Clone, Copy, Debug, PartialEq)]
10#[cfg_attr(feature = "reflect", derive(bevy_reflect::Reflect))]
11pub struct Color {
12    pub r: f32,
13    pub g: f32,
14    pub b: f32,
15    pub a: f32,
16}
17
18impl Color {
19    pub const fn rgba(r: f32, g: f32, b: f32, a: f32) -> Self {
20        Self { r, g, b, a }
21    }
22
23    pub const fn rgb(r: f32, g: f32, b: f32) -> Self {
24        Self { r, g, b, a: 1.0 }
25    }
26
27    /// `Color` from 8-bit sRGB-style channels at full alpha.
28    ///
29    /// Each `u8` is divided by 255 into an f32 component. Convenient when
30    /// transcribing CSS / SVG / Canvas color literals — `Color::from_rgb8(0, 255, 242)`
31    /// instead of `Color::rgb(0.0, 1.0, 242.0 / 255.0)`.
32    pub const fn from_rgb8(r: u8, g: u8, b: u8) -> Self {
33        Self {
34            r: r as f32 / 255.0,
35            g: g as f32 / 255.0,
36            b: b as f32 / 255.0,
37            a: 1.0,
38        }
39    }
40
41    /// `Color` from 8-bit RGBA channels (each `u8` divided by 255).
42    pub const fn from_rgba8(r: u8, g: u8, b: u8, a: u8) -> Self {
43        Self {
44            r: r as f32 / 255.0,
45            g: g as f32 / 255.0,
46            b: b as f32 / 255.0,
47            a: a as f32 / 255.0,
48        }
49    }
50
51    /// Per-channel linear interpolation toward `other` by `t` in `[0, 1]`.
52    ///
53    /// `t = 0` returns `self`; `t = 1` returns `other`. Values outside `[0, 1]`
54    /// extrapolate (callers may want to clamp first).
55    pub fn lerp(self, other: Self, t: f32) -> Self {
56        Self {
57            r: self.r + (other.r - self.r) * t,
58            g: self.g + (other.g - self.g) * t,
59            b: self.b + (other.b - self.b) * t,
60            a: self.a + (other.a - self.a) * t,
61        }
62    }
63
64    pub const fn white() -> Self {
65        Self::rgb(1.0, 1.0, 1.0)
66    }
67
68    pub const fn black() -> Self {
69        Self::rgb(0.0, 0.0, 0.0)
70    }
71
72    pub const fn transparent() -> Self {
73        Self::rgba(0.0, 0.0, 0.0, 0.0)
74    }
75
76    pub fn with_alpha(self, a: f32) -> Self {
77        Self { a, ..self }
78    }
79
80    /// Convert to AGG's 8-bit RGBA format (used at the rasterizer boundary).
81    pub(crate) fn to_rgba8(self) -> Rgba8 {
82        Rgba8::new(
83            (self.r * 255.0).clamp(0.0, 255.0) as u32,
84            (self.g * 255.0).clamp(0.0, 255.0) as u32,
85            (self.b * 255.0).clamp(0.0, 255.0) as u32,
86            (self.a * 255.0).clamp(0.0, 255.0) as u32,
87        )
88    }
89}
90
91impl Default for Color {
92    fn default() -> Self {
93        Self::black()
94    }
95}