4x4 Off-Road Racing Full Screen Graphic Format

From ModdingWiki
Jump to: navigation, search
4x4 Off-Road Racing Full Screen Graphic Format
4x4 Off-Road Racing Full Screen Graphic Format.png
Format typeImage
HardwareCGA, EGA
Colour depth2-bit (CGA)
Minimum size (pixels)320×200
Maximum size (pixels)320×200
PaletteNone
Plane count1
Transparent pixels?No
Hitmap pixels?No
Games

This format is used by 4x4 Off-Road Racing to store full-screen (320 × 200) images. The extension is *.pck, however the game has different graphic formats that use the same extension.

Image

The format has no header. The size of the image and color palette are stored in the EXE, so modification is limited. The format is encoded with a basic run-length encoding. Since the format only supports 2-bit color, each byte of graphic data accounts for 4 pixels.

When decoding the graphic, you read from the beginning, loading one byte for pixel data, and another for the length of the run. Each pixel byte is 4 pixels of data, 2-bits per pixel. The format stores every even line first, then every odd line. However, there is always 1,408 bytes of repeated data at the end of the even lines data that should be discarded. I'm not sure why this is here, possibly included as a delay on the vertical refresh of interlaced monitors?

Data type Name Description
BYTE pixels Binary representation of 4 pixels (2 bits per pixel)
UINT8 length Number of times to repeat this pixel pattern.

Source Code

Viewer

The following FreeBASIC code will read and display each of the graphic formats in the game with their correct EGA or CGA palette which you can specify.

' This program can decode and view the sprites, backgrounds, and full-screen 
' images from the 1988 DOS game, 4x4 Off-Road Racing. It still needs a little 
' work to display the sprites properly.
 
' Images are stored in two formats:
'
' Interlaced Format - Used only in full screen background images.
' Draws every even line until it reaches the bottom and then loops back to the 
' top and draws every odd line. Has some redundant data at the end of the even 
' lines.
'
' Flat Format - Used in all other images. Reads from left to right, top to 
' bottom.
'
' None of the formats have headers. All image dimensions and palettes are 
' stored in the EXE.
 
Declare Function GetColor(Bit1 As Byte, Bit2 As Byte) As UByte
 
Dim bPixels As UByte, bLength As UByte, bRepeat As UShort
Dim X As Short, Y As Short, Z As Short, W As Short, lLoc As ULong
Dim sWidth As UShort, bHeightJump As UByte
Dim bColor As UByte
Dim sName As String, sPath As String
Dim Shared sPalette As String, bColors As UByte
Dim aPalette(0 To 3) As UByte
 
Screen 12
 
' Available palettes include: CGA, EGA.
sPalette = "EGA"
 
' The file to load and the path to load from.
' Take a look at Street.pck to see an Easter Egg!
sName = "TITLE.PCK"
sPath = "D:\\Games\\4x4\\"   ' <-- Remove double slashes.
 
Select Case UCase(sName)
 
' Full screen images. - Interlaced format.
Case "HALLFAME.PCK", "MART.PCK", "ROAD.PCK", "RSCREEN.PCK", "SELECT.PCK",_
    "SHOP.PCK", "STORES.PCK", "STREET.PCK", "TITLE.PCK", "TRUCKSCR.PCK"
    sWidth = 320
    bHeightJump = 2
    If sPalette = "CGA" Then bColors = 1 Else bColors = 0
 
' The track maps. - Flat Format.
Case "MAPS.PCK"
    sWidth = 320
    bHeightJump = 1
    If sPalette = "CGA" Then bColors = 1 Else bColors = 0
 
' The side view of the Trucks with their masks. - Flat Format.
Case "TRUCKS.PCK"
    sWidth = 176
    bHeightJump = 1
    If sPalette = "CGA" Then bColors = 1 Else bColors = 0
 
' Truck driving sprites. - Flat Format.
Case "HIGHLSPR.PCK", "KATACSPR.PCK", "KATANSPR.PCK", "STORMSPR.PCK",_
    "TARACSPR.PCK", "TARANSPR.PCK"
    Select Case UCase(sName)
    Case "HIGHLSPR.PCK"
        sWidth = 44
    Case "KATANSPR.PCK", "KATACSPR.PCK"
        sWidth = 40
    Case "STORMSPR.PCK"
        sWidth = 48
    Case "TARANSPR.PCK", "TARACSPR.PCK"
        sWidth = 44
    End Select
 
    bHeightJump = 1
    If sPalette = "CGA" Then bColors = 1 Else bColors = 2
 
