1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
#[cfg(feature = "serialize")] use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] pub struct Rgba32 { pub r: u8, pub g: u8, pub b: u8, pub a: u8, } impl Rgba32 { pub const fn new(r: u8, g: u8, b: u8, a: u8) -> Self { Self { r, g, b, a } } pub const fn new_rgb(r: u8, g: u8, b: u8) -> Self { Self { r, g, b, a: 255 } } pub const fn new_grey(x: u8) -> Self { Self { r: x, g: x, b: x, a: 255, } } pub fn to_f32_array_01(self) -> [f32; 4] { [ self.r as f32 / 255., self.g as f32 / 255., self.b as f32 / 255., self.a as f32 / 255., ] } pub fn to_f32_array_rgb_01(self) -> [f32; 3] { [ self.r as f32 / 255., self.g as f32 / 255., self.b as f32 / 255., ] } pub const fn with_r(self, r: u8) -> Self { Self { r, ..self } } pub const fn with_g(self, g: u8) -> Self { Self { g, ..self } } pub const fn with_b(self, b: u8) -> Self { Self { b, ..self } } pub const fn with_a(self, a: u8) -> Self { Self { a, ..self } } pub const fn linear_interpolate(self, to: Rgba32, by: u8) -> Self { const fn interpolate_channel(from: u8, to: u8, by: u8) -> u8 { let total_delta = to as i32 - from as i32; let current_delta = (total_delta * by as i32) / 255; (from as i32 + current_delta) as u8 } Self { r: interpolate_channel(self.r, to.r, by), g: interpolate_channel(self.g, to.g, by), b: interpolate_channel(self.b, to.b, by), a: interpolate_channel(self.a, to.a, by), } } pub fn alpha_composite(self, below: Rgba32) -> Rgba32 { fn mul_u8(a: u8, b: u8) -> u8 { ((a as u16 * b as u16) / 255) as u8 } fn div_u8(a: u8, b: u8) -> u8 { ((255 * a as u16) / b as u16) as u8 } let alpha_out_rhs = mul_u8(below.a, 255 - self.a); let alpha_out = self.a + alpha_out_rhs; let single_channel = |c_a: u8, c_b: u8| div_u8(mul_u8(c_a, self.a) + mul_u8(c_b, alpha_out_rhs), alpha_out); Self { r: single_channel(self.r, below.r), g: single_channel(self.g, below.g), b: single_channel(self.b, below.b), a: alpha_out, } } pub const fn normalised_scalar_mul(self, scalar: u8) -> Self { const fn single_channel(c: u8, scalar: u8) -> u8 { ((c as u32 * scalar as u32) / 255) as u8 } Self { r: single_channel(self.r, scalar), g: single_channel(self.g, scalar), b: single_channel(self.b, scalar), a: self.a, } } pub fn saturating_scalar_mul_div(self, numerator: u32, denominator: u32) -> Self { fn single_channel(channel: u8, numerator: u32, denominator: u32) -> u8 { let as_u32 = ((channel as u32) * (numerator)) / denominator; as_u32.min(::std::u8::MAX as u32) as u8 } Self { r: single_channel(self.r, numerator, denominator), g: single_channel(self.g, numerator, denominator), b: single_channel(self.b, numerator, denominator), a: self.a, } } } pub const fn rgba32(r: u8, g: u8, b: u8, a: u8) -> Rgba32 { Rgba32::new(r, g, b, a) } pub const fn rgba32_rgb(r: u8, g: u8, b: u8) -> Rgba32 { Rgba32::new_rgb(r, g, b) } pub const fn rgba32_grey(x: u8) -> Rgba32 { Rgba32::new_grey(x) }