Nametable Package

Submodules

Animator Module

class AnimatedProtocol(*args, **kwargs)

Bases: Protocol

A class that ensures that the animator dictates which frame is being shown for an animated object.

Attributes
animator: The instance of the animator controlling the frame shown.
animator: nametable.Animator.AnimatorProtocol
class Animator(frame: int)

Bases: object

A generic implementation of AnimatorProtocol that utilizes a simple dataclass().

Attributes
frame: int

The current frame that the AnimatedProtocol is on.

frame: int
class AnimatorProtocol(*args, **kwargs)

Bases: Protocol

A class that handles the changing one an integer, representing the frame that the AnimatedProtocol is on.

Attributes
frame: The current frame that the :class:`~nametable.Animator.AnimatedProtocol` is on.
frame: int

Block Module

class Block(pattern_table: nametable.PatternTable.PatternTableProtocol, patterns: tuple[int, int, int, int])

Bases: object

A generic implementation of BlockProtocol that utilizes a simple dataclass().

Raises
BlockInvalidSizeException

Raised if the length of patterns is not equal to four.

PatternTableIndexException

Raise if any index inside patterns would result in an IndexError.

Examples

To create an instance of a Block.

>>> Block(
...     PatternTable(
...         (
...             Pattern(PatternMeta
...                 (
...                     bytes.fromhex("41 C2 44 48 10 20 40 80 01 02 04 08 16 21 42 87"))
...                 ),
...         )
...     ),
...     (0, 0, 0, 0,)
... )
Block(PatternTable((Pattern(PatternMeta(...)),)), (0, 0, 0, 0,))
Attributes
pattern_table: PatternTableProtocol

The instance of PatternTableProtocol to serve as the lookup table of instances of PatternProtocol.

patterns: tuple[int, int, int, int]

The indexes into pattern_table to create instances of PatternProtocol from.

property numpy_array: numpy.ndarray[Any, numpy.dtype[numpy.uint8]]

Generates a two dimensional array with two bits per pixel, representing the respective instances of PatternProtocol numpy_array concatenate together to form a 16 by 16 pixel grid. The order of they are shown is top left, top right, bottom left, bottom right, respectively.

Returns
NDArray[ubyte]

This instance represented as an array.

Examples

To create an instance of a Block.

>>> block = Block(
...     PatternTable(
...         (
...             Pattern(PatternMeta
...                 (
...                     bytes.fromhex("41 C2 44 48 10 20 40 80 01 02 04 08 16 21 42 87"))
...                 ),
...         )
...     ),
...     (0, 0, 0, 0,)
... )
>>> block.numpy_array
array(
    [
        [0, 1, 0, 0, 0, 0, 0, 3, 0, 1, 0, 0, 0, 0, 0, 3],
        [1, 1, 0, 0, 0, 0, 3, 0, 1, 1, 0, 0, 0, 0, 3, 0],
        [0, 1, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0],
        [0, 1, 0, 0, 3, 0, 0, 0, 0, 1, 0, 0, 3, 0, 0, 0],
        [0, 0, 0, 3, 0, 2, 2, 0, 0, 0, 0, 3, 0, 2, 2, 0],
        [0, 0, 3, 0, 0, 0, 0, 2, 0, 0, 3, 0, 0, 0, 0, 2],
        [0, 3, 0, 0, 0, 0, 2, 0, 0, 3, 0, 0, 0, 0, 2, 0],
        [3, 0, 0, 0, 0, 2, 2, 2, 3, 0, 0, 0, 0, 2, 2, 2],
        [0, 1, 0, 0, 0, 0, 0, 3, 0, 1, 0, 0, 0, 0, 0, 3],
        [1, 1, 0, 0, 0, 0, 3, 0, 1, 1, 0, 0, 0, 0, 3, 0],
        [0, 1, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0],
        [0, 1, 0, 0, 3, 0, 0, 0, 0, 1, 0, 0, 3, 0, 0, 0],
        [0, 0, 0, 3, 0, 2, 2, 0, 0, 0, 0, 3, 0, 2, 2, 0],
        [0, 0, 3, 0, 0, 0, 0, 2, 0, 0, 3, 0, 0, 0, 0, 2],
        [0, 3, 0, 0, 0, 0, 2, 0, 0, 3, 0, 0, 0, 0, 2, 0],
        [3, 0, 0, 0, 0, 2, 2, 2, 3, 0, 0, 0, 0, 2, 2, 2],
    ],
    dtype=ubyte,
)
pattern_table: nametable.PatternTable.PatternTableProtocol
patterns: tuple[int, int, int, int]
exception BlockInvalidSizeException

