The GRP-file-format - used by Blizzard Inc. for StarCraft(TM)
-------------------------------------------------------------

some notes
----------

All decriptions below are based on experiences during coding the CV-tool.
I'll give no guaranties for completeness and correction - it works as 
descripted with at least my tools. Feel free to use that doc at your own risk.
Modifications are only allowed after correspondation with the author. Feel free
to contact me at http://www.cs.tu-berlin.de/~mickyk/2XS.html. 
There you'll find some C++ classes for use with that format.

Thanx for reading this,

      TeLAMoN of 2XS in 1998.
      (mickyk@cs.tu-berlin.de)


The Blizzard GRP-Format
-----------------------

The GRP's are used as graphic-formats for Blizzards StarCraft(TM). The GRP
is a multiple frame format. There are no signature information 
available (so you can only check the file-extension for valid files) nor 
any palette information. After decoding you get a pixel-map which consists
of 8-bit-index-values refering to a local palette.
How it works:

Header:
~~~~~~~
Offset
         +---------------+ 
   0x0000| L  frame-     | one WORD (2Bytes, Low first) for the number of 
         | H  count      | following frames
         +---------------+
   0x0002| L  X-Dim      | one WORD for the X-dimension of the whole frame
         | H             |
         +---------------+
   0x0004| L  Y-Dim      | one WORD for the Y-dimension of the whole frame
         | H             |
         +---------------+

FrameTab:
~~~~~~~~~
Offset
         +---------------+ 
   0x0006| xOffset       | one Byte for the xOffSet of the first frame
         +---------------+
   0x0007| yOffset       | one Byte for the yOffSet of the first frame
         +---------------+
   0x0008| ?             | these two Bytes I've no idea - maybe you ?!
         | ?             |
         +---------------+
   0x000a| L Offset in   | one DOUBLEWORD (Low first) where we can find
         |   the file,   | the frame-data
         |   to find the | <pFrameData>
         | H framedata   |
         +---------------+
         ... 

         That block repeates as often as frames are present (see framecount)

FrameData:
~~~~~~~~~~
Offset
               +---------------+ 
<pFrameData>   | L Offset first| one WORD for the offset, where to find the first
               | H line        | line-data  <oL1> (to get the number of lines-1 
               +---------------+ for that frame you have to calculate <oL1>/2)
               | L Offset 2.   |
               | H line        |
               +---------------+
               ...

               That block repeats until <oL1> is reached (the same as the number 
               of lines are present within this frame)
               
LineData:
~~~~~~~~~
Offset
                   +---------------+ 
<pFrameData>+<oL1> | BYTE 1        | Bytestream coded with the following 
                   +---------------+ algorythm: see below
                   | BYTE 2        |
                   ...
                   | BYTE <oL2>-1  |
                   +---------------+

                   +---------------+ 
<pFrameData>+<oL2> | BYTE 1        | Bytestream  
                   +---------------+ 
                   | BYTE 2        |
                   ...
                   | BYTE <oL3>-1  |
                   +---------------+

                   ... repeated for all lines...


Ok, how we get the whole frame composed ? Well, let's start:

First to say, we start at the lower-right corner of the frame. So a line
will be assembled from right to left. AND don't forget the xOffset and yOffset
for the start position. 

on_Top:

If the BYTE we get is >=0x80 (Values in Hex):

   -subtract 0x80 from that BYTE and subtract the result from our 
    current_X_position. 

    Example: We get 0x85 as value. Subract 0x80 and we get 0x05. If our
    current_X_position is 0x43 the new value will be (0x43-0x05) 0x3e.
    How it looks in our framebuffer: ( ^ - is the current_X_position)

    before:    [... 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 10 1f ...] 
                                                              ^
    after:     [... 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 10 1f ...] 
                                               ^


else

if the BYTE we get is >0x40:

   -subtract 0x40 from that BYTE and store the result as LOOP
   -get the next BYTE and put that BYTE LOOP-times into our frame-buffer

    Example: We get 0x43. Then LOOP will be 0x03. The next BYTE is 0x62.
    Then our framebuffer will look like this:

    before:    [... 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 10 1f ...] 
                                               ^
    after:     [... 00 00 00 00 00 00 00 62 62 62 00 00 00 00 00 20 10 1f ...] 
                                      ^

else

if the BYTE we get is <0x40:

   -put that BYTE into LOOP
   -copy the following LOOP BYTES into out framebuffer

   Example: The grp looks like ... 06 14 2a 34 3a a1 f1 ... then LOOP will be 0x06
   and out framebuffer looks like:

    before:    [... 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 10 1f ...] 
                                      ^
    after:     [... 00 f1 a1 3a 34 2a 14 62 62 62 00 00 00 00 00 20 10 1f ...] 
                    ^

now get the next BYTE (until the end of the line is reached) and go back to on_Top:.


Mhhh, thats all. With that you should be able to read GRP's. If you don't want to
code your own C++ classes or routines then you can take a look at 
http://www.cs.tu-berlin.de/~mickyk/cv.html . There you'll find some sources
and maybe an actuall version of these expl. If you have questions or
corrections or whatever else please write a mail.


LOF with that expl and remember: REAL CODE IS TIMELESS !!!


TeLAMoN of 2XS in 1998
