Viewport: Cache landscape pixels in map mode

Avoid invalidating landscape pixels for non-landscape updates
(vehicles, overlays, etc.)
pull/195/head
Jonathan G Rennison 4 years ago
parent 8071976b0e
commit a474e71243

@ -376,47 +376,58 @@ void Blitter_32bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int
}
}
void Blitter_32bppAnim::SetLine(void *video, int x, int y, uint8 *colours, uint width)
void Blitter_32bppAnim::SetRect(void *video, int x, int y, const uint8 *colours, uint lines, uint width, uint pitch)
{
Colour *dst = (Colour *)video + x + y * _screen.pitch;
if (_screen_disable_anim) {
do {
*dst = LookupColourInPalette(*colours);
dst++;
colours++;
} while (--width);
uint w = width;
do {
*dst = LookupColourInPalette(*colours);
dst++;
colours++;
} while (--w);
dst += _screen.pitch - width;
colours += pitch - width;
} while (--lines);
} else {
uint16 *dstanim = (uint16 *)(&this->anim_buf[this->ScreenToAnimOffset((uint32 *)video) + x + y * this->anim_buf_pitch]);
do {
*dstanim = *colours | (DEFAULT_BRIGHTNESS << 8);
*dst = LookupColourInPalette(*colours);
dst++;
dstanim++;
colours++;
} while (--width);
uint w = width;
do {
*dstanim = *colours | (DEFAULT_BRIGHTNESS << 8);
*dst = LookupColourInPalette(*colours);
dst++;
dstanim++;
colours++;
} while (--w);
dst += _screen.pitch - width;
dstanim += this->anim_buf_pitch - width;
colours += pitch - width;
} while (--lines);
}
}
void Blitter_32bppAnim::SetLine32(void *video, int x, int y, uint32 *colours, uint width)
void Blitter_32bppAnim::SetRect32(void *video, int x, int y, const uint32 *colours, uint lines, uint width, uint pitch)
{
Colour *dst = (Colour *)video + x + y * _screen.pitch;
uint32 *dst = (uint32 *)video + x + y * _screen.pitch;
if (_screen_disable_anim) {
do {
*dst = *colours;
dst++;
colours++;
} while (--width);
memcpy(dst, colours, width * sizeof(uint32));
dst += _screen.pitch;
colours += pitch;
} while (--lines);
} else {
uint16 *dstanim = (uint16 *)(&this->anim_buf[this->ScreenToAnimOffset((uint32 *)video) + x + y * this->anim_buf_pitch]);
do {
*dstanim = 0;
*dst = *colours;
dst++;
dstanim++;
colours++;
} while (--width);
memcpy(dst, colours, width * sizeof(uint32));
memset(dstanim, 0, width * sizeof(uint16));
dst += _screen.pitch;
dstanim += this->anim_buf_pitch;
colours += pitch;
} while (--lines);
}
}

@ -39,8 +39,8 @@ public:
void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) override;
void SetPixel(void *video, int x, int y, uint8 colour) override;
void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash) override;
void SetLine(void *video, int x, int y, uint8 *colours, uint width) override;
void SetLine32(void *video, int x, int y, uint32 *colours, uint width) override;
void SetRect(void *video, int x, int y, const uint8 *colours, uint lines, uint width, uint pitch) override;
void SetRect32(void *video, int x, int y, const uint32 *colours, uint lines, uint width, uint pitch) override;
void DrawRect(void *video, int width, int height, uint8 colour) override;
void CopyFromBuffer(void *video, const void *src, int width, int height) override;
void CopyToBuffer(const void *video, void *dst, int width, int height) override;

@ -31,24 +31,29 @@ void Blitter_32bppBase::DrawLine(void *video, int x, int y, int x2, int y2, int
});
}
void Blitter_32bppBase::SetLine(void *video, int x, int y, uint8 *colours, uint width)
void Blitter_32bppBase::SetRect(void *video, int x, int y, const uint8 *colours, uint lines, uint width, uint pitch)
{
Colour *dst = (Colour *)video + x + y * _screen.pitch;
do {
*dst = LookupColourInPalette(*colours);
dst++;
colours++;
} while (--width);
uint w = width;
do {
*dst = LookupColourInPalette(*colours);
dst++;
colours++;
} while (--w);
dst += _screen.pitch - width;
colours += pitch - width;
} while (--lines);
}
void Blitter_32bppBase::SetLine32(void *video, int x, int y, uint32 *colours, uint width)
void Blitter_32bppBase::SetRect32(void *video, int x, int y, const uint32 *colours, uint lines, uint width, uint pitch)
{
Colour *dst = (Colour *)video + x + y * _screen.pitch;
uint32 *dst = (uint32 *)video + x + y * _screen.pitch;
do {
*dst = *colours;
dst++;
colours++;
} while (--width);
memcpy(dst, colours, width * sizeof(uint32));
dst += _screen.pitch;
colours += pitch;
} while (--lines);
}
void Blitter_32bppBase::DrawRect(void *video, int width, int height, uint8 colour)

@ -22,8 +22,8 @@ public:
void *MoveTo(void *video, int x, int y) override;
void SetPixel(void *video, int x, int y, uint8 colour) override;
void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash) override;
void SetLine(void *video, int x, int y, uint8 *colours, uint width) override;
void SetLine32(void *video, int x, int y, uint32 *colours, uint width) override;
void SetRect(void *video, int x, int y, const uint8 *colours, uint lines, uint width, uint pitch) override;
void SetRect32(void *video, int x, int y, const uint32 *colours, uint lines, uint width, uint pitch) override;
void DrawRect(void *video, int width, int height, uint8 colour) override;
void CopyFromBuffer(void *video, const void *src, int width, int height) override;
void CopyToBuffer(const void *video, void *dst, int width, int height) override;

