summaryrefslogtreecommitdiff
path: root/src/types/sprite_buffer.rs
blob: 74c7b55734f5aa72e7dc949873964da1abe98581 (plain) (blame)
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
use crate::*;


pub struct SpriteBuffer {
    pub mem: [u8; 16],
    pub pointer: usize,
    pub cached: Option<(Sprite, u8)>,
}

impl SpriteBuffer {
    pub fn new() -> Self {
        Self {
            mem: [0; 16],
            pointer: 0,
            cached: None,
        }
    }

    pub fn push_byte(&mut self, byte: u8) {
        self.mem[self.pointer] = byte;
        self.pointer = (self.pointer + 1) % 16;
        self.cached = None;
    }

    pub fn read_1bit_sprite(&mut self, draw: u8) -> Sprite {
        if let Some((sprite, transform)) = self.cached {
            if transform == (draw & 0x77) {
                return sprite;
            }
        }
        macro_rules! c {
            ($v:ident=mem[$p:ident++]) => { let $v = self.mem[$p % 16]; $p = $p.wrapping_add(1); };
            ($v:ident=mem[--$p:ident]) => { $p = $p.wrapping_sub(1); let $v = self.mem[$p % 16]; };
        }
        let mut sprite = [[0; 8]; 8];
        let mut p = match draw & 0x02 != 0 {
            true  => self.pointer,
            false => self.pointer + 8,
        };
        match draw & 0x07 {
            0x0 => { for y in 0..8 { c!(l=mem[p++]); for x in 0..8 { sprite[y][x] = l>>(7-x) & 1; } } },
            0x1 => { for y in 0..8 { c!(l=mem[p++]); for x in 0..8 { sprite[y][x] = l>>(  x) & 1; } } },
            0x2 => { for y in 0..8 { c!(l=mem[--p]); for x in 0..8 { sprite[y][x] = l>>(7-x) & 1; } } },
            0x3 => { for y in 0..8 { c!(l=mem[--p]); for x in 0..8 { sprite[y][x] = l>>(  x) & 1; } } },
            0x4 => { for y in 0..8 { c!(l=mem[p++]); for x in 0..8 { sprite[x][y] = l>>(7-x) & 1; } } },
            0x5 => { for y in 0..8 { c!(l=mem[p++]); for x in 0..8 { sprite[x][y] = l>>(  x) & 1; } } },
            0x6 => { for y in 0..8 { c!(l=mem[--p]); for x in 0..8 { sprite[x][y] = l>>(7-x) & 1; } } },
            0x7 => { for y in 0..8 { c!(l=mem[--p]); for x in 0..8 { sprite[x][y] = l>>(  x) & 1; } } },
            _ => unreachable!(),
        }
        self.cached = Some((sprite, draw & 0x77));
        return sprite;
    }

    pub fn read_2bit_sprite(&mut self, draw: u8) -> Sprite {
        if let Some((sprite, transform)) = self.cached {
            if transform == (draw & 0x77) {
                return sprite;
            }
        }
        macro_rules! c {
            ($v:ident=mem[$p:ident++]) => { let $v = self.mem[$p % 16]; $p = $p.wrapping_add(1); };
            ($v:ident=mem[--$p:ident]) => { $p = $p.wrapping_sub(1); let $v = self.mem[$p % 16]; };
        }
        let mut sprite = [[0; 8]; 8];
        let mut p = match draw & 0x02 != 0 {
            true  => self.pointer,
            false => self.pointer + 8,
        };
        let mut s = p + 8;
        match draw & 0x07 {
            0x0 => for y in 0..8 { c!(l=mem[p++]); c!(h=mem[s++]); for x in 0..8 { let i=7-x; sprite[y][x] = (l>>i & 1) | (h>>i & 1) << 1; } },
            0x1 => for y in 0..8 { c!(l=mem[p++]); c!(h=mem[s++]); for x in 0..8 { let i=  x; sprite[y][x] = (l>>i & 1) | (h>>i & 1) << 1; } },
            0x2 => for y in 0..8 { c!(l=mem[--p]); c!(h=mem[--s]); for x in 0..8 { let i=7-x; sprite[y][x] = (l>>i & 1) | (h>>i & 1) << 1; } },
            0x3 => for y in 0..8 { c!(l=mem[--p]); c!(h=mem[--s]); for x in 0..8 { let i=  x; sprite[y][x] = (l>>i & 1) | (h>>i & 1) << 1; } },
            0x4 => for y in 0..8 { c!(l=mem[p++]); c!(h=mem[s++]); for x in 0..8 { let i=7-x; sprite[x][y] = (l>>i & 1) | (h>>i & 1) << 1; } },
            0x5 => for y in 0..8 { c!(l=mem[p++]); c!(h=mem[s++]); for x in 0..8 { let i=  x; sprite[x][y] = (l>>i & 1) | (h>>i & 1) << 1; } },
            0x6 => for y in 0..8 { c!(l=mem[--p]); c!(h=mem[--s]); for x in 0..8 { let i=7-x; sprite[x][y] = (l>>i & 1) | (h>>i & 1) << 1; } },
            0x7 => for y in 0..8 { c!(l=mem[--p]); c!(h=mem[--s]); for x in 0..8 { let i=  x; sprite[x][y] = (l>>i & 1) | (h>>i & 1) << 1; } },
            _ => unreachable!(),
        }
        self.cached = Some((sprite, draw & 0x77));
        return sprite;
    }
}