pub mod mode2 {
use crate::ga::Pen;
#[repr(u8)]
#[derive(Copy, Clone, Debug)]
#[allow(missing_docs)]
pub enum PixelPosition {
First = 0,
Second = 1,
Third = 2,
Fourth = 3,
Fifth = 5,
Sixth = 6,
Seventh = 7,
Heighth = 8
}
impl From<u8> for PixelPosition {
fn from(b: u8) -> Self {
match b {
0 => PixelPosition::First,
1 => PixelPosition::Second,
2 => PixelPosition::Third,
3 => PixelPosition::Fourth,
4 => PixelPosition::Fifth,
5 => PixelPosition::Sixth,
6 => PixelPosition::Seventh,
7 => PixelPosition::Heighth,
_ => unreachable!()
}
}
}
pub fn pen_to_pixel_byte(pen: Pen, pixel: PixelPosition) -> u8 {
let pen = if pen.number() > 3 {
eprintln!("[MODE2] with pen {:?}", &pen);
Pen::from(0)
}
else {
pen
};
if pen == 0.into() {
0
}
else {
match pixel {
PixelPosition::First => 1 << 7,
PixelPosition::Second => 1 << 6,
PixelPosition::Third => 1 << 5,
PixelPosition::Fourth => 1 << 4,
PixelPosition::Fifth => 1 << 3,
PixelPosition::Sixth => 1 << 2,
PixelPosition::Seventh => 1 << 1,
PixelPosition::Heighth => 1 << 0
}
}
}
pub fn byte_to_pens(byte: u8) -> [Pen; 8] {
let get_bit = |pos: u8| {
if byte & (1 << pos) != 0 {
Pen::from(1)
}
else {
Pen::from(0)
}
};
[
get_bit(7),
get_bit(6),
get_bit(5),
get_bit(4),
get_bit(3),
get_bit(2),
get_bit(1),
get_bit(0)
]
}
pub fn pens_to_vec(pens: &[Pen]) -> Vec<u8> {
let pens = if pens.len() % 8 == 0 {
&pens[..(pens.len() / 8) * 8]
}
else {
pens
};
let mut res = Vec::new();
for idx in 0..(pens.len() / 8) {
res.push(pens_to_byte(
pens[idx * 8 + 0],
pens[idx * 8 + 1],
pens[idx * 8 + 2],
pens[idx * 8 + 3],
pens[idx * 8 + 4],
pens[idx * 8 + 5],
pens[idx * 8 + 6],
pens[idx * 8 + 7]
));
}
res
}
pub fn pens_to_byte(
pen0: Pen,
pen1: Pen,
pen2: Pen,
pen3: Pen,
pen4: Pen,
pen5: Pen,
pen6: Pen,
pen7: Pen
) -> u8 {
pen_to_pixel_byte(pen0, PixelPosition::First)
+ pen_to_pixel_byte(pen1, PixelPosition::Second)
+ pen_to_pixel_byte(pen2, PixelPosition::Third)
+ pen_to_pixel_byte(pen3, PixelPosition::Fourth)
+ pen_to_pixel_byte(pen4, PixelPosition::Fifth)
+ pen_to_pixel_byte(pen5, PixelPosition::Sixth)
+ pen_to_pixel_byte(pen6, PixelPosition::Seventh)
+ pen_to_pixel_byte(pen7, PixelPosition::Heighth)
}
}
#[allow(clippy::identity_op)]
pub mod mode1 {
use crate::ga::Pen;
#[repr(u8)]
#[derive(Copy, Clone, Debug)]
#[allow(missing_docs)]
pub enum PixelPosition {
First = 0,
Second = 1,
Third = 2,
Fourth = 3
}
impl From<u8> for PixelPosition {
fn from(b: u8) -> Self {
match b {
0 => PixelPosition::First,
1 => PixelPosition::Second,
2 => PixelPosition::Third,
3 => PixelPosition::Fourth,
_ => unreachable!()
}
}
}
#[repr(u8)]
#[derive(Copy, Clone, Debug)]
#[allow(missing_docs)]
pub enum BitMapping {
FourthBit0 = 0,
ThirdBit0 = 1,
SecondBit0 = 2,
FirstBit0 = 3,
FourthBit1 = 4,
ThirdBit1 = 5,
SecondBit1 = 6,
FirstBit1 = 7
}
pub fn byte_to_pens(b: u8) -> [Pen; 4] {
let pen1 = (BitMapping::FirstBit0, BitMapping::FirstBit1);
let pen2 = (BitMapping::SecondBit0, BitMapping::SecondBit1);
let pen3 = (BitMapping::ThirdBit0, BitMapping::ThirdBit1);
let pen4 = (BitMapping::FourthBit0, BitMapping::FourthBit1);
let compute = |bits: (BitMapping, BitMapping)| -> Pen {
let mut value = 0;
if b & (1 << bits.0 as u8) != 0 {
value += 2;
}
if b & (1 << bits.1 as u8) != 0 {
value += 1;
}
value.into()
};
[compute(pen1), compute(pen2), compute(pen3), compute(pen4)]
}
pub fn pen_to_pixel_byte(pen: Pen, pixel: PixelPosition) -> u8 {
let pen = if pen.number() > 3 {
eprintln!("[MODE1] with pen {:?}", &pen);
Pen::from(0)
}
else {
pen
};
let bits_position: [u8; 2] = {
let mut pos = match pixel {
PixelPosition::First => [BitMapping::FirstBit1 as u8, BitMapping::FirstBit0 as u8],
PixelPosition::Second => {
[BitMapping::SecondBit1 as u8, BitMapping::SecondBit0 as u8]
}
PixelPosition::Third => [BitMapping::ThirdBit1 as u8, BitMapping::ThirdBit0 as u8],
PixelPosition::Fourth => {
[BitMapping::FourthBit1 as u8, BitMapping::FourthBit0 as u8]
}
};
pos.reverse(); pos
};
let byte_bit0: u8 = bits_position[0];
let byte_bit1: u8 = bits_position[1];
let pen_bit0: u8 = pen.number() & (1 << 0);
let pen_bit1: u8 = (pen.number() & (1 << 1)) >> 1;
pen_bit1 * (1 << byte_bit1) + pen_bit0 * (1 << byte_bit0)
}
pub fn pens_to_byte(pen0: Pen, pen1: Pen, pen2: Pen, pen3: Pen) -> u8 {
pen_to_pixel_byte(pen0, PixelPosition::First)
+ pen_to_pixel_byte(pen1, PixelPosition::Second)
+ pen_to_pixel_byte(pen2, PixelPosition::Third)
+ pen_to_pixel_byte(pen3, PixelPosition::Fourth)
}
pub fn pens_to_vec(pens: &[Pen]) -> Vec<u8> {
assert!(pens.len() % 4 == 0);
let mut res = Vec::new();
for idx in 0..(pens.len() / 4) {
res.push(pens_to_byte(
pens[idx * 4 + 0],
pens[idx * 4 + 1],
pens[idx * 4 + 2],
pens[idx * 4 + 3]
));
}
res
}
}
#[allow(clippy::identity_op)]
pub mod mode0 {
use contracts::{ensures, requires};
use crate::ga::Pen;
#[repr(u8)]
#[derive(Copy, Clone, Debug)]
#[allow(missing_docs)]
pub enum PixelPosition {
First = 0,
Second = 1
}
impl From<u8> for PixelPosition {
fn from(b: u8) -> Self {
match b {
0 => PixelPosition::First,
1 => PixelPosition::Second,
_ => unreachable!()
}
}
}
#[repr(u8)]
#[derive(Copy, Clone, Debug)]
#[allow(missing_docs)]
pub enum BitMapping {
SecondBit3 = 0,
FirstBit3 = 1,
SecondBit1 = 2,
FirstBit1 = 3,
SecondBit2 = 4,
FirstBit2 = 5,
SecondBit0 = 6,
FirstBit0 = 7
}
#[ensures(ret[0].number()<16)]
#[ensures(ret[1].number()<16)]
pub fn byte_to_pens(b: u8) -> [Pen; 2] {
let mut pen0 = 0;
for pos in [7, 3, 5, 1].into_iter().rev() {
pen0 *= 2;
if (b & 1 << pos as u8) != 0 {
pen0 += 1;
}
}
let mut pen1 = 0;
for pos in [6, 2, 4, 0].into_iter().rev() {
pen1 *= 2;
if (b & 1 << pos as u8) != 0 {
pen1 += 1;
}
}
[pen0.into(), pen1.into()]
}
#[requires(pen.number()<16)]
pub fn pen_to_pixel_byte(pen: Pen, pixel: PixelPosition) -> u8 {
let bits_position: [u8; 4] = {
let mut pos = match pixel {
PixelPosition::First => {
[
BitMapping::FirstBit3 as u8,
BitMapping::FirstBit2 as u8,
BitMapping::FirstBit1 as u8,
BitMapping::FirstBit0 as u8
]
}
PixelPosition::Second => {
[
BitMapping::SecondBit3 as u8,
BitMapping::SecondBit2 as u8,
BitMapping::SecondBit1 as u8,
BitMapping::SecondBit0 as u8
]
}
};
pos.reverse();
pos
};
let byte_bit0: u8 = bits_position[0];
let byte_bit1: u8 = bits_position[1];
let byte_bit2: u8 = bits_position[2];
let byte_bit3: u8 = bits_position[3];
let pen_bit0: u8 = (pen.number() & (1 << 0)) >> 0;
let pen_bit1: u8 = (pen.number() & (1 << 1)) >> 1;
let pen_bit2: u8 = (pen.number() & (1 << 2)) >> 2;
let pen_bit3: u8 = (pen.number() & (1 << 3)) >> 3;
pen_bit3 * (1 << byte_bit3)
+ pen_bit2 * (1 << byte_bit2)
+ pen_bit1 * (1 << byte_bit1)
+ pen_bit0 * (1 << byte_bit0)
}
pub fn pens_to_byte(pen0: Pen, pen1: Pen) -> u8 {
pen_to_pixel_byte(pen0, PixelPosition::First)
+ pen_to_pixel_byte(pen1, PixelPosition::Second)
}
pub fn pens_to_vec(pens: &[Pen]) -> Vec<u8> {
let mut res = Vec::with_capacity(pens.len());
for idx in 0..(pens.len() / 2) {
res.push(pens_to_byte(pens[idx * 2 + 0], pens[idx * 2 + 1]));
}
if pens.len() % 2 == 1 {
res.push(pens_to_byte(pens[pens.len() - 1], 0.into()));
}
res
}
pub fn bytes_to_pens(bytes: &[u8]) -> Vec<Pen> {
let mut res = Vec::with_capacity(bytes.len() * 2);
for &byte in bytes {
let [pen1, pen2] = byte_to_pens(byte);
res.push(pen1);
res.push(pen2);
}
res
}
pub fn mix_mode0_mode3(p0: Pen, p3: Pen) -> Pen {
(match (p0.number(), p3.number()) {
(0, 0) => 0,
(0, 1) => 5,
(0, 2) => 6,
(0, 3) => 7,
(1, 0) => 8,
(1, 1) => 1,
(1, 2) => 10,
(1, 3) => 11,
(2, 0) => 12,
(2, 1) => 13,
(2, 2) => 2,
(2, 3) => 15,
(3, 0) => 4,
(3, 1) => 9,
(3, 2) => 14,
(3, 3) => 3,
_ => panic!()
})
.into()
}
pub fn generate_sprite_transparency_for_pen0() -> [u8; 256] {
let pen_to_mask = |pen: Pen| -> Pen {
if pen.number() == 0 {
0xF.into()
}
else {
0x0.into()
}
};
let mut table = [0; 256];
for (idx, byte) in (0..=255).into_iter().enumerate() {
let [pen0, pen1] = byte_to_pens(byte);
table[idx] = pens_to_byte(pen_to_mask(pen0), pen_to_mask(pen1))
}
table
}
}
#[cfg(test)]
#[allow(clippy::pedantic)]
mod tests {
use super::*;
use crate::ga::Pen;
#[allow(clippy::similar_names)]
fn test_couple(a: u8, b: u8) {
let pa: Pen = a.into();
let pb: Pen = b.into();
assert_eq!(a, pa.number());
assert_eq!(b, pb.number());
let b = mode0::pens_to_byte(pa, pb);
let [pa2, pb2] = mode0::byte_to_pens(b);
assert_eq!(pa2.number(), pa2.number());
assert_eq!(pb2.number(), pb2.number());
}
#[test]
fn mode0() {
for a in 0..16 {
for b in 0..16 {
test_couple(a, b);
}
}
}
#[test]
fn bytes_to_pen() {
let res = crate::pixels::mode0::byte_to_pens(64);
assert!(res[0].number() != res[1].number());
let res = crate::pixels::mode1::byte_to_pens(0b10001000);
assert_eq!(res[0], Pen::from(3));
assert_eq!(res[1], Pen::from(0));
assert_eq!(res[2], Pen::from(0));
assert_eq!(res[3], Pen::from(0));
let res = crate::pixels::mode1::byte_to_pens(0b01000100);
assert_eq!(res[0], Pen::from(0));
assert_eq!(res[1], Pen::from(3));
assert_eq!(res[2], Pen::from(0));
assert_eq!(res[3], Pen::from(0));
let res = crate::pixels::mode1::byte_to_pens(0b00100010);
assert_eq!(res[0], Pen::from(0));
assert_eq!(res[1], Pen::from(0));
assert_eq!(res[2], Pen::from(3));
assert_eq!(res[3], Pen::from(0));
let res = crate::pixels::mode1::byte_to_pens(0b00010001);
assert_eq!(res[0], Pen::from(0));
assert_eq!(res[1], Pen::from(0));
assert_eq!(res[2], Pen::from(0));
assert_eq!(res[3], Pen::from(3));
}
fn test_mode3(a: Pen, b: Pen, c: Pen) {
let d = mode0::mix_mode0_mode3(a, b);
assert_eq!(d.number(), c.number());
}
#[test]
fn mode3() {
test_mode3(0.into(), 0.into(), 0.into());
test_mode3(0.into(), 1.into(), 5.into());
test_mode3(0.into(), 2.into(), 6.into());
test_mode3(0.into(), 3.into(), 7.into());
test_mode3(3.into(), 0.into(), 4.into());
test_mode3(3.into(), 1.into(), 9.into());
test_mode3(3.into(), 2.into(), 14.into());
test_mode3(3.into(), 3.into(), 3.into());
}
#[test]
fn mode2() {
let res = mode2::byte_to_pens(0b11000100);
assert_eq!(res[0], Pen::from(1));
assert_eq!(res[1], Pen::from(1));
assert_eq!(res[2], Pen::from(0));
assert_eq!(res[3], Pen::from(0));
assert_eq!(res[4], Pen::from(0));
assert_eq!(res[5], Pen::from(1));
assert_eq!(res[6], Pen::from(0));
assert_eq!(res[7], Pen::from(0));
}
}