Bases: ValueError

Raised when the length of patterns is an invalid size for a BlockProtocol.

class BlockProtocol(*args, **kwargs)

Bases: Protocol

A representation of a combination of four instances of PatternProtocol. Despite sounding unintuitive, this format was widely adopted throughout NES development due to limitations of the Picture Processing Unit: ‘PPU’ and memory space on the NES: The PPU attribute tables could only change the color attribute every 16 pixel in both dimensions, known as a ‘Block’. Similarly, to store each Pattern of each Block as a list in memory would take up the kilobytes of memory. By storing common sections of 2x2 Patterns, most programmers during this era found that memory required was dramatically reduced.

Attributes
pattern_table: PatternTableProtocol

The instance of PatternTableProtocol to serve as the lookup table of instances of PatternProtocol.

patterns: tuple[int, int, int, int]

The indexes into pattern_table to create instances of PatternProtocol from.

property numpy_array: numpy.ndarray[Any, numpy.dtype[numpy.uint8]]

Generates a two dimensional array with two bits per pixel, representing the respective instances of PatternProtocol numpy_array concatenate together to form a 16 by 16 pixel grid. The order of they are shown is top left, top right, bottom left, bottom right, respectively.

Returns
NDArray[ubyte]

This instance represented as an array.

pattern_table: nametable.PatternTable.PatternTableProtocol
patterns: tuple[int, int, int, int]
exception PatternTableIndexException

Bases: IndexError

Raised when the int inside patterns is an invalid index into pattern_array of pattern_table.

Nametable Module

class Nametable(blocks: tuple)

Bases: object

blocks: tuple[nametable.Block.BlockProtocol, ...]
class NametableProtocol(*args, **kwargs)

Bases: Protocol

blocks: tuple[nametable.Block.BlockProtocol, ...]

Pattern Module

class Pattern(meta: nametable.PatternMeta.PatternMeta)

Bases: object

A generic implementation of PatternProtocol.

classmethod from_numpy_array(array: numpy.ndarray[Any, numpy.dtype[numpy.uint8]])

Wraps from_numpy_array() to create an instance directly.

Parameters
arrayNDArray[ubyte]

The numpy array to be converted.

See also

PatternProtocol
property meta: nametable.PatternMeta.PatternMeta

Provides the wrapped meta class that the instance is representing.

Returns
PatternMeta

The current PatternMeta that this instance is representing.

property numpy_array: numpy.ndarray[Any, numpy.dtype[numpy.uint8]]

Provides a Numpy array that represents the pattern as a 2D matrix of the pixels of the pattern.

Returns
NDArray[ubyte]

The array is equivalent to the meta that the instance is representing.

Notes

The instance ensures that array provided is identical to the wrapped meta it represents.

This method is more efficient than the meta instance, with the results being cached, dramatically reducing math operations for large-scale operations.

The array provided should never be modified. If it is modified, this will interfere with the caching of the Pattern and may cause undesired artifacts.

Examples

When creating the instance, the class will check if the an equivalent instance of meta was already utilized to create this class. If one exists, it will return the instance of the already instantiated Pattern, otherwise it will create a new instance and cache it into a weak reference dictionary for future instantiations.

>>> meta = PatternMeta(bytes.fromhex("41 C2 44 48 10 20 40 80 01 02 04 08 16 21 42 87"))
>>> pattern1 = Pattern(meta)
>>> pattern2 = Pattern(meta)
>>> pattern1 is pattern2
True

