Sunday, 27 September 2020

Lunchtime Coder #1 - ZX Spectrum (16k or 48k) 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 ZX Spectrum .sna .tzx .z80 .tap files into columns 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

The snapshot Output

With this done, I decided to add an extra mode, Screen Buffer Interpreter or TV Screen mode.

.sna files are snapshots of the ZX spectrums memory, including the screen buffer area.

The ZX spectrum is pretty nifty when it comes to storing colour graphics in a small amount of memory. It had one screen mode and the resolution of that mode was 256 x 192. It could also display 16 colours (well 15 really as two of the colours are Black). It displayed the standard 8 colour pallette: Black, White, Red, Yellow, Green, Blue, Cyan and Magenta. There was also two brightnesses that each of these colours could be displayed at.

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 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 pixel 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 x 24 8by8 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 Colour clash happens.

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