Device: Screen
The screen device provides access to a rectangular bitmapped screen with two layers and a sixteen-colour palette.
Port | Name | Description | Read | Write |
---|---|---|---|---|
0x50 | Width | Width of screen in pixels. | ✓ | ✓ |
0x51 | continued | continued | ✓ | ✓ |
0x52 | Height | Height of screen in pixels. | ✓ | ✓ |
0x53 | continued | continued | ✓ | ✓ |
0x54 | Horizontal position | Horizontal cursor position. | ✓ | ✓ |
0x55 | continued | continued | ✓ | ✓ |
0x56 | Vertical position | Vertical cursor position. | ✓ | ✓ |
0x57 | continued | continued | ✓ | ✓ |
0x58 | Palette | Insert colours into palette. | ✗ | ✓ |
0x59 | continued | continued | ✗ | ✓ |
0x5A | Colours | Select colours for sprite drawing. | ✗ | ✓ |
0x5B | continued | continued | ✗ | ✓ |
0x5C | Sprite | Load a sprite into sprite memory. | ✗ | ✓ |
0x5D | aliased | aliased | ✗ | ✓ |
0x5E | Draw | Draw to the screen. | ✗ | ✓ |
0x5F | Move | Move the screen cursor. | ✗ | ✓ |
The screen comprises two overlapping layers, a foreground layer and a background layer, and a sixteen-colour palette. The format of each palette colour is 4 bits per channel RGB.
Each pixel on each layer of the screen is represented by a 4 bit value which references one of the sixteen palette indices. When rendering a pixel, the pixel will be rendered as the colour referenced by the value of the background pixel if the value of the foreground pixel is zero, otherwise the pixel will be rendered as the colour referenced by the value of the foreground pixel.
The initial value of each pixel on each layer of the screen is zero.
Ports
Width
The value of this port is a double representing the width of the screen in pixels. If no screen is available, the value of this port will be zero.
Reading a byte from the first port of the pair will retrieve the value of this port, returning the high byte and caching the low byte. Reading a byte from the second port of the pair will return the cached byte. The initial value of the cached byte is zero.
Writing a byte to the first port of the pair will cache the byte written. Writing a byte to the second port of the pair will construct a double, the high byte being the cached byte and the low byte being the byte written, and then the screen width will be resized to the value of that double, if supported by the host system. The initial value of the cached byte is zero.
After the screen width has been set by a write operation, the value of each pixel on each layer of the screen will be implementation defined, and the user will be prevented from changing the screen width until the program terminates, if supported by the host system.
Height
The value of this port is a double representing the height of the screen in pixels. If no screen is available, the value of this port will be zero.
Reading a byte from the first port of the pair will retrieve the value of this port, returning the high byte and caching the low byte. Reading a byte from the second port of the pair will return the cached byte. The initial value of the cached byte is zero.
Writing a byte to the first port of the pair will cache the byte written. Writing a byte to the second port of the pair will construct a double, the high byte being the cached byte and the low byte being the byte written, and then the screen height will be resized to the value of that double, if supported by the host system. The initial value of the cached byte is zero.
After the screen height has been set by a write operation, the value of each pixel on each layer of the screen will be implementation defined, and the user will be prevented from changing the screen height until the program terminates, if supported by the host system.
Horizontal position
The value of this port is a signed double representing the horizontal component of the cursor position to be used during the next draw operation. The horizontal position of the left-most pixel of the screen is zero, and increases to the right. The initial value of this port is zero.
Vertical position
The value of this port is a signed double representing the vertical component of the cursor position to be used during the next draw operation. The vertical position of the top-most pixel of the screen is zero, and increases downwards. The initial value of this port is zero.
Palette
Writing a byte to the first port of the pair will cache the byte written. Writing a byte to the second port of the pair will cause the palette colour indexed by the upper four bits of the cached value to be overwritten, if supported by the host system. The palette colour will be overwritten by a colour with the value of the red channel being the lower four bits of the cached value, the value of the green channel being the upper four bits of the byte written, and the value of the blue channel being the lower four bits of the byte written. The initial value of the cached byte is zero.
When a palette colour is overwritten, every screen pixel which references the overwritten colour will be re-rendered as the new colour.
The initial value of each colour in the colour palette is implementation defined.
If the host system uses a two-colour monochrome screen, the first and then every second palette index will map to the off colour, and the second and then every second palette index will map to the on colour. If the host system uses a three-colour monochrome screen, the fourth and then every fourth palette index will instead map to the intermediate colour. If the host system uses a four-colour monochrome screen, the third and then every fourth palette index will instead map to the dim intermediate colour, and the fourth and then every fourth palette index will instead map to the bright intermediate colour.
Colours
The value of this port is a double representing the four palette indices to use when drawing a sprite to the screen. The upper four bits of the first port represent the first sprite colour, the lower four bits of the first port represent the second sprite colour, the upper four bits of the second port represent the third sprite colour, and the lower four bits of the second port represent the fourth sprite colour.
The initial value of this port is zero.
Sprite
This port is associated with a 16-byte circular buffer which holds sprite pixel data, and a 4-bit buffer pointer which contains the address of the buffer location which represents the first byte of the sprite. The initial value of each byte of buffer memory is zero. The initial value of the buffer pointer is implementation defined.
Writing a byte to either port of the pair will write the byte to the buffer location referenced by the buffer pointer, and then will increment the value of the buffer pointer by 1, wrapping to zero on overflow.
The buffer memory is divided into two planes, positioned relative to the value of the buffer pointer. A plane is represented by an array of eight bytes. The upper eight bytes of memory, starting from the buffer location referenced by the value of the buffer pointer, represent the high plane. The second eight bytes of memory, starting from the buffer location directly following the upper plane, represent the low plane.
A sprite is an image 8 pixels wide and 8 pixels high. A 1-bit sprite can contain up to two different colours, with the colour of each pixel represented by a 1-bit value. A 2-bit sprite can contain up to four different colours, with the colour of each pixel represented by a 2-bit value.
The pixel values of a 1-bit sprite are determined by the low plane of buffer memory. Each byte of the low plane represents one row of the sprite, with the first byte representing the top row of the sprite and each subsequent byte representing the next row downwards. Each bit of a byte represents the colour of one pixel of a row, with the highest bit representing the colour of the left-most pixel of the row and each subsequent bit representing the colour of the next pixel rightwards. If the bit representing a pixel is set, the pixel will be drawn as the second sprite colour, otherwise the pixel will be drawn as the first sprite colour.
The pixel values of a 2-bit sprite are determined by both the high and low planes of buffer memory. Each bit of each byte of each plane maps to the pixels of the sprite in the same way as for a 1-bit sprite, with each pixel of the sprite being represented by one bit of the high plane and one bit of the low plane. If both the high and low bits are set, the pixel will be drawn as the fourth sprite colour. If the high bit is set and the low bit is unset, the pixel will be drawn as the third sprite colour. If the high bit is unset and the low bit is set, the pixel will be drawn as the second sprite colour. Otherwise, the pixel will be drawn as the first sprite colour.
Draw
Writing a byte to this port will perform a draw operation to the screen. The upper four bits of the byte written represent the operation to be performed, as per the following table.
Value | Layer | Vector | Size | Sprite | Operation |
---|---|---|---|---|---|
0x0 | ✗ | ✗ | ✗ | ✗ | Draw a pixel to the background layer. |
0x1 | ✗ | ✗ | ✗ | ✓ | Draw a 1-bit sprite to the background layer. |
0x2 | ✗ | ✗ | ✓ | ✗ | Fill the background layer with a solid colour. |
0x3 | ✗ | ✗ | ✓ | ✓ | Draw a 2-bit sprite to the background layer. |
0x4 | ✗ | ✓ | ✗ | ✗ | Draw a solid line to the background layer. |
0x5 | ✗ | ✓ | ✗ | ✓ | Draw a 1-bit textured line to the background layer. |
0x6 | ✗ | ✓ | ✓ | ✗ | Draw a solid rectangle to the background layer. |
0x7 | ✗ | ✓ | ✓ | ✓ | Draw a 1-bit textured rectangle to the background layer. |
0x8 | ✓ | ✗ | ✗ | ✗ | Draw a pixel to the foreground layer. |
0x9 | ✓ | ✗ | ✗ | ✓ | Draw a 1-bit sprite to the foreground layer. |
0xA | ✓ | ✗ | ✓ | ✗ | Fill the foreground layer with a solid colour. |
0xB | ✓ | ✗ | ✓ | ✓ | Draw a 2-bit sprite to the foreground layer. |
0xC | ✓ | ✓ | ✗ | ✗ | Draw a solid line to the foreground layer. |
0xD | ✓ | ✓ | ✗ | ✓ | Draw a 1-bit textured line to the foreground layer. |
0xE | ✓ | ✓ | ✓ | ✗ | Draw a solid rectangle to the foreground layer. |
0xF | ✓ | ✓ | ✓ | ✓ | Draw a 1-bit textured rectangle to the foreground layer. |
Depending on the operation, the lower four bits of the byte written will represent either the palette index of the colour used for this operation, referred to as the active colour, or the sprite transformation used for this operation, referred to as the active transformation and described by the following table.
Bit | Mask | Name |
---|---|---|
0x7 | 0x80 | Layer |
0x6 | 0x40 | Vector |
0x5 | 0x20 | Size |
0x4 | 0x10 | Sprite |
0x3 | 0x08 | Transparent |
0x2 | 0x04 | Flip diagonal |
0x1 | 0x02 | Flip vertical |
0x0 | 0x01 | Flip horizontal |
If the flip horizontal flag is set, the order of the columns of the sprite will be reversed. Then, if the flip vertical bit is set, the order of the rows of the sprite will be reversed. Then, if the flip diagonal bit is set, the sprite is transposed such that each row of the sprite from top to bottom becomes a column from left to right, with the pixels of a row from left to right becoming the pixels of a column from top to bottom.
If the transparent bit of the active transformation is set, each pixel of the sprite which would be drawn using the first sprite colour is instead not drawn.
The current cursor position is a point with the horizontal component being a signed integer represented by the value of the horizontal position port and the vertical component being a signed integer represented by the value of the vertical position port. The previous cursor position is the point which was the current cursor position during the previous draw operation. The initial vaue of the previous cursor position is a point with a horizontal component of zero and a vertical component of zero.
When drawing a pixel to a layer, the pixel on that layer at the current cursor position will be set to the active colour.
When filling a layer with a solid colour, every pixel on that layer will be set to the active colour.
When drawing a 1-bit sprite to a layer, a 1-bit sprite is read from the sprite buffer, then the active transformation is applied to the sprite, and then each pixel of the sprite is drawn to the layer, with the top-left pixel of the sprite being placed at the current cursor position.
When drawing a 2-bit sprite to a layer, a 2-bit sprite is read from the sprite buffer, then the active transformation is applied to the sprite, and then each pixel of the sprite is drawn to the layer, with the top-left pixel of the sprite being placed at the current cursor position.
When drawing a solid line to a layer, all pixels on that layer which belong to the shortest line of pixels connected orthogonally or diagonally between the previous cursor position and the current cursor position will be set to the active colour.
When drawing a solid rectangle to a layer, all pixels on that layer which belong to the smallest axis-aligned rectangle containing both the previous cursor position and the current cursor position will be set to the active colour.
When drawing a 1-bit textured rectangle to a layer, a 1-bit sprite is read from the sprite buffer, then the active transformation is applied to the sprite, and then each pixel on that layer which belongs to the shortest line of pixels connected orthogonally or diagonally between the previous cursor position and the current cursor position will be drawn as the corresponding sprite pixel.
When drawing a 1-bit textured rectangle to a layer, a 1-bit sprite is read from the sprite buffer, then the active transformation is applied to the sprite, and then each pixel on that layer which belongs to the smallest axis-aligned rectangle containing both the previous cursor position and the current cursor position will be drawn as the corresponding sprite pixel.
The sprite pixel which corresponds with a given screen pixel is the sprite pixel that, were the sprite to be drawn from the top-left pixel of the screen and then tiled seamlessly rightwards and downwards, would be drawn at the same position as the given screen pixel.
Move
Writing a byte to this port will move the cursor position by a distance and in a direction represented by the value of the byte written. The highest two bits of the byte written represent the direction in which to move the cursor, and the lower six bits of the byte written represent the distance by which to move the cursor, as per the following table.
Bit | Mask | Purpose |
---|---|---|
0x7 | 0x80 | Negative |
0x6 | 0x40 | Vertical |
... | 0x3f | Distance |
If both the negative and vertical bits are set, the distance will be subtracted from the value of the vertical position port, moving the cursor upwards. If the negative bit is set and the vertical bit is unset, the distance will be subtracted from the value of the horizontal position port, moving the cursor leftwards. If the negative bit is unset and the vertical bit is set, the distance will be added to the value of the vertical position port, moving the cursor downwards. Otherwise, the distance will be added to the value of the horizontal position port, moving the cursor rightwards. The values will wrap around on underflow or overflow.
The distance by which the cursor will be moved is represented by the value of the lower six bits of the byte written. The minimum value is 0x00
, representing a distance of zero pixels, and the maximum value is 0x3f
, representing a distance of 63 pixels.
System wake
This device will send a wake event to the system device when the size of the screen changes, other than as a result of a write operation to the screen width or screen height ports, or when the screen contents have been damaged. The value of each pixel on each layer of the screen after this device wakes the system from sleep is implementation defined.