]> granicus.if.org Git - nethack/commitdiff
Win32GUI: Use a back buffer for all status rendering
authorBart House <bart@barthouse.com>
Mon, 9 Oct 2017 04:13:33 +0000 (21:13 -0700)
committerPasi Kallinen <paxed@alt.org>
Mon, 9 Oct 2017 17:43:36 +0000 (20:43 +0300)
This eliminates all flickering when status is updated.

win/win32/mhstatus.c

index fe1badb48ceefed8ebf6308e0e49b107d81659c3..a362c60bd5e7f048fa9a67279cf8141edf5c4d27 100644 (file)
 
 extern COLORREF nhcolor_to_RGB(int c); /* from mhmap */
 
+typedef struct back_buffer {
+    HWND hWnd;
+    HDC hdc;
+    HBITMAP bm;
+    HBITMAP orig_bm;
+    int width;
+    int height;
+} back_buffer_t;
+
+void back_buffer_free(back_buffer_t * back_buffer)
+{
+    if (back_buffer->bm != NULL) {
+        SelectObject(back_buffer->hdc, back_buffer->orig_bm);
+        DeleteObject(back_buffer->bm);
+        back_buffer->bm = NULL;
+    }
+}
+
+void back_buffer_allocate(back_buffer_t * back_buffer, int width, int height)
+{
+    HDC hdc = GetDC(back_buffer->hWnd);
+    back_buffer->bm = CreateCompatibleBitmap(hdc, width, height);
+    back_buffer->orig_bm =  SelectObject(back_buffer->hdc, back_buffer->bm);
+    back_buffer->width = width;
+    back_buffer->height = height;
+    ReleaseDC(back_buffer->hWnd, hdc);
+}
+
+void back_buffer_size(back_buffer_t * back_buffer, int width, int height)
+{
+    if (back_buffer->bm == NULL || back_buffer->width != width
+                                || back_buffer->height != height) {
+        back_buffer_free(back_buffer);
+        back_buffer_allocate(back_buffer, width, height);
+    }
+}
+
+void back_buffer_init(back_buffer_t * back_buffer, HWND hWnd, int width, int height)
+{
+    back_buffer->hWnd = hWnd;
+    back_buffer->hdc = CreateCompatibleDC(NULL);
+    back_buffer->bm = NULL;
+
+    back_buffer_size(back_buffer, width, height);
+}
+
 typedef struct mswin_nethack_status_window {
     int index;
     char window_text[NHSW_LINES][MAXWINDOWTEXT + 1];
@@ -20,6 +66,7 @@ typedef struct mswin_nethack_status_window {
     boolean *activefields;
     int *percents;
     int *colors;
+    back_buffer_t back_buffer;
 } NHStatusWindow, *PNHStatusWindow;
 
 static int fieldorder1[] = { BL_TITLE, BL_STR, BL_DX,    BL_CO,    BL_IN,
@@ -45,6 +92,7 @@ mswin_init_status_window()
     HWND ret;
     NHStatusWindow *data;
     RECT rt;
+    int width, height;
 
     if (!run_once) {
         register_status_window_class();
@@ -59,12 +107,14 @@ mswin_init_status_window()
     }
 
     /* create status window object */
+    width = rt.right - rt.left;
+    height = rt.bottom - rt.top;
     ret = CreateWindow(szStatusWindowClass, NULL,
                        WS_CHILD | WS_CLIPSIBLINGS | WS_SIZEBOX,
-                       rt.left,            /* horizontal position of window */
-                       rt.top,             /* vertical position of window */
-                       rt.right - rt.left, /* window width */
-                       rt.bottom - rt.top, /* window height */
+                       rt.left, /* horizontal position of window */
+                       rt.top,  /* vertical position of window */
+                       width,   /* window width */
+                       height,  /* window height */
                        GetNHApp()->hMainWnd, NULL, GetNHApp()->hApp, NULL);
     if (!ret)
         panic("Cannot create status window");
@@ -80,8 +130,20 @@ mswin_init_status_window()
     ZeroMemory(data, sizeof(NHStatusWindow));
     SetWindowLongPtr(ret, GWLP_USERDATA, (LONG_PTR) data);
 
+    back_buffer_init(&data->back_buffer, ret, width, height);
+
     mswin_apply_window_style(ret);
 
+    if (status_bg_brush == NULL) {
+        status_bg_color = (COLORREF)GetSysColor(DEFAULT_COLOR_BG_STATUS);
+        status_bg_brush = CreateSolidBrush(status_bg_color);
+    }
+
+    if (status_fg_brush == NULL) {
+        status_fg_color = (COLORREF)GetSysColor(DEFAULT_COLOR_FG_STATUS);
+        status_fg_brush = CreateSolidBrush(status_fg_color);
+    }
+
     return ret;
 }
 
@@ -98,9 +160,7 @@ register_status_window_class()
     wcex.hInstance = GetNHApp()->hApp;
     wcex.hIcon = NULL;
     wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
-    wcex.hbrBackground = status_bg_brush
-                             ? status_bg_brush
-                             : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_STATUS);
+    wcex.hbrBackground = NULL;
     wcex.lpszMenuName = NULL;
     wcex.lpszClassName = szStatusWindowClass;
 
