tartanlib/
colours.rs

1use crate::tartan_register_shades::SHADES;
2use alloc::collections::BTreeMap;
3use alloc::vec::Vec;
4use core::iter::repeat;
5use no_std_compat::cmp::Ordering;
6
7#[derive(Debug, PartialEq)]
8pub enum Pivot {
9    True,
10    False,
11    Maybe,
12}
13
14#[derive(Debug, PartialEq)]
15pub struct Span {
16    pub colour: Colour,
17    pub count: usize,
18    pub pivot: Pivot,
19}
20
21impl Span {
22    pub fn new(colour: &str, count: &str) -> Self {
23        Self {
24            colour: Colour::get(colour).unwrap(),
25            count: count.parse::<usize>().unwrap(),
26            pivot: Pivot::Maybe,
27        }
28    }
29    pub fn pivot(colour: &str, count: &str) -> Self {
30        Self {
31            colour: Colour::get(colour).unwrap(),
32            count: count.parse::<usize>().unwrap(),
33            pivot: Pivot::True,
34        }
35    }
36}
37
38#[derive(Debug, PartialEq)]
39pub enum Weft {
40    Identical,
41    Different,
42}
43
44#[derive(Debug, PartialEq)]
45pub struct Sett {
46    pub pattern: Vec<Span>,
47    pub symmetric: bool,
48    pub weft: Weft,
49}
50
51impl Default for Sett {
52    fn default() -> Self {
53        Self::new()
54    }
55}
56
57impl Sett {
58    pub fn new() -> Self {
59        Self {
60            pattern: vec![],
61            symmetric: true,
62            weft: Weft::Identical,
63        }
64    }
65
66    /// Infinite iterator that goes over the colour spans and back.
67    pub fn shuttle(&self) -> impl Iterator<Item = &Span> {
68        let len = self.pattern.len();
69        self.pattern
70            .iter()
71            .chain(self.pattern.iter().rev().skip(1).take(len - 2))
72            .cycle()
73    }
74
75    pub fn colours(&self, skip: usize) -> impl Iterator<Item = &Colour> {
76        self.shuttle()
77            .skip(skip)
78            .flat_map(|span| repeat(&span.colour).take(span.count))
79    }
80
81    pub fn coord_colours(
82        &self,
83        width: u32,
84        height: u32,
85        skip: usize,
86    ) -> impl Iterator<Item = (u32, u32, &Colour)> {
87        (0..height).flat_map(move |y| {
88            (0..width).zip(self.colours(skip)).map(move |(x, colour)| {
89                if (x + y) / 2 % 2 == 0 {
90                    (x, y, colour)
91                } else {
92                    (y, x, colour)
93                }
94            })
95        })
96    }
97}
98
99#[derive(Copy, Clone, Debug, PartialEq)]
100pub struct Shade {
101    pub colour: Colour,
102    pub tone: Tone,
103    pub rgb: [u8; 3],
104}
105
106#[derive(Copy, Clone, Debug, PartialEq)]
107pub enum Tone {
108    Light,
109    Medium,
110    Dark,
111}
112
113#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd)]
114pub enum Colour {
115    Red,
116    Orange,
117    Yellow,
118    Green,
119    Blue,
120    Purple,
121    White,
122    Grey,
123    Black,
124    Brown,
125}
126
127impl Colour {
128    pub fn get(letter: &str) -> Option<Self> {
129        use Colour::*;
130
131        match letter {
132            "R" => Some(Red),
133            "O" => Some(Orange),
134            "Y" => Some(Yellow),
135            "G" => Some(Green),
136            "B" => Some(Blue),
137            "RB" => Some(Blue), // Royal Blue
138            "P" => Some(Purple),
139            "W" => Some(White),
140            "N" => Some(Grey), // Neutral
141            "K" => Some(Black),
142            "Bk" => Some(Black),
143            "T" => Some(Brown), // Tan
144            _ => None,
145        }
146    }
147
148    pub fn to_array(&self, palette: &Palette) -> [u8; 3] {
149        if let Some(shade) = palette.shades.get(self) {
150            shade.rgb
151        } else {
152            [0, 255, 0]
153        }
154    }
155}
156
157#[allow(clippy::derive_ord_xor_partial_ord)]
158impl Ord for Colour {
159    fn cmp(&self, other: &Self) -> Ordering {
160        (format!("{:?}", &self)).cmp(&format!("{:?}", &other))
161    }
162}
163
164#[derive(Debug, PartialEq)]
165pub enum Colourway {
166    Modern,
167    Ancient,
168    Reproduction,
169    Weathered, // Withered
170    Muted,
171    Standard,
172}
173impl Default for Colourway {
174    fn default() -> Self {
175        Colourway::Modern
176    }
177}
178
179#[derive(Debug, PartialEq)]
180pub enum Variation {
181    Hunting,
182    Dress,
183}
184
185#[derive(Debug)]
186pub struct Palette {
187    pub colourway: Option<Colourway>,
188    pub variation: Option<Variation>,
189    pub shades: BTreeMap<Colour, Shade>,
190}
191
192impl Default for Palette {
193    fn default() -> Self {
194        use Colour::*;
195
196        let shades = BTreeMap::from([
197            (Red, SHADES[7]),
198            (Orange, SHADES[20]),
199            (Yellow, SHADES[32]),
200            (Green, SHADES[62]),
201            (Blue, SHADES[89]),
202            (Purple, SHADES[99]),
203            (White, SHADES[106]),
204            (Grey, SHADES[113]),
205            (Black, SHADES[119]),
206            (Brown, SHADES[131]),
207        ]);
208        Palette {
209            colourway: Some(Colourway::default()),
210            variation: None,
211            shades,
212        }
213    }
214}