Raw EGA data

From ModdingWiki
Jump to: navigation, search

This page describes a number of generic arrangements for storing EGA graphics data. The graphics in many EGA games are stored based on one of these formats.

To avoid confusion, the term graphic refers to a single large image (such as a full-screen picture, or the entire contents of an image file) while the term tile refers to a much smaller image, which could either exist on its own or be one of many tiles that make up a large graphic. In this use, all tiles in a single graphic need not be of the same dimensions.

Contents

Introduction

Unlike conventional image formats, EGA data is made up of a number of planes. Each plane is like a black-and-white image that stores information about a single colour - for example if a bit is set in the blue plane as well as the red plane, that pixel will appear purple on-screen. The reason the image data is stored like this is because it mirrors the way the data must be loaded into memory for display on the EGA.

There are four standard colour planes (red, green, blue and intensity) with many games adding a fifth plane for transparency, and some even a sixth plane for 'hitmapping' (to detect when two sprites touch.) If an image is stored in planar format and it has four planes, it will be stored like four black-and-white images, one after the other (e.g. all the blue pixels first, then all the green pixels, and so on.)

The actual order of the planes depends on the implementation. It is almost always B-G-R-I, but may be the reverse, I-R-G-B, or indeed any combination at all. You can usually expect to see a masking plane with sprite graphics (for transparent parts of the image), unless the game uses a separate black and white image as the mask (as is done in many older games.)

There are several ways in which the data may be stored, depending on how graphics are divided into planes. The simplest, and most widely used, is to divide the file itself into four or more planes. When this happens, usually all the graphics are loaded at once. The next most common is for each individual graphic to be divided into four planes. Usually this happens when each individual graphic may or may not be loaded in a level. Finally each byte may be divided across the planes, providing one or two full-colour pixels per byte (this is the "conventional" linear format, where each byte is a colour number, or in the case of 4-bit EGA graphics, a single 8-bit byte contains colour numbers for two pixels.) These arrangements are described in more detail below.

Graphic-planar EGA data

Offsets into file data
Pixels Plane
0 1 2 3
(0,0) to (7,0) 00 10 20 30
(8,0) to (15,0) 01 11 21 31
(0,1) to (7,1) 02 12 22 32
(8,1) to (15,1) 03 13 23 33
(0,2) to (7,2) 04 14 24 34
(8,2) to (15,2) 05 15 25 35
(0,3) to (7,3) 06 16 26 36
(8,3) to (15,3) 07 17 27 37
(0,4) to (7,4) 08 18 28 38
(8,4) to (15,4) 09 19 29 39
(0,5) to (7,5) 0A 1A 2A 3A
(8,5) to (15,5) 0B 1B 2B 3B
(0,6) to (7,6) 0C 1C 2C 3C
(8,6) to (15,6) 0D 1D 2D 3D
(0,7) to (7,7) 0E 1E 2E 3E
(8,7) to (15,7) 0F 1F 2F 3F

This arrangement stores complete planes one after the other, where each plane contains data for the entire image.

A game that loads all its tiles at startup (such as Commander Keen 1) will tend to have all its tiles stored as a single planar graphic. Tiles will consist of areas "cropped" out of the main graphic. As such the program will usually need to know the size of the tile and its location in the planar data. This may be stored in the file before EGA data or in a separate data file.

This arrangement is also used for single graphic files loaded all at once, such as a 320×200 full-screen image.

An 16×8 image in this arrangement is described in the table on the right. The byte at index 00 is for the first eight blue pixels on the first line, and the byte at index 12 is for the first eight green pixels on the second line.

Some tilesets are comprised of multiple images in this arrangement, concatenated together. This allows each sub-image (tile) to be self-contained with data for all planes required, but only for that specific tile. This avoids decoding more data than is necessary for display.

In this case the game will usually store the size of each tile somewhere, from which the location and plane size can be calculated in the cases where each tile is of different dimensions. Often tiles are the same size, which saves a lot of trouble since the location of any particular tile (as well as the number of tiles in the file), can be easily calculated.

This arrangement is efficient enough that many games will have separate files in this format separate from all other graphics (e.g. Dangerous Dave 2).


Row-planar EGA data