Likewise, when creating an array, the Pattern will cache the result after its first creation. The following code will only result in one execution of a numpy array.

>>> pattern1.numpy_array
...
>>> pattern2.numpy_array
...
class PatternProtocol(*args, **kwargs)

Bases: Protocol

An Object Oriented wrapper around PatternMeta. This class enables easier extensions and edits on PatternMeta without needing to understand the internals of the NES.

property meta: nametable.PatternMeta.PatternMeta

Provides the wrapped meta class that the instance is representing.

Returns
PatternMeta

The current PatternMeta that this instance is representing.

property numpy_array: numpy.ndarray[Any, numpy.dtype[numpy.uint8]]

Provides a Numpy array that represents the pattern as a 2D matrix of the pixels of the pattern.

Returns
NDArray[ubyte]

The array is equivalent to the meta that the instance is representing.

See also

PatternMeta

Notes

The purpose of extending the responsibility of creating an array to this instance is to provide additional ability to cache and utilize other techniques to improve performance.

PatternAnimated Module

class PatternAnimated(stack: tuple[nametable.Pattern.PatternProtocol], animator: nametable.Animator.AnimatorProtocol)

Bases: object

A generic implementation of PatternAnimatedProtocol that utilizes an instance of AnimatorProtocol to dictate the PatternMeta meta for the instance from a tuple of PatternProtocol.

Notes

The user must ensure that the animator must never have a frame greater than the length of stack.

Attributes
stack: tuple[PatternProtocol]

A tuple of patterns that the instance’s animator selects from for a given frame.

animator: AnimatorProtocol

The instance of the animator controlling the frame shown.

animator: nametable.Animator.AnimatorProtocol
property meta: nametable.PatternMeta.PatternMeta

Provides the meta the wrapped meta class that the pattern of the current nametable.Pattern.PatternProtocol inside stack is representing.

Returns
PatternMeta

The current PatternMeta that this instance is representing, dictated by animator.

Examples

The animator can dynamically change the meta provided

>>> data = bytes.fromhex("41 C2 44 48 10 20 40 80 01 02 04 08 16 21 42 87")
>>> pattern = PatternAnimated(
...     (Pattern(PatternMeta(data)), Pattern(PatternMeta(data[::-1]))),
...     Animator(0)
... )
>>> pattern.meta
PatternMeta(data)
>>> pattern.animator.frame = 1
>>> pattern.meta
PatternMeta(data[::-1])
property numpy_array: numpy.ndarray[Any, numpy.dtype[numpy.uint8]]

Provides an array that represents the pattern as a 2D matrix of the pixels of the pattern of the current nametable.Pattern.PatternProtocol inside stack.

Returns
NDArray[ubyte]

The array of the current nametable.Pattern.PatternProtocol dictated by animator.

Examples

The animator can dynamically change the array provided

>>> data = bytes.fromhex("41 C2 44 48 10 20 40 80 01 02 04 08 16 21 42 87")
>>> pattern = PatternAnimated(
...     (Pattern(PatternMeta(data)), Pattern(PatternMeta(data[::-1]))),
...     Animator(0)
... )
>>> pattern.numpy_array
array(
    [
        [0, 1, 0, 0, 0, 0, 0, 3],
        [1, 1, 0, 0, 0, 0, 3, 0],
        [0, 1, 0, 0, 0, 3, 0, 0],
        [0, 1, 0, 0, 3, 0, 0, 0],
        [0, 0, 0, 3, 0, 2, 2, 0],
        [0, 0, 3, 0, 0, 0, 0, 2],
        [0, 3, 0, 0, 0, 0, 2, 0],
        [3, 0, 0, 0, 0, 2, 2, 2],
    ],
    dtype=ubyte,
)
>>> pattern.animator.frame = 1
>>> pattern.numpy_array
array(
    [
        [0, 0, 0, 3, 0, 1, 0, 0],
        [0, 0, 3, 0, 1, 1, 0, 0],
        [0, 3, 0, 0, 0, 1, 0, 0],
        [3, 0, 0, 0, 0, 1, 0, 0],
        [0, 2, 2, 0, 0, 0, 0, 3],
        [0, 0, 0, 2, 0, 0, 1, 2],
        [0, 0, 2, 0, 0, 1, 2, 0],
        [0, 2, 2, 2, 2, 1, 1, 0],
    ],
    dtype=ubyte,
)
stack: tuple[nametable.Pattern.PatternProtocol]
class PatternAnimatedProtocol(*args, **kwargs)

