Win32GUI: Use a back buffer for all status rendering
This eliminates all flickering when status is updated.
This commit is contained in:
committed by
Pasi Kallinen
parent
7c24b420a9
commit
1ec7bed529
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user