The Lush Engine





Introduction
General Assembler
Mono Gameboy
Gameboy Colour
Introduction
Palettes
Reference




Gameboy Colour Palettes

Title :Gameboy Colour Palettes
Overview :An explanation of how the colour palettes work on the Gameboy Colour.
Audience :Gameboy Colour programmers.
Requirements :An understanding of binary number systems and a general understanding of how to program the Gameboy.
Objectives :Make the reader comfortable with how the colour palettes work.

Section 1 - Introduction

To work with the colour palettes, you must understand how the BITs are arranged within a BYTE. If you are unsure, quickly read the number systems tutorial in the general assembler section.

Section 2 - Overview

The Gameboy Colour can display 56 different colours on screen at once from a total of 32,768 different colours. With clever code, you can display more than that, but it takes some doing, and that kind of trick is beyond the scope of this tutorial.

The magic number of 56 is due to the fact that there are eight separate palettes for the background (the window uses the same palettes), each of which has four colours (8 x 4 = 32), and there are also eight separate palettes for the objects (sprites) and although each palette has four colour entries, colour 0 is always transparent, leaving three useable colour entries (8 x 3 = 24).

The total of 32,768 for the number of different colours is reached due to the fact that each colour is made up of 32 shades of red, green, and blue, with the shades ranging from 0 to 31 (0 being none of the colour, 31 being the highest amount of the colour). 32 x 32 x 32 = 32,768.

Section 3 - Colour Palette Data

In Binary, the number range 0-31 can be represented by five BITs. This means that a single palette entry requires fifteen BITs to specify which colour is being displayed (five BITs for the red part, five for the blue part, and five for the green part). Fifteen BITs fit nicely into two BYTEs with one BIT to spare, so two BYTEs are used for each palette entry.

The two BYTEs are referred to as Colour Palette High and Colour Palette Low. The table below shows the two BYTEs, and what each BIT is used for.

Data Byte H i g h L o w
Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
Data X B B B B B G G G G G R R R R R

Data Key
X : Not Used
B : Blue data
G : Green data
R : Red data

As the table above shows, the green data is split between the two bytes. This isn't a problem, you just need to remember that the high data BYTE holds the high BITs of the green data and the low data BYTE holds the low BITs of the green data.

Section 4 - Preparing the data

Getting the two data BYTEs ready for writing to a palette entry can be thought of as difficult. However, it isn't really.

So long as you already have three colour values ranging from 0-31, the preparation of the colour data BYTEs is fairly straightforward.

As a point of interest, if you have colour values ranging from 0-255 for the three colours, and you want to convert them to a 0-31 range, an easy method is to simply shift the data right three times (each shift right halves the data, losing any fractions, so three shifts right is halved, then quartered, then eighthed).

The command in assembler to shift the data right is SRL. So, assuming that you bring the colour value into the accumulator, the commands would be:

 SRL	A	; halves the data
 SRL	A	; halves it again
 SRL	A	; halves it one final time
Anyway, back to the data preparation. Let's assume that the red value is held in E, the green value is held in H, and the blue value is held in L. We will be storing the high data BYTE in E, and the low data BYTE in D.

For this example, we will create the low data BYTE first, and then the high data BYTE.

To start off with, we take the red data value and place it in the low data BYTE store. The code is as follows;

 LD	A,E
 AND	31
 LD	D,A
The AND command is used to mask out any unwanted data, just in case we have a colour value that is greater than 31.

That's the red part finished. Now the green. We need the right hand three BITs of the green data merged with the red data (placed in BITs 7, 6, and 5 of the low data BYTE).

The easiest way to do this is to shift the green data left five times, which pushes the left five BITs off into oblivion, and leaves the remaining three BITs in the correct positions. The code is as follows;

 LD	A,H
 SLA	A
 SLA	A
 SLA	A
 SLA	A
 SLA	A
Now we need to merge this with the red data already in the low data BYTE. A simple OR operation will do this for us, as follows;
 OR	D
 LD	D,A
