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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/* pixels.rs
 *
 * Developed by Tim Walls <tim.walls@snowgoons.com>
 * Copyright (c) All Rights Reserved, Tim Walls
 */
//! Individual picture elements

// Imports ===================================================================

// Declarations ==============================================================
/// A pixel which can either be off or on
#[cfg_attr(not(target_arch="avr"), derive(Debug))]
#[cfg_attr(target_arch="avr", derive(ufmt::derive::uDebug))]
#[derive(Copy,Clone,Eq,PartialEq)]
pub struct Monochromatic(bool);

/// A pixel which can be a range between black and white
#[cfg_attr(not(target_arch="avr"), derive(Debug))]
#[cfg_attr(target_arch="avr", derive(ufmt::derive::uDebug))]
#[derive(Copy,Clone,Eq,PartialEq)]
pub struct Grey(u8);

/// A 4-bit RGB value
#[cfg_attr(not(target_arch="avr"), derive(Debug))]
#[cfg_attr(target_arch="avr", derive(ufmt::derive::uDebug))]
#[derive(Copy,Clone,Eq,PartialEq)]
pub struct Rgb4bit(u16);

/// An 8-bit RGB value
#[cfg_attr(not(target_arch="avr"), derive(Debug))]
#[cfg_attr(target_arch="avr", derive(ufmt::derive::uDebug))]
#[derive(Copy,Clone,Eq,PartialEq)]
pub struct Rgb8bit(u8,u8,u8);

// Code ======================================================================
impl Monochromatic {
  pub const BLACK : Self = Monochromatic(false);
  pub const WHITE : Self = Monochromatic(true);

  pub fn is_set(&self) -> bool {
    self.0
  }

  pub fn as_bit(&self) -> u8 {
    match self.0 {
      true => 0b00000001,
      false => 0b00000000
    }
  }
}

impl Grey {
  pub const BLACK : Self = Grey(0);
  pub const WHITE : Self = Grey(255);
  pub const GREY25PC : Self = Grey(64);
  pub const GREY50PC : Self = Grey(128);
  pub const GREY75PC : Self = Grey(192);

  pub const fn percent(percentage: u16) -> Self {
    assert!(percentage <= 100);

    Grey(((256u16 * percentage) / 100u16) as u8)
  }

  pub const fn eightbit(value: u8) -> Self {
    Grey(value)
  }

  pub const fn fourbit(value: u8) -> Self {
    Grey(value << 4)
  }

  pub fn get_value(&self) -> u8 {
    self.0
  }

  pub fn get_value4bit(&self) -> u8 {
    self.0 >> 4
  }
}

impl Rgb4bit {
  pub const BLACK : Self = Rgb4bit(0x0000);
  pub const WHITE : Self = Rgb4bit(0x0fff);
}

impl Rgb8bit {
  pub const BLACK : Self = Rgb8bit(0,0,0);
  pub const WHITE : Self = Rgb8bit(255,255,255);
}


impl From<Grey> for Monochromatic {
  fn from(g: Grey) -> Self {
    Monochromatic(g.0 > 127)
  }
}

impl From<Monochromatic> for Grey {
  fn from(m: Monochromatic) -> Self {
    if m.is_set() {
      Grey::WHITE
    } else {
      Grey::BLACK
    }
  }
}

impl From<Rgb8bit> for Grey {
  fn from(rgb: Rgb8bit) -> Self {
    // @todo this is a placeholder, not a proper graphics algorithm
    Grey((((rgb.0 as u16) + (rgb.1 as u16) + (rgb.2 as u16)) / 3u16) as u8)
  }
}

impl From<Rgb8bit> for Rgb4bit {
  fn from(rgb: Rgb8bit) -> Self {
    Rgb4bit(
      ((((rgb.0 & 0xf0) >> 4) as u16) << 8) |
      ((((rgb.1 & 0xf0) >> 4) as u16) << 4) |
      ((((rgb.2 & 0xf0) >> 4) as u16) << 0)
    )
  }
}

impl From<Rgb4bit> for Rgb8bit {
  fn from(rgb: Rgb4bit) -> Self {
    Rgb8bit((((rgb.0 & 0x0f00) >> 8) as u8) << 4,
            (((rgb.0 & 0x00f0) >> 4) as u8) << 4,
            (((rgb.0 & 0x000f) >> 0) as u8) << 4)
  }
}


// Tests =====================================================================
#[cfg(test)]
mod tests {
  use avrox_display::gfx::pixels::{Grey, Monochromatic, Rgb4bit, Rgb8bit};

  #[test]
  fn test_pixel_conversions() {
    let colour = Rgb8bit(0xff,0x00,0xaa);

    let smallercolour : Rgb4bit = colour.into();

    assert_eq!(smallercolour, Rgb4bit(0x0f0a));

    let greyscale : Grey = colour.into();
    assert_eq!(greyscale, Grey(141));

    let monochrome : Monochromatic = greyscale.into();
    assert_eq!(monochrome, Monochromatic(true));

    println!("Colour     = {:?}", colour);
    println!("4b Colour  = {:?}", smallercolour);
    println!("Greyscale  = {:?}", greyscale);
    println!("Monochrome = {:?}", monochrome);
  }

}