@ -41,9 +41,14 @@ void Blitter_8bppBase::DrawLine(void *video, int x, int y, int x2, int y2, int s
});
}
void Blitter_8bppBase::SetLine(void *video, int x, int y, uint8 *colours, uint width)
void Blitter_8bppBase::SetRect(void *video, int x, int y, const uint8 *colours, uint lines, uint width, uint pitch)
{
memcpy((uint8 *)video + x + y * _screen.pitch, colours, width * sizeof(uint8));
uint8 *dst = (uint8 *)video + x + y * _screen.pitch;
do {
memcpy(dst, colours, width * sizeof(uint8));
dst += _screen.pitch;
colours += pitch;
} while (--lines);
}
void Blitter_8bppBase::DrawRect(void *video, int width, int height, uint8 colour)

@ -20,7 +20,7 @@ public:
void *MoveTo(void *video, int x, int y) override;
void SetPixel(void *video, int x, int y, uint8 colour) override;
void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash) override;
void SetLine(void *video, int x, int y, uint8 *colours, uint width) override;
void SetRect(void *video, int x, int y, const uint8 *colours, uint lines, uint width, uint pitch) override;
void DrawRect(void *video, int width, int height, uint8 colour) override;
void CopyFromBuffer(void *video, const void *src, int width, int height) override;
void CopyToBuffer(const void *video, void *dst, int width, int height) override;

@ -115,24 +115,28 @@ public:
virtual void SetPixel(void *video, int x, int y, uint8 colour) = 0;
/**
* Draw a sequence of pixels on the video-buffer.
* Draw a rectangle of pixels on the video-buffer.
* @param video The destination pointer (video-buffer).
* @param x The x position within video-buffer.
* @param y The y position within video-buffer.
* @param colours A 8bpp colour mapping buffer.
* @param width The length of the line.
* @param lines The number of lines.
* @param width The length of the lines.
* @param pitch The pitch of the colours buffer
*/
virtual void SetLine(void *video, int x, int y, uint8 *colours, uint width) = 0;
virtual void SetRect(void *video, int x, int y, const uint8 *colours, uint lines, uint width, uint pitch) = 0;
/**
* Draw a sequence of pixels on the video-buffer (no LookupColourInPalette).
* Draw a rectangle of pixels on the video-buffer (no LookupColourInPalette).
* @param video The destination pointer (video-buffer).
* @param x The x position within video-buffer.
* @param y The y position within video-buffer.
* @param colours A 32bpp colour buffer.
* @param width The length of the line.
* @param lines The number of lines.
* @param width The length of the lines.
* @param pitch The pitch of the colours buffer.
*/
virtual void SetLine32(void *video, int x, int y, uint32 *colours, uint width) { NOT_REACHED(); };
virtual void SetRect32(void *video, int x, int y, const uint32 *colours, uint lines, uint width, uint pitch) { NOT_REACHED(); };
/**
* Make a single horizontal line in a single colour on the video-buffer.

@ -23,8 +23,8 @@ public:
void SetPixel(void *video, int x, int y, uint8 colour) override {};
void DrawRect(void *video, int width, int height, uint8 colour) override {};
void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash) override {};
void SetLine(void *video, int x, int y, uint8 *colours, uint width) override {};
void SetLine32(void *video, int x, int y, uint32 *colours, uint width) override {};
void SetRect(void *video, int x, int y, const uint8 *colours, uint lines, uint width, uint pitch) override {};
void SetRect32(void *video, int x, int y, const uint32 *colours, uint lines, uint width, uint pitch) override {};
void CopyFromBuffer(void *video, const void *src, int width, int height) override {};
void CopyToBuffer(const void *video, void *dst, int width, int height) override {};
void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) override {};

@ -1328,9 +1328,6 @@ void ScreenSizeChanged()
{
MarkWholeScreenDirty();
extern uint32 *_vp_map_line;
_vp_map_line = ReallocT<uint32>(_vp_map_line, _screen.width);
/* screen size changed and the old bitmap is invalid now, so we don't want to undraw it */
_cursor.visible = false;
}

@ -88,18 +88,18 @@ void LinkGraphOverlay::MarkStationViewportLinksDirty(const Station *st)
Viewport *vp = this->window->viewport;
const Point pt = RemapCoords2(TileX(st->xy) * TILE_SIZE, TileY(st->xy) * TILE_SIZE);
const int padding = ScaleByZoom(3 * this->scale, vp->zoom);
MarkViewportDirty(vp, pt.x - padding, pt.y - padding, pt.x + padding, pt.y - padding, VMDF_NONE);
MarkViewportDirty(vp, pt.x - padding, pt.y - padding, pt.x + padding, pt.y - padding, VMDF_NOT_LANDSCAPE);
const int block_radius = ScaleByZoom(10, vp->zoom);
for (LinkList::iterator i(this->cached_links.begin()); i != this->cached_links.end(); ++i) {
if (i->from_id == st->index) {
const Station *stb = Station::GetIfValid(i->to_id);
if (stb == nullptr) continue;
MarkViewportLineDirty(vp, pt, RemapCoords2(TileX(stb->xy) * TILE_SIZE, TileY(stb->xy) * TILE_SIZE), block_radius, VMDF_NONE);
MarkViewportLineDirty(vp, pt, RemapCoords2(TileX(stb->xy) * TILE_SIZE, TileY(stb->xy) * TILE_SIZE), block_radius, VMDF_NOT_LANDSCAPE);
} else if (i->to_id == st->index) {
const Station *sta = Station::GetIfValid(i->from_id);
if (sta == nullptr) continue;
MarkViewportLineDirty(vp, RemapCoords2(TileX(sta->xy) * TILE_SIZE, TileY(sta->xy) * TILE_SIZE), pt, block_radius, VMDF_NONE);
MarkViewportLineDirty(vp, RemapCoords2(TileX(sta->xy) * TILE_SIZE, TileY(sta->xy) * TILE_SIZE), pt, block_radius, VMDF_NOT_LANDSCAPE);
}
}
}