Bases: nametable.Pattern.PatternProtocol, nametable.Animator.AnimatedProtocol, Protocol

A PatternProtocol that determines the PatternMeta that is represented by the frame inside AnimatorProtocol.

Attributes
animator: AnimatorProtocol

The instance of the animator controlling the frame shown.

animator: nametable.Animator.AnimatorProtocol

PatternMeta Module

class PatternMeta(data: bytes)

Bases: object

A wrapper around a fixed series of 16 bytes that represents an eight by eight square for a two bit image, typically associated with the Nintendo Entertainment System.

This format is derived from the Picture Processing Unit: ‘PPU’. The PPU functioned as a primitive graphics card for the NES, allowing a hard-wired implementation for graphics to be streamlined from the CPU onto the consumer’s television. This development enabled a great advance in the sophistication of graphics and hardware. Prior consoles, such as the Atari 2600 had to race the beam to render graphics onto the screen. With the fixed format of the PPU, much of the overhead that previously burdened the developer was reduced into a space in RAM devoted to a few flags and memory used for sprites and background graphics. The core element of this was the Tile, which is synonymous with Pattern. This class utilizes this format and fluffs the one dimensional byte array into a two dimensional array of bytes, which can easily be transposed into other picture formats for editing and viewing. Likewise, it can flatten these two dimensional arrays back down into the format utilized by the PPU.

See also

Pattern

Notes

For large creation of patterns, it is recommended that Pattern should be used instead. Pattern will store multiple copies of the same pattern as one type, and enable more sophisticated use throughout the program. Specifically, it is easier to extend, due to not being immutable.

Examples

To create a pattern, provide a series of 16 bytes.

>>> pattern = PatternMeta(bytes.fromhex("41 C2 44 48 10 20 40 80 01 02 04 08 16 21 42 87"))
>>> pattern
PatternMeta(b'...')
HEIGHT = 8
WIDTH = 8
data: bytes
classmethod from_numpy_array(array: numpy.ndarray[Any, numpy.dtype[numpy.uint8]])

Flattens a two dimensional array into a fixed series of 16 bytes that represent a two bits per pixel pattern that was commonly used for the NES. Each byte inside the two dimensional array is expected to contain only two bits. If other bits are set, they will be strictly ignored, as the NES format does not enable such modifications.

Parameters
arrayNDArray[ubyte]

The numpy array to be converted.

Examples

Any two dimension array of type ubyte, with the representation of two bits and a size of (8, 8) can be transferred back to a pattern.

>>> pattern1 = PatternMeta(bytes.fromhex("41 C2 44 48 10 20 40 80 01 02 04 08 16 21 42 87"))
>>> pattern2 = PatterMeta.from_numpy_array(pattern1.numpy_array)
>>> pattern1 == pattern2
True

If more than two bits are represented inside an array, those bits will be truncated.

>>> modified_array = pattern1.numpy_array
>>> modified_array[0][0] = 0b1111
>>> pattern3 = PatternMeta.from_numpy_array(modified_array)
>>> pattern1 == pattern3
False
>>> modified_array[0][0] = 0b1100
>>> pattern4 = PatternMeta.from_numpy_array(modified_array)
>>> pattern1 == pattern4
True
property numpy_array: numpy.ndarray[Any, numpy.dtype[numpy.uint8]]

Fluffs the byte array into a two dimensional array with two bits per pixel, as specified in the pattern format.

Returns
NDArray[ubyte]

The PatternMeta represented as an array.

Notes

The format of a pattern is represented by two fixed series of eight bytes. The series represent the first and second bit of the palette index of the pattern, respectively. If the neither bit is set, the pixel is transparent.

