If done wrongly, this could produce a dramatic slowdown in DF; doing it right would be a lot of work.
So don't prod too hard. You don't want a half-assed implementation of this.
I...actually, doesn't the skyblock code do about 70% of this?
A: Only if it's done stupidly. The smart way to skyblock is check the "light" flag on the tile X layers down (of the "outside/light/aboveground" set, one will do the trick. I may be picking the wrong one, but one definitely will work)
So, if I wanted to make a similarly quick way to implement this...it'd be to make some sort of "tiles down to nonempty" (below, "drop_z") count in the tile, and update that when things change it, rather than constantly checking what it is, meaning only two tile lookups per tile, a constant. Worse than single-view, but you could do something like
#define DEPTH_DISCOUNT 0.1
for each(tile view_tile in view) {
temp_graphic = get_tile_graphic(view_tile.x, view_tile.y, (view.z - view_tile.drop_z));
//get the tile that we're drawing, however far down it is
temp_graphic -= (temp_graphic * DEPTH_DISCOUNT) * view_tile.drop_z;
//adjust brightness based on depth down
//...should cap so we don't get funkylicious graphics when it would fully black out or more, not done here
//can be different calculation, this is just linear 10%
view.draw (view_tile.view_x, view_tile.view_y, temp_graphic);
//and, draw the thing.
}
This need not be in three statements, obviously, but I did it for clarity.
Of note is that it should be doable at roughly the same step as you're applying colors to the tile (not shown)...
Of course, what's expensive is implementing all the things that change drop_z- though, all these should be done wherever the "Light" flags are fiddled with. Which is a lot of places (building completion, buildings changing state due to lever, building deconstruction, building destruction in many ways, digging, caveins, obsidian formation, ice melting/freezing...)
this is still an O(h) solution per tile, in the tile changes, but O(1) in the renderer...actually could be optimised to O(1) in the tile changes by only checking/updating drop_z up to where it stops mattering (drop_z >= 10, in this case, as that's complete blackout of tile...this would also solve the dimming-capping problem without needing to add more logic to the drawing routines)
Thinking more still, the light flags(light/outside/subterrane) could have an optimisation that doesn't go so well with the drop_z sort of thing- simply storing where the light falls down to for each (x,y) rather than storing "is this tile light/outside/subterrane"...this doesn't work for the drop_z since you need to have arbitrarily many drop_z layers (though most forts will not need more than a few, anything structured like a tree/platform/bridge city would inflict a great deal of it)
edit:
I forgot a significant one needing to update drop_z: flying/falling creature/vermin/item motion. But only for when they're moving through empty tiles, which is what restricts it to flying/falling. Unfortunately these states are not so rare that they could be ignored...flingify(), crossbows, enemies(or their limbs) being sent flying,
flying creatures, melancholy...
...ALL flows...
What's worse is, e'en RAINfall can change midair tile occupancy (it destroys webs, so only for outdoor GCS- the vermin only seem to web on floored tiles?)
Yes, this is a mess to think about.