@ -416,19 +416,19 @@ struct MainWindow : Window
case GHK_CHANGE_MAP_MODE_PREV:
if (_focused_window && _focused_window->viewport && _focused_window->viewport->zoom >= ZOOM_LVL_DRAW_MAP) {
_focused_window->viewport->map_type = ChangeRenderMode(_focused_window->viewport, true);
ChangeRenderMode(_focused_window->viewport, true);
_focused_window->SetDirty();
} else if (this->viewport->zoom >= ZOOM_LVL_DRAW_MAP) {
this->viewport->map_type = ChangeRenderMode(this->viewport, true);
ChangeRenderMode(this->viewport, true);
this->SetDirty();
}
break;
case GHK_CHANGE_MAP_MODE_NEXT:
if (_focused_window && _focused_window->viewport && _focused_window->viewport->zoom >= ZOOM_LVL_DRAW_MAP) {
_focused_window->viewport->map_type = ChangeRenderMode(_focused_window->viewport, false);
ChangeRenderMode(_focused_window->viewport, false);
_focused_window->SetDirty();
} else if (this->viewport->zoom >= ZOOM_LVL_DRAW_MAP) {
this->viewport->map_type = ChangeRenderMode(this->viewport, false);
ChangeRenderMode(this->viewport, false);
this->SetDirty();
}
break;
@ -451,7 +451,7 @@ struct MainWindow : Window
{
if (_ctrl_pressed) {
/* Cycle through the drawing modes */
this->viewport->map_type = ChangeRenderMode(this->viewport, wheel < 0);
ChangeRenderMode(this->viewport, wheel < 0);
this->SetDirty();
} else if (_settings_client.gui.scrollwheel_scrolling != 2) {
ZoomInOrOutToCursorWindow(wheel < 0, this);

@ -56,7 +56,7 @@ struct PlanLine {
if (cnt > 0) {
const TileIndex last_tile = this->tiles[cnt - 1];
if (last_tile == tile) return false;
MarkTileLineDirty(last_tile, tile);
MarkTileLineDirty(last_tile, tile, VMDF_NOT_LANDSCAPE);
if (cnt > 1) {
const TileIndex t0 = this->tiles[cnt - 2];
@ -72,7 +72,7 @@ struct PlanLine {
if (abs(x2 - x1) <= abs(x2 - x0) && abs(y2 - y1) <= abs(y2 - y0)) { // Tile i+1 is between i and i+2.
/* The new tile is in the continuity, just update the last tile. */
this->tiles[cnt - 1] = tile;
MarkTileLineDirty(t1, tile);
MarkTileLineDirty(t1, tile, VMDF_NOT_LANDSCAPE);
return true;
}
}
@ -107,7 +107,7 @@ struct PlanLine {
{
const uint sz = (uint) this->tiles.size();
for (uint i = 1; i < sz; i++) {
MarkTileLineDirty(this->tiles[i-1], this->tiles[i]);
MarkTileLineDirty(this->tiles[i-1], this->tiles[i], VMDF_NOT_LANDSCAPE);
}
}

@ -1343,7 +1343,19 @@ static bool ViewportMapShowTunnelModeChanged(int32 p1)
{
extern void ViewportMapBuildTunnelCache();
ViewportMapBuildTunnelCache();
return RedrawScreen(p1);
extern void MarkAllViewportMapLandscapesDirty();
MarkAllViewportMapLandscapesDirty();
return true;
}
static bool ViewportMapLandscapeModeChanged(int32 p1)
{
extern void MarkAllViewportMapLandscapesDirty();
MarkAllViewportMapLandscapesDirty();
return true;
}
static bool UpdateLinkgraphColours(int32 p1)

@ -54,6 +54,7 @@ static bool SimulatedWormholeSignalsChanged(int32 p1);
static bool EnableSingleVehSharedOrderGuiChanged(int32 p1);
static bool CheckYapfRailSignalPenalties(int32 p1);
static bool ViewportMapShowTunnelModeChanged(int32 p1);
static bool ViewportMapLandscapeModeChanged(int32 p1);
static bool UpdateLinkgraphColours(int32 p1);
static bool UpdateClientName(int32 p1);
@ -4137,21 +4138,21 @@ var = gui.viewport_map_scan_surroundings
flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
def = true
str = STR_CONFIG_SETTING_VIEWPORT_MAP_SCAN_SURROUNDINGS
proc = RedrawScreen
proc = ViewportMapLandscapeModeChanged
[SDTC_BOOL]
var = gui.show_slopes_on_viewport_map
flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
def = true
str = STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_SLOPES
proc = RedrawScreen
proc = ViewportMapLandscapeModeChanged
[SDTC_BOOL]
var = gui.show_bridges_on_map
flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
def = true
str = STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_BRIDGES
proc = RedrawScreen
proc = ViewportMapLandscapeModeChanged
[SDTC_BOOL]
var = gui.show_tunnels_on_map
@ -4192,7 +4193,7 @@ var = gui.use_owner_colour_for_tunnelbridge
flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
def = false
str = STR_CONFIG_SETTING_VIEWPORT_MAP_USE_OWNER_COLOUR_BRIDGE_TUNNEL
proc = RedrawScreen
proc = ViewportMapLandscapeModeChanged
[SDTC_VAR]
var = gui.show_scrolling_viewport_on_map

@ -275,7 +275,7 @@ public:
this->town->show_zone = new_show_state;
this->SetWidgetLoweredState(widget, new_show_state);
MarkWholeScreenDirty();
MarkWholeNonMapViewportsDirty();
break;
}

@ -2303,7 +2303,7 @@ void ReverseTrainDirection(Train *v)
if (IsTunnelBridgeWithSignalSimulation(v->tile) && IsTunnelBridgeSignalSimulationEntrance(v->tile)) {
/* Flip signal on tunnel entrance tile red. */
SetTunnelBridgeEntranceSignalState(v->tile, SIGNAL_STATE_RED);
MarkTileDirtyByTile(v->tile);
MarkTileDirtyByTile(v->tile, VMDF_NOT_MAP_MODE);
/* Clear counters. */
v->wait_counter = 0;
v->tunnel_bridge_signal_num = 0;
@ -2750,9 +2750,9 @@ static void HandleLastTunnelBridgeSignals(TileIndex tile, TileIndex end, DiagDir
int signal_offset = GetAndClearLastBridgeEntranceSetSignalIndex(end);
if (signal_offset) {
TileIndex last_signal_tile = end + (TileOffsByDiagDir(dir) * _settings_game.construction.simulated_wormhole_signals * signal_offset);
MarkTileDirtyByTile(last_signal_tile);
MarkTileDirtyByTile(last_signal_tile, VMDF_NOT_MAP_MODE);
}
MarkTileDirtyByTile(tile);
MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE);
}
if (free) {
/* Open up the wormhole and clear m2. */
@ -2763,11 +2763,11 @@ static void HandleLastTunnelBridgeSignals(TileIndex tile, TileIndex end, DiagDir
if (IsTunnelBridgeSignalSimulationEntrance(end) && GetTunnelBridgeEntranceSignalState(end) == SIGNAL_STATE_RED) {
SetTunnelBridgeEntranceSignalState(end, SIGNAL_STATE_GREEN);
MarkTileDirtyByTile(end);
MarkTileDirtyByTile(end, VMDF_NOT_MAP_MODE);
}
if (IsTunnelBridgeSignalSimulationEntrance(tile) && GetTunnelBridgeEntranceSignalState(tile) == SIGNAL_STATE_RED) {
SetTunnelBridgeEntranceSignalState(tile, SIGNAL_STATE_GREEN);
MarkTileDirtyByTile(tile);
MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE);
}
}
}
@ -3973,11 +3973,11 @@ static void HandleSignalBehindTrain(Train *v, int signal_number)
/* Flip signal on ramp. */
if (IsTunnelBridgeSignalSimulationEntrance(tile) && GetTunnelBridgeEntranceSignalState(tile) == SIGNAL_STATE_RED) {
SetTunnelBridgeEntranceSignalState(tile, SIGNAL_STATE_GREEN);
MarkTileDirtyByTile(tile);
MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE);
}
} else if (IsBridge(v->tile) && signal_number >= 0) {
SetBridgeEntranceSimulatedSignalState(v->tile, signal_number, SIGNAL_STATE_GREEN);
MarkTileDirtyByTile(tile);
MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE);
}
}
@ -4270,12 +4270,12 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
}
/* Flip signal on tunnel entrance tile red. */
SetTunnelBridgeEntranceSignalState(gp.new_tile, SIGNAL_STATE_RED);
MarkTileDirtyByTile(gp.new_tile);
MarkTileDirtyByTile(gp.new_tile, VMDF_NOT_MAP_MODE);
if (IsTunnelBridgeSignalSimulationBidirectional(gp.new_tile)) {
/* Set incoming signal in other direction to red as well */
TileIndex other_end = GetOtherTunnelBridgeEnd(gp.new_tile);
SetTunnelBridgeEntranceSignalState(other_end, SIGNAL_STATE_RED);
MarkTileDirtyByTile(other_end);
MarkTileDirtyByTile(other_end, VMDF_NOT_MAP_MODE);
}
}
}
@ -4360,7 +4360,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
/* flip signal in front to red on bridges*/
if (distance == 0 && IsBridge(v->tile)) {
SetBridgeEntranceSimulatedSignalState(v->tile, v->tunnel_bridge_signal_num, SIGNAL_STATE_RED);
MarkTileDirtyByTile(gp.new_tile);
MarkTileDirtyByTile(gp.new_tile, VMDF_NOT_MAP_MODE);
}
}
}

