mirror of
https://github.com/KrisKennaway/ii-vision.git
synced 2024-09-28 11:55:26 +00:00
ab29b01d0f
- For HGRBitmap introduce a packed representation in the form hhHaaaaaaaABbbbbbbbFff where capitals indicate the location of the palette bit. i.e. for header and footer we include the neighbouring 2 data bits as in DHGR but also the palette bit from that byte, which is necessary to understand how these data bits unpack into dots. The nonstandard ordering of the palette bit for the odd data byte (B) is so that the masking by byte offset produces a contiguous sequence of bits, i.e. the 14-bit masked representation is still dense. - Introduce a to_dots() classmethod that converts from the masked bit representation of dots influenced by a screen byte to the actual sequence of screen dots. For DHGR this is the identity map since there are no shenanigans with palette bits causing dots to shift around. - Add a bunch more unit tests, and add back the Sather tests for HGR artifact colours from palette bit interference, which now all pass! - Reduce the size of the precomputed edit distance matrix by half by exploiting the fact that it is symmetrical under i << N + j <-> j << N + i where N is the size of the masked bit representation (i.e. transposing the original (i, j) -> dist metric matrix).
1073 lines
37 KiB
Python
1073 lines
37 KiB
Python
"""Tests for the screen module."""
|
|
|
|
import unittest
|
|
|
|
import numpy as np
|
|
|
|
import screen
|
|
import colours
|
|
from palette import Palette
|
|
|
|
|
|
class TestDHGRBitmap(unittest.TestCase):
|
|
def setUp(self) -> None:
|
|
self.aux = screen.MemoryMap(screen_page=1)
|
|
self.main = screen.MemoryMap(screen_page=1)
|
|
|
|
def test_make_header(self):
|
|
self.assertEqual(
|
|
0b100,
|
|
screen.DHGRBitmap._make_header(
|
|
np.uint64(0b0001000011111010110000111110101000))
|
|
)
|
|
|
|
def test_make_footer(self):
|
|
self.assertEqual(
|
|
0b1010000000000000000000000000000000,
|
|
screen.DHGRBitmap._make_footer(
|
|
np.uint64(0b0001000011111010110000111110101000))
|
|
)
|
|
|
|
def test_pixel_packing_offset_0(self):
|
|
# PBBBAAAA
|
|
self.aux.page_offset[0, 0] = 0b11110101
|
|
# PDDCCCCB
|
|
self.main.page_offset[0, 0] = 0b01000011
|
|
# PFEEEEDD
|
|
self.aux.page_offset[0, 1] = 0b11110101
|
|
# PGGGGFFF
|
|
self.main.page_offset[0, 1] = 0b01000011
|
|
|
|
dhgr = screen.DHGRBitmap(
|
|
main_memory=self.main, aux_memory=self.aux, palette=Palette.NTSC)
|
|
|
|
self.assertEqual(
|
|
0b0001000011111010110000111110101000,
|
|
dhgr.packed[0, 0]
|
|
)
|
|
|
|
# Check header on neighbouring byte
|
|
self.assertEqual(
|
|
0b0000000000000000000000000000000100,
|
|
dhgr.packed[0, 1]
|
|
)
|
|
|
|
# No other entries should be set, in particular no footer since we
|
|
# are at packed offset 0
|
|
self.assertEqual(2, np.count_nonzero(dhgr.packed))
|
|
|
|
def test_pixel_packing_offset_1(self):
|
|
# PBBBAAAA
|
|
self.aux.page_offset[0, 2] = 0b11110101
|
|
# PDDCCCCB
|
|
self.main.page_offset[0, 2] = 0b01000011
|
|
# PFEEEEDD
|
|
self.aux.page_offset[0, 3] = 0b11110101
|
|
# PGGGGFFF
|
|
self.main.page_offset[0, 3] = 0b01000011
|
|
|
|
dhgr = screen.DHGRBitmap(
|
|
main_memory=self.main, aux_memory=self.aux, palette=Palette.NTSC)
|
|
|
|
self.assertEqual(
|
|
0b0001000011111010110000111110101000,
|
|
dhgr.packed[0, 1]
|
|
)
|
|
|
|
# Check footer on neighbouring byte
|
|
self.assertEqual(
|
|
0b1010000000000000000000000000000000,
|
|
dhgr.packed[0, 0]
|
|
)
|
|
|
|
# Check header on neighbouring byte
|
|
self.assertEqual(
|
|
0b0000000000000000000000000000000100,
|
|
dhgr.packed[0, 2]
|
|
)
|
|
|
|
# No other entries should be set
|
|
self.assertEqual(3, np.count_nonzero(dhgr.packed))
|
|
|
|
def test_pixel_packing_offset_127(self):
|
|
# PBBBAAAA
|
|
self.aux.page_offset[0, 254] = 0b11110101
|
|
# PDDCCCCB
|
|
self.main.page_offset[0, 254] = 0b01000011
|
|
# PFEEEEDD
|
|
self.aux.page_offset[0, 255] = 0b11110101
|
|
# PGGGGFFF
|
|
self.main.page_offset[0, 255] = 0b01000011
|
|
|
|
dhgr = screen.DHGRBitmap(
|
|
main_memory=self.main, aux_memory=self.aux, palette=Palette.NTSC)
|
|
|
|
self.assertEqual(
|
|
0b0001000011111010110000111110101000,
|
|
dhgr.packed[0, 127]
|
|
)
|
|
|
|
# Check footer on neighbouring byte
|
|
self.assertEqual(
|
|
0b1010000000000000000000000000000000,
|
|
dhgr.packed[0, 126]
|
|
)
|
|
|
|
# No other entries should be set, in particular header should not
|
|
# propagate to next row
|
|
self.assertEqual(2, np.count_nonzero(dhgr.packed))
|
|
|
|
def test_byte_offset(self):
|
|
self.assertEqual(0, screen.DHGRBitmap.byte_offset(0, is_aux=True))
|
|
self.assertEqual(1, screen.DHGRBitmap.byte_offset(0, is_aux=False))
|
|
self.assertEqual(2, screen.DHGRBitmap.byte_offset(1, is_aux=True))
|
|
self.assertEqual(3, screen.DHGRBitmap.byte_offset(1, is_aux=False))
|
|
|
|
def test_byte_offsets(self):
|
|
self.assertEqual((0, 2), screen.DHGRBitmap._byte_offsets(is_aux=True))
|
|
self.assertEqual((1, 3), screen.DHGRBitmap._byte_offsets(is_aux=False))
|
|
|
|
def test_mask_and_shift_data(self):
|
|
int13_max = np.uint64(2 ** 13 - 1)
|
|
int34_max = np.uint64(2 ** 34 - 1)
|
|
|
|
dhgr = screen.DHGRBitmap(
|
|
main_memory=self.main, aux_memory=self.aux, palette=Palette.NTSC)
|
|
|
|
for o in range(3):
|
|
self.assertEqual(
|
|
int13_max,
|
|
dhgr.mask_and_shift_data(
|
|
screen.DHGRBitmap.BYTE_MASKS[o], o
|
|
)
|
|
)
|
|
|
|
# Now check complement, i.e. no bits taken from outside expected
|
|
# range
|
|
self.assertEqual(
|
|
0,
|
|
dhgr.mask_and_shift_data(
|
|
~screen.DHGRBitmap.BYTE_MASKS[o] & int34_max, o
|
|
)
|
|
)
|
|
|
|
def test_masked_update(self):
|
|
self.assertEqual(
|
|
0b0000000000000000000000001111111000,
|
|
screen.DHGRBitmap.masked_update(
|
|
0, np.uint64(0), np.uint8(0xff))
|
|
)
|
|
self.assertEqual(
|
|
0b0000000000000000011111110000000000,
|
|
screen.DHGRBitmap.masked_update(
|
|
1, np.uint64(0), np.uint8(0xff))
|
|
)
|
|
self.assertEqual(
|
|
0b0000000000111111100000000000000000,
|
|
screen.DHGRBitmap.masked_update(
|
|
2, np.uint64(0), np.uint8(0xff))
|
|
)
|
|
self.assertEqual(
|
|
0b0001111111000000000000000000000000,
|
|
screen.DHGRBitmap.masked_update(
|
|
3, np.uint64(0), np.uint8(0xff))
|
|
)
|
|
|
|
# Now test masking out existing values
|
|
|
|
int34_max = np.uint64(2 ** 34 - 1)
|
|
|
|
self.assertEqual(
|
|
0b1111111111111111111111110000000111,
|
|
screen.DHGRBitmap.masked_update(0, int34_max, np.uint8(0x00))
|
|
)
|
|
self.assertEqual(
|
|
0b1111111111111111100000001111111111,
|
|
screen.DHGRBitmap.masked_update(1, int34_max, np.uint8(0x00))
|
|
)
|
|
self.assertEqual(
|
|
0b1111111111000000011111111111111111,
|
|
screen.DHGRBitmap.masked_update(2, int34_max, np.uint8(0x00))
|
|
)
|
|
self.assertEqual(
|
|
0b1110000000111111111111111111111111,
|
|
screen.DHGRBitmap.masked_update(3, int34_max, np.uint8(0x00))
|
|
)
|
|
|
|
# Test that masked_update can broadcast to numpy arrays
|
|
ary = np.zeros((2, 2), dtype=np.uint64)
|
|
|
|
elt = np.uint64(0b1111111000)
|
|
self.assertTrue(np.array_equal(
|
|
np.array([[elt, elt], [elt, elt]], dtype=np.uint64),
|
|
screen.DHGRBitmap.masked_update(0, ary, np.uint8(0xff))
|
|
))
|
|
|
|
def test_apply(self):
|
|
dhgr = screen.DHGRBitmap(
|
|
main_memory=self.main, aux_memory=self.aux, palette=Palette.NTSC)
|
|
|
|
dhgr.apply(page=0, offset=0, is_aux=True, value=np.uint8(0xff))
|
|
self.assertEqual(0b1111111000, dhgr.packed[0, 0])
|
|
|
|
dhgr.apply(page=12, offset=36, is_aux=True, value=np.uint8(0xff))
|
|
# Neighbouring header
|
|
self.assertEqual(
|
|
0,
|
|
dhgr.packed[12, 19])
|
|
# Body
|
|
self.assertEqual(
|
|
0b1111111000,
|
|
dhgr.packed[12, 18])
|
|
# Neighbouring footer
|
|
self.assertEqual(
|
|
0b1110000000000000000000000000000000,
|
|
dhgr.packed[12, 17])
|
|
|
|
# Now update the next aux offset in same uint64
|
|
dhgr.apply(page=12, offset=37, is_aux=True, value=np.uint8(0xff))
|
|
# Neighbouring header
|
|
self.assertEqual(
|
|
0,
|
|
dhgr.packed[12, 19])
|
|
# Body
|
|
self.assertEqual(
|
|
0b0000000111111100000001111111000,
|
|
dhgr.packed[12, 18]
|
|
)
|
|
# Neighbouring footer
|
|
self.assertEqual(
|
|
0b1110000000000000000000000000000000,
|
|
dhgr.packed[12, 17])
|
|
|
|
# Update offset 3, should propagate to next header
|
|
dhgr.apply(page=12, offset=37, is_aux=False, value=np.uint8(0b1010101))
|
|
self.assertEqual(
|
|
0b101,
|
|
dhgr.packed[12, 19])
|
|
self.assertEqual(
|
|
0b1010101111111100000001111111000,
|
|
dhgr.packed[12, 18]
|
|
)
|
|
self.assertEqual(
|
|
0b1110000000000000000000000000000000,
|
|
dhgr.packed[12, 17])
|
|
|
|
dhgr.apply(page=12, offset=36, is_aux=False, value=np.uint8(0b0001101))
|
|
self.assertEqual(
|
|
0b101,
|
|
dhgr.packed[12, 19])
|
|
self.assertEqual(
|
|
0b1010101111111100011011111111000,
|
|
dhgr.packed[12, 18]
|
|
)
|
|
self.assertEqual(
|
|
0b1110000000000000000000000000000000,
|
|
dhgr.packed[12, 17])
|
|
|
|
# Change offset 0, should propagate to neighbouring footer
|
|
dhgr.apply(page=12, offset=36, is_aux=True, value=np.uint8(0b0001101))
|
|
# Neighbouring header
|
|
self.assertEqual(
|
|
0b101,
|
|
dhgr.packed[12, 19])
|
|
self.assertEqual(
|
|
0b1010101111111100011010001101000,
|
|
dhgr.packed[12, 18]
|
|
)
|
|
# Neighbouring footer
|
|
self.assertEqual(
|
|
0b1010000000000000000000000000000000,
|
|
dhgr.packed[12, 17])
|
|
|
|
# Now propagate new header from neighbour onto (12, 18)
|
|
dhgr.apply(page=12, offset=35, is_aux=False, value=np.uint8(0b1010101))
|
|
self.assertEqual(
|
|
0b1010101111111100011010001101101,
|
|
dhgr.packed[12, 18]
|
|
)
|
|
# Neighbouring footer
|
|
self.assertEqual(
|
|
0b1011010101000000000000000000000000,
|
|
dhgr.packed[12, 17])
|
|
|
|
def test_fix_array_neighbours(self):
|
|
dhgr = screen.DHGRBitmap(
|
|
main_memory=self.main, aux_memory=self.aux, palette=Palette.NTSC)
|
|
|
|
packed = dhgr.masked_update(0, dhgr.packed, np.uint8(0x7f))
|
|
dhgr._fix_array_neighbours(packed, 0)
|
|
|
|
# Should propagate to all footers
|
|
self.assertEqual(
|
|
0, np.count_nonzero(
|
|
packed[packed != 0b1110000000000000000000001111111000]
|
|
)
|
|
)
|
|
|
|
# Should not change headers/footers
|
|
packed = dhgr.masked_update(1, packed, np.uint8(0b1010101))
|
|
dhgr._fix_array_neighbours(packed, 1)
|
|
|
|
self.assertEqual(
|
|
0, np.count_nonzero(
|
|
packed[packed != 0b1110000000000000010101011111111000]
|
|
)
|
|
)
|
|
|
|
# Should propagate to all headers
|
|
packed = dhgr.masked_update(3, packed, np.uint8(0b0110110))
|
|
dhgr._fix_array_neighbours(packed, 3)
|
|
|
|
self.assertEqual(
|
|
0, np.count_nonzero(
|
|
packed[packed != 0b1110110110000000010101011111111011]
|
|
)
|
|
)
|
|
|
|
|
|
def binary(a):
|
|
return np.vectorize("{:032b}".format)(a)
|
|
|
|
|
|
class TestHGRBitmap(unittest.TestCase):
|
|
def setUp(self) -> None:
|
|
self.main = screen.MemoryMap(screen_page=1)
|
|
|
|
def test_make_header(self):
|
|
self.assertEqual(
|
|
0b111,
|
|
screen.HGRBitmap._make_header(
|
|
np.uint64(0b0001100000100000000000))
|
|
)
|
|
|
|
# Now check palette bit ends up in right spot
|
|
self.assertEqual(
|
|
0b100,
|
|
screen.HGRBitmap._make_header(
|
|
np.uint64(0b0000000000100000000000))
|
|
)
|
|
|
|
def test_make_footer(self):
|
|
self.assertEqual(
|
|
0b1110000000000000000000,
|
|
screen.HGRBitmap._make_footer(
|
|
np.uint64(0b0000000000010000011000))
|
|
)
|
|
|
|
# Now check palette bit ends up in right spot
|
|
self.assertEqual(
|
|
0b0010000000000000000000,
|
|
screen.HGRBitmap._make_footer(
|
|
np.uint64(0b0000000000010000000000))
|
|
)
|
|
|
|
def test_pixel_packing_p0_p0(self):
|
|
# PDCCBBAA
|
|
self.main.page_offset[0, 0] = 0b01000011
|
|
# PGGFFEED
|
|
self.main.page_offset[0, 1] = 0b01000011
|
|
|
|
hgr = screen.HGRBitmap(main_memory=self.main, palette=Palette.NTSC)
|
|
|
|
want = 0b0001000011001000011000
|
|
got = hgr.packed[0, 0]
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
def test_pixel_packing_p0_p1(self):
|
|
# PDCCBBAA
|
|
self.main.page_offset[0, 0] = 0b01000011
|
|
# PGGFFEED
|
|
self.main.page_offset[0, 1] = 0b11000011
|
|
|
|
hgr = screen.HGRBitmap(main_memory=self.main, palette=Palette.NTSC)
|
|
|
|
want = 0b0001000011101000011000
|
|
got = hgr.packed[0, 0]
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
def test_pixel_packing_p1_p0(self):
|
|
# PDCCBBAA
|
|
self.main.page_offset[0, 0] = 0b11000011
|
|
# PGGFFEED
|
|
self.main.page_offset[0, 1] = 0b01000011
|
|
|
|
hgr = screen.HGRBitmap(main_memory=self.main, palette=Palette.NTSC)
|
|
|
|
want = 0b0001000011011000011000
|
|
got = hgr.packed[0, 0]
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
def test_pixel_packing_p1_p1(self):
|
|
# PDCCBBAA
|
|
self.main.page_offset[0, 0] = 0b11000011
|
|
# PGGFFEED
|
|
self.main.page_offset[0, 1] = 0b11000011
|
|
|
|
hgr = screen.HGRBitmap(main_memory=self.main, palette=Palette.NTSC)
|
|
|
|
want = 0b1000011111000011000
|
|
got = hgr.packed[0, 0]
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
def test_masked_update(self):
|
|
|
|
hgr = screen.HGRBitmap(main_memory=self.main, palette=Palette.NTSC)
|
|
|
|
hgr.apply(0, 0, False, 0b11000011)
|
|
hgr.apply(0, 1, False, 0b11000011)
|
|
|
|
want = 0b1000011111000011000
|
|
got = hgr.packed[0, 0]
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
def test_double_pixels(self):
|
|
want = 0b111001100110011
|
|
got = screen.HGRBitmap._double_pixels(0b1010101)
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
def test_to_dots_offset_0(self):
|
|
# Header has P=0, Body has P=0
|
|
want = 0b00000000000000000111
|
|
got = screen.HGRBitmap.to_dots(0b00000000000011, 0)
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
# Header has P=1, body has P=0 - cuts off
|
|
want = 0b00000000000000000111
|
|
got = screen.HGRBitmap.to_dots(0b00000000000111, 0)
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
# Header has P=1, body has P=1
|
|
want = 0b00000000000000001111
|
|
got = screen.HGRBitmap.to_dots(0b00010000000111, 0)
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
# Header has P=1, body has P=1, footer has P=0 - cuts off body
|
|
want = 0b00010011001100111111
|
|
got = screen.HGRBitmap.to_dots(0b00011010101111, 0)
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
# Header has P=1, body has P=1, footer has P=1
|
|
want = 0b00110011001100111111
|
|
got = screen.HGRBitmap.to_dots(0b00111010101111, 0)
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
# Header has P=1, body has P=1, footer has P=1
|
|
want = 0b100110011001100111111
|
|
got = screen.HGRBitmap.to_dots(0b10111010101111, 0)
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
# Header has P=0, body has P=0, footer has P=1
|
|
want = 0b100000000000000000000
|
|
got = screen.HGRBitmap.to_dots(0b10100000000000, 0)
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
# Header has P=0, body has P=0, footer has P=0
|
|
want = 0b110000000000000000000
|
|
got = screen.HGRBitmap.to_dots(0b10000000000000, 0)
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
def test_to_dots_offset_1(self):
|
|
# Header has P=0, Body has P=0
|
|
want = 0b000000000000000000111
|
|
got = screen.HGRBitmap.to_dots(0b00000000000011, 1)
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
# Header has P=1, body has P=0 - cuts off
|
|
want = 0b000000000000000000111
|
|
got = screen.HGRBitmap.to_dots(0b00000000000111, 1)
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
# Header has P=1, body has P=1
|
|
want = 0b000000000000000001111
|
|
got = screen.HGRBitmap.to_dots(0b00000000001111, 1)
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
# Header has P=1, body has P=1, footer has P=0 - cuts off body
|
|
want = 0b000010011001100111111
|
|
got = screen.HGRBitmap.to_dots(0b00010101011111, 1)
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
# Header has P=1, body has P=1, footer has P=1
|
|
want = 0b000110011001100111111
|
|
got = screen.HGRBitmap.to_dots(0b00110101011111, 1)
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
# Header has P=1, body has P=1, footer has P=1
|
|
want = 0b100110011001100111111
|
|
got = screen.HGRBitmap.to_dots(0b10110101011111, 1)
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
# Header has P=0, body has P=0, footer has P=1
|
|
want = 0b100000000000000000000
|
|
got = screen.HGRBitmap.to_dots(0b10100000000000, 1)
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
# Header has P=0, body has P=0, footer has P=0
|
|
want = 0b110000000000000000000
|
|
got = screen.HGRBitmap.to_dots(0b10000000000000, 1)
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
|
|
class TestNominalColours(unittest.TestCase):
|
|
def setUp(self) -> None:
|
|
self.main = screen.MemoryMap(screen_page=1)
|
|
|
|
self.maxDiff = None
|
|
|
|
def test_nominal_colours(self):
|
|
# PDCCBBAA
|
|
self.main.page_offset[0, 0] = 0b01010101
|
|
# PGGFFEED
|
|
self.main.page_offset[0, 1] = 0b00101010
|
|
# PDCCBBAA
|
|
self.main.page_offset[0, 2] = 0b01010101
|
|
|
|
self.hgr = screen.HGRBitmap(main_memory=self.main, palette=Palette.NTSC)
|
|
|
|
want = 0b0100101010001010101000
|
|
got = self.hgr.packed[0, 0]
|
|
|
|
self.assertEqual(
|
|
want, got, "\n%s\n%s" % (binary(want), binary(got))
|
|
)
|
|
|
|
masked = int(screen.HGRBitmap.mask_and_shift_data(
|
|
self.hgr.packed[0, 0], byte_offset=0))
|
|
dots = screen.HGRBitmap.to_dots(masked, byte_offset=0)
|
|
self.assertEqual(
|
|
(
|
|
colours.HGRColours.MAGENTA,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
),
|
|
colours.dots_to_nominal_colour_pixels(
|
|
18, dots, colours.HGRColours,
|
|
init_phase=screen.HGRBitmap.PHASES[0])
|
|
)
|
|
|
|
# Now check byte offset 1
|
|
|
|
masked = int(screen.HGRBitmap.mask_and_shift_data(
|
|
self.hgr.packed[0, 0], byte_offset=1))
|
|
dots = screen.HGRBitmap.to_dots(masked, byte_offset=1)
|
|
self.assertEqual(
|
|
(
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET,
|
|
),
|
|
colours.dots_to_nominal_colour_pixels(
|
|
18, dots, colours.HGRColours,
|
|
init_phase=screen.HGRBitmap.PHASES[1])
|
|
)
|
|
|
|
# See Figure 8.15 from Sather, "Understanding the Apple IIe"
|
|
|
|
def test_nominal_colours_sather_even_1(self):
|
|
# Extend violet into light blue
|
|
|
|
# PDCCBBAA
|
|
self.main.page_offset[0, 0] = 0b01000000
|
|
# PGGFFEED
|
|
self.main.page_offset[0, 1] = 0b10000000
|
|
|
|
self.hgr = screen.HGRBitmap(main_memory=self.main, palette=Palette.NTSC)
|
|
|
|
masked = int(screen.HGRBitmap.mask_and_shift_data(
|
|
self.hgr.packed[0, 0], byte_offset=0))
|
|
dots = screen.HGRBitmap.to_dots(masked, byte_offset=0)
|
|
|
|
self.assertEqual(
|
|
(
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.MAGENTA, # 1000
|
|
colours.HGRColours.VIOLET, # 1100
|
|
colours.HGRColours.LIGHT_BLUE, # 1110
|
|
colours.HGRColours.LIGHT_BLUE, # 1110
|
|
colours.HGRColours.MED_BLUE, # 0110
|
|
# last repeated bit from byte 0
|
|
colours.HGRColours.DARK_GREEN, # 0010
|
|
),
|
|
colours.dots_to_nominal_colour_pixels(
|
|
18, dots, colours.HGRColours,
|
|
init_phase=screen.HGRBitmap.PHASES[0])
|
|
)
|
|
|
|
def test_nominal_colours_sather_even_2(self):
|
|
# Cut off blue with black to produce dark blue
|
|
|
|
# PDCCBBAA
|
|
self.main.page_offset[0, 0] = 0b11000000
|
|
# PGGFFEED
|
|
self.main.page_offset[0, 1] = 0b00000000
|
|
|
|
self.hgr = screen.HGRBitmap(main_memory=self.main, palette=Palette.NTSC)
|
|
|
|
masked = int(screen.HGRBitmap.mask_and_shift_data(
|
|
self.hgr.packed[0, 0], byte_offset=0))
|
|
dots = screen.HGRBitmap.to_dots(masked, byte_offset=0)
|
|
|
|
self.assertEqual(
|
|
(
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.DARK_BLUE, # 0100
|
|
colours.HGRColours.DARK_BLUE,
|
|
colours.HGRColours.DARK_BLUE,
|
|
colours.HGRColours.DARK_BLUE,
|
|
colours.HGRColours.BLACK,
|
|
),
|
|
colours.dots_to_nominal_colour_pixels(
|
|
18, dots, colours.HGRColours,
|
|
init_phase=screen.HGRBitmap.PHASES[0])
|
|
)
|
|
|
|
def test_nominal_colours_sather_even_3(self):
|
|
# Cut off blue with green to produce aqua
|
|
|
|
# PDCCBBAA
|
|
self.main.page_offset[0, 0] = 0b11000000
|
|
# PGGFFEED
|
|
self.main.page_offset[0, 1] = 0b00000001
|
|
|
|
self.hgr = screen.HGRBitmap(main_memory=self.main, palette=Palette.NTSC)
|
|
|
|
masked = int(screen.HGRBitmap.mask_and_shift_data(
|
|
self.hgr.packed[0, 0], byte_offset=0))
|
|
dots = screen.HGRBitmap.to_dots(masked, byte_offset=0)
|
|
|
|
self.assertEqual(
|
|
(
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.DARK_BLUE,
|
|
colours.HGRColours.MED_BLUE,
|
|
colours.HGRColours.AQUA,
|
|
colours.HGRColours.AQUA,
|
|
colours.HGRColours.GREEN,
|
|
),
|
|
colours.dots_to_nominal_colour_pixels(
|
|
18, dots, colours.HGRColours,
|
|
init_phase=screen.HGRBitmap.PHASES[0])
|
|
)
|
|
|
|
def test_nominal_colours_sather_even_4(self):
|
|
# Cut off white with black to produce pink
|
|
|
|
# PDCCBBAA
|
|
self.main.page_offset[0, 0] = 0b11100000
|
|
# PGGFFEED
|
|
self.main.page_offset[0, 1] = 0b00000000
|
|
|
|
self.hgr = screen.HGRBitmap(main_memory=self.main, palette=Palette.NTSC)
|
|
|
|
masked = int(screen.HGRBitmap.mask_and_shift_data(
|
|
self.hgr.packed[0, 0], byte_offset=0))
|
|
dots = screen.HGRBitmap.to_dots(masked, byte_offset=0)
|
|
|
|
self.assertEqual(
|
|
(
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BROWN,
|
|
colours.HGRColours.ORANGE,
|
|
colours.HGRColours.PINK,
|
|
colours.HGRColours.PINK,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.DARK_BLUE,
|
|
colours.HGRColours.BLACK,
|
|
),
|
|
colours.dots_to_nominal_colour_pixels(
|
|
18, dots, colours.HGRColours,
|
|
init_phase=screen.HGRBitmap.PHASES[0])
|
|
)
|
|
|
|
def test_nominal_colours_sather_even_5(self):
|
|
# Cut off orange-black with green to produce bright green
|
|
|
|
# "Bright" here is because the sequence of pixels has high intensity
|
|
# Orange-Orange-Yellow-Yellow-Green-Green
|
|
|
|
# PDCCBBAA
|
|
self.main.page_offset[0, 0] = 0b10100000
|
|
# PGGFFEED
|
|
self.main.page_offset[0, 1] = 0b00000001
|
|
|
|
self.hgr = screen.HGRBitmap(main_memory=self.main, palette=Palette.NTSC)
|
|
|
|
masked = int(screen.HGRBitmap.mask_and_shift_data(
|
|
self.hgr.packed[0, 0], byte_offset=0))
|
|
dots = screen.HGRBitmap.to_dots(masked, byte_offset=0)
|
|
|
|
self.assertEqual(
|
|
(
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BROWN, # 0001
|
|
colours.HGRColours.ORANGE, # 1001
|
|
colours.HGRColours.ORANGE, # 1001
|
|
colours.HGRColours.YELLOW, # 1011
|
|
colours.HGRColours.YELLOW, # 1011
|
|
colours.HGRColours.GREEN, # 0011
|
|
colours.HGRColours.GREEN, # 0011
|
|
),
|
|
colours.dots_to_nominal_colour_pixels(
|
|
18, dots, colours.HGRColours,
|
|
init_phase=screen.HGRBitmap.PHASES[0])
|
|
)
|
|
|
|
def test_nominal_colours_sather_odd_1(self):
|
|
# Extend green into light brown
|
|
|
|
# PDCCBBAA
|
|
self.main.page_offset[0, 1] = 0b01000000
|
|
# PGGFFEED
|
|
self.main.page_offset[0, 2] = 0b10000000
|
|
|
|
self.hgr = screen.HGRBitmap(main_memory=self.main, palette=Palette.NTSC)
|
|
|
|
masked = int(screen.HGRBitmap.mask_and_shift_data(
|
|
self.hgr.packed[0, 0], byte_offset=1))
|
|
dots = screen.HGRBitmap.to_dots(masked, byte_offset=1)
|
|
|
|
self.assertEqual(
|
|
(
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.DARK_GREEN,
|
|
colours.HGRColours.GREEN,
|
|
colours.HGRColours.YELLOW,
|
|
colours.HGRColours.YELLOW,
|
|
colours.HGRColours.ORANGE,
|
|
colours.HGRColours.MAGENTA,
|
|
),
|
|
colours.dots_to_nominal_colour_pixels(
|
|
18, dots, colours.HGRColours,
|
|
init_phase=screen.HGRBitmap.PHASES[1])
|
|
)
|
|
|
|
def test_nominal_colours_sather_odd_2(self):
|
|
# Cut off orange with black to produce dark brown
|
|
|
|
# PDCCBBAA
|
|
self.main.page_offset[0, 1] = 0b11000000
|
|
# PGGFFEED
|
|
self.main.page_offset[0, 2] = 0b00000000
|
|
|
|
self.hgr = screen.HGRBitmap(main_memory=self.main, palette=Palette.NTSC)
|
|
|
|
masked = int(screen.HGRBitmap.mask_and_shift_data(
|
|
self.hgr.packed[0, 0], byte_offset=1))
|
|
dots = screen.HGRBitmap.to_dots(masked, byte_offset=1)
|
|
|
|
self.assertEqual(
|
|
(
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BROWN,
|
|
colours.HGRColours.BROWN,
|
|
colours.HGRColours.BROWN,
|
|
colours.HGRColours.BROWN,
|
|
colours.HGRColours.BLACK,
|
|
),
|
|
colours.dots_to_nominal_colour_pixels(
|
|
18, dots, colours.HGRColours,
|
|
init_phase=screen.HGRBitmap.PHASES[1])
|
|
)
|
|
|
|
def test_nominal_colours_sather_odd_3(self):
|
|
# Cut off orange with violet to produce pink
|
|
|
|
# PDCCBBAA
|
|
self.main.page_offset[0, 1] = 0b11000000
|
|
# PGGFFEED
|
|
self.main.page_offset[0, 2] = 0b00000001
|
|
|
|
self.hgr = screen.HGRBitmap(main_memory=self.main, palette=Palette.NTSC)
|
|
|
|
masked = int(screen.HGRBitmap.mask_and_shift_data(
|
|
self.hgr.packed[0, 0], byte_offset=1))
|
|
dots = screen.HGRBitmap.to_dots(masked, byte_offset=1)
|
|
|
|
self.assertEqual(
|
|
(
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BROWN,
|
|
colours.HGRColours.ORANGE,
|
|
colours.HGRColours.PINK,
|
|
colours.HGRColours.PINK,
|
|
colours.HGRColours.VIOLET,
|
|
),
|
|
colours.dots_to_nominal_colour_pixels(
|
|
18, dots, colours.HGRColours,
|
|
init_phase=screen.HGRBitmap.PHASES[1])
|
|
)
|
|
|
|
def test_nominal_colours_sather_odd_4(self):
|
|
# Cut off white with black to produce aqua
|
|
|
|
# PDCCBBAA
|
|
self.main.page_offset[0, 1] = 0b11100000
|
|
# PGGFFEED
|
|
self.main.page_offset[0, 2] = 0b00000000
|
|
|
|
self.hgr = screen.HGRBitmap(main_memory=self.main, palette=Palette.NTSC)
|
|
|
|
masked = int(screen.HGRBitmap.mask_and_shift_data(
|
|
self.hgr.packed[0, 0], byte_offset=1))
|
|
dots = screen.HGRBitmap.to_dots(masked, byte_offset=1)
|
|
|
|
self.assertEqual(
|
|
(
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.DARK_BLUE,
|
|
colours.HGRColours.MED_BLUE,
|
|
colours.HGRColours.AQUA,
|
|
colours.HGRColours.AQUA,
|
|
colours.HGRColours.GREEN,
|
|
colours.HGRColours.BROWN,
|
|
colours.HGRColours.BLACK,
|
|
),
|
|
colours.dots_to_nominal_colour_pixels(
|
|
18, dots, colours.HGRColours,
|
|
init_phase=screen.HGRBitmap.PHASES[1])
|
|
)
|
|
|
|
def test_nominal_colours_sather_odd_5(self):
|
|
# Cut off blue-black with violet to produce bright violet
|
|
|
|
# "Bright" here is because the sequence of pixels has high intensity
|
|
# Blue-Blue-Light Blue-Light Blue-Violet-Violet
|
|
|
|
# PDCCBBAA
|
|
self.main.page_offset[0, 1] = 0b10100000
|
|
# PGGFFEED
|
|
self.main.page_offset[0, 2] = 0b00000001
|
|
|
|
self.hgr = screen.HGRBitmap(main_memory=self.main, palette=Palette.NTSC)
|
|
|
|
masked = int(screen.HGRBitmap.mask_and_shift_data(
|
|
self.hgr.packed[0, 0], byte_offset=1))
|
|
dots = screen.HGRBitmap.to_dots(masked, byte_offset=1)
|
|
|
|
self.assertEqual(
|
|
(
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.BLACK,
|
|
colours.HGRColours.DARK_BLUE,
|
|
colours.HGRColours.MED_BLUE,
|
|
colours.HGRColours.MED_BLUE,
|
|
colours.HGRColours.LIGHT_BLUE,
|
|
colours.HGRColours.LIGHT_BLUE,
|
|
colours.HGRColours.VIOLET,
|
|
colours.HGRColours.VIOLET
|
|
),
|
|
colours.dots_to_nominal_colour_pixels(
|
|
18, dots, colours.HGRColours,
|
|
init_phase=screen.HGRBitmap.PHASES[1])
|
|
)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|