1use std::{fmt, ops};
2
3use crate::{Factor, FactorPercent, about_eq, about_eq_hash};
4
5#[repr(C)]
13#[derive(Default, Copy, Clone, serde::Serialize, serde::Deserialize)]
14pub struct Rgba {
15 pub red: f32,
17 pub green: f32,
19 pub blue: f32,
21 pub alpha: f32,
23}
24impl PartialEq for Rgba {
25 fn eq(&self, other: &Self) -> bool {
26 about_eq(self.red, other.red, EPSILON)
27 && about_eq(self.green, other.green, EPSILON)
28 && about_eq(self.blue, other.blue, EPSILON)
29 && about_eq(self.alpha, other.alpha, EPSILON)
30 }
31}
32impl std::hash::Hash for Rgba {
33 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
34 about_eq_hash(self.red, EPSILON, state);
35 about_eq_hash(self.green, EPSILON, state);
36 about_eq_hash(self.blue, EPSILON, state);
37 about_eq_hash(self.alpha, EPSILON, state);
38 }
39}
40impl Rgba {
41 pub fn new<C: Into<RgbaComponent>, A: Into<RgbaComponent>>(red: C, green: C, blue: C, alpha: A) -> Rgba {
43 Rgba {
44 red: red.into().0,
45 green: green.into().0,
46 blue: blue.into().0,
47 alpha: alpha.into().0,
48 }
49 }
50
51 pub fn set_red<R: Into<RgbaComponent>>(&mut self, red: R) {
53 self.red = red.into().0
54 }
55
56 pub fn set_green<G: Into<RgbaComponent>>(&mut self, green: G) {
58 self.green = green.into().0
59 }
60
61 pub fn set_blue<B: Into<RgbaComponent>>(&mut self, blue: B) {
63 self.blue = blue.into().0
64 }
65
66 pub fn set_alpha<A: Into<RgbaComponent>>(&mut self, alpha: A) {
68 self.alpha = alpha.into().0
69 }
70
71 pub fn with_red<R: Into<RgbaComponent>>(mut self, red: R) -> Self {
73 self.set_red(red);
74 self
75 }
76
77 pub fn with_green<R: Into<RgbaComponent>>(mut self, green: R) -> Self {
79 self.set_green(green);
80 self
81 }
82
83 pub fn with_blue<B: Into<RgbaComponent>>(mut self, blue: B) -> Self {
85 self.set_blue(blue);
86 self
87 }
88
89 pub fn with_alpha<A: Into<RgbaComponent>>(mut self, alpha: A) -> Self {
91 self.set_alpha(alpha);
92 self
93 }
94
95 pub fn transparent(self) -> Self {
97 self.with_alpha(0.0)
98 }
99
100 pub fn to_bytes(self) -> [u8; 4] {
102 [
103 (self.red * 255.0) as u8,
104 (self.green * 255.0) as u8,
105 (self.blue * 255.0) as u8,
106 (self.alpha * 255.0) as u8,
107 ]
108 }
109}
110impl fmt::Debug for Rgba {
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 if f.alternate() {
113 f.debug_struct("Rgba")
114 .field("red", &self.red)
115 .field("green", &self.green)
116 .field("blue", &self.blue)
117 .field("alpha", &self.alpha)
118 .finish()
119 } else {
120 fn i(n: f32) -> u8 {
121 (clamp_normal(n) * 255.0).round() as u8
122 }
123 let a = i(self.alpha);
124 if a == 255 {
125 write!(f, "rgb({}, {}, {})", i(self.red), i(self.green), i(self.blue))
126 } else {
127 write!(f, "rgba({}, {}, {}, {})", i(self.red), i(self.green), i(self.blue), a)
128 }
129 }
130 }
131}
132impl fmt::Display for Rgba {
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 fn i(n: f32) -> u32 {
135 (clamp_normal(n) * 255.0).round() as u32
136 }
137
138 let mut rgb: u32 = 0;
139 rgb |= i(self.red) << 16;
140 rgb |= i(self.green) << 8;
141 rgb |= i(self.blue);
142
143 let a = i(self.alpha);
144 if a == 255 {
145 write!(f, "#{rgb:0>6X}")
146 } else {
147 let rgba = (rgb << 8) | a;
148 write!(f, "#{rgba:0>8X}")
149 }
150 }
151}
152impl ops::Add<Self> for Rgba {
153 type Output = Self;
154
155 fn add(self, rhs: Self) -> Self::Output {
156 Rgba {
157 red: self.red + rhs.red,
158 green: self.green + rhs.green,
159 blue: self.blue + rhs.blue,
160 alpha: self.alpha + rhs.alpha,
161 }
162 }
163}
164impl ops::AddAssign<Self> for Rgba {
165 fn add_assign(&mut self, rhs: Self) {
166 *self = *self + rhs;
167 }
168}
169impl ops::Sub<Self> for Rgba {
170 type Output = Self;
171
172 fn sub(self, rhs: Self) -> Self::Output {
173 Rgba {
174 red: self.red - rhs.red,
175 green: self.green - rhs.green,
176 blue: self.blue - rhs.blue,
177 alpha: self.alpha - rhs.alpha,
178 }
179 }
180}
181impl ops::SubAssign<Self> for Rgba {
182 fn sub_assign(&mut self, rhs: Self) {
183 *self = *self - rhs;
184 }
185}
186
187const EPSILON: f32 = 0.00001;
189
190fn clamp_normal(i: f32) -> f32 {
192 i.clamp(0.0, 1.0)
193}
194
195#[derive(Clone, Copy)]
207pub struct RgbaComponent(pub f32);
208impl From<f32> for RgbaComponent {
210 fn from(f: f32) -> Self {
211 RgbaComponent(f)
212 }
213}
214impl From<f64> for RgbaComponent {
216 fn from(f: f64) -> Self {
217 RgbaComponent(f as f32)
218 }
219}
220impl From<u8> for RgbaComponent {
222 fn from(u: u8) -> Self {
223 RgbaComponent(f32::from(u) / 255.)
224 }
225}
226impl From<FactorPercent> for RgbaComponent {
228 fn from(p: FactorPercent) -> Self {
229 RgbaComponent(p.0 / 100.)
230 }
231}
232impl From<Factor> for RgbaComponent {
234 fn from(f: Factor) -> Self {
235 RgbaComponent(f.0)
236 }
237}