@ -16,6 +16,7 @@
#include "command_func.h"
#include "sound_func.h"
#include "tree_map.h"
#include "viewport_func.h"
#include "widgets/tree_widget.h"
@ -117,13 +118,13 @@ public:
case WID_BT_MANY_RANDOM: // place trees randomly over the landscape
if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP);
PlaceTreesRandomly();
MarkWholeScreenDirty();
MarkWholeNonMapViewportsDirty();
break;
case WID_BT_REMOVE_ALL: // remove all trees over the landscape
if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP);
RemoveAllTrees();
MarkWholeScreenDirty();
MarkWholeNonMapViewportsDirty();
break;
}

@ -2332,7 +2332,7 @@ void Vehicle::UpdateViewport(bool dirty)
min(old_coord.top, this->coord.top),
max(old_coord.right, this->coord.right),
max(old_coord.bottom, this->coord.bottom),
this->type != VEH_EFFECT ? VMDF_NONE : VMDF_NOT_MAP_MODE
VMDF_NOT_LANDSCAPE | (this->type != VEH_EFFECT ? VMDF_NONE : VMDF_NOT_MAP_MODE)
);
}
}
@ -2352,7 +2352,7 @@ void Vehicle::UpdatePositionAndViewport()
*/
void Vehicle::MarkAllViewportsDirty() const
{
::MarkAllViewportsDirty(this->coord.left, this->coord.top, this->coord.right, this->coord.bottom, this->type != VEH_EFFECT ? VMDF_NONE : VMDF_NOT_MAP_MODE);
::MarkAllViewportsDirty(this->coord.left, this->coord.top, this->coord.right, this->coord.bottom, VMDF_NOT_LANDSCAPE | (this->type != VEH_EFFECT ? VMDF_NONE : VMDF_NOT_MAP_MODE));
}
VehicleOrderID Vehicle::GetFirstWaitingLocation(bool require_wait_timetabled) const