' Track background images. - Flat Format.
Case "BAJABCK.PCK", "DVALBCK.PCK", "GEORBCK.PCK", "MICHBCK.PCK"
    sWidth = 576
    bHeightJump = 1
 
    ' Figure out what palette to use.
    Select Case UCase(sName)
    Case "BAJABCK.PCK"
        If sPalette = "CGA" Then bColors = 1 Else bColors = 2
    Case "DVALBCK.PCK", "GEORBCK.PCK"
        If sPalette = "CGA" Then bColors = 4 Else bColors = 3
    Case "MICHBCK.PCK"
        If sPalette = "CGA" Then bColors = 1 Else bColors = 2
    End Select
 
' Road objects and masks. - Flat Format.
Case "BAJAOBS.PCK", "DVALOBS.PCK", "GEOROBS.PCK", "MICHOBS.PCK"
    sWidth = 24
    bHeightJump = 1
 
    ' Figure out what palette to use.
    Select Case UCase(sName)
    Case "BAJAOBS.PCK"
        If sPalette = "CGA" Then bColors = 1 Else bColors = 2
    Case "DVALOBS.PCK", "GEOROBS.PCK"
        If sPalette = "CGA" Then bColors = 4 Else bColors = 3
    Case "MICHOBS.PCK"
        If sPalette = "CGA" Then bColors = 1 Else bColors = 2
    End Select
End Select
 
' This section is the palette lookup.
' Note, 4x4 uses the 3rd CGA color palette so it uses red rather than magenta.
Select Case bColors
Case 0      ' EGA - Default
    aPalette(0) = 0   ' Black
    aPalette(1) = 4   ' Red
    aPalette(2) = 1   ' Blue
    aPalette(3) = 7   ' Lt. Gray
Case 1      ' CGA - Default / CGA Michigan / CGA Baja
    aPalette(0) = 0   ' Black
    aPalette(1) = 12  ' Bright Red
    aPalette(2) = 11  ' Bright Cyan
    aPalette(3) = 15  ' White
Case 2      ' EGA - Baja / EGA - Michigan
    aPalette(0) = 0   ' Black
    aPalette(1) = 4   ' Red
    aPalette(2) = 3   ' Cyan
    aPalette(3) = 15  ' White
Case 3      ' EGA - Death Valley / EGA - Georgia
    aPalette(0) = 0   ' Black
    aPalette(1) = 4   ' Red
    aPalette(2) = 3   ' Cyan
    aPalette(3) = 14  ' Yellow
Case 4      ' CGA - Death Valley / CGA - Georgia
    aPalette(0) = 0   ' Black
    aPalette(1) = 12  ' Bright Red
    aPalette(2) = 10  ' Green
    aPalette(3) = 14  ' Yellow
End Select
 
Dim sKey As String
 
Open sPath + sName For Binary As #1
 
' Loop through the file until we hit the end.
X = 0
Y = 0
Do Until EOF(1)
    ' Grab two bytes. The first is the pixel data, the second is the number of 
    ' times to draw the data.
    Get #1, , bPixels
    Get #1, , bLength
    lLoc = lLoc + 2
 
    ' Repeat the drawing process as many times as specified.
    For bRepeat = 1 To bLength
        W = 0
        ' The binary data is stored backwards, so loop though it back to front.
        For Z = 3 To 0 Step -1
            ' Every 2 bits is a color. Send them to our GetColor function.
            bColor = GetColor(Bit(bPixels, (Z * 2) + 1), Bit(bPixels, Z * 2))
 
            ' Once the color has been deciphered, plot a pixel.
            Pset(X + W, Y), aPalette(bColor)
            W = W + 1
        Next Z
        X = X + 4
 
        ' When we hit the right edge, drop back to the left.
        If X = sWidth Then
            X = 0
            ' Increment one or two lines based on the format.
            Y = Y + bHeightJump
        End If
 
        ' The full screen graphic format doesn't just store 1 screen worth of 
        ' data. Some of the pixels from the middle of the image are stored at 
        ' the end of the first pass. This data is redundant as the second pass 
        ' will fill in all the blanks.
        If bHeightJump = 2 Then
            If Y = 204 And X = 128 Then
                Y = 1
                X = 0
            End If
        End If
    Next bRepeat
Loop
 
Close #1
Sleep
 
' This function converts the 2 bits into a single color.
Function GetColor(Bit1 As Byte, Bit2 As Byte) As UByte
    Dim bCol As UByte
 
    ' First, get the index.
    If Bit1 = 0 and Bit2 = 0 Then bCol = 0
    If Bit1 = -1 and Bit2 = 0 Then bCol = 1
    If Bit1 = 0 and Bit2 = -1 Then bCol = 2
    If Bit1 = -1 and Bit2 = -1 Then bCol = 3
 
    ' Return the color.
    Return bCol
End Function

Credits

This graphic format was reverse engineered by TheAlmightyGuru. If you find this information helpful in a project you're working on, please give credit where credit is due. (A link back to this wiki would be nice too!)