Skip to navigation


Colouring the Commodore 64 bitmap screen

Adding a distinctive dash of colour to the Commodore 64 dashboard

The Commodore 64 version of Elite is a colourful game. Here it is, with its multicolour dashboard and brightly coloured laser sights:

A space station in Commodore 64 Elite

You could never accuse the original BBC Micro version of being brightly coloured. It does have colour, but there isn't a great deal of it:

A space station in BBC Micro cassette Elite

The Commodore 64 supports a number of different screen modes, of which we use standard bitmap mode for the space view and multicolour bitmap mode for the dashboard. For Elite, this is what we have:

  • The space view is in standard bitmap mode, which provides a one bit-per-pixel screen of resolution 320x200 pixels. The space view uses 260x144 pixels of this.
  • The dashboard is in multicolour bitmap mode, which provides a two bits-per-pixel screen of resolution 160x200 pixels. The dashboard uses 130x56 pixels of this.

Meanwhile, the BBC Micro also supports a number of different screen modes, and for Elite, we need two of them:

  • The space view is in a custom version of mode 4, which provides a one bit-per-pixel screen of resolution 256x248 pixels. The space view uses 256x192 pixels of this.
  • The dashboard is in a custom version of mode 5, which provides a two bits-per-pixel screen of resolution 128x248 pixels. The space view uses 128x56 pixels of this.

The BBC Micro's space view is taller, but this aside, the game screens on the two different systems are practically identical. The screens on the two systems have identical resolutions, with one bit per pixel in the space view and two bits per pixel in the dashboard, and they have very similar widths. The only real difference is that the Commodore 64 version draws its yellow box borders just outside of the 256-pixel wide playing area, because its full screen is actually 320 pixels wide; this means it can use these outer margins, while the BBC mode is 256 pixels wide, so it has no choice but to draw its border box just inside the space view.

So how come the Commodore 64 version is so awash with colour, when the screen modes are so similar? The answer is in the Commodore's powerful VIC-II video controller chip, so let's take a look at how Elite uses the VIC-II to give such a colourful experience.

Screen RAM and the space view
-----------------------------

The secret to the colourful dashboard in Commodore 64 Elite is the way the VIC-II handles colour in bitmap mode. The BBC Micro has a very simple palette system, so for the space view we get to choose two colours from a palette of eight (so we choose black and white), and for the dashboard we get to choose four colours from the same palette (so we choose red, green, yellow and black for the standard dashboard, and change the palette to white, cyan, magenta and black when an escape pod is fitted).

In the Commodore 64, we also choose a palette of two or four colours for the space view and dashboard, but there are 16 colours to choose from, and even more impressively, we can set a different palette for every single character block on the screen. These character blocks work in a similar way to the BBC Micro, and the Commodore 64 screen consists of 25 character rows with 40 character blocks on each row. So in standard bitmap mode (320x200 pixels) each character block is eight rows of eight pixels, while in multicolour bitmap mode (160x200 pixels) each character block is eight rows of four pixels.

This is where screen RAM comes in: it is used to store the palettes for each of these on-screen character blocks. There are 25 rows of 40 characters, which is a total of 1000 characters, so it's no surprise to find that screen RAM takes up 1000 bytes. There's a one-to-one mapping between screen RAM and the character blocks on the screen, working from left to right and up to down.

To see how screen RAM works, let's look at how the palette is set in the space view; we'll look at the more complicated dashboard in the next section. First, we need to know the colour numbers for the Commodore 64. Here they are:

  • $0 = black
  • $1 = white
  • $2 = red
  • $3 = cyan
  • $4 = purple
  • $5 = green
  • $6 = blue
  • $7 = yellow
  • $8 = orange
  • $9 = brown
  • $A = pink
  • $B = dark grey
  • $C = grey
  • $D = light green
  • $E = light blue
  • $F = light grey

So each colour number only requires four bits to store.

We also need to talk about the screen bitmap, which is where screen pixels are set. The screen bitmap is basically the same as screen memory in the BBC Micro, as follows:

  • For the space view, the bitmap is one bit per pixel, and just like the BBC Micro's mode 4, the bitmap is split up into character blocks of eight rows, with eight pixels on each row in the character block; see the deep dive on drawing monochrome pixels on the BBC Micro for details.
  • For the dashboard, the bitmap is two bits per pixel, and just like the BBC Micro's mode 5, the bitmap is split up into character blocks of eight rows, with four pixels on each row in the character block; see the deep dive on drawing monochrome pixels in mode 5 for details.