@@ -216,30 +276,35 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam)
     int *f;
     int **fop;
     SIZE sz;
-    HGDIOBJ oldFont, normalFont, boldFont;
+    HGDIOBJ normalFont, boldFont;
     TCHAR wbuf[BUFSZ];
-    COLORREF OldBg, OldFg, Bg, Fg;
     RECT rt;
     PAINTSTRUCT ps;
     HDC hdc;
     PNHStatusWindow data;
+    int width, height;
+    RECT clear_rect;
+    HDC front_buffer_hdc;
 
     data = (PNHStatusWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
 
-    hdc = BeginPaint(hWnd, &ps);
+    front_buffer_hdc = BeginPaint(hWnd, &ps);
     GetClientRect(hWnd, &rt);
 
+    width = rt.right - rt.left;
+    height = rt.bottom - rt.top;
+
+    back_buffer_size(&data->back_buffer, width, height);
+
+    hdc = data->back_buffer.hdc;
+
     normalFont = mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE);
     boldFont = mswin_get_font(NHW_STATUS, ATR_BOLD, hdc, FALSE);
-    oldFont = SelectObject(hdc, normalFont);
 
-    Bg = status_bg_brush ? status_bg_color
-                         : (COLORREF) GetSysColor(DEFAULT_COLOR_BG_STATUS);
-    OldBg = SetBkColor(hdc, Bg);
+    SelectObject(hdc, normalFont);
 
-    Fg = status_fg_brush ? status_fg_color
-                         : (COLORREF) GetSysColor(DEFAULT_COLOR_FG_STATUS);
-    OldFg = SetTextColor(hdc, Fg);
+    SetBkColor(hdc, status_bg_color);
+    SetTextColor(hdc, status_fg_color);
 
     if (iflags.wc2_hitpointbar && BL_HP < data->n_fields
         && data->activefields[BL_HP]) {
@@ -247,6 +312,13 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam)
         hpbar_color = data->colors[BL_HP] & 0x00ff;
     }
 
+    clear_rect.left = 0;
+    clear_rect.top = 0;
+    clear_rect.right = width;
+    clear_rect.bottom = height;
+
+    FillRect(hdc, &clear_rect, status_bg_brush);
+
     for (fop = fieldorders; *fop; fop++) {
         LONG left = rt.left;
         LONG cy = 0;
@@ -275,9 +347,10 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam)
             else if (atr & HL_DIM)
                 fntatr = ATR_DIM;
             fnt = mswin_get_font(NHW_STATUS, fntatr, hdc, FALSE);
-            nFg = (clr == NO_COLOR ? Fg :
-                   ((clr >= 0 && clr < CLR_MAX) ? nhcolor_to_RGB(clr) : Fg));
-            nBg = Bg;
+            nFg = (clr == NO_COLOR ? status_fg_color
+                   : ((clr >= 0 && clr < CLR_MAX) ? nhcolor_to_RGB(clr)
+                      : status_fg_color));
+            nBg = status_bg_color;
 
             GetTextExtentPoint32(hdc, wbuf, vlen, &sz);
             if (*f == BL_TITLE && iflags.wc2_hitpointbar) {
@@ -287,7 +360,7 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam)
                 /* first draw title normally */
                 SelectObject(hdc, fnt);
                 SetBkMode(hdc, OPAQUE);
-                SetBkColor(hdc, Bg);
+                SetBkColor(hdc, status_bg_color);
                 SetTextColor(hdc, nhcolor_to_RGB(hpbar_color));
                 DrawText(hdc, wbuf, vlen, &rt, DT_LEFT);
 
@@ -323,13 +396,13 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam)
             rt.left += sz.cx;
             cy = max(cy, sz.cy);
         }
+
         rt.left = left;
         rt.top += cy;
     }
 
-    SelectObject(hdc, oldFont);
-    SetTextColor(hdc, OldFg);
-    SetBkColor(hdc, OldBg);
+    BitBlt(front_buffer_hdc, 0, 0, width, height, hdc, 0, 0, SRCCOPY);
+
     EndPaint(hWnd, &ps);
 
     return 0;