I just spent two hours inspecting that bridge issue deeper (and a third one writing that forum post

). See the attached screenshot illustrating the problem.
First a bit of background about how my viewport algorithm works: It basically performs the following steps:
1. Given the region to paint in screen coordinates, calculate which tiles would bound that region *if* the whole map would have height zero
2. For each column on the isometric map, determine the actual top and bottom row to paint.
Step 2 is a bit complicate, since it cannot be calculated in one closed formula. I solve it using the observation, that the higher a tile is, the more in the north it will be painted. This, in order words, means that if at some screen coordinate y, assuming height zero, tile T would be painted, the tile actually painted at that screen coordinate y (with height > zero) will always be south of T.
Thus, I can use binary search on the area defined by the tiles bounding the area assuming height zero, and the lower map edge, for finding the tile actually bounding the painting area given in screen coordinates above.
In each step of that search, log(map_height) times, I call GetViewportY(tile).
(more details about this algorithm can be found in the patched source code, a patched viewport.cpp contains extensive comments about that).
The problem with bridges now is, that a bridge tile in fact can be higher (painted more northwards) than a tile is actually more in the north. Something which otherwise only happens for buildings, which have a somewhat limited height.
If you look at the screenshot, you see a glitch. The reason for that glitch is, that the algorithm inspects the tile behind the glitch, calculates correctly, there is a tile with height 15. It cannot find the bridge tile southwards, which actually has height, say, 25, which can only be determined by IsBridgeAbove and GetBridgeHeight.
BTW, if there is a hill behind the bridge, the problem quickly disappears, i.e. what you see here is actually near the worst case landscape.
Now, what options do I have?
(1.) Inspect all tiles south of the chosen tile, wether there is maybe a bridge that triggers correction of the calculated tile.
This would result in a considerable performance loss, for an actually quite seldom case. Thus, I am very reluctant concerning thinking in this direction.
2. High buildings are treated using this piece of code:
Code: Select all
int viewport_bottom = _vd.dpi.top + _vd.dpi.height + 116;
i.e. I artificially expand the region considered dirty by 116 pixels (the value is taken from the old code as far as I remember) into the south. Obviously, the higher the added constant is, the higher bridges can become without triggering problems. Furthermore, the height (in terms of screen coordinates) of one heightlevel is well-known (TILE_HEIGHT =

.
Thus, one could think about introducing a configuration variable "Maximum Bridge Height", together with a warning "high values result in a performance loss". Then, I could make the 116 above a variable depending on the configuration variable. If the user chooses 5 or 6, the 116 can stay, if the user chooses e.g. 15, then we probably are somewhere between 200 and 300. Which of course means, that every render operation affects a considerable bigger region, i.e. it costs performance.
(actually, in a worst case landscape as seen in the screenshot, and given the quite high steel suspension bridge, the first glitches start at about height 6 - quite seldom, since the border of the repaint region additionally needs to be located exactly on the bridge, but they exist).
3. The third approach would be using some sort of an bridge index for finding out wether there is a bridge. One could, for each section of e.g. 16 x 32 tiles, store a vector with all tiles being containing a bridge higher than the minimal glitch height (or maybe those being shadowed). Assuming that high bridges are quite seldom, that map would be fairly small. Then, the algorithm from 2. above could, after it has calculated the searched tile, with one map get() determine wether in its region is a high bridge. In 99.9% of all cases, the answer will be no, in the remaining 0.1%, it will have to search southwards until some limit for a bridge.
Nevertheless, this would need quite complicate bookkeeping, additional code to be triggered on terraforming and on bridge building and destroying, also there would be the problem that the map would have to be calculated on savegame load().
===> I doubt that this actually makes sense.
Conclusion: I think that approach 2. is the most senseful one. The only problem is the support for old savegames, if one sets the setting to e.g. 10, and someone loads a old savegame with a bridge of height 15 (which is allowed, although probably quite seldom), then there will be glitches.
Maybe the AfterLoad() function could issue a warning, if an old savegame with a high bridge is loaded. One time in the support code for old savegames, scanning the whole map for a high bridge should be ok IMHO, similar on changes of the setting in-game.
What do you think?
One can also postpone that decision until the Viewport patch is reviewed, as discussing this is probably simpler if there is at least a second person knowing in detail how the algorithm works.