use bytemuck;
use std;
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, bytemuck::Pod, bytemuck::Zeroable)]
pub struct Color([u8; 3]);
impl Color {
pub fn new(r: u8, g: u8, b: u8) -> Self {
Color([r, g, b])
}
pub fn from_hsv(h: f32, s: f32, v: f32) -> Self {
let hh = ((h % 360.0) + if h < 0.0 { 360.0 } else { 0.0 }) / 60.0;
let ss = s.min(1.0).max(0.0);
let vv = v.min(1.0).max(0.0);
let chroma = vv * ss;
let x = chroma * (1.0 - (hh % 2.0 - 1.0).abs());
let m = vv - chroma;
let i = ((chroma + m) * 255.0) as u8;
let j = ((x + m) * 255.0) as u8;
let k = (m * 255.0) as u8;
match hh as i32 {
0 => Color([i, j, k]),
1 => Color([j, i, k]),
2 => Color([k, i, j]),
3 => Color([k, j, i]),
4 => Color([j, k, i]),
_ => Color([i, k, j]),
}
}
pub fn from_hsl(h: f32, s: f32, l: f32) -> Self {
let hh = ((h % 360.0) + if h < 0.0 { 360.0 } else { 0.0 }) / 60.0;
let ss = s.min(1.0).max(0.0);
let ll = l.min(1.0).max(0.0);
let chroma = (1.0 - (2.0 * ll - 1.0).abs()) * ss;
let x = chroma * (1.0 - (hh % 2.0 - 1.0).abs());
let m = ll - chroma / 2.0;
let i = ((chroma + m) * 255.0) as u8;
let j = ((x + m) * 255.0) as u8;
let k = (m * 255.0) as u8;
match hh as i32 {
0 => Color([i, j, k]),
1 => Color([j, i, k]),
2 => Color([k, i, j]),
3 => Color([k, j, i]),
4 => Color([j, k, i]),
_ => Color([i, k, j]),
}
}
pub fn to_hsv(&self) -> [f32; 3] {
if self.0[0] == 0 && self.0[1] == 0 && self.0[2] == 0 {
return [0.0, 0.0, 0.0];
}
let rf = self.0[0] as f32 / 255.0;
let gf = self.0[1] as f32 / 255.0;
let bf = self.0[2] as f32 / 255.0;
let min = rf.min(gf.min(bf));
let max = rf.max(gf.max(bf));
let v = max;
let s = (max - min) / max;
let h;
if max - min == 0.0 {
h = 0.0;
} else if rf == max {
h = (gf - bf) / (max - min);
} else if gf == max {
h = 2.0 + (bf - rf) / (max - min);
} else {
h = 4.0 + (rf - gf) / (max - min);
}
[(h * 60.0) % 360.0, s, v]
}
pub fn from_hwb(h: f32, w: f32, b: f32) -> Self {
let ww = w.max(0.0);
let bb = b.max(0.0);
let www = if ww + bb > 1.0 { ww / (ww + bb) } else { ww };
let bbb = if ww + bb > 1.0 { bb / (ww + bb) } else { bb };
Self::from_hsv(h, 1.0 - www / (1.0 - bbb), 1.0 - bbb)
}
}
impl From<Color> for [f32; 4] {
fn from(c: Color) -> Self {
[
c.0[0] as f32 / 255.0,
c.0[1] as f32 / 255.0,
c.0[2] as f32 / 255.0,
1.0,
]
}
}
impl From<Color> for (f32, f32, f32) {
fn from(c: Color) -> Self {
(
c.0[0] as f32 / 255.0,
c.0[1] as f32 / 255.0,
c.0[2] as f32 / 255.0,
)
}
}
impl From<(f32, f32, f32)> for Color {
fn from((r, g, b): (f32, f32, f32)) -> Self {
Color([(r * 255.0) as u8, (g * 255.0) as u8, (b * 255.0) as u8])
}
}
impl From<[f32; 3]> for Color {
fn from([r, g, b]: [f32; 3]) -> Self {
Color([(r * 255.0) as u8, (g * 255.0) as u8, (b * 255.0) as u8])
}
}
impl From<Color> for [u8; 3] {
fn from(c: Color) -> Self {
c.0
}
}
impl From<[u8; 3]> for Color {
fn from(c: [u8; 3]) -> Self {
Color([c[0], c[1], c[2]])
}
}
impl From<(u8, u8, u8)> for Color {
fn from((r, g, b): (u8, u8, u8)) -> Self {
Color([r, g, b])
}
}
impl From<Color> for wgpu::Color {
fn from(c: Color) -> Self {
wgpu::Color {
r: c.0[0] as f64 / 255.0,
g: c.0[1] as f64 / 255.0,
b: c.0[2] as f64 / 255.0,
a: 1.0,
}
}
}
impl Default for Color {
fn default() -> Self {
[0, 0, 0].into()
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Palette {
colors: [[u8; 3]; 16],
}
impl Palette {
pub fn set<C: Into<[u8; 3]>>(mut self, i: usize, color: C) -> Self {
self.colors[i] = color.into();
self
}
pub fn mono<C: Into<[u8; 3]>>(color: C) -> Self {
Palette {
colors: [color.into(); 16],
}
}
}
impl Default for Palette {
fn default() -> Self {
Palette {
colors: [
[0x00, 0x00, 0x00],
[0x00, 0x00, 0xaa],
[0x00, 0xaa, 0x00],
[0x00, 0xaa, 0xaa],
[0xaa, 0x00, 0x00],
[0xaa, 0x00, 0xaa],
[0xaa, 0x55, 0x00],
[0xaa, 0xaa, 0xaa],
[0x55, 0x55, 0x55],
[0x55, 0x55, 0xff],
[0x55, 0xff, 0x55],
[0x55, 0xff, 0xff],
[0xff, 0x55, 0x55],
[0xff, 0x55, 0xff],
[0xff, 0xff, 0x55],
[0xff, 0xff, 0xff],
],
}
}
}
impl From<Palette> for [[u8; 3]; 16] {
fn from(p: Palette) -> Self {
p.colors
}
}
impl From<Palette> for [[u8; 4]; 16] {
fn from(p: Palette) -> Self {
let mut result = [[0; 4]; 16];
for (i, o) in p.colors.iter().zip(result.iter_mut()) {
*o = [i[0], i[1], i[2], 255]
}
result
}
}
impl From<[[u8; 3]; 16]> for Palette {
fn from(c: [[u8; 3]; 16]) -> Self {
Palette { colors: c }
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum PaletteIndex {
P0,
P1,
P2,
P3,
P4,
P5,
P6,
P7,
P8,
P9,
P10,
P11,
P12,
P13,
P14,
P15,
}
impl PaletteIndex {
pub fn iter() -> impl Iterator<Item = &'static PaletteIndex> {
static INDICES: [PaletteIndex; 16] = [
PaletteIndex::P0,
PaletteIndex::P1,
PaletteIndex::P2,
PaletteIndex::P3,
PaletteIndex::P4,
PaletteIndex::P5,
PaletteIndex::P6,
PaletteIndex::P7,
PaletteIndex::P8,
PaletteIndex::P9,
PaletteIndex::P10,
PaletteIndex::P11,
PaletteIndex::P12,
PaletteIndex::P13,
PaletteIndex::P14,
PaletteIndex::P15,
];
INDICES.iter()
}
}
impl From<PaletteIndex> for u8 {
fn from(p: PaletteIndex) -> u8 {
match p {
PaletteIndex::P0 => 0,
PaletteIndex::P1 => 1,
PaletteIndex::P2 => 2,
PaletteIndex::P3 => 3,
PaletteIndex::P4 => 4,
PaletteIndex::P5 => 5,
PaletteIndex::P6 => 6,
PaletteIndex::P7 => 7,
PaletteIndex::P8 => 8,
PaletteIndex::P9 => 9,
PaletteIndex::P10 => 10,
PaletteIndex::P11 => 11,
PaletteIndex::P12 => 12,
PaletteIndex::P13 => 13,
PaletteIndex::P14 => 14,
PaletteIndex::P15 => 15,
}
}
}
impl From<PaletteIndex> for usize {
fn from(p: PaletteIndex) -> usize {
<PaletteIndex as Into<u8>>::into(p) as usize
}
}
impl std::ops::Index<PaletteIndex> for Palette {
type Output = [u8; 3];
fn index(&self, i: PaletteIndex) -> &Self::Output {
match i {
PaletteIndex::P0 => &self.colors[0],
PaletteIndex::P1 => &self.colors[1],
PaletteIndex::P2 => &self.colors[2],
PaletteIndex::P3 => &self.colors[3],
PaletteIndex::P4 => &self.colors[4],
PaletteIndex::P5 => &self.colors[5],
PaletteIndex::P6 => &self.colors[6],
PaletteIndex::P7 => &self.colors[7],
PaletteIndex::P8 => &self.colors[8],
PaletteIndex::P9 => &self.colors[9],
PaletteIndex::P10 => &self.colors[10],
PaletteIndex::P11 => &self.colors[11],
PaletteIndex::P12 => &self.colors[12],
PaletteIndex::P13 => &self.colors[13],
PaletteIndex::P14 => &self.colors[14],
PaletteIndex::P15 => &self.colors[15],
}
}
}
impl std::ops::IndexMut<PaletteIndex> for Palette {
fn index_mut(&mut self, i: PaletteIndex) -> &mut Self::Output {
match i {
PaletteIndex::P0 => &mut self.colors[0],
PaletteIndex::P1 => &mut self.colors[1],
PaletteIndex::P2 => &mut self.colors[2],
PaletteIndex::P3 => &mut self.colors[3],
PaletteIndex::P4 => &mut self.colors[4],
PaletteIndex::P5 => &mut self.colors[5],
PaletteIndex::P6 => &mut self.colors[6],
PaletteIndex::P7 => &mut self.colors[7],
PaletteIndex::P8 => &mut self.colors[8],
PaletteIndex::P9 => &mut self.colors[9],
PaletteIndex::P10 => &mut self.colors[10],
PaletteIndex::P11 => &mut self.colors[11],
PaletteIndex::P12 => &mut self.colors[12],
PaletteIndex::P13 => &mut self.colors[13],
PaletteIndex::P14 => &mut self.colors[14],
PaletteIndex::P15 => &mut self.colors[15],
}
}
}
impl std::ops::Index<usize> for Palette {
type Output = [u8; 3];
fn index(&self, i: usize) -> &[u8; 3] {
self.colors.index(i)
}
}
impl std::ops::IndexMut<usize> for Palette {
fn index_mut(&mut self, i: usize) -> &mut [u8; 3] {
self.colors.index_mut(i)
}
}
#[derive(Default)]
pub struct ProceduralPalette([ColorExpression; 16]);
impl ProceduralPalette {
pub fn eval(&self, p: Palette) -> Palette {
fn convert((r, g, b): (f32, f32, f32)) -> [u8; 3] {
[(r * 255.0) as u8, (g * 255.0) as u8, (b * 255.0) as u8]
}
Palette {
colors: [
convert(self.0[0].eval(p, PaletteIndex::P0)),
convert(self.0[1].eval(p, PaletteIndex::P1)),
convert(self.0[2].eval(p, PaletteIndex::P2)),
convert(self.0[3].eval(p, PaletteIndex::P3)),
convert(self.0[4].eval(p, PaletteIndex::P4)),
convert(self.0[5].eval(p, PaletteIndex::P5)),
convert(self.0[6].eval(p, PaletteIndex::P6)),
convert(self.0[7].eval(p, PaletteIndex::P7)),
convert(self.0[8].eval(p, PaletteIndex::P8)),
convert(self.0[9].eval(p, PaletteIndex::P9)),
convert(self.0[10].eval(p, PaletteIndex::P10)),
convert(self.0[11].eval(p, PaletteIndex::P11)),
convert(self.0[12].eval(p, PaletteIndex::P12)),
convert(self.0[13].eval(p, PaletteIndex::P13)),
convert(self.0[14].eval(p, PaletteIndex::P14)),
convert(self.0[15].eval(p, PaletteIndex::P15)),
],
}
}
}
#[derive(Debug)]
pub enum ColorExpression {
Null,
PaletteMap(PaletteIndex),
Rgb(
Box<ValueExpression>,
Box<ValueExpression>,
Box<ValueExpression>,
),
Mono(Box<ValueExpression>),
}
impl ColorExpression {
fn eval(&self, p: Palette, i: PaletteIndex) -> (f32, f32, f32) {
match self {
ColorExpression::Null => Color::from(p[i]).into(),
ColorExpression::PaletteMap(pi) => Color::from(p[*pi]).into(),
ColorExpression::Rgb(r, g, b) => (r.eval(p, i), g.eval(p, i), b.eval(p, i)),
ColorExpression::Mono(v) => {
let vv = v.eval(p, i);
(vv, vv, vv)
}
}
}
}
impl Default for ColorExpression {
fn default() -> Self {
ColorExpression::Null
}
}
#[derive(Debug)]
pub enum ValueExpression {
Constant(f32),
Red(Box<ColorExpression>),
Green(Box<ColorExpression>),
Blue(Box<ColorExpression>),
Neg(Box<ValueExpression>),
Add(Box<ValueExpression>, Box<ValueExpression>),
Sub(Box<ValueExpression>, Box<ValueExpression>),
Mul(Box<ValueExpression>, Box<ValueExpression>),
Div(Box<ValueExpression>, Box<ValueExpression>),
Min(Box<ValueExpression>, Box<ValueExpression>),
Max(Box<ValueExpression>, Box<ValueExpression>),
}
impl ValueExpression {
pub fn eval(&self, p: Palette, i: PaletteIndex) -> f32 {
match self {
ValueExpression::Constant(f) => *f,
ValueExpression::Red(c) => c.eval(p, i).0,
ValueExpression::Green(c) => c.eval(p, i).1,
ValueExpression::Blue(c) => c.eval(p, i).2,
ValueExpression::Neg(v) => -v.eval(p, i),
ValueExpression::Add(a, b) => a.eval(p, i) + b.eval(p, i),
ValueExpression::Sub(a, b) => a.eval(p, i) - b.eval(p, i),
ValueExpression::Mul(a, b) => a.eval(p, i) * b.eval(p, i),
ValueExpression::Div(a, b) => a.eval(p, i) / b.eval(p, i),
ValueExpression::Min(a, b) => f32::min(a.eval(p, i), b.eval(p, i)),
ValueExpression::Max(a, b) => f32::max(a.eval(p, i), b.eval(p, i)),
}
}
}