From f51ad862c93038effeb5e599afd199890c3f2794 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 22 Aug 2020 13:00:15 +0100 Subject: [PATCH] Refactor window drawing --- src/openrct2/drawing/Drawing.cpp | 12 ++++ src/openrct2/drawing/Drawing.h | 2 + src/openrct2/interface/Window.cpp | 100 ++++++++++++------------------ 3 files changed, 54 insertions(+), 60 deletions(-) diff --git a/src/openrct2/drawing/Drawing.cpp b/src/openrct2/drawing/Drawing.cpp index da060ea4ab..885b8cd090 100644 --- a/src/openrct2/drawing/Drawing.cpp +++ b/src/openrct2/drawing/Drawing.cpp @@ -772,3 +772,15 @@ std::optional GetPaletteMapForColour(colour_t paletteId) } return std::nullopt; } + +rct_drawpixelinfo rct_drawpixelinfo::Crop(int32_t newX, int32_t newY, int32_t newWidth, int32_t newHeight) +{ + rct_drawpixelinfo result = *this; + result.bits = bits + newX + (((size_t)width + pitch) * newY); + result.x = static_cast(newX); + result.y = static_cast(newY); + result.width = static_cast(newWidth); + result.height = static_cast(newHeight); + result.pitch = static_cast(width + pitch - newWidth); + return result; +} diff --git a/src/openrct2/drawing/Drawing.h b/src/openrct2/drawing/Drawing.h index 48079e118b..e053c161f3 100644 --- a/src/openrct2/drawing/Drawing.h +++ b/src/openrct2/drawing/Drawing.h @@ -110,6 +110,8 @@ struct rct_drawpixelinfo ZoomLevel zoom_level{}; OpenRCT2::Drawing::IDrawingEngine* DrawingEngine{}; + + rct_drawpixelinfo Crop(int32_t newX, int32_t newY, int32_t newWidth, int32_t newHeight); }; struct rct_g1_element_32bit diff --git a/src/openrct2/interface/Window.cpp b/src/openrct2/interface/Window.cpp index 9dcb834e5f..5044c31ac1 100644 --- a/src/openrct2/interface/Window.cpp +++ b/src/openrct2/interface/Window.cpp @@ -84,8 +84,7 @@ namespace WindowCloseFlags static constexpr uint32_t CloseSingle = (1 << 1); } // namespace WindowCloseFlags -static int32_t window_draw_split( - rct_drawpixelinfo* dpi, rct_window* w, int32_t left, int32_t top, int32_t right, int32_t bottom); +static void window_draw_core(rct_drawpixelinfo* dpi, rct_window* w, int32_t left, int32_t top, int32_t right, int32_t bottom); static void window_draw_single(rct_drawpixelinfo* dpi, rct_window* w, int32_t left, int32_t top, int32_t right, int32_t bottom); std::list>::iterator window_get_iterator(const rct_window* w) @@ -1088,51 +1087,14 @@ void main_window_zoom(bool zoomIn, bool atCursor) } /** - * Draws a window that is in the specified region. - * rct2: 0x006E756C - * left (ax) - * top (bx) - * right (dx) - * bottom (bp) + * Splits a drawing of a window into regions that can be seen and are not hidden + * by other opaque overlapping windows. */ void window_draw(rct_drawpixelinfo* dpi, rct_window* w, int32_t left, int32_t top, int32_t right, int32_t bottom) { if (!window_is_visible(w)) return; - // Split window into only the regions that require drawing - if (window_draw_split(dpi, w, left, top, right, bottom)) - return; - - // Clamp region - left = std::max(left, w->windowPos.x); - top = std::max(top, w->windowPos.y); - right = std::min(right, w->windowPos.x + w->width); - bottom = std::min(bottom, w->windowPos.y + w->height); - if (left >= right) - return; - if (top >= bottom) - return; - - // Draw the window in this region - for (auto it = window_get_iterator(w); it != g_window_list.end(); it++) - { - // Don't draw overlapping opaque windows, they won't have changed - auto v = (*it).get(); - if ((w == v || (v->flags & WF_TRANSPARENT)) && window_is_visible(v)) - { - window_draw_single(dpi, v, left, top, right, bottom); - } - } -} - -/** - * Splits a drawing of a window into regions that can be seen and are not hidden - * by other opaque overlapping windows. - */ -static int32_t window_draw_split( - rct_drawpixelinfo* dpi, rct_window* w, int32_t left, int32_t top, int32_t right, int32_t bottom) -{ // Divide the draws up for only the visible regions of the window recursively auto itPos = window_get_iterator(w); for (auto it = std::next(itPos); it != g_window_list.end(); it++) @@ -1150,34 +1112,60 @@ static int32_t window_draw_split( if (topwindow->windowPos.x > left) { // Split draw at topwindow.left - window_draw(dpi, w, left, top, topwindow->windowPos.x, bottom); - window_draw(dpi, w, topwindow->windowPos.x, top, right, bottom); + window_draw_core(dpi, w, left, top, topwindow->windowPos.x, bottom); + window_draw_core(dpi, w, topwindow->windowPos.x, top, right, bottom); } else if (topwindow->windowPos.x + topwindow->width < right) { // Split draw at topwindow.right - window_draw(dpi, w, left, top, topwindow->windowPos.x + topwindow->width, bottom); - window_draw(dpi, w, topwindow->windowPos.x + topwindow->width, top, right, bottom); + window_draw_core(dpi, w, left, top, topwindow->windowPos.x + topwindow->width, bottom); + window_draw_core(dpi, w, topwindow->windowPos.x + topwindow->width, top, right, bottom); } else if (topwindow->windowPos.y > top) { // Split draw at topwindow.top - window_draw(dpi, w, left, top, right, topwindow->windowPos.y); - window_draw(dpi, w, left, topwindow->windowPos.y, right, bottom); + window_draw_core(dpi, w, left, top, right, topwindow->windowPos.y); + window_draw_core(dpi, w, left, topwindow->windowPos.y, right, bottom); } else if (topwindow->windowPos.y + topwindow->height < bottom) { // Split draw at topwindow.bottom - window_draw(dpi, w, left, top, right, topwindow->windowPos.y + topwindow->height); - window_draw(dpi, w, left, topwindow->windowPos.y + topwindow->height, right, bottom); + window_draw_core(dpi, w, left, top, right, topwindow->windowPos.y + topwindow->height); + window_draw_core(dpi, w, left, topwindow->windowPos.y + topwindow->height, right, bottom); } // Drawing for this region should be done now, exit - return 1; + return; } // No windows overlap - return 0; + window_draw_core(dpi, w, left, top, right, bottom); +} + +/** + * Draws the given window and any other overlapping transparent windows. + */ +static void window_draw_core(rct_drawpixelinfo* dpi, rct_window* w, int32_t left, int32_t top, int32_t right, int32_t bottom) +{ + // Clamp region + left = std::max(left, w->windowPos.x); + top = std::max(top, w->windowPos.y); + right = std::min(right, w->windowPos.x + w->width); + bottom = std::min(bottom, w->windowPos.y + w->height); + if (left >= right) + return; + if (top >= bottom) + return; + + // Draw the window and any other overlapping transparent windows + for (auto it = window_get_iterator(w); it != g_window_list.end(); it++) + { + auto v = (*it).get(); + if ((w == v || (v->flags & WF_TRANSPARENT)) && window_is_visible(v)) + { + window_draw_single(dpi, v, left, top, right, bottom); + } + } } static void window_draw_single(rct_drawpixelinfo* dpi, rct_window* w, int32_t left, int32_t top, int32_t right, int32_t bottom) @@ -2018,15 +2006,7 @@ bool window_is_visible(rct_window* w) */ void window_draw_all(rct_drawpixelinfo* dpi, int16_t left, int16_t top, int16_t right, int16_t bottom) { - rct_drawpixelinfo windowDPI = *dpi; - windowDPI.bits = dpi->bits + left + ((dpi->width + dpi->pitch) * top); - windowDPI.x = left; - windowDPI.y = top; - windowDPI.width = right - left; - windowDPI.height = bottom - top; - windowDPI.pitch = dpi->width + dpi->pitch + left - right; - windowDPI.zoom_level = 0; - + auto windowDPI = dpi->Crop(left, top, right - left, bottom - top); window_visit_each([&windowDPI, left, top, right, bottom](rct_window* w) { if (w->flags & WF_TRANSPARENT) return;