Screen device

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.