Before, every next frame was calculated from the current time.
If for some reason the current frame was drifting a bit, the
next would too, and the next more, etc etc. This meant we rarely
hit the targets we would like, like 33.33fps.
Instead, allow video-drivers to drift slightly, and schedule the
next frame based on the time the last should have happened. Only
if the drift gets too much, that deadlines are missed for longer
period of times, schedule the next frame based on the current
time.
This makes the FPS a lot smoother, as sleeps aren't as exact as
you might think.
During fast-forward, the game was drawing as fast as it could. This
means that the fast-forward was limited also by how fast we could
draw, something that people in general don't expect.
To give an extreme case, if you are fully zoomed out on a busy
map, fast-forward would be mostly limited because of the time it
takes to draw the screen.
By decoupling the draw-tick and game-tick, we can keep the pace
of the draw-tick the same while speeding up the game-tick. To use
the extreme case as example again, if you are fully zoomed out
now, the screen only redraws 33.33 times per second, fast-forwarding
or not. This means fast-forward is much more likely to go at the
same speed, no matter what you are looking at.
_realtime_tick was reset every time the diff was calculated. This
means if it would trigger, say, every N.9 milliseconds, it would
after two iterations already drift a millisecond. This adds up
pretty quick.
On all OSes we tested the std::chrono::steady_clock is of a high
enough resolution to do millisecond measurements, which is all we
need.
By accident, this fixes a Win32 driver bug, where we would never
hit our targets, as the resolution of the clock was too low to
do accurate millisecond measurements with (it was ~16ms resolution
instead).
InvalidateWindowData with mode SBI_NEWS_DELETED was called on the
status bar when checking for a new item of news to be shown in the
ticker, even if there is no news queued and no change occurs.
When there are a lot of rects to redraw, of which one of the last
ones is almost the full screen, visual tearing happens over the
vertical axis. This is most visible when scrolling the map.
This can be prevented by using less rects. To simplify the situation,
and as solutions like OpenGL need this anyway, keep a single rect
that shows the biggest size that updates everything correctly.
Although this means it needs a bit more time redrawing where it
is strictly seen not needed, it also means less commands have
to be executed in the backend. In the end, this is a trade-off,
and from experiments it seems the approach of this commit gives
a better result.
During resizing, there can still be dirty-rects ready to blit based
on the old dimensions. X11 with shared memory enabled crashes if
you try to do this. So, instead, if we resize, reset the dirty-rects.
This is fine, as moments later we mark the whole (new) screen as
dirty anyway.
The first point was counted, but also initialized as "last". As
such, it didn't add to "total", but did add to "count", which made
the "count" 1 more than the total actually represents.
korean: 2 changes by telk5093
indonesian: 11 changes by dimaspaf14
russian: 2 changes by Ln-Wolf
finnish: 3 changes by hpiirai
french: 4 changes by glx22
The zoom level suggestion is based on the DPI scaling set in Windows.
We use 150% scaling as the threshold for 2X zoom and 300% scaling
as the threshold for 4X zoom.