[refactor] represent colors with arrays
This commit is contained in:
parent
9823e4d63c
commit
dc40a5d31d
4 changed files with 162 additions and 176 deletions
|
@ -1,23 +1,149 @@
|
||||||
use crate::math::clamp;
|
use crate::math::clamp;
|
||||||
|
|
||||||
/// 0-255 gamma space `sRGBA` color with premultiplied alpha.
|
/// 0-255 gamma space `sRGBA` color with premultiplied alpha.
|
||||||
|
/// Alpha channel is in linear space.
|
||||||
|
/// This format is used for space-efficient color representation.
|
||||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
pub struct Srgba {
|
pub struct Srgba(pub [u8; 4]);
|
||||||
pub r: u8,
|
|
||||||
pub g: u8,
|
impl std::ops::Index<usize> for Srgba {
|
||||||
pub b: u8,
|
type Output = u8;
|
||||||
/// Alpha is in linear space (not subject to sRGBA gamma conversion)
|
fn index(&self, index: usize) -> &u8 {
|
||||||
pub a: u8,
|
&self.0[index]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::ops::IndexMut<usize> for Srgba {
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut u8 {
|
||||||
|
&mut self.0[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn srgba(r: u8, g: u8, b: u8, a: u8) -> Srgba {
|
||||||
|
Srgba([r, g, b, a])
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Srgba {
|
||||||
|
pub const fn gray(l: u8) -> Self {
|
||||||
|
Self([l, l, l, 255])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn black_alpha(a: u8) -> Self {
|
||||||
|
Self([0, 0, 0, a])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn additive_luminance(l: u8) -> Self {
|
||||||
|
Self([l, l, l, 0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
pub const TRANSPARENT: Srgba = srgba(0, 0, 0, 0);
|
||||||
|
pub const BLACK: Srgba = srgba(0, 0, 0, 255);
|
||||||
|
pub const LIGHT_GRAY: Srgba = srgba(220, 220, 220, 255);
|
||||||
|
pub const GRAY: Srgba = srgba(160, 160, 160, 255);
|
||||||
|
pub const WHITE: Srgba = srgba(255, 255, 255, 255);
|
||||||
|
pub const RED: Srgba = srgba(255, 0, 0, 255);
|
||||||
|
pub const GREEN: Srgba = srgba(0, 255, 0, 255);
|
||||||
|
pub const BLUE: Srgba = srgba(0, 0, 255, 255);
|
||||||
|
pub const YELLOW: Srgba = srgba(255, 255, 0, 255);
|
||||||
|
pub const LIGHT_BLUE: Srgba = srgba(140, 160, 255, 255);
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/// 0-1 linear space `RGBA` color with premultiplied alpha.
|
/// 0-1 linear space `RGBA` color with premultiplied alpha.
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
pub struct Rgba {
|
pub struct Rgba(pub [f32; 4]);
|
||||||
pub r: f32,
|
|
||||||
pub g: f32,
|
impl std::ops::Index<usize> for Rgba {
|
||||||
pub b: f32,
|
type Output = f32;
|
||||||
pub a: f32,
|
fn index(&self, index: usize) -> &f32 {
|
||||||
|
&self.0[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::IndexMut<usize> for Rgba {
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut f32 {
|
||||||
|
&mut self.0[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rgba {
|
||||||
|
pub const TRANSPARENT: Rgba = Rgba::new(0.0, 0.0, 0.0, 0.0);
|
||||||
|
pub const BLACK: Rgba = Rgba::new(0.0, 0.0, 0.0, 1.0);
|
||||||
|
pub const WHITE: Rgba = Rgba::new(1.0, 1.0, 1.0, 1.0);
|
||||||
|
pub const RED: Rgba = Rgba::new(1.0, 0.0, 0.0, 1.0);
|
||||||
|
pub const GREEN: Rgba = Rgba::new(0.0, 1.0, 0.0, 1.0);
|
||||||
|
pub const BLUE: Rgba = Rgba::new(0.0, 0.0, 1.0, 1.0);
|
||||||
|
|
||||||
|
pub const fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
|
||||||
|
Self([r, g, b, a])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn gray(l: f32) -> Self {
|
||||||
|
Self([l, l, l, 1.0])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn luminance_alpha(l: f32, a: f32) -> Self {
|
||||||
|
debug_assert!(0.0 <= l && l <= 1.0);
|
||||||
|
debug_assert!(0.0 <= a && a <= 1.0);
|
||||||
|
Self([l * a, l * a, l * a, a])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transparent white
|
||||||
|
pub fn white_alpha(a: f32) -> Self {
|
||||||
|
debug_assert!(0.0 <= a && a <= 1.0);
|
||||||
|
Self([a, a, a, a])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Multiply with e.g. 0.5 to make us half transparent
|
||||||
|
pub fn multiply(self, alpha: f32) -> Self {
|
||||||
|
Self([
|
||||||
|
alpha * self[0],
|
||||||
|
alpha * self[1],
|
||||||
|
alpha * self[2],
|
||||||
|
alpha * self[3],
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Add for Rgba {
|
||||||
|
type Output = Rgba;
|
||||||
|
fn add(self, rhs: Rgba) -> Rgba {
|
||||||
|
Rgba([
|
||||||
|
self[0] + rhs[0],
|
||||||
|
self[1] + rhs[1],
|
||||||
|
self[2] + rhs[2],
|
||||||
|
self[3] + rhs[3],
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Mul<f32> for Rgba {
|
||||||
|
type Output = Rgba;
|
||||||
|
fn mul(self, factor: f32) -> Rgba {
|
||||||
|
Rgba([
|
||||||
|
self[0] * factor,
|
||||||
|
self[1] * factor,
|
||||||
|
self[2] * factor,
|
||||||
|
self[3] * factor,
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Mul<Rgba> for f32 {
|
||||||
|
type Output = Rgba;
|
||||||
|
fn mul(self, rgba: Rgba) -> Rgba {
|
||||||
|
Rgba([
|
||||||
|
self * rgba[0],
|
||||||
|
self * rgba[1],
|
||||||
|
self * rgba[2],
|
||||||
|
self * rgba[3],
|
||||||
|
])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -25,23 +151,23 @@ pub struct Rgba {
|
||||||
|
|
||||||
impl From<Srgba> for Rgba {
|
impl From<Srgba> for Rgba {
|
||||||
fn from(srgba: Srgba) -> Rgba {
|
fn from(srgba: Srgba) -> Rgba {
|
||||||
Rgba {
|
Rgba([
|
||||||
r: linear_from_srgb_byte(srgba.r),
|
linear_from_srgb_byte(srgba[0]),
|
||||||
g: linear_from_srgb_byte(srgba.g),
|
linear_from_srgb_byte(srgba[1]),
|
||||||
b: linear_from_srgb_byte(srgba.b),
|
linear_from_srgb_byte(srgba[2]),
|
||||||
a: srgba.a as f32 / 255.0,
|
srgba[3] as f32 / 255.0,
|
||||||
}
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Rgba> for Srgba {
|
impl From<Rgba> for Srgba {
|
||||||
fn from(rgba: Rgba) -> Srgba {
|
fn from(rgba: Rgba) -> Srgba {
|
||||||
Srgba {
|
Srgba([
|
||||||
r: srgb_byte_from_linear(rgba.r),
|
srgb_byte_from_linear(rgba[0]),
|
||||||
g: srgb_byte_from_linear(rgba.g),
|
srgb_byte_from_linear(rgba[1]),
|
||||||
b: srgb_byte_from_linear(rgba.b),
|
srgb_byte_from_linear(rgba[2]),
|
||||||
a: clamp(rgba.a * 255.0, 0.0..=255.0).round() as u8,
|
clamp(rgba[3] * 255.0, 0.0..=255.0).round() as u8,
|
||||||
}
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,143 +200,3 @@ fn test_srgba_conversion() {
|
||||||
assert_eq!(srgb_byte_from_linear(l), b);
|
assert_eq!(srgb_byte_from_linear(l), b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
pub const fn srgba(r: u8, g: u8, b: u8, a: u8) -> Srgba {
|
|
||||||
Srgba { r, g, b, a }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Srgba {
|
|
||||||
pub const fn gray(l: u8) -> Self {
|
|
||||||
Self {
|
|
||||||
r: l,
|
|
||||||
g: l,
|
|
||||||
b: l,
|
|
||||||
a: 255,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn black_alpha(a: u8) -> Self {
|
|
||||||
Self {
|
|
||||||
r: 0,
|
|
||||||
g: 0,
|
|
||||||
b: 0,
|
|
||||||
a,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn additive_luminance(l: u8) -> Self {
|
|
||||||
Self {
|
|
||||||
r: l,
|
|
||||||
g: l,
|
|
||||||
b: l,
|
|
||||||
a: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
pub const TRANSPARENT: Srgba = srgba(0, 0, 0, 0);
|
|
||||||
pub const BLACK: Srgba = srgba(0, 0, 0, 255);
|
|
||||||
pub const LIGHT_GRAY: Srgba = srgba(220, 220, 220, 255);
|
|
||||||
pub const GRAY: Srgba = srgba(160, 160, 160, 255);
|
|
||||||
pub const WHITE: Srgba = srgba(255, 255, 255, 255);
|
|
||||||
pub const RED: Srgba = srgba(255, 0, 0, 255);
|
|
||||||
pub const GREEN: Srgba = srgba(0, 255, 0, 255);
|
|
||||||
pub const BLUE: Srgba = srgba(0, 0, 255, 255);
|
|
||||||
pub const YELLOW: Srgba = srgba(255, 255, 0, 255);
|
|
||||||
pub const LIGHT_BLUE: Srgba = srgba(140, 160, 255, 255);
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
impl Rgba {
|
|
||||||
pub const TRANSPARENT: Rgba = Rgba::new(0.0, 0.0, 0.0, 0.0);
|
|
||||||
pub const BLACK: Rgba = Rgba::new(0.0, 0.0, 0.0, 1.0);
|
|
||||||
pub const WHITE: Rgba = Rgba::new(1.0, 1.0, 1.0, 1.0);
|
|
||||||
pub const RED: Rgba = Rgba::new(1.0, 0.0, 0.0, 1.0);
|
|
||||||
pub const GREEN: Rgba = Rgba::new(0.0, 1.0, 0.0, 1.0);
|
|
||||||
pub const BLUE: Rgba = Rgba::new(0.0, 0.0, 1.0, 1.0);
|
|
||||||
|
|
||||||
pub const fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
|
|
||||||
Self { r, g, b, a }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn gray(l: f32) -> Self {
|
|
||||||
Self {
|
|
||||||
r: l,
|
|
||||||
g: l,
|
|
||||||
b: l,
|
|
||||||
a: 1.0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn luminance_alpha(l: f32, a: f32) -> Self {
|
|
||||||
debug_assert!(0.0 <= l && l <= 1.0);
|
|
||||||
debug_assert!(0.0 <= a && a <= 1.0);
|
|
||||||
Self {
|
|
||||||
r: l * a,
|
|
||||||
g: l * a,
|
|
||||||
b: l * a,
|
|
||||||
a,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Transparent white
|
|
||||||
pub fn white_alpha(a: f32) -> Self {
|
|
||||||
debug_assert!(0.0 <= a && a <= 1.0);
|
|
||||||
Self {
|
|
||||||
r: a,
|
|
||||||
g: a,
|
|
||||||
b: a,
|
|
||||||
a,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Multiply with e.g. 0.5 to make us half transparent
|
|
||||||
pub fn multiply(self, alpha: f32) -> Self {
|
|
||||||
Self {
|
|
||||||
r: alpha * self.r,
|
|
||||||
g: alpha * self.g,
|
|
||||||
b: alpha * self.b,
|
|
||||||
a: alpha * self.a,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Add for Rgba {
|
|
||||||
type Output = Rgba;
|
|
||||||
fn add(self, rhs: Rgba) -> Rgba {
|
|
||||||
Rgba {
|
|
||||||
r: self.r + rhs.r,
|
|
||||||
g: self.g + rhs.g,
|
|
||||||
b: self.b + rhs.b,
|
|
||||||
a: self.a + rhs.a,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Mul<f32> for Rgba {
|
|
||||||
type Output = Rgba;
|
|
||||||
fn mul(self, factor: f32) -> Rgba {
|
|
||||||
Rgba {
|
|
||||||
r: self.r * factor,
|
|
||||||
g: self.g * factor,
|
|
||||||
b: self.b * factor,
|
|
||||||
a: self.a * factor,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Mul<Rgba> for f32 {
|
|
||||||
type Output = Rgba;
|
|
||||||
fn mul(self, rgba: Rgba) -> Rgba {
|
|
||||||
Rgba {
|
|
||||||
r: self * rgba.r,
|
|
||||||
g: self * rgba.g,
|
|
||||||
b: self * rgba.b,
|
|
||||||
a: self * rgba.a,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -430,9 +430,9 @@ fn ui_slider_vec2(ui: &mut Ui, value: &mut Vec2, range: std::ops::RangeInclusive
|
||||||
fn ui_color(ui: &mut Ui, srgba: &mut Srgba, text: &str) {
|
fn ui_color(ui: &mut Ui, srgba: &mut Srgba, text: &str) {
|
||||||
ui.horizontal_centered(|ui| {
|
ui.horizontal_centered(|ui| {
|
||||||
ui.label(format!("{} sRGBA: ", text));
|
ui.label(format!("{} sRGBA: ", text));
|
||||||
ui.add(DragValue::u8(&mut srgba.r)).tooltip_text("r");
|
ui.add(DragValue::u8(&mut srgba[0])).tooltip_text("r");
|
||||||
ui.add(DragValue::u8(&mut srgba.g)).tooltip_text("g");
|
ui.add(DragValue::u8(&mut srgba[1])).tooltip_text("g");
|
||||||
ui.add(DragValue::u8(&mut srgba.b)).tooltip_text("b");
|
ui.add(DragValue::u8(&mut srgba[2])).tooltip_text("b");
|
||||||
ui.add(DragValue::u8(&mut srgba.a)).tooltip_text("a");
|
ui.add(DragValue::u8(&mut srgba[3])).tooltip_text("a");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -234,7 +234,7 @@ impl Painter {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|v| Vertex {
|
.map(|v| Vertex {
|
||||||
a_pos: [v.pos.x, v.pos.y],
|
a_pos: [v.pos.x, v.pos.y],
|
||||||
a_srgba: [v.color.r, v.color.g, v.color.b, v.color.a],
|
a_srgba: v.color.0,
|
||||||
a_tc: [v.uv.0, v.uv.1],
|
a_tc: [v.uv.0, v.uv.1],
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
|
@ -226,10 +226,10 @@ impl Painter {
|
||||||
);
|
);
|
||||||
// TODO: sRGBA ?
|
// TODO: sRGBA ?
|
||||||
gl.clear_color(
|
gl.clear_color(
|
||||||
bg_color.r as f32 / 255.0,
|
bg_color[0] as f32 / 255.0,
|
||||||
bg_color.g as f32 / 255.0,
|
bg_color[1] as f32 / 255.0,
|
||||||
bg_color.b as f32 / 255.0,
|
bg_color[2] as f32 / 255.0,
|
||||||
bg_color.a as f32 / 255.0,
|
bg_color[3] as f32 / 255.0,
|
||||||
);
|
);
|
||||||
gl.clear(Gl::COLOR_BUFFER_BIT);
|
gl.clear(Gl::COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
@ -277,10 +277,10 @@ impl Painter {
|
||||||
|
|
||||||
let mut colors: Vec<u8> = Vec::with_capacity(4 * triangles.vertices.len());
|
let mut colors: Vec<u8> = Vec::with_capacity(4 * triangles.vertices.len());
|
||||||
for v in &triangles.vertices {
|
for v in &triangles.vertices {
|
||||||
colors.push(v.color.r);
|
colors.push(v.color[0]);
|
||||||
colors.push(v.color.g);
|
colors.push(v.color[1]);
|
||||||
colors.push(v.color.b);
|
colors.push(v.color[2]);
|
||||||
colors.push(v.color.a);
|
colors.push(v.color[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in a new issue