Offsets into file data
Pixels Plane
0 1 2 3
(0,0) to (7,0) 00 02 04 06
(8,0) to (15,0) 01 03 05 07
(0,1) to (7,1) 08 0A 0C 0E
(8,1) to (15,1) 09 0B 0D 0F
(0,2) to (7,2) 10 12 14 16
(8,2) to (15,2) 11 13 15 17
(0,3) to (7,3) 18 1A 1C 1E
(8,3) to (15,3) 19 1B 1D 1F
(0,4) to (7,4) 20 22 24 26
(8,4) to (15,4) 21 23 25 27
(0,5) to (7,5) 28 2A 2C 2E
(8,5) to (15,5) 29 2B 2D 2F
(0,6) to (7,6) 30 32 34 36
(8,6) to (15,6) 31 33 35 37
(0,7) to (7,7) 38 3A 3C 3E
(8,7) to (15,7) 39 3B 3D 3F

This arrangement has more to do with how graphics are loaded rather than whether or not all graphics are loaded at once. Like graphic-planar above, each image is separate, however instead of storing each plane in its entirety, the planes are split up by row. This means once all the pixel data has been read in for a given row, the data following refers to the next plane on the same row. Only once all the planes have been read in does the data advance to the next row.

An example 16×8 image in this arrangement is shown on the right. Here the width of a row is 16 pixels, or 2 bytes of EGA data. Again, graphics in this format are often grouped together and the game will need to store the graphic's size and location.


Byte-planar EGA data

Offsets into file data
Pixels Plane
0 1 2 3
(0,0) to (7,0) 00 01 02 03
(8,0) to (15,0) 04 05 06 07
(0,1) to (7,1) 08 09 0A 0B
(8,1) to (15,1) 0C 0D 0E 0F
(0,2) to (7,2) 10 11 12 13
(8,2) to (15,2) 14 15 16 17
(0,3) to (7,3) 18 19 1A 1B
(8,3) to (15,3) 1C 1D 1E 1F
(0,4) to (7,4) 20 21 22 23
(8,4) to (15,4) 24 25 26 27
(0,5) to (7,5) 28 29 2A 2B
(8,5) to (15,5) 2C 2D 2E 2F
(0,6) to (7,6) 30 31 32 33
(8,6) to (15,6) 34 35 36 37
(0,7) to (7,7) 38 39 3A 3B
(8,7) to (15,7) 3C 3D 3E 3F

This arrangement has more to do with how graphics are loaded rather than whether or not all graphics are loaded at once. Like graphic-planar above, each image is separate, however instead of storing each plane in its entirety, the planes are split up at the byte level. This means each byte contains data for one plane of eight pixels, with the following byte containing data for the next plane of the same eight pixels. After four bytes have been read, all four planes will have been read for a group of eight pixels.

An example 16×8 image in this format is shown on the right. Here the width of a row is 16 pixels, or 8 bytes of EGA data. Again, graphics in this format are often grouped together and the game will need to store the graphic's size and location. (Unless it is a list of tiles which are all of the same, known, dimensions.)


Linear EGA data

Offsets into file data
Line (Y) Column (X)
0-1 2-3 4-5 6-7 8-9 A-B C-D E-F
0 00 01 02 03 04 05 06 07
1 08 09 0A 0B 0C 0D 0E 0F
2 10 11 12 13 14 15 16 17
3 18 19 1A 1B 1C 1D 1E 1F
4 20 21 22 23 24 25 26 27
5 28 29 2A 2B 2C 2D 2E 2F
6 30 31 32 33 34 35 36 37
7 38 39 3A 3B 3C 3D 3E 3F

This arrangement is the opposite of planar. Instead of the data being split up into planes, it is combined into a collection of pixels. Each nybble (half a byte - four bits) contains data for all four planes for a single pixel. This is otherwise known as 4bpp (four bits-per-pixel) linear data.

When reading a byte, the upper four bits contain data for one pixel, and the lower four bits contain data for a second pixel.

Very few games store data in this format, on account of the extra processing required to load the data into EGA display memory. It is listed here for completeness.


Converting planes into palette indices

Once it is known how the planes are arranged, converting the data into colours is done by combining the bits in each plane together using binary arithmetic. This will return a value between 0 and 15 inclusive, which is an index into the EGA palette.

Plane Value (hex) Value (binary) Value (pixels/flipped binary)
Blue AA AA 10101010 10101010 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
Green CC CC 11001100 11001100 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1
Red F0 F0 11110000 11110000 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
Intensity FF 00 11111111 00000000 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
Result 0 1 2 3 4 5 6 7 8 9 A B C D E F

Examples of games that use each type