Saturday, 28 August 2021

Galaxian Part 2 - Graphics formats

The format of the graphics in an arcade game like Galaxian is optimised for the video circuitry rendering the image as the raster beam scans down the screen.

Specifically for Galaxian, the graphics data for each bitplane is stored in a separate device (ROM chip) so that colour data for each pixel can be accessed in parallel, and data for one line of each (8x8) tile is contained in a single byte from each device. Additionally, Galaxian has a vertical monitor, which means pixel ordering differs from, for example, a PC with a horizontal monitor; a straight dump of the graphics data results in the images rotated 90 degrees and in some cases, also mirrored.

This of course isn't very convenient at all for a machine like a PC that may be emulating the game. Here is a snippet of the macro-filled array that MAME uses to construct tile data from the original graphics ROMS:

static const gfx_layout galaxian_charlayout =
{
8,8,
RGN_FRAC(1,2),
2,
{ RGN_FRAC(0,2), RGN_FRAC(1,2) },
{ STEP8(0,1) },
{ STEP8(0,8) },
8*8
};

There's little point going into an explanation here, but suffice it to say it's not an ideal starting point to convert the graphics into whatever format the host language/environment/platform requires.

Arguably the easiest format to start with is a 1 byte-per-pixel (bpp), pre-rotated, array in C. From there, it is much easier to convert to another format, whether that be rendered directly into memory bitmaps for the Allegro graphics library, or re-arranged into binary ROM images for the Neo Geo.

And so, first order of business was to rip the graphics from the Galaxian ROM images into the abovementioned C array. Once for the 8x8 tiles, once again for the 16x16 sprites - both of which are stored in the same ROM (we have several orders of magnitude more space to work with on modern machines). A small C program that outputs a C source file did the trick. At the same time I also added the colour PROM data, converted to platform-independent RGB values.

Here's what the output for a tile looks like:

uint8_t tile[256][64] =
{
  // $00
  {
    0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x00, 0x00,     //    ###  
    0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x03, 0x00,     //   #  ## 
    0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03,     //  ##   ##
    0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03,     //  ##   ##
    0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03,     //  ##   ##
    0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x03, 0x00,     //   ##  # 
    0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x00, 0x00,     //    ###  
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,     //         
  },

Note that I added the 'ASCII art' rendering of the tiles to both serve as documentation, and a sanity check that the conversion was correct.

Since I am prototyping the transcode on the PC using the Allegro graphics library, I need simply to incorporate the output of my conversion utility into the build and the raw, platform-indepedent graphics data is included in the program. And in this particular case, the startup code for the Galaxian port will read the graphics array, initalise the palettes and render the tiles & sprites into memory bitmaps to be blitted to the screen at run time.

I'm hoping that Miro will be able to use a similar technique for Javascript, in which case I'll tweak my utility to (also) output a Javascript source file. If not, Miro should at least be able to write a small utility to convert the same data into something he can use to render the graphics.

For porting to systems that read graphics data directly from ROMS for example, that C file would be included in a small utility that produced the respective ROM file images. This is something I did for Scramble on the Neo Geo.

So now we have all the graphics data in a source file that can be rendered - directly or indirectly - onto the host platform display. Exactly what we need to be able to check the progress of the transcode.

Next step is to get a project and software framework for the game up and running, and I generally write some test code to render all the tiles and sprites as a sanity check.

No comments:

Post a Comment