Lemmingologist
05 Aug 2005 15:02:55
Instructions for editing graphics files
The graphics for the Lemmings levels are contained in the GROUND and VGAGR files. The GROUND files are uncompressed. Their purpose is to organize the raw data contained in the corresponding VGAGR graphics files. The VGAGR files are compressed (see post entitled, "Explanation of Lemmings file compression"), but the data in the GROUND files refers to the VGAGR files after decompression.

Each GROUND file is 1056 bytes long and has the following structure:
Bytes $000-$1BF: objects
Bytes $1C0-$3BF: terrain
Bytes $3C0-$41F: color palettes


Objects (bytes $000-$1BF)

The objects section contains up to 16 records, each record being 28 bytes long. These specify various pieces of information about each object (objects include the entrance and exit, traps, and water). The structure of an object record is as follows (all multi-byte integers are little-endian). The first record in the file is always the exit and the second is always the entrance door (although these objects can be anywhere in the object block of the VGAGR file).

Bytes 0-2: set these bytes to:
00 00 00 - if the object is non-animated
01 00 00 - if the object is a trap
02 00 00 - if the object is animated but not a trap
03 00 01 - if the object is the entrance door
Byte 3: the number of frames in the animation of the object.
Byte 4: width of the object, in pixels.
Byte 5: height of the object, in pixels.
Bytes 6-7: size, in bytes, of each frame plus its mask in the uncompressed graphics file (the mask is one-fourth the size of the frame).
Bytes 8-9: size, in bytes, of each frame in the uncompressed graphics file. This is equal to half the product of the width and the height.
Bytes 10-11: size, in bytes, of each frame in the uncompressed graphics file (repeated).
Bytes 12-13: half the size, in bytes, of each frame in the uncompressed graphics file.

Note: Bytes 14-19 apply differently to the entrance door or objects which have no effect. If the object has no effect, these bytes should be set to 00 00 00 00 01 01. If it is the entrance door, they should be set to 01 00 00 00 00 01. Otherwise, proceed as described below.

Bytes 14-15: one-fourth the distance, measured in pixels from the left side of the object, of the left side of the area of the object in which a lemming is affected.
Bytes 16-17: one-fourth the distance, measured in pixels from the top of the object, of the top of the area of the object in which a lemming is affected (does not apply to the entrance door or objects which have no effect).
Byte 18: one-fourth the horizontal dimension, in pixels, of the area of the object in which a lemming is affected.
Byte 19: one-fourth the vertical dimension, in pixels, of the area of the object in which a lemming is affected.

