mirror of https://github.com/OpenRCT2/OpenRCT2.git
Merge pull request #21981 from AaronVanGeffen/map-window
Rework map window to take map size into account
This commit is contained in:
commit
47d0996b4f
|
@ -2,6 +2,10 @@
|
|||
------------------------------------------------------------------------
|
||||
- Feature: [#21714] [Plugin] Costume assignment is now tailored to each staff type.
|
||||
- Feature: [#21913] [Plugin] Allow precise and safe control of peep animations.
|
||||
- Improved: [#21981] Rendering performance of the map window has been improved considerably.
|
||||
- Improved: [#21981] The map window now defaults to showing as much of the map as fits the screen.
|
||||
- Change: [#7248] Small mini-maps are now centred in the map window.
|
||||
- Fix: [#13294] Map corners are cut off in some directions (original bug).
|
||||
|
||||
0.4.11 (2024-05-05)
|
||||
------------------------------------------------------------------------
|
||||
|
|
|
@ -53,13 +53,39 @@ namespace OpenRCT2::Ui::Windows
|
|||
{
|
||||
return MapColour2((colour & 0xFF00) >> 8, PALETTE_INDEX_10);
|
||||
}
|
||||
|
||||
constexpr int32_t MAP_WINDOW_MAP_SIZE = kMaximumMapSizeTechnical * 2;
|
||||
static int32_t getTechnicalMapSize()
|
||||
{
|
||||
// Take non-square maps into account
|
||||
return std::max(GetGameState().MapSize.x, GetGameState().MapSize.y) - 2;
|
||||
}
|
||||
static int32_t getTechnicalMapSizeBig()
|
||||
{
|
||||
return getTechnicalMapSize() * COORDS_XY_STEP;
|
||||
}
|
||||
static int32_t getMaxTileStartXY()
|
||||
{
|
||||
return getTechnicalMapSizeBig() - COORDS_XY_STEP;
|
||||
}
|
||||
static int32_t getMiniMapWidth()
|
||||
{
|
||||
return getTechnicalMapSize() * 2;
|
||||
}
|
||||
|
||||
static constexpr StringId WINDOW_TITLE = STR_MAP_LABEL;
|
||||
static constexpr int32_t WH = 259;
|
||||
static constexpr int32_t WW = 245;
|
||||
|
||||
static constexpr uint16_t kReservedHSpace = 6;
|
||||
static constexpr uint16_t kReservedTopSpace = 46;
|
||||
static constexpr uint16_t kScenarioEditorReservedSpace = 72;
|
||||
static constexpr uint16_t kRidesTabReservedSpace = 4 * kListRowHeight + 4;
|
||||
static constexpr uint16_t kDefaultReservedSpace = 14;
|
||||
|
||||
static int32_t getMapOffset(int16_t width)
|
||||
{
|
||||
return (width - getMiniMapWidth() - kReservedHSpace - SCROLLBAR_SIZE) / 2;
|
||||
}
|
||||
|
||||
// Some functions manipulate coordinates on the map. These are the coordinates of the pixels in the
|
||||
// minimap. In order to distinguish those from actual coordinates, we use a separate name.
|
||||
using MapCoordsXY = TileCoordsXY;
|
||||
|
@ -126,17 +152,18 @@ static Widget window_map_widgets[] = {
|
|||
MakeWidget ({110, 189}, {131, 14}, WindowWidgetType::Button, WindowColour::Secondary, STR_MAPGEN_WINDOW_TITLE, STR_MAP_GENERATOR_TIP ),
|
||||
kWidgetsEnd,
|
||||
};
|
||||
|
||||
// used in transforming viewport view coordinates to minimap coordinates
|
||||
// rct2: 0x00981BBC
|
||||
static constexpr ScreenCoordsXY MiniMapOffsets[] = {
|
||||
{ kMaximumMapSizeTechnical - 8, 0 },
|
||||
{ 2 * kMaximumMapSizeTechnical - 8, kMaximumMapSizeTechnical },
|
||||
{ kMaximumMapSizeTechnical - 8, 2 * kMaximumMapSizeTechnical },
|
||||
{ 0 - 8, kMaximumMapSizeTechnical },
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
// These represent a coefficient for the map size to be multiplied
|
||||
// Used in transforming viewport view coordinates to minimap coordinates
|
||||
// rct2: 0x00981BBC (analogous)
|
||||
static constexpr ScreenCoordsXY MiniMapOffsetFactors[] = {
|
||||
{ 1, 0 },
|
||||
{ 2, 1 },
|
||||
{ 1, 2 },
|
||||
{ 0, 1 },
|
||||
};
|
||||
|
||||
static constexpr StringId MapLabels[] = {
|
||||
STR_MAP_RIDE, STR_MAP_FOOD_STALL, STR_MAP_DRINK_STALL, STR_MAP_SOUVENIR_STALL,
|
||||
STR_MAP_INFO_KIOSK, STR_MAP_FIRST_AID, STR_MAP_CASH_MACHINE, STR_MAP_TOILET,
|
||||
|
@ -209,11 +236,6 @@ static constexpr ScreenCoordsXY MiniMapOffsets[] = {
|
|||
uint16_t _flashingFlags = 0;
|
||||
|
||||
public:
|
||||
MapWindow()
|
||||
{
|
||||
_mapImageData.resize(MAP_WINDOW_MAP_SIZE * MAP_WINDOW_MAP_SIZE);
|
||||
}
|
||||
|
||||
void OnOpen() override
|
||||
{
|
||||
widgets = window_map_widgets;
|
||||
|
@ -224,11 +246,11 @@ static constexpr ScreenCoordsXY MiniMapOffsets[] = {
|
|||
|
||||
flags |= WF_RESIZABLE;
|
||||
min_width = WW;
|
||||
max_width = 800;
|
||||
min_height = WH;
|
||||
max_height = 560;
|
||||
|
||||
ResizeMap();
|
||||
SetInitialWindowDimensions();
|
||||
ResetMaxWindowDimensions();
|
||||
ResizeMiniMap();
|
||||
InitScrollWidgets();
|
||||
CalculateTextLayout();
|
||||
|
||||
|
@ -353,6 +375,7 @@ static constexpr ScreenCoordsXY MiniMapOffsets[] = {
|
|||
selected_tab = widgetIndex;
|
||||
list_information_type = 0;
|
||||
_recalculateScrollbars = true;
|
||||
ResetMaxWindowDimensions();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -734,14 +757,22 @@ static constexpr ScreenCoordsXY MiniMapOffsets[] = {
|
|||
|
||||
ScreenSize OnScrollGetSize(int32_t scrollIndex) override
|
||||
{
|
||||
return ScreenSize(MAP_WINDOW_MAP_SIZE, MAP_WINDOW_MAP_SIZE);
|
||||
return ScreenSize(getMiniMapWidth(), getMiniMapWidth());
|
||||
}
|
||||
|
||||
void OnScrollMouseDown(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) override
|
||||
{
|
||||
CoordsXY c = ScreenToMap(screenCoords);
|
||||
auto mapCoords = CoordsXY{ std::clamp(c.x, 0, MAXIMUM_MAP_SIZE_BIG - 1),
|
||||
std::clamp(c.y, 0, MAXIMUM_MAP_SIZE_BIG - 1) };
|
||||
// Adjust coordinates for any map offset to centre
|
||||
auto adjCoords = screenCoords;
|
||||
auto mapOffset = getMapOffset(width);
|
||||
if (mapOffset > 0)
|
||||
{
|
||||
adjCoords -= ScreenCoordsXY(mapOffset, mapOffset);
|
||||
}
|
||||
|
||||
CoordsXY c = ScreenToMap(adjCoords);
|
||||
auto mapCoords = CoordsXY{ std::clamp(c.x, 0, getTechnicalMapSizeBig() - 1),
|
||||
std::clamp(c.y, 0, getTechnicalMapSizeBig() - 1) };
|
||||
auto mapZ = TileElementHeight(mapCoords);
|
||||
|
||||
WindowBase* mainWindow = WindowGetMain();
|
||||
|
@ -801,25 +832,32 @@ static constexpr ScreenCoordsXY MiniMapOffsets[] = {
|
|||
{
|
||||
GfxClear(dpi, PALETTE_INDEX_10);
|
||||
|
||||
// Ensure small maps are centred
|
||||
DrawPixelInfo clipDPI = dpi;
|
||||
auto mapOffset = getMapOffset(width);
|
||||
if (mapOffset > 0)
|
||||
{
|
||||
auto screenOffset = ScreenCoordsXY(mapOffset, mapOffset);
|
||||
ClipDrawPixelInfo(clipDPI, dpi, screenOffset, dpi.width, dpi.height);
|
||||
}
|
||||
|
||||
G1Element g1temp = {};
|
||||
g1temp.offset = _mapImageData.data();
|
||||
g1temp.width = MAP_WINDOW_MAP_SIZE;
|
||||
g1temp.height = MAP_WINDOW_MAP_SIZE;
|
||||
g1temp.x_offset = -8;
|
||||
g1temp.y_offset = -8;
|
||||
g1temp.width = getMiniMapWidth();
|
||||
g1temp.height = getMiniMapWidth();
|
||||
GfxSetG1Element(SPR_TEMP, &g1temp);
|
||||
DrawingEngineInvalidateImage(SPR_TEMP);
|
||||
GfxDrawSprite(dpi, ImageId(SPR_TEMP), { 0, 0 });
|
||||
GfxDrawSprite(clipDPI, ImageId(SPR_TEMP), { 0, 0 });
|
||||
|
||||
if (selected_tab == PAGE_PEEPS)
|
||||
{
|
||||
PaintPeepOverlay(dpi);
|
||||
PaintPeepOverlay(clipDPI);
|
||||
}
|
||||
else
|
||||
{
|
||||
PaintTrainOverlay(dpi);
|
||||
PaintTrainOverlay(clipDPI);
|
||||
}
|
||||
PaintHudRectangle(dpi);
|
||||
PaintHudRectangle(clipDPI);
|
||||
}
|
||||
|
||||
void OnPrepareDraw() override
|
||||
|
@ -848,7 +886,7 @@ static constexpr ScreenCoordsXY MiniMapOffsets[] = {
|
|||
|
||||
// Resize widgets to window size
|
||||
ResizeFrameWithPage();
|
||||
ResizeMap();
|
||||
ResizeMiniMap();
|
||||
|
||||
widgets[WIDX_MAP_SIZE_SPINNER_Y].top = height - 15;
|
||||
widgets[WIDX_MAP_SIZE_SPINNER_Y].bottom = height - 4;
|
||||
|
@ -1017,6 +1055,7 @@ static constexpr ScreenCoordsXY MiniMapOffsets[] = {
|
|||
private:
|
||||
void InitMap()
|
||||
{
|
||||
_mapImageData.resize(getMiniMapWidth() * getMiniMapWidth());
|
||||
std::fill(_mapImageData.begin(), _mapImageData.end(), PALETTE_INDEX_10);
|
||||
_currentLine = 0;
|
||||
}
|
||||
|
@ -1030,14 +1069,14 @@ static constexpr ScreenCoordsXY MiniMapOffsets[] = {
|
|||
if (mainWindow == nullptr || mainWindow->viewport == nullptr)
|
||||
return;
|
||||
|
||||
auto offset = MiniMapOffsets[GetCurrentRotation()];
|
||||
auto offset = MiniMapOffsetFactors[GetCurrentRotation()];
|
||||
|
||||
// calculate centre view point of viewport and transform it to minimap coordinates
|
||||
|
||||
cx = ((mainWindow->viewport->view_width >> 1) + mainWindow->viewport->viewPos.x) >> 5;
|
||||
dx = ((mainWindow->viewport->view_height >> 1) + mainWindow->viewport->viewPos.y) >> 4;
|
||||
cx += offset.x;
|
||||
dx += offset.y;
|
||||
cx += offset.x * getTechnicalMapSize();
|
||||
dx += offset.y * getTechnicalMapSize();
|
||||
|
||||
// calculate width and height of minimap
|
||||
|
||||
|
@ -1093,9 +1132,9 @@ static constexpr ScreenCoordsXY MiniMapOffsets[] = {
|
|||
{
|
||||
int32_t x = 0, y = 0, dx = 0, dy = 0;
|
||||
|
||||
int32_t pos = (_currentLine * (MAP_WINDOW_MAP_SIZE - 1)) + kMaximumMapSizeTechnical - 1;
|
||||
auto destinationPosition = ScreenCoordsXY{ pos % MAP_WINDOW_MAP_SIZE, pos / MAP_WINDOW_MAP_SIZE };
|
||||
auto destination = _mapImageData.data() + (destinationPosition.y * MAP_WINDOW_MAP_SIZE) + destinationPosition.x;
|
||||
int32_t pos = (_currentLine * (getMiniMapWidth() - 1)) + getTechnicalMapSize() - 1;
|
||||
auto destinationPosition = ScreenCoordsXY{ pos % getMiniMapWidth(), pos / getMiniMapWidth() };
|
||||
auto destination = _mapImageData.data() + (destinationPosition.y * getMiniMapWidth()) + destinationPosition.x;
|
||||
switch (GetCurrentRotation())
|
||||
{
|
||||
case 0:
|
||||
|
@ -1105,26 +1144,26 @@ static constexpr ScreenCoordsXY MiniMapOffsets[] = {
|
|||
dy = COORDS_XY_STEP;
|
||||
break;
|
||||
case 1:
|
||||
x = MAXIMUM_TILE_START_XY;
|
||||
x = getMaxTileStartXY();
|
||||
y = _currentLine * COORDS_XY_STEP;
|
||||
dx = -COORDS_XY_STEP;
|
||||
dy = 0;
|
||||
break;
|
||||
case 2:
|
||||
x = MAXIMUM_MAP_SIZE_BIG - ((_currentLine + 1) * COORDS_XY_STEP);
|
||||
y = MAXIMUM_TILE_START_XY;
|
||||
x = getTechnicalMapSizeBig() - ((_currentLine + 1) * COORDS_XY_STEP);
|
||||
y = getMaxTileStartXY();
|
||||
dx = 0;
|
||||
dy = -COORDS_XY_STEP;
|
||||
break;
|
||||
case 3:
|
||||
x = 0;
|
||||
y = MAXIMUM_MAP_SIZE_BIG - ((_currentLine + 1) * COORDS_XY_STEP);
|
||||
y = getTechnicalMapSizeBig() - ((_currentLine + 1) * COORDS_XY_STEP);
|
||||
dx = COORDS_XY_STEP;
|
||||
dy = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < kMaximumMapSizeTechnical; i++)
|
||||
for (int32_t i = 0; i < getTechnicalMapSize(); i++)
|
||||
{
|
||||
if (!MapIsEdge({ x, y }))
|
||||
{
|
||||
|
@ -1146,10 +1185,10 @@ static constexpr ScreenCoordsXY MiniMapOffsets[] = {
|
|||
|
||||
destinationPosition.x++;
|
||||
destinationPosition.y++;
|
||||
destination = _mapImageData.data() + (destinationPosition.y * MAP_WINDOW_MAP_SIZE) + destinationPosition.x;
|
||||
destination = _mapImageData.data() + (destinationPosition.y * getMiniMapWidth()) + destinationPosition.x;
|
||||
}
|
||||
_currentLine++;
|
||||
if (_currentLine >= kMaximumMapSizeTechnical)
|
||||
if (_currentLine >= static_cast<uint32_t>(getTechnicalMapSize()))
|
||||
_currentLine = 0;
|
||||
}
|
||||
|
||||
|
@ -1346,7 +1385,10 @@ static constexpr ScreenCoordsXY MiniMapOffsets[] = {
|
|||
if (mainViewport == nullptr)
|
||||
return;
|
||||
|
||||
auto offset = MiniMapOffsets[GetCurrentRotation()];
|
||||
auto offset = MiniMapOffsetFactors[GetCurrentRotation()];
|
||||
offset.x *= getTechnicalMapSize();
|
||||
offset.y *= getTechnicalMapSize();
|
||||
|
||||
auto leftTop = ScreenCoordsXY{ (mainViewport->viewPos.x >> 5) + offset.x,
|
||||
(mainViewport->viewPos.y >> 4) + offset.y };
|
||||
auto rightBottom = ScreenCoordsXY{ ((mainViewport->viewPos.x + mainViewport->view_width) >> 5) + offset.x,
|
||||
|
@ -1438,7 +1480,7 @@ static constexpr ScreenCoordsXY MiniMapOffsets[] = {
|
|||
|
||||
CoordsXY ScreenToMap(ScreenCoordsXY screenCoords)
|
||||
{
|
||||
screenCoords.x = ((screenCoords.x + 8) - kMaximumMapSizeTechnical) / 2;
|
||||
screenCoords.x = ((screenCoords.x + 8) - getTechnicalMapSize()) / 2;
|
||||
screenCoords.y = ((screenCoords.y + 8)) / 2;
|
||||
auto location = TileCoordsXY(screenCoords.y - screenCoords.x, screenCoords.x + screenCoords.y).ToCoordsXY();
|
||||
|
||||
|
@ -1447,11 +1489,11 @@ static constexpr ScreenCoordsXY MiniMapOffsets[] = {
|
|||
case 0:
|
||||
return location;
|
||||
case 1:
|
||||
return { MAXIMUM_MAP_SIZE_BIG - 1 - location.y, location.x };
|
||||
return { getTechnicalMapSizeBig() - 1 - location.y, location.x };
|
||||
case 2:
|
||||
return { MAXIMUM_MAP_SIZE_BIG - 1 - location.x, MAXIMUM_MAP_SIZE_BIG - 1 - location.y };
|
||||
return { getTechnicalMapSizeBig() - 1 - location.x, getTechnicalMapSizeBig() - 1 - location.y };
|
||||
case 3:
|
||||
return { location.y, MAXIMUM_MAP_SIZE_BIG - 1 - location.x };
|
||||
return { location.y, getTechnicalMapSizeBig() - 1 - location.x };
|
||||
}
|
||||
|
||||
return { 0, 0 }; // unreachable
|
||||
|
@ -1465,15 +1507,15 @@ static constexpr ScreenCoordsXY MiniMapOffsets[] = {
|
|||
{
|
||||
case 3:
|
||||
std::swap(x, y);
|
||||
x = MAXIMUM_MAP_SIZE_BIG - 1 - x;
|
||||
x = getTechnicalMapSizeBig() - 1 - x;
|
||||
break;
|
||||
case 2:
|
||||
x = MAXIMUM_MAP_SIZE_BIG - 1 - x;
|
||||
y = MAXIMUM_MAP_SIZE_BIG - 1 - y;
|
||||
x = getTechnicalMapSizeBig() - 1 - x;
|
||||
y = getTechnicalMapSizeBig() - 1 - y;
|
||||
break;
|
||||
case 1:
|
||||
std::swap(x, y);
|
||||
y = MAXIMUM_MAP_SIZE_BIG - 1 - y;
|
||||
y = getTechnicalMapSizeBig() - 1 - y;
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
|
@ -1481,19 +1523,42 @@ static constexpr ScreenCoordsXY MiniMapOffsets[] = {
|
|||
x /= 32;
|
||||
y /= 32;
|
||||
|
||||
return { -x + y + kMaximumMapSizeTechnical - 8, x + y - 8 };
|
||||
return { -x + y + getTechnicalMapSize(), x + y };
|
||||
}
|
||||
|
||||
void ResizeMap()
|
||||
uint16_t GetReservedBottomSpace()
|
||||
{
|
||||
if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || GetGameState().Cheats.SandboxMode)
|
||||
return kScenarioEditorReservedSpace;
|
||||
else if (selected_tab == PAGE_RIDES)
|
||||
return kRidesTabReservedSpace;
|
||||
else
|
||||
return kDefaultReservedSpace;
|
||||
}
|
||||
|
||||
void SetInitialWindowDimensions()
|
||||
{
|
||||
// The initial mini map size should be able to show a reasonably sized map
|
||||
auto initSize = std::clamp(getTechnicalMapSize(), 100, 254) * 2;
|
||||
width = initSize + kReservedHSpace + SCROLLBAR_SIZE;
|
||||
height = initSize + kReservedTopSpace + GetReservedBottomSpace() + SCROLLBAR_SIZE;
|
||||
|
||||
auto maxWindowHeight = ContextGetHeight() - 68;
|
||||
width = std::min<int16_t>(width, ContextGetWidth());
|
||||
height = std::min<int16_t>(height, maxWindowHeight);
|
||||
}
|
||||
|
||||
void ResetMaxWindowDimensions()
|
||||
{
|
||||
max_width = std::clamp(getMiniMapWidth() + kReservedHSpace + SCROLLBAR_SIZE, WW, ContextGetWidth());
|
||||
max_height = std::clamp(
|
||||
getMiniMapWidth() + kReservedTopSpace + GetReservedBottomSpace() + SCROLLBAR_SIZE, WH, ContextGetHeight() - 68);
|
||||
}
|
||||
|
||||
void ResizeMiniMap()
|
||||
{
|
||||
widgets[WIDX_MAP].right = width - 4;
|
||||
|
||||
if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) || GetGameState().Cheats.SandboxMode)
|
||||
widgets[WIDX_MAP].bottom = height - 1 - 72;
|
||||
else if (selected_tab == PAGE_RIDES)
|
||||
widgets[WIDX_MAP].bottom = height - 1 - (4 * kListRowHeight + 4);
|
||||
else
|
||||
widgets[WIDX_MAP].bottom = height - 1 - 14;
|
||||
widgets[WIDX_MAP].bottom = height - 1 - GetReservedBottomSpace();
|
||||
}
|
||||
|
||||
void CalculateTextLayout()
|
||||
|
|
Loading…
Reference in New Issue