2019-03-09 10:02:49 +00:00
|
|
|
//! Utilities for working with standard 24-bit RGB color pixels
|
|
|
|
|
|
|
|
/// An RGB color value in some perceptual color space;
|
|
|
|
/// ideally this will be gamma-corrected before display,
|
|
|
|
/// but this form is better for doing gradient/fade/etc calculations on.
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
pub struct Rgb(pub u8, pub u8, pub u8);
|
|
|
|
|
|
|
|
impl core::ops::Add for Rgb {
|
|
|
|
type Output = Rgb;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn add(self, rhs: Rgb) -> Rgb {
|
|
|
|
Rgb(
|
|
|
|
self.0.saturating_add(rhs.0),
|
|
|
|
self.1.saturating_add(rhs.1),
|
|
|
|
self.2.saturating_add(rhs.2)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl core::ops::Mul for Rgb {
|
|
|
|
type Output = Rgb;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn mul(self, rhs: Rgb) -> Rgb {
|
|
|
|
Rgb(
|
|
|
|
(self.0 as usize * rhs.0 as usize / 255) as u8,
|
|
|
|
(self.1 as usize * rhs.1 as usize / 255) as u8,
|
|
|
|
(self.2 as usize * rhs.2 as usize / 255) as u8
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl core::ops::Mul<u8> for Rgb
|
|
|
|
{
|
|
|
|
type Output = Rgb;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn mul(self, rhs: u8) -> Rgb {
|
|
|
|
Rgb(
|
|
|
|
self.0.saturating_mul(rhs),
|
|
|
|
self.1.saturating_mul(rhs),
|
|
|
|
self.2.saturating_mul(rhs)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-09 22:02:26 +00:00
|
|
|
/// Construct an [Rgb] from a monochrome value.
|
2019-03-09 10:02:49 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn gray(gray: u8) -> Rgb {
|
|
|
|
Rgb(gray, gray, gray)
|
|
|
|
}
|
|
|
|
|
2019-03-09 22:02:26 +00:00
|
|
|
/// Interpolate linearly between two colors.
|
|
|
|
///
|
|
|
|
/// The "mix" value is RGB to permit blending channels individually,
|
|
|
|
/// but most often you will probably use [gray] to generate the mix value.
|
2019-03-09 10:02:49 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn blend(a: Rgb, b: Rgb, mix: Rgb) -> Rgb {
|
|
|
|
(a * Rgb(255 - mix.0, 255 - mix.1, 255 - mix.2)) + (b * mix)
|
|
|
|
}
|