ii-vision/transcoder/screen_test.py

1134 lines
39 KiB
Python
Raw Permalink Normal View History

"""Tests for the screen module."""
import unittest
import numpy as np
import screen
import colours
from palette import Palette
def binary(a):
return np.vectorize("{:032b}".format)(a)
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):
"""Header extracted correctly from packed representation."""
self.assertEqual(
0b100,
screen.DHGRBitmap._make_header(
np.uint64(0b0001000011111010110000111110101000))
)
def test_make_footer(self):
"""Footer extracted correctly from packed representation."""
self.assertEqual(
0b1010000000000000000000000000000000,
screen.DHGRBitmap._make_footer(
np.uint64(0b0001000011111010110000111110101000))
)
def test_pixel_packing_offset_0(self):
"""Screen byte packing happens correctly at offset 0."""
# 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):
"""Screen byte packing happens correctly at offset 1."""
# 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):
"""Screen byte packing happens correctly at offset 127."""
# 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):
"""Test the byte_offset behaviour."""
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):
"""Test the _byte_offsets behaviour."""
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):
"""Verify that mask_and_shift_data extracts the right bit positions."""
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):
"""Verify that masked_update updates the expected bit positions."""
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):
"""Test that apply() correctly updates neighbours."""
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):
"""Test that _fix_array_neighbours DTRT after masked_update."""
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]
)
)
class TestHGRBitmap(unittest.TestCase):
def setUp(self) -> None:
self.main = screen.MemoryMap(screen_page=1)
def test_make_header(self):
"""Header extracted correctly from packed representation."""
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):
"""Footer extracted correctly from packed representation."""
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):
"""Screen byte packing happens correctly with P=0, P=0 palette bits."""
# 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):
"""Screen byte packing happens correctly with P=0, P=1 palette bits."""
# 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):
"""Screen byte packing happens correctly with P=1, P=0 palette bits."""
# 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):
"""Screen byte packing happens correctly with P=1, P=1 palette bits."""
# 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_apply(self):
"""Test that header, body and footer are placed correctly."""
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))
)
# Now check with 4 consecutive bytes, i.e. even/odd pair plus the
# neighbouring header/footer.
hgr = screen.HGRBitmap(main_memory=self.main, palette=Palette.NTSC)
hgr.apply(1, 197, False, 128)
hgr.apply(1, 198, False, 143)
hgr.apply(1, 199, False, 192)
hgr.apply(1, 200, False, 128)
want = 0b0011000000110001111100
got = hgr.packed[1, 199 // 2]
self.assertEqual(
want, got, "\n%s\n%s" % (binary(want), binary(got))
)
def test_double_pixels(self):
"""Verify behaviour of _double_pixels."""
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):
"""Verify to_dots behaviour with byte_offset=0"""
# 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):
"""Verify to_dots behaviour with byte_offset=1"""
# 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):