VGA Palette

From ModdingWiki
Jump to: navigation, search
VGA Palette
Format typePalette
HardwareVGA
Colour depth18-bit, 24-bit
Number of colours256
GamesStargunner, Zone 66, F-117A Nighthawk
Hocus Pocus palette

As far as games are concerned, VGA normally means 256 colours. Whereas the EGA standard allowed 16 colours to be displayed at the same time out of a possible 64 (2-bits per channel), VGA allows 256 colours to be displayed at the same time out of a possible 262,144 (6-bits per channel.)

Unlike EGA games which rarely changed the palette, almost all VGA games alter the palette to their preferred group of 256 colours. When games store the palette on disk, there are two common layouts used.

Contents

The "Classic" format

The classic palette format maps exactly to the VGA registers. Each colour takes up three bytes (one each for red, green and blue) and only the lower six bits of each byte are used (as the VGA only uses six bits per colour.) In practice this means each byte will only contain values between zero and 63 inclusive. (However be aware that some games use values between zero and 64! In these cases 64 should be treated the same as 63, as this is what the VGA does.)

This format is often referred to as 6-bit RGB.

The "Modern" format

Since the widespread use of video cards capable of displaying 24-bit images, 256 colour palettes have been increased to use the full eight bits in each byte for storing colour levels. All this means is that each of the red, green and blue bytes will have the full range of values (0-255) instead of the limited VGA values (0-63).

This format is often referred to as 8-bit RGB.

Some variants of this format pad the values out to 32-bits, and this format is often referred to as 8-bit RGBA. In most cases the fourth byte (A) isn't used and can be ignored.

Conversion

To easily convert between one format to another, some simple formulae can be used for each of the red, green and blue values:

// 6-bit VGA to 8-bit RGB:
eight_bit_value = (six_bit_value * 255) / 63

// 8-bit RGB to 6-bit VGA
six_bit_value = (eight_bit_value * 63) / 255

Performing the multiplication before the division removes the need to use floating point numbers and minimises any rounding errors.

More efficient conversions can also be used when speed is more important than code readability:

// 6-bit VGA to 8-bit RGB
eight_bit_value = (six_bit_value << 2) | (six_bit_value >> 4)

// 8-bit RGB to 6-bit VGA
six_bit_value = eight_bit_value >> 2

Note however that the input VGA values may need to be capped to 0x3F (63) as some games output the value 0x40 for 100% instead of 0x3F (TODO: Confirm/link to example). The VGA treats 0x40 the same as 0x3F however (TODO: Confirm).

Detection

It is relatively simple to "detect" a VGA palette file, particularly if they are 6-bit RGB as the files will be exactly 768 bytes long - almost no other files are exactly this size. Looking at the palette in a hex editor will often reveal the file starts with three 0x00 bytes, on account of nearly all games using palette index #0 as black. Seeing groups of the same value (e.g. 10 10 10 20 20 20 30 30 30) is also a good indication of a palette with a greyscale section in it, which is another common feature. This can be seen in the very last row of the Hocus Pocus palette above, where the colour varies from black, through grey and up to white.


Source Code

Viewer

This program will open a 6 or 8 bit headerless palette file and display swatches for each color, and save a bitmap if you like.

' Generic palette viewer.
' ------------------------------------------
' This viewer assumes that the file has no 
' header, that there are 256 colors, 
' each color is represented by three bytes.
' This program can display both 6 and 8 
' bit color palettes, but you must specify
' which depth you want.
 
' Declare work variables.
Dim ColorIndex As UShort
Dim BitDepth As UByte
Dim Red As UByte, Green As UByte, Blue As UByte
Dim Col As UShort, Row As UShort
Dim SwatchSize As UByte, SwatchBorder As UByte, BorderColor As UShort
Dim File As String, Bitmap As String
 
 
' Custom variables
' ------------------------------------------
' You can adjust the following variables 
' to customize the display of the palette 
' and save a bitmap if you choose.
 
 
' The file path to the palette file you want to open.
File = "E:\Games\F-117A Nighthawk\flight.pal"
 
' Save a bitmap with the same name as the palette file? Leave blank for no.
Bitmap = "E:\Games\F-117A Nighthawk\flight.bmp"
 
' Is this palette a 6-bit or an 8-bit palette?
' You can tell a 6-bit because none of the color 
' attributes go above 63 (6 or 8).
BitDepth = 6
 
' How big should the swatches be? (1-12)
SwatchSize = 12
 
' Draw a border around the swatch? (0 - No, 1 - Yes)
SwatchBorder = 1
 
' If there is a border, use this color index. (0-255)
BorderColor = 0
 
' Open the palette file.
Open File For Binary As #1
 
' Set screen to 320x200, 256 colors.
Screen 13
 
' Loop through all 256 colors.
Row = 0
Col = 0
For ColorIndex = 0 to 255
    ' Read the color attributes from the file.
    Get #1, , Red
    Get #1, , Green
    Get #1, , Blue
 
    ' Allow for both 6 and 8 bit color depth.
    If BitDepth = 6 Then
        Red   = Red * 4
        Green = Green * 4
        Blue  = Blue * 4
    End If
 
    ' Change the palette.
    Palette ColorIndex, Red, Green, Blue
 
    ' Draw a swatch.
    Line (Col, Row)-(Col + SwatchSize, Row + SwatchSize), ColorIndex, BF
    If SwatchBorder = 1 Then
        Line (Col, Row)-(Col + SwatchSize, Row + SwatchSize), BorderColor, B
    End If
 
    ' Increase the swatch position.
    Col = Col + SwatchSize
    If Col = SwatchSize * 16 Then
        Col = 0
        Row = Row + SwatchSize
    End If
Next ColorIndex
 
' Close the palette file.
Close #1
 
' Save a bitmap of the palette if desired.
If Bitmap <> "" Then
    ' Quick check to make sure they didn't accidentally use the same file name for both.
    If Bitmap <> File Then
        BSave Bitmap, 0
    End If
End If
 
' Wait for cursor input.
Sleep