In the diagram below, ‘.’ represents a transparent pixel. Numbers 1, 2, 3 represent the palette index for a given pattern.:

Bit Planes                  Pixel Pattern
[0x0] = 0x41 = 0b01000001
[0x1] = 0xC2 = 0b11000010
[0x2] = 0x44 = 0b01000100
[0x3] = 0x48 = 0b01001000
[0x4] = 0x10 = 0b00010000
[0x5] = 0x20 = 0b00100000         .1.....3
[0x6] = 0x40 = 0b01000000         11....3.
[0x7] = 0x80 = 0b10000000  =====  .1...3..
                                  .1..3...
[0x8] = 0x01 = 0b00000001  =====  ...3.22.
[0x9] = 0x02 = 0b00000010         ..3....2
[0xA] = 0x04 = 0b00000100         .3....2.
[0xB] = 0x08 = 0b00001000         3....222
[0xC] = 0x16 = 0b00010110
[0xD] = 0x21 = 0b00100001
[0xE] = 0x42 = 0b01000010
[0xF] = 0x87 = 0b10000111

Examples

Any pattern can be transferred to a 2 dimensional array.

>>> pattern = PatternMeta(bytes.fromhex("41 C2 44 48 10 20 40 80 01 02 04 08 16 21 42 87"))
>>> pattern_array = pattern.numpy_array
>>> pattern_array
array(
    [
        [0, 1, 0, 0, 0, 0, 0, 3],
        [1, 1, 0, 0, 0, 0, 3, 0],
        [0, 1, 0, 0, 0, 3, 0, 0],
        [0, 1, 0, 0, 3, 0, 0, 0],
        [0, 0, 0, 3, 0, 2, 2, 0],
        [0, 0, 3, 0, 0, 0, 0, 2],
        [0, 3, 0, 0, 0, 0, 2, 0],
        [3, 0, 0, 0, 0, 2, 2, 2],
    ],
    dtype=ubyte,
)

PatternTable Module

class PatternTable(pattern_array: tuple[nametable.Pattern.Pattern, ...])

Bases: object

A generic implementation of PatternTableProtocol that utilizes a simple dataclass().

Attributes
pattern_array: tuple[Pattern, …]

A group of Patterns used for quickly indexing BlockProtocol.

pattern_array: tuple[nametable.Pattern.Pattern, ...]
class PatternTableProtocol(*args, **kwargs)

Bases: Protocol

A wrapper around a tuple of Pattern that represent the field of possible Patterns available on a given item. This enabled a byte to index the range of patterns on the PPU to form BlockProtocol on the Picture Processing Unit:.

Attributes
pattern_array: tuple[Pattern, …]

A group of Patterns used for quickly indexing BlockProtocol.

pattern_array: tuple[nametable.Pattern.Pattern, ...]

PatternTableAnimated Module

class PatternTableAnimated(pattern_tables: tuple[nametable.PatternTable.PatternTableProtocol], animator: nametable.Animator.AnimatorProtocol)

Bases: object

A generic implementation of PatternTableAnimatedProtocol that determines the pattern_tables from the frame specified inside AnimatorProtocol.

Attributes
pattern_array: tuple[Pattern, …]

A group of Patterns used for quickly indexing BlockProtocol.

animator: AnimatorProtocol

The instance of the animator controlling the frame shown.

animator: nametable.Animator.AnimatorProtocol
property pattern_array: tuple[nametable.Pattern.Pattern, ...]
pattern_tables: tuple[nametable.PatternTable.PatternTableProtocol]
class PatternTableAnimatedProtocol(*args, **kwargs)

Bases: nametable.PatternTable.PatternTableProtocol, nametable.Animator.AnimatedProtocol, Protocol

A PatternTableProtocol that determines the pattern_array from AnimatorProtocol denoted by AnimatedProtocol.

See also

PatternTable
Attributes
pattern_array: tuple[Pattern, …]

A group of Patterns used for quickly indexing BlockProtocol.

animator: AnimatorProtocol

The instance of the animator controlling the frame shown.

pattern_array: tuple[nametable.Pattern.Pattern, ...]

Module contents