Now let's see how we can store palette information in screen RAM to add colour to the screen bitmap for the space view.

In the space view's standard bitmap mode, the byte of screen RAM that's associated with each character block defines two colours: foreground and background. The number of the foreground colour goes in the high nibble, while the number of the background colour goes in the low nibble. The screen bitmap then works as follows:

  • Pixels that are set to 0 in the bitmap are drawn in the background colour, i.e. the colour number from the low nibble of the corresponding character block entry in screen RAM.
  • Pixels that are set to 1 in the bitmap are drawn in the foreground colour, i.e. the colour number from the high nibble of the corresponding character block entry in screen RAM.

So for the core of the space view we define the background colour as black (colour 0) and the foreground colour as white (colour 1), and for the border box around the edge of the screen, which is just outside the 256-pixel-wide space view and therefore has its own character blocks, we define the foreground colour as yellow (colour 7). You can see the box border palette being set up in screen RAM part 5 of the game loader.

Not only can we use screen RAM to define the palette for the space view, but we can also use it for text views like this:

The Status Mode screen in Commodore 64 Elite

The system charts and trading screens also use standard bitmap mode, but they have slightly different requirements; for example, their border boxes reach all the way down to the bottom of the screen, and they cover all four screen edges rather than the three around the space view (in the space view, the lower border is actually part of the dashboard image). Luckily it is possible to reprogram the VIC-II chip to change the address where it looks for screen RAM, so we actually set up two blocks of screen RAM, one for the space view and another for the text views. You can see these two blocks in the memory map (see the Commodore 64 Elite memory map for the full picture):

  :                                   :
  :                                   :
  +-----------------------------------+   $6800 = SPRITELOC%
  |                                   |
  | Screen RAM for space view (1K)    |
  |                                   |
  +-----------------------------------+   $6400
  |                                   |
  | Screen RAM for text view (1K)     |
  |                                   |
  +-----------------------------------+   $6000
  |                                   |
  | Screen bitmap (8K)                |
  |                                   |
  +-----------------------------------+   $4000 = SCBASE
  :                                   :
  :                                   :

The current address of screen RAM is controlled by the interrupt routine at COMIRQ1, and in particular the zebop and abraxas variables. The interrupt routine configures the correct address for screen RAM by writing the value of zebop to VIC-II register $18 for the top portion of the screen, and the value of abraxas to VIC-II register $18 for the lower portion of the screen.

zebop is always set to $81, which will set the address of screen RAM to offset $2000 within the VIC-II bank at $4000, so the colour data for the top part of the screen is always at screen RAM at $6000.

abraxas is $81 by default, in which case this will also set screen RAM to $6000 for the lower part of the screen, so for the text views both parts of the screen fetch colour data from screen RAM at $6000.

When we need to display the space view and the dashboard, the wantdials routine changes abraxas to $91, and setting VIC-II register $18 to this value sets the address of screen RAM to offset $2400 within the VIC-II bank at $4000, so the screen RAM address for the lower part of the screen gets changed to $6400.

In other words:

  • When abraxas is $81, the colour of the lower part of the screen is determined by screen RAM at $6000 (i.e. when the dashboard is not being shown).
  • When abraxas is $91, the colour of the lower part of the screen is determined by screen RAM at $6400 (i.e. when the dashboard is being shown).

This enables us to colour the dashboard independently from the corresponding lower part of the text view, so let's look at that now.

Colour RAM and the dashboard
----------------------------

When used with the space view, each byte in screen RAM defines two colours for each character block, with one colour in each nibble. In the dashboard, each pixel can be one of four colours, so our palette needs to be able to define a four-colour palette for each character block. To help us do this, we need another block of memory. This is colour RAM, which is also 1000 bytes in size, but this time the address is fixed and cannot be changed: colour RAM is always at address $D800.

In the dashboard's multicolour bitmap mode, the colour of each two-bit pixel is set as follows:

  • Pixels that are set to 0 (%00) in the bitmap are drawn in the background colour, which we set in VIC register $21.
  • Pixels that are set to 1(%01) in the bitmap are drawn in the colour given in the top nibble of screen RAM.
  • Pixels that are set to 2 (%10) in the bitmap are drawn in the colour given in the bottom nibble of screen RAM.
  • Pixels that are set to 3 (%11) in the bitmap are drawn in the colour given in the bottom nibble of colour RAM.

