I hope this might help:
I use 2 caching systems:
1. map section caching
2. tile caching
Lets work with a small example. Say you have a map, 256x256. I divide this into a 4x4 grid of sections. Each map element, is a 32 bit unsigned long. I use half, 16 bits for a tile index into a tile set defined by that section. This allows me to store 65535 tiles per section. The other 16 bits are used for attributes, walkable etc.
Now the rendering engine, asks the map cache manager, where we are on the map. The map manager figures out what map sections need to be drawn. The map manager keeps 4 sections in memory at any time, once we encounter a section that was not loaded from disk previously, the manager evicts one map section and replaces it with the new one. (you can use your own eviction rules, LRU (Least recently used) is a common one.)
This way you can walk through your map, seemlessly, and the map manger handles the loading of sections for you, so your map size is virtually unlimited.
An example layout of map sections would be:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
You see the most sections that are displayable at anyone time is 4, that is if you are in the viewable area of 4 sections.(Hence the 4 cache entries, for performance issues, you might want to increase the cache size) And each section contains 64x64 elements.
So now when the render as for a map element, the map manager handles the loading/caching of its sections and returns a 32 bit value. Half contains a tile index, the other a tile set identifier.
We then pass this info onto the Tile Cache manager, who examines it's cache to see if that tile set is currently loaded. If not it loads it, and returns the tile bitmap to the renderer. It uses the same caching system as the map manager (Base class abstracted), with a larger cache size.
The beauty of this system, is that it's abstracted at a level that makes it easy to use. Given any x,y location, your renderer code might look like this:
.
.
.
while(y{
while(x {
tileinfo = MapManger->GetMapElement(x,y);
surface = TileManager->GetTileBitmap(tileinfo);
Blit surface at appropriate location
}
y++;
}Obviously this is a small example, I use larger map sections, map size and a slightly more complicated tile/object caching system, but the essential design is the same.
For Jim:
I don't quite understand your pointer to a tileset, and how that works? When you loaded a map from disk, each map element's tileset pointer would be different each time? i.e your tileset gets allocated to a differnt memory location each time your program is run. Also wouldn't you have to populate this element with the tileset pointer each time you loaded a map.