Port dirty block handling from JGRPP

This commit is contained in:
dP
2023-03-29 21:47:07 +04:00
parent ef7d1c5f04
commit ef9f6aa7f3
22 changed files with 837 additions and 193 deletions

View File

@@ -622,7 +622,7 @@ void Window::RaiseButtons(bool autoraise)
* Invalidate a widget, i.e. mark it as being changed and in need of redraw.
* @param widget_index the widget to redraw.
*/
void Window::SetWidgetDirty(byte widget_index) const
void Window::SetWidgetDirty(byte widget_index)
{
/* Sometimes this function is called before the window is even fully initialized */
if (this->nested_array == nullptr) return;
@@ -889,27 +889,6 @@ static void DispatchMouseWheelEvent(Window *w, NWidgetCore *nwid, int wheel)
}
}
/**
* Returns whether a window may be shown or not.
* @param w The window to consider.
* @return True iff it may be shown, otherwise false.
*/
static bool MayBeShown(const Window *w)
{
/* If we're not modal, everything is okay. */
if (!HasModalProgress()) return true;
switch (w->window_class) {
case WC_MAIN_WINDOW: ///< The background, i.e. the game.
case WC_MODAL_PROGRESS: ///< The actual progress window.
case WC_CONFIRM_POPUP_QUERY: ///< The abort window.
return true;
default:
return false;
}
}
/**
* Generate repaint events for the visible part of window w within the rectangle.
*
@@ -921,8 +900,9 @@ static bool MayBeShown(const Window *w)
* @param top Top edge of the rectangle that should be repainted
* @param right Right edge of the rectangle that should be repainted
* @param bottom Bottom edge of the rectangle that should be repainted
* @param gfx_dirty Whether to mark gfx dirty
*/
static void DrawOverlappedWindow(Window *w, int left, int top, int right, int bottom)
void DrawOverlappedWindow(Window *w, int left, int top, int right, int bottom, DrawOverlappedWindowFlags flags)
{
Window::IteratorToFront it(w);
++it;
@@ -937,26 +917,26 @@ static void DrawOverlappedWindow(Window *w, int left, int top, int right, int bo
int x;
if (left < (x = v->left)) {
DrawOverlappedWindow(w, left, top, x, bottom);
DrawOverlappedWindow(w, x, top, right, bottom);
DrawOverlappedWindow(w, left, top, x, bottom, flags);
DrawOverlappedWindow(w, x, top, right, bottom, flags);
return;
}
if (right > (x = v->left + v->width)) {
DrawOverlappedWindow(w, left, top, x, bottom);
DrawOverlappedWindow(w, x, top, right, bottom);
DrawOverlappedWindow(w, left, top, x, bottom, flags);
DrawOverlappedWindow(w, x, top, right, bottom, flags);
return;
}
if (top < (x = v->top)) {
DrawOverlappedWindow(w, left, top, right, x);
DrawOverlappedWindow(w, left, x, right, bottom);
DrawOverlappedWindow(w, left, top, right, x, flags);
DrawOverlappedWindow(w, left, x, right, bottom, flags);
return;
}
if (bottom > (x = v->top + v->height)) {
DrawOverlappedWindow(w, left, top, right, x);
DrawOverlappedWindow(w, left, x, right, bottom);
DrawOverlappedWindow(w, left, top, right, x, flags);
DrawOverlappedWindow(w, left, x, right, bottom, flags);
return;
}
@@ -974,6 +954,14 @@ static void DrawOverlappedWindow(Window *w, int left, int top, int right, int bo
dp->dst_ptr = BlitterFactory::GetCurrentBlitter()->MoveTo(_screen.dst_ptr, left, top);
dp->zoom = ZOOM_LVL_NORMAL;
w->OnPaint();
if (unlikely(flags & DOWF_SHOW_DEBUG)) {
extern void ViewportDrawDirtyBlocks();
ViewportDrawDirtyBlocks();
}
if (flags & DOWF_MARK_DIRTY) {
VideoDriver::GetInstance()->MakeDirty(left, top, right - left, bottom - top);
UnsetDirtyBlocks(left, top, right, bottom);
}
}
/**
@@ -997,19 +985,34 @@ void DrawOverlappedWindowForAll(int left, int top, int right, int bottom)
left < w->left + w->width &&
top < w->top + w->height) {
/* Window w intersects with the rectangle => needs repaint */
DrawOverlappedWindow(w, std::max(left, w->left), std::max(top, w->top), std::min(right, w->left + w->width), std::min(bottom, w->top + w->height));
DrawOverlappedWindow(w, std::max(left, w->left), std::max(top, w->top), std::min(right, w->left + w->width), std::min(bottom, w->top + w->height), DOWF_NONE);
}
}
_cur_dpi = old_dpi;
}
/**
* Mark entire window as dirty (in need of re-paint)
* @ingroup dirty
*/
void Window::SetDirty()
{
this->flags |= WF_DIRTY;
}
/**
* Mark entire window as dirty (in need of re-paint)
* @ingroup dirty
*/
void Window::SetDirty() const
void Window::SetDirtyAsBlocks()
{
AddDirtyBlock(this->left, this->top, this->left + this->width, this->top + this->height);
extern bool _gfx_draw_active;
if (_gfx_draw_active) {
AddPendingDirtyBlocks(this->left, this->top, this->left + this->width, this->top + this->height);
} else {
AddDirtyBlock(this->left, this->top, this->left + this->width, this->top + this->height);
}
}
/**
@@ -1020,7 +1023,7 @@ void Window::SetDirty() const
*/
void Window::ReInit(int rx, int ry)
{
this->SetDirty(); // Mark whole current window as dirty.
this->SetDirtyAsBlocks(); // Mark whole current window as dirty.
/* Save current size. */
int window_width = this->width;
@@ -1135,7 +1138,7 @@ void Window::Close()
this->CloseChildWindows();
this->SetDirty();
this->SetDirtyAsBlocks();
Window::closed_windows.push_back(this);
}
@@ -2102,7 +2105,7 @@ void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen)
if (new_bottom >= (int)_screen.height) delta_y -= Ceil(new_bottom - _screen.height, std::max(1U, w->nested_root->resize_y));
}
w->SetDirty();
w->SetDirtyAsBlocks();
uint new_xinc = std::max(0, (w->nested_root->resize_x == 0) ? 0 : (int)(w->nested_root->current_x - w->nested_root->smallest_x) + delta_x);
uint new_yinc = std::max(0, (w->nested_root->resize_y == 0) ? 0 : (int)(w->nested_root->current_y - w->nested_root->smallest_y) + delta_y);
@@ -2118,7 +2121,14 @@ void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen)
/* Always call OnResize to make sure everything is initialised correctly if it needs to be. */
w->OnResize();
w->SetDirty();
// TODO incapsulate into a function
extern bool _gfx_draw_active;
if (_gfx_draw_active) {
AddPendingDirtyBlocks(w->left, w->top, w->left + w->width, w->top + w->height);
} else {
w->SetDirty();
}
}
/**
@@ -2166,7 +2176,10 @@ static EventState HandleWindowDragging()
break;
}
w->SetDirty();
if (!(w->flags & WF_DRAG_DIRTIED)) {
w->flags |= WF_DRAG_DIRTIED;
w->SetDirtyAsBlocks();
}
int x = _cursor.pos.x + _drag_delta.x;
int y = _cursor.pos.y + _drag_delta.y;
@@ -2299,7 +2312,7 @@ static EventState HandleWindowDragging()
_drag_delta.y += y;
if ((w->flags & WF_SIZING_LEFT) && x != 0) {
_drag_delta.x -= x; // x > 0 -> window gets longer -> left-edge moves to left -> subtract x to get new position.
w->SetDirty();
w->SetDirtyAsBlocks();
w->left -= x; // If dragging left edge, move left window edge in opposite direction by the same amount.
/* ResizeWindow() below ensures marking new position as dirty. */
} else {
@@ -3164,7 +3177,7 @@ void UpdateWindows()
*/
void SetWindowDirty(WindowClass cls, WindowNumber number)
{
for (const Window *w : Window::Iterate()) {
for (Window *w : Window::Iterate()) {
if (w->window_class == cls && w->window_number == number) w->SetDirty();
}
}
@@ -3177,7 +3190,7 @@ void SetWindowDirty(WindowClass cls, WindowNumber number)
*/
void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, byte widget_index)
{
for (const Window *w : Window::Iterate()) {
for (Window *w : Window::Iterate()) {
if (w->window_class == cls && w->window_number == number) {
w->SetWidgetDirty(widget_index);
}
@@ -3190,7 +3203,7 @@ void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, byte widget_inde
*/
void SetWindowClassesDirty(WindowClass cls)
{
for (const Window *w : Window::Iterate()) {
for (Window *w : Window::Iterate()) {
if (w->window_class == cls) w->SetDirty();
}
}
@@ -3362,7 +3375,7 @@ void CloseConstructionWindows()
}
}
for (const Window *w : Window::Iterate()) w->SetDirty();
for (Window *w : Window::Iterate()) w->SetDirty();
}
/** Close all always on-top windows to get an empty screen */
@@ -3486,7 +3499,7 @@ int PositionNetworkChatWindow(Window *w)
*/
void ChangeVehicleViewports(VehicleID from_index, VehicleID to_index)
{
for (const Window *w : Window::Iterate()) {
for (Window *w : Window::Iterate()) {
if (w->viewport != nullptr && w->viewport->follow_vehicle == from_index) {
w->viewport->follow_vehicle = to_index;
w->SetDirty();