Slobu also asked the question on SpritesMind, where I replied with this:
Well, I imagine you already know the general gist of the idea, so here's a quick run through of the simplest case.
Meta-blocks, one way to see it, is a form of basic data compression, storing maps of patterns of tiles instead of individual tiles.
Let's say you have a 32 x 2 map, where the data looks like this, stored in an array of 16 bit values:
Code:
[1][1][2][2][3][3][4][4][1][1][2][2][3][3][4][4][1][1][2][2][3][3][4][4][1][1][2][2][3][3][4][4]
[1][1][2][2][3][3][4][4][1][1][2][2][3][3][4][4][1][1][2][2][3][3][4][4][1][1][2][2][3][3][4][4]
legend: [X] -> represents a tile index.
If the map is large, like 512x512, it would take 524288 bytes. This is obviously a lot. The example would take 128 bytes of storage.
But there's something peculiar about the data. As you probably noticed, there are 2x2 patterns of blocks that are repeated. Because of the patterns, you could represent the data differently by not storing individual tile, but patterns of tiles.
Code:
pattern 1:
[1][1]
[1][1]
pattern 2:
[2][2]
[2][2]
pattern 3:
[3][3]
[3][3]
pattern 4:
[4][4]
[4][4]
our map stored as a series of patterns:
[1][2][3][4][1][2][3][4][1][2][3][4][1][2][3][4]
Because the map is now represented as a series of patterns and not individual tiles, you start seeing some savings in rom storage. Here, the patterns would take 32 bytes and the map data would take 32 bytes for a total of 64.
If you had that 512x512 map with the same pattern of data, that map would take 131072 bytes. Plus the 32 bytes for the patterns. So with patterns, you could save a fair bit of rom space.
Of course, my example is pretty contrived and artificial but it does give you an idea of how it works.
*************
Another way of see it, from the point of view of a game designer, is not as a compression scheme but as a way to build maps. You create a set of patterns use them as building blocks to build a map. Because you're working with sets of 2x2 patterns, it's faster to build maps than placing individual tiles. Of course what you gain in speed you lose in flexibility. You have to make sure that the patterns go together well and that they can repeat. If you have lots of specific patterns, you start losing the memory savings.
Code:
patterns the game designer works with:
grass pattern:
[1][1]
[1][1]
house pattern:
[2][2]
[2][2]
tree pattern:
[3][3]
[3][3]
townsfolk pattern:
[4][4]
[4][4]
the saved map built by a game designer:
[1][2][3][1][2][3][4][4][4]
[4][1][2][3][4][1][2][3][4]
[1][2][3][4][2][2][3][3][3]
*************
That's the theory. Of course the storage savings aren't free. There are two practical problems, one of storing the data and one of retrieving the data.
1. Storing the data.
There are two cases, a) you're using a pre-built editor like Mappy or Tiled or b) you have your own editor.
a) pre-built editor like Mappy or Tiled.
To save the map into meta-blocks, the programmer will have to write an exporter. The exporter will have to analyze the map data, looking for 2x2 patterns (or whatever size you choose). The exporter analyzes the map in 2x2 tile chunks. It also keeps a list of 2x2 tile patterns in memory while analyzing the map. There will also be a new map, the meta-block map, which will be a quarter of the size of the map where every item is an index into the pattern set.
When analyzing the map chunck by chunk, if the 2x2 tile chunk its looking at doesn't exist in the pattern set, it creates a new pattern and adds it to the pattern set. If the pattern already exists, then no new pattern is needed. In either case, the index of the pattern is saved into the meta-block map. When it has finished going through the whole map, where will be a pattern set and a meta-block map.
It's extra work to do the map analysis, but you save work because you're working with pre-made tools. Also, the complexity of the map affects the size of the data. If there are too many individual patterns in the map, meaning that there are very few repeated 2x2 patterns, then you start losing on the storage savings. It's a trade off between unique patterns and storage size. Your game designer will always have to be aware of this when building maps.
b) custom editor
A programmer builds an editor specially made to create maps with 2x2 patterns. The game designer creates the patterns manually and creates a map with them. There's no need for a programmer to analyze the data but it requires writing a custom editor. The game designer is aware at all times that their map is made out of patterns and is most likely more conscious of reusing them efficiently.
2. Retrieving data
Once you have your map data stored in your rom, there needs to be a way to build your map on screen. Because the data is stored as a bunch of patterns instead of a big array, it's trickier to do.
Simplest case:
You know your map on screen is supposed to be 512 x 512 and that every pattern is 2x2 and that your meta-block array is 256x256. To draw an individual tile from your 512x512 map, you need to go from the 512x512 map to the 256x256 meta-block map by dividing by 2 (or whatever the width of your pattern is). Once you know which item of the 256x256 map you're using, you can get the index of the pattern it uses.
Once you have the pattern, you can use modulo to figure out which tile of the pattern you're using.
An example of doing the look up:
Code:
- Tile 0 of the 512x512 map refers to tile 0 of the 256x256 meta-block map.
- Tile 0 of the meta-block map refers to a pattern, lets say pattern 5.
- Tile position (in this case 0), modulo the width of the pattern (2) is tile 0 of pattern 5.
- Draw that tile.
Of course you're drawing one tile at a time. It may be more efficient to use the meta-block map intstead and draw 2x2 patterns on screen directly. I'll leave that as an exercise to the reader
This is just one technique. I'm sure others have better ones.
And I'm sure I've made a mistake or two. Corrections welcome!