
|
The lightmap.tbl files (actually, lightmap1.tbl, lightmap2.tbl, lightmap3.tbl) represent the map data you actually see in EU2. It does not contain sprites (for example, the trees, city, harbour, ... icons),
but only the image of the provinces themselves.
There are 5 lightmap files in the map directory, but lightmap4.tbl and lightmap5.tbl are unused. The data contained in them is not conform to the data in the three other files, so they are probably leftovers from early development. |
File Info |
Location » (eu2 root)\map\lightmap1.tbl
Size » 11,749,936 bytes (11.2 MB)
Location » (eu2 root)\map\lightmap2.tbl
Location » (eu2 root)\map\lightmap3.tbl
|
Zoom levels and map files |
The standard EU2 mapsize is 18944x7296 pixels. This is for the standard zoom level (largest zoom), and that info is contained in lightmap1.tbl.
If you zoom out one time, the size gets divided by two, resulting in a 9472x3648 map. That info is contained in lightmap2.tbl. If you zoom out again, the size gets divided by four, resulting in a 4736x1824 map. That info is contained in lightmap3.tbl. The map is also divided into 32x32 blocks. Each block compresses part of the map. This is unregardless how many provinces are "present" in that block. This is at least one, but it can be as much as 16 or more. That also means that each block has to know what pixel belongs to what province. More on that later. Basically, we have the following table:
The zoom factor basically defines the ratio between a displayed pixel and the number of pixels it represents on the standard zoom. |
File structure and Offsets |
The file is divided into two parts: offsets and blocks:
The number of offsets differs from file to file, because each file contains a different blocks (as seen in the table above).
After the offsets comes a 4 byte integer, which denotes the total size of the datablock. You could also see this as the (totalblocks+1)th offset, padded with an additional 0. And then come the datablocks. Each block is of variable size. |
Datablocks |
It took me quite a while to find this one out, to be fair. If it wasn't for Johan, I guess I wouldn't have found out anyway, as it's quite simple, but hard to decipher. Especially the quadtree part was daunting to find out.
Province ID List
To make this more clear, this is the code used in the lib I use to decompress a block: // C#
for ( int i=0; i<idCount; ++i ) {
if ( idTable[i] <= Province.MaxID ) continue;
ushort id = idTable[((idTable[i]>>9) & 63)-4];
if( id > Province.MaxID )
id = install.Provinces.TerraIncognita.ID;
else {
int river = (idTable[i]>>5) & 15;
if ( river != InvalidAdjacency ) id = install.Provinces[id].GetNeighbor( river ).ID;
idTable[i] = id;
}
}
The processing of the special entries is done after the full list is read in.
Quadtree nodes
The algorithm is actually very simple. It starts off at block level (level = 5, block size 32 pixels). It checks the first bit (and moves the bit pointer to the next one). If it's a 1, the block is divided into 4 smaller blocks, each half the size of the current block (thus 16 pixels). Recursively, the subblocks are processed too (in a bottomright » bottomleft » topright » topleft manner) by doing the same process on each of them. The level is decreased by 1 (as we're one level deeper).
This process stops at level 1 (NOT level 0), which means that we're a 2-pixel resolution. At that level, 4 leafs are created (without a bit in the tree stream). In pseudo code, I'd describe it like this: Proc ReadTree( level ) bit = readNodeBit() moveToNextNodeBit() If bit is set Then If level > 1 Then addBranch() ReadTree( level - 1 ) ReadTree( level - 1 ) ReadTree( level - 1 ) ReadTree( level - 1 ) Else add4Leaves() End If Else addLeaf() End If End ProcStarting it off would be with a call to ReadTree( 5 ).
This just reads in the tree. In effect, you have a tree structure with leafs at the bottom. The values in the parts below are ordered in a breath-first traversal (go as deep as you can in the tree, and start reading there, moving "from left to right" as you go). Using this date to draw it to a surface is another matter. I'll do a seperate document about that!
Leaf Ownership entries
1 province » If there is only one province in the id list, this part is empty. The engine knows there's only one entry and can automatically fill the ownership of each leaf with that province id.
2 provinces » For two provinces in the list, this part is encoded as 1-bit values, one for each leaf. That means there are (leafcount/8) bytes in this part, in this case. 3 or 4 provinces » When there are 3 or 4 provinces in the list, this part is encoded as 2-bit values, one for each leaf. That means there are (leafcount/4) bytes in this part, in this case. 5 to 16 provinces » In this case, this part is encoded as 4-bit values, one for each leaf. This means there are (leafcount/2) bytes in this part. more than 16 provinces » When there are more than 16 provinces in the id list, each entry in this list occupies one bytes, and there will be as many bytes in this part as there are leafs. This also means the upper limit of provinces for a block is 256.
Leaf Color Entries
The color values stored are greyscale values: they are actually offsets into a table generated from the colorscales.csv file, which is used to color the map accordingly. This allows the enging
to use the same map data for the different views, by combining "lighting" values (hence the name, lightmap) with coloring.
Some observations
|
Usability |
These files contain the map data to visualise the EU2 map. |