@ -233,6 +233,8 @@ struct BridgeSetYComparator {
/** Data structure storing rendering information */
struct ViewportDrawer {
DrawPixelInfo dpi;
int offset_x;
int offset_y;
StringSpriteToDrawVector string_sprites_to_draw;
TileSpriteToDrawVector tile_sprites_to_draw;
@ -325,6 +327,7 @@ enum ViewportDebugFlags {
VDF_DIRTY_WHOLE_VIEWPORT,
VDF_DIRTY_BLOCK_PER_SPLIT,
VDF_DISABLE_DRAW_SPLIT,
VDF_SHOW_NO_LANDSCAPE_MAP_DRAW,
};
uint32 _viewport_debug_flags;
@ -336,6 +339,11 @@ static Point MapXYZToViewport(const Viewport *vp, int x, int y, int z)
return p;
}
void ClearViewportLandPixelCache(Viewport *vp)
{
vp->land_pixel_cache.assign(vp->land_pixel_cache.size(), 0xD7);
}
void ClearViewportCache(Viewport *vp)
{
if (vp->zoom >= ZOOM_LVL_DRAW_MAP) {
@ -678,6 +686,7 @@ static void SetViewportPosition(Window *w, int x, int y, bool force_update_overl
if (i >= 0) height -= i;
if (height > 0 && (_vp_move_offs.x != 0 || _vp_move_offs.y != 0)) {
ClearViewportLandPixelCache(vp);
SCOPE_INFO_FMT([&], "DoSetViewportPosition: %d, %d, %d, %d, %d, %d, %s", left, top, width, height, _vp_move_offs.x, _vp_move_offs.y, scope_dumper().WindowInfo(w));
DoSetViewportPosition((Window *) w->z_front, left, top, width, height);
ClearViewportCache(w->viewport);
@ -2882,9 +2891,8 @@ static void ViewportMapDrawScrollingViewportBox(const Viewport * const vp)
}
}
uint32 *_vp_map_line; ///< Buffer for drawing the map of a viewport.
static void ViewportMapDrawBridgeTunnel(const Viewport * const vp, const TunnelBridgeToMap * const tbtm, const int z,
template <bool is_32bpp>
static void ViewportMapDrawBridgeTunnel(Viewport * const vp, const TunnelBridgeToMap * const tbtm, const int z,
const bool is_tunnel, const int w, const int h, Blitter * const blitter)
{
extern LegendAndColour _legend_land_owners[NUM_NO_COMPANY_ENTRIES + MAX_COMPANIES + 1];
@ -2908,14 +2916,21 @@ static void ViewportMapDrawBridgeTunnel(const Viewport * const vp, const TunnelB
const int x = UnScaleByZoomLower(pt.x - _vd.dpi.left, _vd.dpi.zoom);
if (IsInsideMM(x, 0, w)) {
const int y = UnScaleByZoomLower(pt.y - _vd.dpi.top, _vd.dpi.zoom);
if (IsInsideMM(y, 0, h)) blitter->SetPixel(_vd.dpi.dst_ptr, x, y, colour);
if (IsInsideMM(y, 0, h)) {
uint idx = (x + _vd.offset_x) + ((y + _vd.offset_y) * vp->width);
if (is_32bpp) {
reinterpret_cast<uint32 *>(vp->land_pixel_cache.data())[idx] = COL8TO32(colour);
} else {
reinterpret_cast<uint8 *>(vp->land_pixel_cache.data())[idx] = colour;
}
}
}
}
}
/** Draw the map on a viewport. */
template <bool is_32bpp, bool show_slope>
void ViewportMapDraw(const Viewport * const vp)
void ViewportMapDraw(Viewport * const vp)
{
assert(vp != nullptr);
Blitter * const blitter = BlitterFactory::GetCurrentBlitter();
@ -2942,31 +2957,41 @@ void ViewportMapDraw(const Viewport * const vp)
const int h = UnScaleByZoom(_vd.dpi.height, vp->zoom);
int j = 0;
const int land_cache_start = _vd.offset_x + (_vd.offset_y * vp->width);
uint32 *land_cache_ptr32 = reinterpret_cast<uint32 *>(vp->land_pixel_cache.data()) + land_cache_start;
uint8 *land_cache_ptr8 = reinterpret_cast<uint8 *>(vp->land_pixel_cache.data()) + land_cache_start;
bool cache_updated = false;
/* Render base map. */
do { // For each line
int i = w;
uint colour_index = colour_index_base;
colour_index_base ^= 2;
uint32 *vp_map_line_ptr32 = _vp_map_line;
uint8 *vp_map_line_ptr8 = (uint8*) _vp_map_line;
int c = b - a;
int d = b + a;
do { // For each pixel of a line
if (is_32bpp) {
*vp_map_line_ptr32 = ViewportMapGetColour<is_32bpp, show_slope>(vp, c, d, colour_index);
vp_map_line_ptr32++;
if (*land_cache_ptr32 == 0xD7D7D7D7) {
*land_cache_ptr32 = ViewportMapGetColour<is_32bpp, show_slope>(vp, c, d, colour_index);
cache_updated = true;
}
land_cache_ptr32++;
} else {
*vp_map_line_ptr8 = (uint8) ViewportMapGetColour<is_32bpp, show_slope>(vp, c, d, colour_index);
vp_map_line_ptr8++;
if (*land_cache_ptr8 == 0xD7) {
*land_cache_ptr8 = (uint8) ViewportMapGetColour<is_32bpp, show_slope>(vp, c, d, colour_index);
cache_updated = true;
}
land_cache_ptr8++;
}
colour_index = (colour_index + 1) & 3;
c -= incr_a;
d += incr_a;
} while (--i);
if (is_32bpp) {
blitter->SetLine32(_vd.dpi.dst_ptr, 0, j, _vp_map_line, w);
land_cache_ptr32 += (vp->width - w);
} else {
blitter->SetLine(_vd.dpi.dst_ptr, 0, j, (uint8*) _vp_map_line, w);
land_cache_ptr8 += (vp->width - w);
}
b += incr_b;
} while (++j < h);
@ -2989,35 +3014,48 @@ void ViewportMapDraw(const Viewport * const vp)
const int y_to = UnScaleByZoomLower(pt_to.y - _vd.dpi.top, _vd.dpi.zoom);
if ((y_from < 0 && y_to < 0) || (y_from > h && y_to > h)) continue;
ViewportMapDrawBridgeTunnel(vp, &ttm.tb, tunnel_z, true, w, h, blitter);
ViewportMapDrawBridgeTunnel<is_32bpp>(vp, &ttm.tb, tunnel_z, true, w, h, blitter);
}
};
/* Render tunnels */
if (_settings_client.gui.show_tunnels_on_map && _vd.tunnel_to_map_x.tunnels.size() != 0) {
const int y_intercept_min = _vd.dpi.top + (_vd.dpi.left / 2);
const int y_intercept_max = _vd.dpi.top + _vd.dpi.height + ((_vd.dpi.left + _vd.dpi.width) / 2);
draw_tunnels(y_intercept_min, y_intercept_max, _vd.tunnel_to_map_x);
}
if (_settings_client.gui.show_tunnels_on_map && _vd.tunnel_to_map_y.tunnels.size() != 0) {
const int y_intercept_min = _vd.dpi.top - ((_vd.dpi.left + _vd.dpi.width) / 2);
const int y_intercept_max = _vd.dpi.top + _vd.dpi.height - (_vd.dpi.left / 2);
draw_tunnels(y_intercept_min, y_intercept_max, _vd.tunnel_to_map_y);
}
if (cache_updated) {
/* Render tunnels */
if (_settings_client.gui.show_tunnels_on_map && _vd.tunnel_to_map_x.tunnels.size() != 0) {
const int y_intercept_min = _vd.dpi.top + (_vd.dpi.left / 2);
const int y_intercept_max = _vd.dpi.top + _vd.dpi.height + ((_vd.dpi.left + _vd.dpi.width) / 2);
draw_tunnels(y_intercept_min, y_intercept_max, _vd.tunnel_to_map_x);
}
if (_settings_client.gui.show_tunnels_on_map && _vd.tunnel_to_map_y.tunnels.size() != 0) {
const int y_intercept_min = _vd.dpi.top - ((_vd.dpi.left + _vd.dpi.width) / 2);
const int y_intercept_max = _vd.dpi.top + _vd.dpi.height - (_vd.dpi.left / 2);
draw_tunnels(y_intercept_min, y_intercept_max, _vd.tunnel_to_map_y);
}
/* Render bridges */
if (_settings_client.gui.show_bridges_on_map && _vd.bridge_to_map_x.size() != 0) {
for (const auto &it : _vd.bridge_to_map_x) { // For each bridge
TunnelBridgeToMap tbtm { it.first, it.second };
ViewportMapDrawBridgeTunnel(vp, &tbtm, (GetBridgeHeight(tbtm.from_tile) - 1) * TILE_HEIGHT, false, w, h, blitter);
/* Render bridges */
if (_settings_client.gui.show_bridges_on_map && _vd.bridge_to_map_x.size() != 0) {
for (const auto &it : _vd.bridge_to_map_x) { // For each bridge
TunnelBridgeToMap tbtm { it.first, it.second };
ViewportMapDrawBridgeTunnel<is_32bpp>(vp, &tbtm, (GetBridgeHeight(tbtm.from_tile) - 1) * TILE_HEIGHT, false, w, h, blitter);
}
}
}
if (_settings_client.gui.show_bridges_on_map && _vd.bridge_to_map_y.size() != 0) {
for (const auto &it : _vd.bridge_to_map_y) { // For each bridge
TunnelBridgeToMap tbtm { it.first, it.second };
ViewportMapDrawBridgeTunnel(vp, &tbtm, (GetBridgeHeight(tbtm.from_tile) - 1) * TILE_HEIGHT, false, w, h, blitter);
if (_settings_client.gui.show_bridges_on_map && _vd.bridge_to_map_y.size() != 0) {
for (const auto &it : _vd.bridge_to_map_y) { // For each bridge
TunnelBridgeToMap tbtm { it.first, it.second };
ViewportMapDrawBridgeTunnel<is_32bpp>(vp, &tbtm, (GetBridgeHeight(tbtm.from_tile) - 1) * TILE_HEIGHT, false, w, h, blitter);
}
}
}
if (is_32bpp) {
blitter->SetRect32(_vd.dpi.dst_ptr, 0, 0, reinterpret_cast<uint32 *>(vp->land_pixel_cache.data()) + land_cache_start, h, w, vp->width);
} else {
blitter->SetRect(_vd.dpi.dst_ptr, 0, 0, reinterpret_cast<uint8 *>(vp->land_pixel_cache.data()) + land_cache_start, h, w, vp->width);
}
if (unlikely(HasBit(_viewport_debug_flags, VDF_SHOW_NO_LANDSCAPE_MAP_DRAW)) && !cache_updated) {
ViewportDrawDirtyBlocks();
++_dirty_block_colour;
}
}
static void ViewportProcessParentSprites()
@ -3114,8 +3152,10 @@ void ViewportDoDraw(Viewport *vp, int left, int top, int right, int bottom)
_vd.dpi.pitch = old_dpi->pitch;
_vd.last_child = nullptr;
int x = UnScaleByZoomLower(_vd.dpi.left - (vp->virtual_left & mask), vp->zoom) + vp->left;
int y = UnScaleByZoomLower(_vd.dpi.top - (vp->virtual_top & mask), vp->zoom) + vp->top;
_vd.offset_x = UnScaleByZoomLower(_vd.dpi.left - (vp->virtual_left & mask), vp->zoom);
_vd.offset_y = UnScaleByZoomLower(_vd.dpi.top - (vp->virtual_top & mask), vp->zoom);
int x = _vd.offset_x + vp->left;
int y = _vd.offset_y + vp->top;
_vd.dpi.dst_ptr = BlitterFactory::GetCurrentBlitter()->MoveTo(old_dpi->dst_ptr, x - old_dpi->left, y - old_dpi->top);
@ -3346,8 +3386,16 @@ void UpdateViewportSizeZoom(Viewport *vp)
if (vp->zoom >= ZOOM_LVL_DRAW_MAP) {
memset(vp->map_draw_vehicles_cache.done_hash_bits, 0, sizeof(vp->map_draw_vehicles_cache.done_hash_bits));
vp->map_draw_vehicles_cache.vehicle_pixels.assign(vp->width * vp->height, false);
if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 32) {
vp->land_pixel_cache.assign(vp->height * vp->width * 4, 0xD7);
} else {
vp->land_pixel_cache.assign(vp->height * vp->width, 0xD7);
}
} else {
vp->map_draw_vehicles_cache.vehicle_pixels.clear();
vp->land_pixel_cache.clear();
vp->land_pixel_cache.shrink_to_fit();
}
}
@ -3441,6 +3489,19 @@ void MarkViewportDirty(Viewport * const vp, int left, int top, int right, int bo
pos += column_skip;
}
vp->is_dirty = true;
if (unlikely(vp->zoom >= ZOOM_LVL_DRAW_MAP && !(flags & VMDF_NOT_LANDSCAPE))) {
uint l = UnScaleByZoomLower(left, vp->zoom);
uint t = UnScaleByZoomLower(top, vp->zoom);
uint w = UnScaleByZoom(right, vp->zoom) - l;
uint h = UnScaleByZoom(bottom, vp->zoom) - t;
uint bitdepth = BlitterFactory::GetCurrentBlitter()->GetScreenDepth() / 8;
uint8 *land_cache = vp->land_pixel_cache.data() + ((l + (t * vp->width)) * bitdepth);
while (--h) {
memset(land_cache, 0xD7, w * bitdepth);
land_cache += vp->width * bitdepth;
}
}
}
/**
@ -3474,7 +3535,7 @@ static void MarkRouteStepDirty(const TileIndex tile, uint order_nr)
for (Viewport * const vp : _viewport_window_cache) {
const int half_width = ScaleByZoom((_vp_route_step_width / 2) + 1, vp->zoom);
const int height = ScaleByZoom(_vp_route_step_height_top + char_height * order_nr + _vp_route_step_height_bottom, vp->zoom);
MarkViewportDirty(vp, pt.x - half_width, pt.y - height, pt.x + half_width, pt.y, VMDF_NONE);
MarkViewportDirty(vp, pt.x - half_width, pt.y - height, pt.x + half_width, pt.y, VMDF_NOT_LANDSCAPE);
}
}
@ -3503,7 +3564,30 @@ void MarkAllViewportMapsDirty(int left, int top, int right, int bottom)
Viewport *vp = w->viewport;
if (vp != nullptr && vp->zoom >= ZOOM_LVL_DRAW_MAP) {
assert(vp->width != 0);
MarkViewportDirty(vp, left, top, right, bottom, VMDF_NONE);
MarkViewportDirty(vp, left, top, right, bottom, VMDF_NOT_LANDSCAPE);
}
}
}
void MarkAllViewportMapLandscapesDirty()
{
Window *w;
FOR_ALL_WINDOWS_FROM_BACK(w) {
Viewport *vp = w->viewport;
if (vp != nullptr && vp->zoom >= ZOOM_LVL_DRAW_MAP) {
ClearViewportLandPixelCache(vp);
w->SetDirty();
}
}
}
void MarkWholeNonMapViewportsDirty()
{
Window *w;
FOR_ALL_WINDOWS_FROM_BACK(w) {
Viewport *vp = w->viewport;
if (vp != nullptr && vp->zoom < ZOOM_LVL_DRAW_MAP) {
w->SetDirty();
}
}
}
@ -3602,7 +3686,7 @@ void MarkViewportLineDirty(Viewport * const vp, const Point from_pt, const Point
}
}
void MarkTileLineDirty(const TileIndex from_tile, const TileIndex to_tile)
void MarkTileLineDirty(const TileIndex from_tile, const TileIndex to_tile, ViewportMarkDirtyFlags flags)
{
assert(from_tile != INVALID_TILE);
assert(to_tile != INVALID_TILE);
@ -3629,7 +3713,7 @@ void MarkTileLineDirty(const TileIndex from_tile, const TileIndex to_tile)
(y1 - 1) * block_radius,
(x1 + 1) * block_radius,
(y1 + 1) * block_radius,
VMDF_NONE
flags
);
if (x1 == x2 && y1 == y2) break;
const int e2 = 2 * err;
@ -3647,7 +3731,7 @@ void MarkTileLineDirty(const TileIndex from_tile, const TileIndex to_tile)
static void MarkRoutePathsDirty(const std::vector<DrawnPathRouteTileLine> &lines)
{
for (std::vector<DrawnPathRouteTileLine>::const_iterator it = lines.begin(); it != lines.end(); ++it) {
MarkTileLineDirty(it->from_tile, it->to_tile);
MarkTileLineDirty(it->from_tile, it->to_tile, VMDF_NOT_LANDSCAPE);
}
}
@ -3662,7 +3746,7 @@ void MarkAllRoutePathsDirty(const Vehicle *veh)
break;
}
for (const auto &iter : _vp_route_paths) {
MarkTileLineDirty(iter.from_tile, iter.to_tile);
MarkTileLineDirty(iter.from_tile, iter.to_tile, VMDF_NOT_LANDSCAPE);
}
_vp_route_paths_last_mark_dirty.swap(_vp_route_paths);
_vp_route_paths.clear();
@ -3758,7 +3842,7 @@ static void SetSelectionTilesDirty()
static const int OVERLAY_WIDTH = 4 * ZOOM_LVL_BASE; // part of selection sprites is drawn outside the selected area (in particular: terraforming)
/* For halftile foundations on SLOPE_STEEP_S the sprite extents some more towards the top */
MarkAllViewportsDirty(l - OVERLAY_WIDTH, t - OVERLAY_WIDTH - TILE_HEIGHT * ZOOM_LVL_BASE, r + OVERLAY_WIDTH, b + OVERLAY_WIDTH);
MarkAllViewportsDirty(l - OVERLAY_WIDTH, t - OVERLAY_WIDTH - TILE_HEIGHT * ZOOM_LVL_BASE, r + OVERLAY_WIDTH, b + OVERLAY_WIDTH, VMDF_NOT_MAP_MODE);
/* haven't we reached the topmost tile yet? */
if (top_x != x_start) {
@ -3787,7 +3871,7 @@ static void SetSelectionTilesDirty()
uint y = (_thd.pos.y + (a - b) / 2) / TILE_SIZE;
if (x < MapMaxX() && y < MapMaxY()) {
MarkTileDirtyByTile(TileXY(x, y));
MarkTileDirtyByTile(TileXY(x, y), VMDF_NOT_MAP_MODE);
}
}
}
@ -5495,13 +5579,14 @@ void ResetObjectToPlace()
SetObjectToPlace(SPR_CURSOR_MOUSE, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
}
ViewportMapType ChangeRenderMode(const Viewport *vp, bool down) {
void ChangeRenderMode(Viewport *vp, bool down) {
ViewportMapType map_type = vp->map_type;
if (vp->zoom < ZOOM_LVL_DRAW_MAP) return map_type;
if (vp->zoom < ZOOM_LVL_DRAW_MAP) return;
ClearViewportLandPixelCache(vp);
if (down) {
return (map_type == VPMT_MIN) ? VPMT_MAX : (ViewportMapType) (map_type - 1);
vp->map_type = (map_type == VPMT_MIN) ? VPMT_MAX : (ViewportMapType) (map_type - 1);
} else {
return (map_type == VPMT_MAX) ? VPMT_MIN : (ViewportMapType) (map_type + 1);
vp->map_type = (map_type == VPMT_MAX) ? VPMT_MIN : (ViewportMapType) (map_type + 1);
}
}
@ -5644,17 +5729,17 @@ void StoreRailPlacementEndpoints(TileIndex start_tile, TileIndex end_tile, Track
static void MarkCatchmentTilesDirty()
{
if (_viewport_highlight_town != nullptr) {
MarkWholeScreenDirty();
MarkWholeNonMapViewportsDirty();
return;
}
if (_viewport_highlight_station != nullptr) {
if (_viewport_highlight_station->catchment_tiles.tile == INVALID_TILE) {
MarkWholeScreenDirty();
MarkWholeNonMapViewportsDirty();
_viewport_highlight_station = nullptr;
} else {
BitmapTileIterator it(_viewport_highlight_station->catchment_tiles);
for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) {
MarkTileDirtyByTile(tile);
MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE);
}
}
}
@ -5742,10 +5827,10 @@ void SetViewportCatchmentTown(const Town *t, bool sel)
if (sel && _viewport_highlight_town != t) {
_viewport_highlight_station = nullptr;
_viewport_highlight_town = t;
MarkWholeScreenDirty();
MarkWholeNonMapViewportsDirty();
} else if (!sel && _viewport_highlight_town == t) {
_viewport_highlight_town = nullptr;
MarkWholeScreenDirty();
MarkWholeNonMapViewportsDirty();
}
if (_viewport_highlight_town != nullptr) SetWindowDirty(WC_TOWN_VIEW, _viewport_highlight_town->index);
}

@ -36,10 +36,12 @@ void UpdateViewportSizeZoom(Viewport *vp);
void MarkViewportDirty(Viewport * const vp, int left, int top, int right, int bottom, ViewportMarkDirtyFlags flags);
void MarkAllViewportsDirty(int left, int top, int right, int bottom, ViewportMarkDirtyFlags flags = VMDF_NONE);
void MarkAllViewportMapsDirty(int left, int top, int right, int bottom);
void MarkAllViewportMapLandscapesDirty();
void MarkWholeNonMapViewportsDirty();
void MarkAllViewportOverlayStationLinksDirty(const Station *st);
void MarkAllRouteStepsDirty(const Vehicle *veh);
void MarkViewportLineDirty(Viewport * const vp, const Point from_pt, const Point to_pt, const int block_radius, ViewportMarkDirtyFlags flags);
void MarkTileLineDirty(const TileIndex from_tile, const TileIndex to_tile);
void MarkTileLineDirty(const TileIndex from_tile, const TileIndex to_tile, ViewportMarkDirtyFlags flags);
void MarkAllRoutePathsDirty(const Vehicle *veh);
void CheckMarkDirtyFocusedRoutePaths(const Vehicle *veh);
@ -112,7 +114,7 @@ static inline void MarkTileDirtyByTile(TileIndex tile, ViewportMarkDirtyFlags fl
void MarkTileGroundDirtyByTile(TileIndex tile, ViewportMarkDirtyFlags flags);
ViewportMapType ChangeRenderMode(const Viewport *vp, bool down);
void ChangeRenderMode(Viewport *vp, bool down);
Point GetViewportStationMiddle(const Viewport *vp, const Station *st);

@ -144,7 +144,7 @@ public:
{
if (_ctrl_pressed) {
/* Cycle through the drawing modes */
this->viewport->map_type = ChangeRenderMode(this->viewport, wheel < 0);
ChangeRenderMode(this->viewport, wheel < 0);
this->SetDirty();
} else if (_settings_client.gui.scrollwheel_scrolling != 2) {
ZoomInOrOutToCursorWindow(wheel < 0, this);

@ -60,6 +60,7 @@ struct Viewport {
bool is_dirty = false;
bool is_drawn = false;
ViewPortMapDrawVehiclesCache map_draw_vehicles_cache;
std::vector<byte> land_pixel_cache;
uint GetDirtyBlockWidthShift() const { return this->GetDirtyBlockShift(); }
uint GetDirtyBlockHeightShift() const { return this->GetDirtyBlockShift(); }
@ -218,6 +219,7 @@ enum FoundationPart {
enum ViewportMarkDirtyFlags : byte {
VMDF_NONE = 0,
VMDF_NOT_MAP_MODE = 0x1,
VMDF_NOT_LANDSCAPE = 0x2,
};
DECLARE_ENUM_AS_BIT_SET(ViewportMarkDirtyFlags)

@ -410,7 +410,7 @@ void ZoningMarkDirtyStationCoverageArea(const Station *st, ZoningModeMask mask)
Rect rect = st->GetCatchmentRectUsingRadius(radius);
for (int y = rect.top; y <= rect.bottom; y++) {
for (int x = rect.left; x <= rect.right; x++) {
MarkTileDirtyByTile(TileXY(x, y));
MarkTileDirtyByTile(TileXY(x, y), VMDF_NOT_MAP_MODE);
}
}
auto invalidate_cache_rect = [&](btree::btree_set<uint32> &cache) {
@ -441,7 +441,7 @@ void ZoningTownAuthorityRatingChange()
if (_zoning.inner == ZEM_AUTHORITY) mask |= ZMM_INNER;
if (_zoning.outer == ZEM_AUTHORITY) mask |= ZMM_OUTER;
if (mask != ZMM_NOTHING) {
MarkWholeScreenDirty();
MarkWholeNonMapViewportsDirty();
}
}
@ -460,5 +460,5 @@ void SetZoningMode(bool inner, ZoningEvaluationMode mode)
current_mode = mode;
cache.clear();
MarkWholeScreenDirty();
MarkWholeNonMapViewportsDirty();
}

Loading…
Cancel
Save