Byte 20: object type indicator.
00 - has no effect on lemmings
01 - exit or entrance door (can only be used in first and second objects)
04 - trap
05 - water
07 - left arrows (preventing rightward digging)
08 - right arrows (preventing leftward digging)
Bytes 21-22: start position of the image data in the uncompressed graphics file (on rare occasions this isn't actually equal to the start position).
Bytes 23-24: start position of the image data in the uncompressed graphics file (this one is always reliable).
Bytes 25-26: start position of the image data in the uncompressed graphics file, multiplied by four-fifths (again, this is occasionally inaccurate).
Byte 27: does not appear to have any effect.

If there are less than 16 objects, the rest of this section is filled with zeros.


Terrain (bytes $1C0-$3BF)

Terrain pieces are inanimate and do not affect the lemmings. The records in this section simply indicate the positions of each terrain piece in the corresponding graphics file (after the graphics are decompressed). There can be up to 64 terrain pieces, each record is 8 bytes long, and all multi-byte integers are little-endian.

Byte 0: width of the object, in pixels.
Byte 1: height of the object, in pixels.
Bytes 2-3: start position of the image data in the uncompressed graphics file.
Bytes 4-5: start position plus 3/8 of the size, in bytes, of the image data (the size is equal to half the product of the width and height).
Bytes 6-7: start position plus 1/4 of the size, in bytes, of the image data.

If there are less than 64 terrain pieces, the rest of this section is filled with zeros.
Lemmingologist
05 Aug 2005 15:03:54
Editing graphics files continued
Color palettes (bytes $3C0-$41F)

There are four color palettes in each GROUND file: EGA level, EGA preview, VGA level, and VGA preview. Each graphic set uses 16 colors, represented in the graphics file (after it has been decompressed and the images have been deplanarized) by four-bit integers (hexadecimal digits). The level palettes consist of colors 8-F, used when drawing the actual level. The preview palettes include all 16 colors (0-F),  but these are only used only for drawing the title screen preview of the level.

The first 8 bytes ($3C0-$3C7) are the EGA level palette (colors 8-F, one byte per color). There are only 16 possible colors, and the hexadecimal values representing the colors in this palette (not to be confused with the values used in the graphics file) are as follows: 00 = #000000, 01 = #0000AA, 02 = #00AA00, 03 = #00AAAA, 04 = #AA0000, 05 = #AA00AA, 06 = #AA5500, 07 = #AAAAAA, 10 = #555555, 11 = #5555FF, 12 = #55FF55, 13 = #55FFFF, 14 = #FF5555, 15 = #FF55FF, 16 = #FFFF55, 17 = #FFFFFF.
Colors 0-7 are not editable - they always have the following values:
0 = 00 = #000000 = black
1 = 11 = #5555FF = blue
2 = 02 = #00AA00 = green
3 = 17 = #FFFFFF = white
4 = 16 = #FFFF55 = yellow
5 = 14 = #FF5555 = pink
6 = 07 = #AAAAAA = gray
7 = 14 = #FF5555 = pink

The next 16 bytes ($3C8-$3D7) are the EGA preview palette (colors 0-F, also one byte per color). This palette allows for 64 possible colors. The first two bits of each byte are ignored, the next three bits increase red, green, and blue (respectively) by 25%. The last three bits increase their respective colors by 75%. For example: 35 = (00)110101 - both red bits are on, so red = 100%; the 25% green bit is on; and the 75% blue bit is on; the equivalent RGB color would be #FF40BF.

Bytes $3D8-$3EF are the VGA level palette, (colors 8-F, three bytes per color). The values for red, green, and blue each use one byte and are in the range 00-3F (which allows 262144 possible colors). They need to be multiplied by 255/63 in order to get the equivalent RGB colors (for example, 38 2E 0B = #E3BA2D).
Colors 0-7 are not editable - they always have the following values:
0 = 00 00 00 = #000000 = black
1 = 10 10 38 = #4141E3 = blue
2 = 00 2C 00 = #00B200 = green
3 = 3C 34 34 = #F3D2D2 = very pale pink
4 = 3C 3C 00 = #F3F300 = yellow
5 = 3C 08 08 = #F32020 = red
6 = 20 20 20 = #828282 = gray
7 = 30 10 18 = #C24161 = pink

The VGA preview palette (bytes $3F0-$41F) works the same way as the VGA level palette, except that it specifies colors 0-F in the preview.


Graphics files

The VGAGR files, after decompression, each contain two data items. The terrain pieces are stored in the first data item, while the objects are stored in the second. Each terrain piece is stored as raw planar (see "Planar graphics" below) pixel data with four bitplanes, starting from the position in the uncompressed block indicated by the corresponding GROUND file. Terrain pieces are each planarized separately.
In the case of objects, images have multiple frames, which immediately follow each other in the file. Each frame is planarized separately (again, raw data with four bitplanes). After the image data for each frame is a one-bit-per-pixel mask. All non-zero pixels in the frame are represented by 1's in the mask.
Important: the width of each object and terrain piece must be a multiple of 8 pixels, or the image will not be displayed correctly. The height, however, can be any number of pixels.

The MAIN and VGASPEC files are graphics files as well. Each image in MAIN appears to have its own block, but the dimensions of the images are still unknown. The VGASPEC files, with only one block per file, each begin with eight VGA colors, followed by eight EGA colors. The rest of the file is image data mixed with information about the placement of the terrain pieces, but the format of the data is unknown.


Planar graphics

The planar graphics are read by combining the bitplanes (which immediately follow each other in the image data) into a single image, with four bits per pixel. Those four bits correspond to one of the colors in the the color palette. The bits are read one from each bitplane, from bottom to top, as in the following example:
Bitplane 0: 000101000111...
Bitplane 1: 000011111111...
Bitplane 2: 000001000000...
Bitplane 3: 000110111111...
Each pixel corresponds to a column in the table above. So, reading each column from bottom to top, the first 12 pixels in the image are 0000, 0000, 0000, 1001, 1010, 0111, 1010, 1010, 1010, 1011, 1011, 1011; or 0, 0, 0, 9, A, 7, A, A, A, B, B, B.

As replies to this post, I have included code for a planarizer and deplanarizer. These are very slow and should only be used to experiment with editing and displaying Lemmings graphics using a non-planar graphics application (I don't know of any program that can read raw planar graphics). When writing a Lemmings graphics editor, the VGA planar mode should be used, which can display planar graphics with no need for a converter.
Lemmingologist
05 Aug 2005 15:04:44
Planarizer
dim i, j, byte as integer
dim plane (3) as string
dim in, out as binaryStream
dim file as folderItem

file=GetOpenFolderItem("type") //displays "Open File" dialog box
if file <> nil then
     in=file.OpenAsBinaryFile(false)
     out=GetFolderItem(file.name + " Planar").CreateBinaryFile("type")

     while not in.EOF
           byte=in.ReadByte
           for i=7 downto 0
                 plane(i mod 4) = plane(i mod 4) + str(byte\pow(2,i))
                 byte=byte mod pow(2,i)
           next
     wend

     for i=0 to 3
           while plane(i) <> ""
                 byte=0
                 for j=7 downto 0
                       byte=byte+val(left(plane(i), 1))*pow(2,j)
                       plane(i)=right(plane(i), len(plane(i))-1)
                 next
                 out.WriteByte byte
           wend
     next
end if
Lemmingologist
05 Aug 2005 15:05:29
Deplanarizer
dim i, j, k, byte, spacing as integer
dim newFile as string
dim in, out as binaryStream
dim file as folderItem

file=GetOpenFolderItem("type") //displays "Open File" dialog box
if file <> nil then
     in=file.OpenAsBinaryFile(false)
     out=GetFolderItem(file.name + " Non-planar").CreateBinaryFile("type")
     spacing=in.length\4-1

     while len(newFile) < in.length*8
           for k=0 to 3
                 byte=in.ReadByte
                 newFile=left(newFile,len(newFile)-k)+str(byte\pow(2,7-i) mod 2)+right(newFile,k)
                 in.position=in.position+spacing
           next

           i=i+1
           if i=8 then
                 i=0
                 j=j+1
           end if
           in.position=j
     wend

     while newFile <> ""
           byte=0
           for j=7 downto 0
                 byte=byte+val(left(newFile, 1))*pow(2,j)
                 newFile=right(newFile, len(newFile)-1)
           next
           out.WriteByte byte
     wend
end if
Lemmingologist
20 Aug 2005 13:51:44
Update
I discovered a few problems with my previous description of the color palettes. Specifically, I found out that the bitplanes in the VGAGR files are actually read in reverse order, and colors 0-7 are only editable in the title screen overview. The instructions, planarizer, and deplanarizer have all been updated accordingly.
Timballisto
21 Aug 2005 20:53:42
Re: Instructions for editing graphics files
Wow...with you around, we'll be probably be able to do most everything cheapo can do, only we'll be using the original game!

Er, by the way.  Where exactly can you learn all this stuff???????  I mean, half of all this sounds like Japanese or something.
ccexplore (not logged in)
21 Aug 2005 23:27:25
Re: Instructions for editing graphics files
Wow...with you around, we'll be probably be able to do most everything cheapo can do, only we'll be using the original game!

Um, you seem to have forgotten that it takes time and effort to write a graphics editor that's usable by the general public.  I have known about this stuff too and had even e-mailed Mindless months ago on this when he asked, but as you might've noticed, so far neither of us has written anything yet (well, except for myvgaspec).   ;P

But yes, you can at least hope that one day......   ;)
ccexplore (not logged in)
21 Aug 2005 23:51:29
Re: Update
I discovered a few problems with my previous description of the color palettes. Specifically, I found out that the bitplanes in the VGAGR files are actually read in reverse order

Are you sure about this?  I checked a working program of mine written months ago that can extract the VGAGR graphics, and the way it reads the bitplanes clearly indicates that they are stored in the file in the normal order (that is, bitplane 0, then 1, then 2, then 3).  Or maybe I misread your description.
Mindless
22 Aug 2005 01:25:55
Re: Instructions for editing graphics files
...that's usable by the general public.

Oh, yeah... that's my problem... that and I'm lazy.  :D
Timballisto
22 Aug 2005 01:46:32
Re: Instructions for editing graphics files
Where can I learn about all the...stuff you said up there?  Where can I learn about how that all works and what it is?
Lemmingologist
22 Aug 2005 08:51:42
Re: Instructions for editing graphics files
Where can I learn about all the...stuff you said up there?  Where can I learn about how that all works and what it is?

Try getting a hex editor (I'm sure you'll find one with a Google search) and playing around with the GROUND files. You could try changing the colors, or object properties (turn traps into water, for example). I think, once you open one of the files, my instructions will make a bit more sense. As far as editing the actual graphics files, that is difficult at the moment, as a Lemmings graphics editor has not yet been written.
Lemmingologist
22 Aug 2005 08:54:38
Re: Update
Are you sure about this?  I checked a working program of mine written months ago that can extract the VGAGR graphics, and the way it reads the bitplanes clearly indicates that they are stored in the file in the normal order (that is, bitplane 0, then 1, then 2, then 3).  Or maybe I misread your description.

I'm absolutely positive they are read in reverse order. I used my planarizer to test this.

Edit: They are read from bottom to top (right to left). I considered this to be reverse order, but this is actually the usual way to order bitplanes.
Lemmingologist
22 Aug 2005 09:07:47
Re: Instructions for editing graphics files
Oh, yeah... that's my problem... that and I'm lazy.  :D

Same here - I just don't have the patience to write an entire graphics editor from scratch. Maybe we could all collaborate...
ccexplore (not logged in)
13 Sep 2005 08:46:09
Re: Instructions for editing graphics files
Bytes 16-17: one-fourth the distance, measured in pixels from the top of the object, of the top of the area of the object in which a lemming is affected (does not apply to the entrance door or objects which have no effect).

Actually, this is inaccurate.  The distance is measured from 4 pixels above the top of the object.  I've long known this, but now there is clear proof which one can directly obtain by observing the game rather than disassembling:

http://eng-forum.lemmingswelt.de/cgi-bin/yabb/YaBB.cgi?board=news;action=display;num=1117597280;start=270#272

The reason that solution is possible is because the distance is being measured from 4 pixels above the top of the object.  If you examine ground2o.dat, you'll find that the offset x, offset y, width and height of the area of effect are (converted to units of pixels) 0, 0, 32 and 32, which would've fit the entire object perfectly, except it doesn't because the vertical offset distance is measured 4 pixels above the top.  As a result, the trigger area is effectively shifted up 4 pixels from where it should be, and so the last 4 rows of pixels of a one-way area are actually ineffective.

This of course raises the question of whether the same thing is true or not in the Amiga version.

Also, as an addition information, I've now determined that most collisions (excluding those affecting bashing and mining, but including digging) are based on the lemming's feet, which is located at the pixels the row below the white feet you actually see.  In other words, collision with a trigger area is considered to occur when the lemming is standing on top of the trigger area.  Just like how steel areas are handled with respect to digging.