The palettes for the dashboard in screen RAM are set up in part 5 of the game loader, and colour RAM is set up in part 6. The code simply copies data from the sdump and cdump variables into screen RAM and colour RAM, and in the BeebAsm version of the source on this site, these variables are simply blocks of data.

However, in the original source disks, the sdump and cdump tables in the loader binary are built by a BBC BASIC program called S.COMLODS. This takes a set of DATA statements that describe the colour layout of the dashboard, and creates the data in sdump and cdump. BeebAsm isn't as flexible as BBC BASIC, which is why we have to use EQUB statements for the version on this site, but here are the original DATA statements for reference:

  REM 'Yellow' Screen Mem low nybble
  REM   |.....,||,.....||......||.....,||,.....|
  DATA "0007774444777777777777777777777777777000"
  DATA "0007774444777777777777777777773333777000"
  DATA "0007779999777777777777777777773333777000"
  DATA "0007778888777777777777777777774444777000"
  DATA "000777AAAA777777777777777777774444777000"
  DATA "000777DDDD777777777777777777774444777000"
  DATA "0007777777777777777777777777774444777000"

  REM 'Red' Screen Mem high nybble
  REM   |.....,||,.....||......||.....,||,.....|
  DATA "0000117777222222222222222222622222330000"
  DATA "0000112222222222222222222266662222330000"
  DATA "0000332222222222222222222222622222330000"
  DATA "0000332222222222222222222222222222110000"
  DATA "0000332222222222222222222222222222110000"
  DATA "0000332222202222222222222222022222110000"
  DATA "0000CC0000202222222222222222022222110000"

  REM 'Green' Colour Mem nybble
  REM   |.....,||,.....||......||.....,||,.....|
  DATA "0000555555DDDDDDDDDDDDDDDD55555555550000"
  DATA "0000555555DDDDDDDDDDDDDDDD55555555550000"
  DATA "0000555555DDDDDDDDDDDDDDDD55555555550000"
  DATA "0000555555DDDDDDDDDDDDDDDDD5555555550000"
  DATA "0000555555DDDDDDDDDDDDDDDDDDDD5555550000"
  DATA "0000555555DDDDDDDDDDDDDDDDDDDD5555550000"
  DATA "0000FF7777DDDDDDD33333DDDDDDDD7777550000"

The data in sdump is formed from the first two tables, with the digit from the first table in the low nibble and the second table in the high nibble. The data in cdump takes the third table as the low nibble and sets 0 as the high nibble (as the high nibble of colour RAM is not used).

Because of the way colour data works in multicolour bitmap mode, this means that:

  • The first table defines the colour of %10 in the bitmap in each character block.
  • The second table defines the colour of %01 in the bitmap in each character block.
  • The third table defines the colour of %11 in the bitmap in each character block.

As an example, look at the left side of the first table here:

  REM 'Yellow' Screen Mem low nybble
  REM   |.....,||,.....||......||.....,||,.....|
  DATA "0007774444777777777777777777777777777000"
  DATA "0007774444777777777777777777773333777000"
  DATA "0007779999777777777777777777773333777000"
  DATA "0007778888777777777777777777774444777000"
  DATA "000777AAAA777777777777777777774444777000"
  DATA "000777DDDD777777777777777777774444777000"
  DATA "0007777777777777777777777777774444777000"

and compare it to the dashboard here:

A space station in Commodore 64 Elite

The "000777" at the start of each line covers the empty black margin to the left of the game screen and the two-letter indicator labels, but the interesting part is in the next four character blocks, which cover the bars in the indicators. The top two are "4444", then we have "9999", "8888", "AAAA" and "DDDD"; these make the two shield bars purple (4), the fuel bar brown (9), the cabin temperature bar orange (8), the laser temperature bar pink (A) and the altitude bar light green (D). Similarly, you can see four blocks of "4444" in the bottom-right of the DATA block, which correspond to the four purple energy bars in the bottom-right of the dashboard.

Note that in the original source, the REM comments refer to the predominant colours in each block. The first table defines %10 as yellow (7) for the bulk of the scanner, hence the "Yellow screen" comment, the second table defines %01 as red (2) in a similar way, and the third table defines %11 as green (5) for the indicator scale lines down the side of the dashboard. These comments aren't to do with colour channels, even though they sound as if they might be at first glance.

And that's how the Commodore 64 dashboard gets its distinctively colourful look.