That's the low data BYTE done, now the high BYTE. We'll start off by finishing off the green data. We want the left hand two BITs to form the right hand two BITs of the high data BYTE. To start off with, we mask out all the unwanted data, just in case we have a value higher than 31. The code is as follows;
 LD	A,H
 AND	31
Now we can shift the data to the right three times, throwing the data we don't want off the edge and keeping the two BITs we want in the right place. The code is as follows;
 SRL	A
 SRL	A
 SRL	A
This gives us the start of the high BYTE, so we'll stick it in E. The code is as follows;
 LD	E,A
The last colour to deal with now is blue. This value just needs masking and then shifting left two BITs. The code is as follows;
 LD	A,L
 AND	31
 SLA	A
 SLA	A
Now we have the final colour value, we just merge it with the high data BYTE. The code is as follows;
 OR	E

Section 5 - Writing the data

Writing data to a palette is done by using the following Gameboy registers: the write specification register and the write data register.

What you do is set up the write specification register to tell the gameboy what data you are sending, and then place the data in the write data register.

The BITs of the write specification register are used for the following things.

BIT Used for
7 If when writing the actual data, this BIT is set to 1, the next palette is automatically selected after writing the data.
6 Not Used.
5,4,3 These three BITs specify the palette number (0-7).
2,1 These two BITs specify the specific palette entry that is being written (0-3).
0 Specifies which part of the data is being written. If this BIT is set to 0, the low data BYTE is being written, if it is set to 1, the high data BYTE is being written.

A few examples of write specification entries follow:

Entry Explanation
00001010 BIT 7: Not set
BIT 6: Not set
BITs 5,4,3 : Value of 1, so palette 1 is being set
BITs 2,1 : Value of 1, so palette entry 1 is being set
BIT 0 : Not set, so the low data BYTE is being written
00011001 BIT 7: Not set
BIT 6: Not set
BITs 5,4,3 : Value of 3, so palette 3 is being set
BITs 2,1 : Value of 0, so palette entry 0 is being set
BIT 0 : Set, so the high data BYTE is being written
00100100 BIT 7: Not set
BIT 6: Not set
BITs 5,4,3 : Value of 4, so palette 4 is being set
BITs 2,1 : Value of 2, so palette entry 2 is being set
BIT 0 : Not set, so the low data BYTE is being written

You will notice that there is no way within the write specification register to state which type of palette is being written (background of object). This is because there are two write specification registers and two write data registers, one set for background palettes and one for object palettes.

The addresses of these registers are shown in the table below:

Register Address
Background Write Specification (BCPS) FF68
Background Write Data (BCPD) FF69
Object Write Specification (OCPS) FF6A
Object Write Data (OCPD) FF6B

The four letter acronyms in brackets in the table above are the shorthand names for the registers used by Nintendo. Their full names are:

Acronym Full Name
BCPS Background Colour Palette Specification
BCPD Background Colour Palette Data
OCPS Object Colour Palette Specification
OCPD Object Colour Palette Data

An example follows to show how the two data BYTEs are written for a single colour of a background palette. The data bytes are stored in D and E (D being the low data BYTE and E being the high data BYTE as in the example in the previous section).

 LD	HL,$FF68	; set up a pointer to the BCPS
 LD	C,%00001010	; Colour 1 of Palette 1
 LD	A,C		; Load A with the write specification 
			; data
 LD	[HLI],A		; place the data in the specification 
			; register and move the pointer to the 
			; BCPD
 LD	A,D		; get the low data BYTE
 LD	[HL],A		; send the low data BYTE to the register
 LD	HL,$FF68	; set the pointer back to the BCPS
 LD	A,C		; Load A with the write specification 
			; data
 INC	A		; Add 1 to the data, therefore setting 
			; BIT 0 which means we are now writing 
			; the high data BYTE
 LD	[HLI],A		; place the data in the specification 
			; register
			; and move the pointer to the BCPD
 LD	A,E		; get the high data BYTE
 LD	[HL],A		; send the high data BYTE to the register

That's basically all there is to it. The example code is not the best code in the world, but it does show, with simple code, how it all works.

End of Tutorial


Buttons created using the interactive button maker at Coolarchive