ii-vision/transcoder/screen_test.py

1134 lines
39 KiB
Python
Raw 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):