Sunday, 27 September 2020

Lunchtime Coder #1 - Sinclair ZX Spectrum Bitmap and Graphics Buffer Viewer / Editor

As a small lunchtime coding project, I decided to write a ZX Spectrum bitmap viewer.

The idea of this was to arrange the bits in a ZX Spectrum ".sna", ".tzx", ".z80" or ".tap" file into columns of 8, 16, 24 or 32 bits wide in order to be able to view the game bitmaps.

The bits could be stepped through bit by bit or in larger steps and the display flipped upside down if required and if the bitmaps were upside down. When you found some interesting ones, you could snap them or if you wanted to, edit the bits to create custom game files.

The Viewer - Taking a Look at UPTG's "Underwurlde" Bitmaps.

The Snapshot Output.

With this done, I decided to add an extra mode; Screen Buffer Interpreter or TV Screen mode; A mode that would read the Screen Buffer part of the memory, and interpret it into what would actually be displayed on the TV / Monitor screen.

The ZX spectrum is pretty nifty when it comes to storing 16 colour graphics in a small amount of memory.

It has a single screen mode with a resolution of 256 x 192.

It could display 16 colours (well 15 really as two of the colours are Black). It achieved this by having a standard 8 colour pallette: Black, White, Red, Yellow, Green, Blue, Cyan and Magenta, and then having a brightnesses bit that allowed each of the colours to be displayed at two different brightness settings, with the exception of the previously mentioned Black colour. e.g. Red with Brightness bit set to 1 would have an RGB value of 255,0,0 whereas Red with Brightness bit set to 0 would have an RGB value of 215,0,0.

In normal screen buffer terms, If each pixel could be one of 15 colours, each pixel would need 4 bits to describe its colour. If that were the case with the ZX Spectrum, then 49,152 pixels at 4 bits per pixel would need 196,608 bits or 24,576 bytes or 24.5 kB of memory just for the screen buffer.

In a 48 kB ZX spectrum, that would leave you just 23.5 kB for the programing, and in a 16 kB ZX Spectrum, that would leave you no room for programing, and only half of the screen displayed.

Fortunately, Sinclair came up with a way of displaying 16 colours on screen but using considerably less memory, although this did have some limitations and lead to the infamous ZX Spectrum colour clash phenomenon.

Firstly, the actual graphics on screen are stored in just black and white, so that each pixel needs just one bit of memory; either 0 for black or 1 for white.

Then each 8 x 8 pixel square has an attribute byte. This byte has 3 bits for the foreground colour (Ink) and 3 bits for the background colour (Paper). There is then a Bright bit which if set to 1 makes both ink and paper as the brighter colour, rather than the darker colour, and then a flash bit that when set to 1, flashes the colour.

The total memory now used is 49,152 bits or 6 kB for the actual screen pixels, and then 768 bytes for the attributes (32 columns of 24 rows of 8 by 8 pixel squares).

So the whole screen fits in to less than 7 kB. Pretty clever, but comes with limitations. If you have two characters on screen of different colours, and they get close to each other, they will overlap onto each others Ink and Paper attributes, and this is where the infamous ZX Spectrum "Colour Clash" happens.

Note: The only other system I can think of with Colour Clash is the Arcade machine "Berzerk" by STERN, but the colour clash issue with Berzerk is for very different reasons.

The screen buffer part of the memory draws to the screen in a very specific way.
If you imagine the screen as an Excel spreadsheet with 192 rows and 256 columns, with each cell representing an on screen pixel.
To draw the screen, the bits are streamed from the memory to draw in black and white, firstly the whole of row 1, then row 9, then row 17, then row 25 and continuing to draw every eigth row for the top third of the screen.
The process is then repeated only this time starting at row 2, and every eighth row after for top half of screen, then starting at row 3, row 4 etc until you have drawn the whole top third of the screen in black and white.

Now the process is repeated only this time starting at row 65 to draw the middle third of the screen.

Finally the process repeated only this time starting at row 129 to draw the bottom third of the screen.

Once the whole screen is drawn in black and white, the screen attribute bytes are read and the Ink and Paint colours are applied, starting at the top left side of the screen and colouring each 8 x 8 square of pixels.

Screen Buffer in 8 bit width columns - Screen Attribute Bytes on RH side of Highlighted Square

Screen Buffer in 256 bit width - Screen Attribute Bytes at bottom of Highlighted Square
Screen Buffer Interpreted into Screen Display

This method of drawing the screen shouldn't be strange to anyone who owned a ZX Spectrum back in the day, as this is the order that the loading screens drew themselves when loading a game from tape. The bits were streamed from the tape into the first part of the ram, which was the screen buffer, and as they went into the memory, they started to slowly draw the loading screen in this secific order, as the video below shows.

Not exactly cutting edge, but a fun brain exercise for some boring lunchtimes.

No comments:

Post a Comment