   The OMF pilot images are 54 pixels high, and appear to be limited
to 71 pixels in width.  The actual width of each row of the image is
variable.  The width of each row, as well as its offset from the left
margin is coded within the image and followed by the actual image
data for that row.  If the offset for any row is 0 (i.e. it starts
immediately at the left margin) it may be encoded in a shorthand
method.  In addition, there are special coding sequences for runs of
transparent pixels that may be intermixed within a row of opaque
pixels   The final complication is that only certain color values are 
appropriate for use in the pilot images, other color indexes may change 
or fade depending on the color of your robot and the scene you are in
within the game.  In general, the image contains 54 rows (unless you
have runs of transparent pixels), each encoded as follows:  Header, Data, 
repeat as necessary...

   The header data is as follows for normal runs:

key, offset*4, width*4+1

   So for a line like this (periods include transparent pixels):

....XXXXXXX...

   the header would be:

02 00 10 00 1D 00
^     ^     ^
|     |     width - 7 times 4 is 28 plus 1 is 29, which is 1D hex
|     offset - 4 times 4 is 16, which is 10 hex
key - starts out as 0x02 and increases by 4

The header is followed by raw pixel data for that line.

The image you intend to use must conform to these limitations:

   1.  Does not exceed 70x54 pixels in size

       (The width of the image is limited to 70 here rather than 71 to
        simplify the example code below, see the "further exploration"
        section for explanation.)

   2.  Uses only the colors that are used by the original pilot images

       Maybe the easiest way to accomplish this is do a screen capture
       of OMF and then load it into your paint program so that you can
       use the same palette and figure out the valid colors - they're
       mainly within the last 64 palette entries.

You need to be able to get this artwork into an array within your
conversion program in its raw form.  An appropriate storage location
might be:

   unsigned char image[54][70];

The next portion of this discussion is presented as heavily-commented
C code.  This is not an optimal coding method (nor even a good method)
but it is sufficiently wordy to convey these ideas.  Also, this program
is not capable of converting pictures that contain runs of transparent
pixels (e.g. XXX XX  XXXX).

ConvertImage()
  {
  int x, y, i;                    // a plethora of index variables
  int offset;                     // blank space on left margin
  int width;                      // length of opaque pixel run
  int found_non_zero;             // indicates start of opaque run
  unsigned char key=0x02;         // code to indicate start of run
  unsigned char c;                // temp variable for pixel data
  unsigned char linebuffer[70];   // store the opaque pixels here
  FILE *out;                      // handle for output to file

  out=fopen("filename.ext","wb"); // open output file binary mode

  for (y=0; y<54; y++)            // process each row
    {                             // set up variables for this row:
    offset = 1;                   //  we won't deal with offset=0
    width = 0;                    //  no pixels have been save yet
    found_non_zero = 0;           //  haven't found first opaque pixel
    for (x=0; x<70; x++)          // process each column
      {
      c = image[y][x];            // simply read the pixel data
      if (c == 0)                 // if pixel is transparent, then...
        {
        if (!found_non_zero)      // skip transparent til first opaque
          offset++;               // move the left margin over one
        }
      else                        // otherwise it's opaque...
        {
        found_non_zero = 1;       // indicate found opaque (overkill!)
        linebuffer[width]=c;      // save the opaque pixel
        width++;                  // increase width of opaque run
        }
      }                           // done with all columns, save
                                  // 6-byte header: offset != 0
    fputc(key, out);              // indicates start of run
    fputc(0, out);                //   hi byte of int
    fputc(offset*4, out);         // offset 4 times too big
    fputc(0, out);                //   hi byte of int
    fputc((1+4*width)&0xff, out); // width 4 times too big plus 1
    fputc((1+4*width)>>8, out);   //   hi byte of int

    for (i=0; i<width; i++)       // process each opaque pixel
      fputc(linebuffer[i], out);  // write out pixel data
    key += 4;                     // next code to indicate run
                                  // inc by 4, thus: 0x02,0x06,0x0a...

    }                             // done with all rows, finish up
  fputc(7, out);                  // all I've seen ends with this
  fputc(0, out);                  // all I've seen ends with this
  fclose(out);                    // close the output file
  }

Putting it all together:
   The pilot image begins at offset 1560 (decimal) within the pilot
file.  (At least this is true for NorthAm pilots).  All that remains
is to truncate the pilot file to 1560 bytes (keeping bytes 0-1559)
and append the newly created processed image file to it.

For further exploration:
   Reduce this bloated example code down to about 8 lines. <g>
   (Hint: a while loop to do transparent, followed by another for
          opaque, using a pointer to access the image array)

   The special case of left margin = 0 is dealt with by the fact that
offsets are always even, while widths are always odd.  If the int
following the key value is odd then that means that offset was not
encoded, thus left margin=0.  So, run header is reduced from 6 to 4
bytes.  Add this logic to the above routine and you can do 0 left
margin images.  (IOW, test for offset=0, then don't write offset bytes)

   To include runs of transparent pixels, you must use a slightly different
method.  The key value is the new offset*4, the offset is width*4+1, and
there is no width (everything is shifted left).  Here is a diagram to
illustrate.  Suppose your line was this:

...XXXXXX..XX...

   You would use the normal method for the first 6 opaque pixels.  The
header for the next 2 opaque pixels is as follows:

2C 00 09 00

   Followed by pixel data.  The entire line would be:

02 00 0C 00 19 00 {data for 6 pixels} 2C 00 09 00 {data for 2 pixels}

   So, in effect, it's like having more than one line per row.  If you
have any questions, you can contact the author or the editor for more
information (addresses at end of document).

Originally by: Dave Bollinger (CIS# 72510,3623)
Revised and edited by: Craig Boston (CIS# 74442,2200)
