From cf9e4ae0f39816e685369f74c26fde582eca9f8d Mon Sep 17 00:00:00 2001 From: Michael Bernardi Date: Sat, 21 Sep 2024 17:59:54 +1000 Subject: [PATCH] Rewrite ViewportRedrawAfterShift to avoid copying Viewport --- .../engines/opengl/OpenGLDrawingEngine.cpp | 2 +- src/openrct2/drawing/Drawing.cpp | 33 +++--- src/openrct2/drawing/Drawing.h | 3 +- src/openrct2/interface/Viewport.cpp | 109 ++++++++---------- src/openrct2/interface/Window.h | 1 - 5 files changed, 70 insertions(+), 78 deletions(-) diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp index 5b80e51fe4..a5d9500356 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -1181,7 +1181,7 @@ void OpenGLDrawingContext::HandleTransparency() void OpenGLDrawingContext::CalculcateClipping(DrawPixelInfo& dpi) { auto screenDPI = _engine.GetDPI(); - auto bytesPerRow = screenDPI->GetBytesPerRow(); + auto bytesPerRow = screenDPI->LineStride(); auto bitsOffset = static_cast(dpi.bits - screenDPI->bits); # ifndef NDEBUG auto bitsSize = static_cast(screenDPI->ScreenHeight()) * bytesPerRow; diff --git a/src/openrct2/drawing/Drawing.cpp b/src/openrct2/drawing/Drawing.cpp index c74f13dd67..272ee9590a 100644 --- a/src/openrct2/drawing/Drawing.cpp +++ b/src/openrct2/drawing/Drawing.cpp @@ -883,25 +883,20 @@ std::optional GetPaletteMapForColour(colour_t paletteId) return std::nullopt; } -size_t DrawPixelInfo::GetBytesPerRow() const -{ - return static_cast(width) + pitch; -} - uint8_t* DrawPixelInfo::GetBitsOffset(const ScreenCoordsXY& pos) const { - return bits + pos.x + (pos.y * GetBytesPerRow()); + return bits + pos.x + pos.y * LineStride(); } DrawPixelInfo DrawPixelInfo::Crop(const ScreenCoordsXY& pos, const ScreenSize& size) const { DrawPixelInfo result = *this; result.bits = GetBitsOffset(pos); - result.x = static_cast(pos.x); - result.y = static_cast(pos.y); - result.width = static_cast(size.width); - result.height = static_cast(size.height); - result.pitch = static_cast(width + pitch - size.width); + result.x = pos.x; + result.y = pos.y; + result.width = size.width; + result.height = size.height; + result.pitch = width + pitch - size.width; return result; } @@ -1140,7 +1135,7 @@ void ToggleWindowedMode() Config::Save(); } -void DebugDPI(DrawPixelInfo& dpi) +void DebugDPI(const DrawPixelInfo& dpi) { DrawPixelInfo unzoomed = dpi; unzoomed.zoom_level = ZoomLevel{ 0 }; @@ -1150,13 +1145,21 @@ void DebugDPI(DrawPixelInfo& dpi) unzoomed.SetHeight(dpi.ScreenHeight()); ScreenCoordsXY topLeft = { unzoomed.ScreenX(), unzoomed.ScreenY() }; - ScreenCoordsXY topRight = { unzoomed.ScreenX() + unzoomed.ScreenWidth() - 1, unzoomed.ScreenY() }; - ScreenCoordsXY bottomLeft = { unzoomed.ScreenX(), unzoomed.ScreenY() + unzoomed.ScreenHeight() - 1 }; ScreenCoordsXY bottomRight = { unzoomed.ScreenX() + unzoomed.ScreenWidth() - 1, unzoomed.ScreenY() + unzoomed.ScreenHeight() - 1 }; - GfxDrawLine(unzoomed, { topLeft, bottomRight }, PALETTE_INDEX_129); + ScreenCoordsXY topRight = { unzoomed.ScreenX() + unzoomed.ScreenWidth() - 1, unzoomed.ScreenY() }; + ScreenCoordsXY bottomLeft = { unzoomed.ScreenX(), unzoomed.ScreenY() + unzoomed.ScreenHeight() - 1 }; + + GfxDrawLine(unzoomed, { topLeft, bottomRight }, PALETTE_INDEX_136); + GfxDrawLine(unzoomed, { bottomLeft, topRight }, PALETTE_INDEX_136); GfxDrawLine(unzoomed, { topLeft, topRight }, PALETTE_INDEX_129); GfxDrawLine(unzoomed, { topRight, bottomRight }, PALETTE_INDEX_129); GfxDrawLine(unzoomed, { bottomLeft, bottomRight }, PALETTE_INDEX_129); GfxDrawLine(unzoomed, { topLeft, bottomLeft }, PALETTE_INDEX_129); + + GfxDrawLine(unzoomed, { topLeft, topLeft + ScreenCoordsXY{ 4, 0 } }, PALETTE_INDEX_136); + + const auto str = std::to_string(dpi.ScreenX()); + DrawText( + unzoomed, ScreenCoordsXY{ unzoomed.ScreenX(), unzoomed.ScreenY() }, { COLOUR_WHITE, FontStyle::Tiny }, str.c_str()); } \ No newline at end of file diff --git a/src/openrct2/drawing/Drawing.h b/src/openrct2/drawing/Drawing.h index 4fa4a14fa0..4603f54b00 100644 --- a/src/openrct2/drawing/Drawing.h +++ b/src/openrct2/drawing/Drawing.h @@ -124,7 +124,6 @@ public: OpenRCT2::Drawing::IDrawingEngine* DrawingEngine{}; - size_t GetBytesPerRow() const; uint8_t* GetBitsOffset(const ScreenCoordsXY& pos) const; DrawPixelInfo Crop(const ScreenCoordsXY& pos, const ScreenSize& size) const; @@ -685,6 +684,6 @@ void UpdatePaletteEffects(); void RefreshVideo(); void ToggleWindowedMode(); -void DebugDPI(DrawPixelInfo& dpi); +void DebugDPI(const DrawPixelInfo& dpi); #include "NewDrawing.h" diff --git a/src/openrct2/interface/Viewport.cpp b/src/openrct2/interface/Viewport.cpp index 320d07a270..f5932030f6 100644 --- a/src/openrct2/interface/Viewport.cpp +++ b/src/openrct2/interface/Viewport.cpp @@ -326,115 +326,103 @@ CoordsXYZ ViewportAdjustForMapHeight(const ScreenCoordsXY& startCoords, uint8_t /* * rct2: 0x006E7FF3 */ -static void ViewportRedrawAfterShift(DrawPixelInfo& dpi, WindowBase* window, Viewport* viewport, const ScreenCoordsXY& coords) +static void ViewportRedrawAfterShift( + DrawPixelInfo& dpi, WindowBase* window, const WindowBase* originalWindow, const ScreenCoordsXY shift, + const ScreenRect& drawRect) { // sub-divide by intersecting windows if (window != nullptr) { // skip current window and non-intersecting windows - if (viewport == window->viewport || viewport->pos.x + viewport->width <= window->windowPos.x - || viewport->pos.x >= window->windowPos.x + window->width - || viewport->pos.y + viewport->height <= window->windowPos.y - || viewport->pos.y >= window->windowPos.y + window->height) + if (window == originalWindow || drawRect.GetRight() <= window->windowPos.x + || drawRect.GetLeft() >= window->windowPos.x + window->width || drawRect.GetBottom() <= window->windowPos.y + || drawRect.GetTop() >= window->windowPos.y + window->height) { auto itWindowPos = WindowGetIterator(window); auto itNextWindow = itWindowPos != g_window_list.end() ? std::next(itWindowPos) : g_window_list.end(); ViewportRedrawAfterShift( - dpi, itNextWindow == g_window_list.end() ? nullptr : itNextWindow->get(), viewport, coords); + dpi, itNextWindow == g_window_list.end() ? nullptr : itNextWindow->get(), originalWindow, shift, drawRect); return; } - // save viewport - Viewport view_copy = *viewport; - - if (viewport->pos.x < window->windowPos.x) + if (drawRect.GetLeft() < window->windowPos.x) { - viewport->width = window->windowPos.x - viewport->pos.x; - ViewportRedrawAfterShift(dpi, window, viewport, coords); + ScreenRect leftRect = { drawRect.Point1, { window->windowPos.x, drawRect.GetBottom() } }; + ViewportRedrawAfterShift(dpi, window, originalWindow, shift, leftRect); - viewport->pos.x += viewport->width; - viewport->viewPos.x += viewport->zoom.ApplyTo(viewport->width); - viewport->width = view_copy.width - viewport->width; - ViewportRedrawAfterShift(dpi, window, viewport, coords); + ScreenRect rightRect = { { window->windowPos.x, drawRect.GetTop() }, drawRect.Point2 }; + ViewportRedrawAfterShift(dpi, window, originalWindow, shift, rightRect); } - else if (viewport->pos.x + viewport->width > window->windowPos.x + window->width) + else if (drawRect.GetRight() > window->windowPos.x + window->width) { - viewport->width = window->windowPos.x + window->width - viewport->pos.x; - ViewportRedrawAfterShift(dpi, window, viewport, coords); + ScreenRect leftRect = { drawRect.Point1, { window->windowPos.x + window->width, drawRect.GetBottom() } }; + ViewportRedrawAfterShift(dpi, window, originalWindow, shift, leftRect); - viewport->pos.x += viewport->width; - viewport->viewPos.x += viewport->zoom.ApplyTo(viewport->width); - viewport->width = view_copy.width - viewport->width; - ViewportRedrawAfterShift(dpi, window, viewport, coords); + ScreenRect rightRect = { { window->windowPos.x + window->width, drawRect.GetTop() }, drawRect.Point2 }; + ViewportRedrawAfterShift(dpi, window, originalWindow, shift, rightRect); } - else if (viewport->pos.y < window->windowPos.y) + else if (drawRect.GetTop() < window->windowPos.y) { - viewport->height = window->windowPos.y - viewport->pos.y; - ViewportRedrawAfterShift(dpi, window, viewport, coords); + ScreenRect topRect = { drawRect.Point1, { drawRect.GetRight(), window->windowPos.y } }; + ViewportRedrawAfterShift(dpi, window, originalWindow, shift, topRect); - viewport->pos.y += viewport->height; - viewport->viewPos.y += viewport->zoom.ApplyTo(viewport->height); - viewport->height = view_copy.height - viewport->height; - ViewportRedrawAfterShift(dpi, window, viewport, coords); + ScreenRect bottomRect = { { drawRect.GetLeft(), window->windowPos.y }, drawRect.Point2 }; + ViewportRedrawAfterShift(dpi, window, originalWindow, shift, bottomRect); } - else if (viewport->pos.y + viewport->height > window->windowPos.y + window->height) + else if (drawRect.GetBottom() > window->windowPos.y + window->height) { - viewport->height = window->windowPos.y + window->height - viewport->pos.y; - ViewportRedrawAfterShift(dpi, window, viewport, coords); + ScreenRect topRect = { drawRect.Point1, { drawRect.GetRight(), window->windowPos.y + window->height } }; + ViewportRedrawAfterShift(dpi, window, originalWindow, shift, topRect); - viewport->pos.y += viewport->height; - viewport->viewPos.y += viewport->zoom.ApplyTo(viewport->height); - viewport->height = view_copy.height - viewport->height; - ViewportRedrawAfterShift(dpi, window, viewport, coords); + ScreenRect bottomRect = { { drawRect.GetLeft(), window->windowPos.y + window->height }, drawRect.Point2 }; + ViewportRedrawAfterShift(dpi, window, originalWindow, shift, bottomRect); } - - // restore viewport - *viewport = view_copy; } else { - auto left = viewport->pos.x; - auto right = viewport->pos.x + viewport->width; - auto top = viewport->pos.y; - auto bottom = viewport->pos.y + viewport->height; + auto left = drawRect.GetLeft(); + auto right = drawRect.GetRight(); + auto top = drawRect.GetTop(); + auto bottom = drawRect.GetBottom(); - // if moved more than the viewport size - if (abs(coords.x) < viewport->width && abs(coords.y) < viewport->height) + // if moved more than the draw rectangle size + if (abs(shift.x) < drawRect.GetWidth() && abs(shift.y) < drawRect.GetHeight()) { // update whole block ? - DrawingEngineCopyRect(viewport->pos.x, viewport->pos.y, viewport->width, viewport->height, coords.x, coords.y); + DrawingEngineCopyRect( + drawRect.GetLeft(), drawRect.GetTop(), drawRect.GetWidth(), drawRect.GetHeight(), shift.x, shift.y); - if (coords.x > 0) + if (shift.x > 0) { // draw left - auto _right = viewport->pos.x + coords.x; + auto _right = left + shift.x; WindowDrawAll(dpi, left, top, _right, bottom); - left += coords.x; + left += shift.x; } - else if (coords.x < 0) + else if (shift.x < 0) { // draw right - auto _left = viewport->pos.x + viewport->width + coords.x; + auto _left = right + shift.x; WindowDrawAll(dpi, _left, top, right, bottom); - right += coords.x; + right += shift.x; } - if (coords.y > 0) + if (shift.y > 0) { // draw top - bottom = viewport->pos.y + coords.y; + bottom = top + shift.y; WindowDrawAll(dpi, left, top, right, bottom); } - else if (coords.y < 0) + else if (shift.y < 0) { // draw bottom - top = viewport->pos.y + viewport->height + coords.y; + top = bottom + shift.y; WindowDrawAll(dpi, left, top, right, bottom); } } else { - // redraw whole viewport + // redraw whole draw rectangle WindowDrawAll(dpi, left, top, right, bottom); } } @@ -442,6 +430,7 @@ static void ViewportRedrawAfterShift(DrawPixelInfo& dpi, WindowBase* window, Vie static void ViewportShiftPixels(DrawPixelInfo& dpi, WindowBase* window, Viewport* viewport, int32_t x_diff, int32_t y_diff) { + // This loop redraws all parts covered by transparent windows. auto it = WindowGetIterator(window); for (; it != g_window_list.end(); it++) { @@ -484,7 +473,9 @@ static void ViewportShiftPixels(DrawPixelInfo& dpi, WindowBase* window, Viewport WindowDrawAll(dpi, left, top, right, bottom); } - ViewportRedrawAfterShift(dpi, window, viewport, { x_diff, y_diff }); + ViewportRedrawAfterShift( + dpi, window, window, { x_diff, y_diff }, + { viewport->pos, { viewport->pos.x + viewport->width, viewport->pos.y + viewport->height } }); } static void ViewportMove(const ScreenCoordsXY& coords, WindowBase* w, Viewport* viewport) diff --git a/src/openrct2/interface/Window.h b/src/openrct2/interface/Window.h index 536b39db17..d14ebd9a04 100644 --- a/src/openrct2/interface/Window.h +++ b/src/openrct2/interface/Window.h @@ -174,7 +174,6 @@ struct Viewport // from its x, y, z [[nodiscard]] constexpr bool Contains(const ScreenCoordsXY& vpos) const { - // TODO (mber), change to compare in screen space coords. return ( vpos.y >= viewPos.y && vpos.y < viewPos.y + ViewHeight() && vpos.x >= viewPos.x && vpos.x < viewPos.x + ViewWidth());