This specification describes the screen device of the Bedrock computer system.
The screen device provides access to a two-layer raster screen with a configurable 16-colour palette.
Ports
Port | Name | Description | Read | Write |
---|---|---|---|---|
0x50 |
Horizontal coordinate | Horizontal cursor coordinate. | ✓ | ✓ |
0x51 |
grouped | grouped | ✓ | ✓ |
0x52 |
Vertical coordinate | Vertical cursor coordinate. | ✓ | ✓ |
0x53 |
grouped | grouped | ✓ | ✓ |
0x54 |
Screen width | Horizontal screen dimension. | ✓ | ✓ |
0x55 |
grouped | grouped | ✓ | ✓ |
0x56 |
Screen height | Vertical screen dimension. | ✓ | ✓ |
0x57 |
grouped | grouped | ✓ | ✓ |
0x58 |
Palette | Colour palette input. | ✗ | ✓ |
0x59 |
grouped | grouped | ✗ | ✓ |
0x5A |
Colours | Sprite colour selector. | ✗ | ✓ |
0x5B |
grouped | grouped | ✗ | ✓ |
0x5C |
Sprite | Sprite buffer input. | ✗ | ✓ |
0x5D |
aliased | aliased | ✗ | ✓ |
0x5E |
Draw | Draw to the screen. | ✗ | ✓ |
0x5F |
Move | Move the screen cursor. | ✗ | ✓ |
Horizontal coordinate
This port group is associated with the horizontal coordinate of the screen cursor, and exposes that coordinate for reading and writing.
Vertical coordinate
This port group is associated with the vertical coordinate of the screen cursor, and exposes that coordinate for reading and writing.
Screen width
Reading from this port group will perform an atomic read, returning the width of the screen in pixels. If no screen is available, the value zero will be returned.
Writing to this port group will perform a cached write, requesting that the width of the screen be changed and locked to the value written on commit. Locking will not prevent this port from changing the width again.
Screen height
Reading from this port group will perform an atomic read, returning the height of the screen in pixels. If no screen is available, the value zero will be returned.
Writing to this port group will perform a cached write, requesting that the height of the screen be changed and locked to the value written on commit. Locking will not prevent this port from changing the height again.
Palette
Writing to this port group will perform an atomic write, changing a colour in the screen palette on commit.
The upper four bits of the value written determine the palette index that will be overwritten by this colour, and the remaining bits represent the values of the red, green, and blue channels of the colour.
Bits | Description |
---|---|
0xF000 |
Palette index |
0x0F00 |
Red channel |
0x00F0 |
Green channel |
0x000F |
Blue channel |
Colours
Writing to this port group will set the sprite colour list value to the value written.
Sprite
Writing to this port will write the byte written to the sprite buffer.
Draw
Writing to this port will perform a draw operation according to the byte written. The upper four bits determine the operation to be performed, as follows:
Value | Operation |
---|---|
0x0_ |
Set the colour of a pixel in 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_ |
Set the colour of a pixel in 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. |
If bit 0x10
of the byte written is not set, the lower four bits of the byte will represent the palette colour to use. Otherwise, the lower four bits will represent the sprite transformation to apply, as follows:
Bit | Name | Description |
---|---|---|
0x_8 |
Flip X | Flip sprite across vertical center-line. |
0x_4 |
Flip Y | Flip sprite across horizontal center-line. |
0x_2 |
Flip diagonal | Flip sprite across top-left bottom-right diagonal. |
0x_1 |
Transparent | Don’t draw sprite pixels that use sprite colour 0. |
The current cursor position is the current position of the screen cursor. The previous cursor position is the position of the screen cursor during the previous draw operation, or the origin if no draw operation has been performed.
When setting the colour of a pixel on a layer, the pixel on that layer at the current cursor position is changed to the given colour.
When filling a layer with a solid colour, each pixel on that layer is changed to the given colour.
When drawing a sprite to a layer, the sprite is read from the sprite buffer, then the given transformation is applied, and then each pixel of the sprite is drawn to that layer, with the top-left pixel of the sprite placed at the current cursor position.
When drawing a line to a layer, each pixel on the layer belonging to the shortest line that connects the previous and current cursor positions will be affected. Line pixels can connect diagonally or orthogonally. The algorithm chosen must be stable.
When drawing a rectangle to a layer, each pixel on the layer belonging to the smallest axis-aligned rectangle that contains both the previous and current cursor positions will be affected.
When drawing a solid line or rectangle, each pixel belonging to the line or rectangle will be changed to the given colour.
When drawing a textured line or rectangle, a 1-bit sprite is read from the sprite buffer, then the given transformation is applied, and then each pixel belonging to the line or rectangle will be drawn as the corresponding sprite pixel, as if the sprite were tiled outwards from the top-left corner of the screen.
Move
Writing to this port will move the screen cursor a number of pixels in a given direction according to the byte written. The upper two bits determine the direction to move, and the lower six bits determine the distance:
Bit | Name |
---|---|
0x80 |
Operation |
0x40 |
Axis |
0x3F |
Distance |
If bit 0x80
is not set, the distance will be added to the chosen axis, else the distance will be subtracted. If bit 0x40
is not set, the horizontal axis of the screen cursor will be modified, else the vertical axis will be modified.
Value | Direction |
---|---|
0x00 |
Rightwards |
0x40 |
Downwards |
0x80 |
Leftwards |
0xC0 |
Upwards |
Data structures
Screen layer
The screen is made up of two layers, the foreground layer and the background layer. Each screen pixel is rendered using the foreground colour of the pixel if it is not colour zero, otherwise it will be rendered using the background colour of the pixel. The initial foreground and background colour of each pixel is colour zero.
Screen palette
The screen has a 16-colour palette, with colours numbered 0 through 15. Each colour is stored as a 12-bit RGB value, 4 bits per channel. The initial value of each colour in the palette is implementation defined.
For a two-colour screen with a fixed palette, every second colour maps to on and every other colour maps to off. For a three-colour screen, every fourth colour maps instead to grey. For a four-colour screen, the third and fourth colours of every four map instead to dim grey and bright grey.
Index | 2 colour | 3 colour | 4 colour |
---|---|---|---|
0,4,8,C |
Off | Off | Off |
1,5,9,D |
On | On | On |
2,6,A,E |
Off | Off | Dim |
3,7,B,F |
On | Grey | Bright |
Screen cursor
The screen cursor is a two-dimensional point that determines the pixel location for the next draw operation.
The screen cursor has a horizontal coordinate that increases rightwards, and a vertical coordinate that increases downwards. Each coordinate is stored as a signed 16-bit integer. The origin is the top-left pixel of the screen. The initial value of each coordinate is zero.
Sprite colour
A sprite colour is one of the four palette colours that are used when drawing a sprite to the screen. Each colour is a 4-bit palette index, and all four colours are packed together and stored as a single 16-bit sprite colour list value. The initial value of each sprite colour is zero.
Bits | Description |
---|---|
0xF000 |
Index of sprite colour 0 |
0x0F00 |
Index of sprite colour 1 |
0x00F0 |
Index of sprite colour 2 |
0x000F |
Index of sprite colour 3 |
Sprite buffer
The sprite buffer is a 16-byte block of writeable memory with an associated pointer. The sprite buffer contains the pixel data of the current 1-bit and 2-bit sprite. The initial value of each byte of the buffer is zero. The initial value of the pointer is zero.
The sprite buffer is divided into two 8-byte planes by the buffer pointer. The high plane is made up of the eight bytes starting at the address referenced by the pointer, and the low plane is made up of the remaining eight bytes.
Reading a plane from the sprite buffer does not affect the pointer value.
Writing a byte to the sprite buffer will write that byte to the buffer address referenced by the pointer, and then will increment the pointer by 1, wrapping to zero after 15.
Sprite data
A sprite is a small square image, eight pixels by eight pixels. A 1-bit sprite is eight bytes long and can use up to two colours, and a 2-bit sprite is sixteen bytes long and can use up to four colours.
Each plane in the sprite buffer contains 1 bit of data per sprite pixel. Each byte of a plane maps to a row of the sprite, ordered top to bottom. Each bit of a byte maps to a pixel in the row, ordered left to right, from highest bit to lowest.
A 1-bit sprite is drawn using the low plane of the sprite buffer, each pixel corresponding with a 1-bit colour value.
A 2-bit sprite is drawn using both the high and low planes of the sprite buffer, each pixel corresponding with a 2-bit colour value. The high plane determines the high bit of each colour value and the low plane defines the low bit.
Each pixel of a sprite is drawn using the sprite colour that corresponds with the colour value of the pixel.
Value | High | Low | Description |
---|---|---|---|
0 |
0 |
0 |
Pixel uses sprite colour 0 |
1 |
0 |
1 |
Pixel uses sprite colour 1 |
2 |
1 |
0 |
Pixel uses sprite colour 2 |
3 |
1 |
1 |
Pixel uses sprite colour 3 |
Implementation
Double buffering
Double-buffering should be used to reduce flickering. Buffers should be flipped every time the system enters sleep mode.
Palette changes should also be double-buffered in order to prevent the screen colours from updating separately from the image.
Wake
This device will send a wake request to the system device when the current frame has finished rendering, or when the screen dimensions have changed. The duration of each frame is implementation defined.