the foreground task (the game) generates terrain chunks on the fly as
needed from underlying world map data, and stores them in a cache for
use by the renderer. chunks are stored first in inactive cache slots,
and then on a LRU basis once the cache is full.
the background chunk generator looks ahead around the player for
chunks that ought to be generated, and generates them in the background.
background_gen_chunk:{if generating_chunk { if chunk_to_gen is active in the cache, start_generating = true. // the foreground task already generated the chunk on demand, we weren't fast enough! have to start over! if our_cache_slot is active, start_generating = true. // the foreground task used the cache slot we were using to generate a chunk in! // note that some sort of reserved flag in the cache should be able to preclude this issue. but with a LRU // cache, if the foreground grabs our slot, which was the least recently used slot as of pass_number of // frames ago, it must really need it bad, so reserving it could likely result in it being generated in // the foreground before we finish anyway. otoh, we set our slot to inactive, so the renderer doesnt try // to use it while we're still generating it, so its the first slot grabbed by the foreground if the // foreground needs to generate a chunk on the fly right now for the renederer. so maybe a reserved flag // could be of use. it would force the foreground task to use the LRU slot, rather than our inactive one. // but we might then finish genrating only to find its not relly needed anymore. something to think about. }else { // not generating chunk start_generating = true }if start_generating { chunk_to_gen = determine chunk to generate if chunk_to_gen = none, return // all desired chunks already in cache! we're done! getabeer! . our_cache_slot = get free cache slot pass_number = 0 generating_chunk = true }do_a_pass} do_a_pass:{switch pass_number { case 0: // add some stuff to the terrain chunk pass_number++ break case 1: // add some more stuff to the terrain chunk pass_number++ break ... case : // add final stuff to the terrain chunk // all stuff added. set cache slot to active for use by renderer cache[our_cache_entry].active = true generating_chunk = false break } }
deterimine chunk to gen:
this does an outward sweeping search around the player to some pre-defined distance.
chunks are checked to see if they are in the cache or not.
the first one not in the cache is returned as the next chunk_to_gen.
if all chunks out to the prescribed distance are in the cache, it returns
NONE as the next chunk_to_gen.
fine tuning:
increase the number of passes and reduce the items added
to the chunk per pass until speeds are accepatble.
a possible mod:
if generating_chunk && !start_generating // IE on second and subsequent passes... { temp = determine chunk to generate if (temp != chunk_to_gen) { // some other chunk is more important, stop this one and start that one! clear(our_cache_entry) chunk_to_gen = temp pass_number = 0 } }
reserved cache slot mod:
if our_cache_slot is active, start_generating = true.
// the foreground task used the cache slot we were using to generate a chunk in!
// note that some sort of reserved flag in the cache should be able to preclude this issue. but with a LRU
// cache, if the foreground grabs our slot, which was the least recently used slot as of pass_number of
// frames ago, it must really need it bad, so reserving it could likely result in it being generated in
// the foreground before we finish anyway. otoh, we set our slot to inactive, so the renderer doesn't try
// to use it while we're still generating it, so its the first slot grabbed by the foreground if the
// foreground needs to generate a chunk on the fly right now for the renderer. so maybe a reserved flag
// could be of use. it would force the foreground task to use the LRU slot, rather than our inactive one.
// but we might then finish generating only to find its not really needed anymore. something to think about.
not sure if its an improvement or not.