From: Bart House Date: Mon, 9 Oct 2017 04:13:33 +0000 (-0700) Subject: Win32GUI: Use a back buffer for all status rendering X-Git-Tag: NetHack-3.6.1_RC01~296 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1ec7bed5299d0896e5306ff72b8bd5d2f2063302;p=nethack Win32GUI: Use a back buffer for all status rendering This eliminates all flickering when status is updated. --- diff --git a/win/win32/mhstatus.c b/win/win32/mhstatus.c index fe1badb48..a362c60bd 100644 --- a/win/win32/mhstatus.c +++ b/win/win32/mhstatus.c @@ -12,6 +12,52 @@ 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;