diff --git a/include/decl.h b/include/decl.h index 53902a07f..992e86ad5 100644 --- a/include/decl.h +++ b/include/decl.h @@ -424,7 +424,11 @@ E struct plinemsg_type *plinemsg_types; E const char *ARGV0; #endif -enum earlyarg {ARG_DEBUG, ARG_VERSION}; +enum earlyarg {ARG_DEBUG, ARG_VERSION +#ifdef WIN32 + ,ARG_WINDOWS +#endif +}; struct early_opt { enum earlyarg e; diff --git a/src/allmain.c b/src/allmain.c index 9c76b2c00..9aa2f93c4 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -755,8 +755,15 @@ const char *msg; static struct early_opt earlyopts[] = { {ARG_DEBUG, "debug", 5, TRUE}, {ARG_VERSION, "version", 4, TRUE}, +#ifdef WIN32 + {ARG_WINDOWS, "windows", 4, TRUE}, +#endif }; +#ifdef WIN32 +extern int FDECL(windows_early_options, (const char *)); +#endif + /* * Returns: * 0 = no match @@ -826,6 +833,14 @@ enum earlyarg e_arg; early_version_info(insert_into_pastebuf); return 2; } +#ifdef WIN32 + case ARG_WINDOWS: { + if (extended_opt) { + extended_opt++; + return windows_early_options(extended_opt); + } + } +#endif default: break; } diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index cc60b3b3c..393dd0d8d 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -345,6 +345,13 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ argv++; } +#ifdef WIN32 + if (argcheck(argc, argv, ARG_WINDOWS) == 1) { + argc--; + argv++; + } +#endif + if (argc > 1 && !strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') { /* avoid matching "-dec" for DECgraphics; since the man page * says -d directory, hope nobody's using -desomething_else diff --git a/sys/winnt/winnt.c b/sys/winnt/winnt.c index e3aaf640e..5b0fd8bc8 100644 --- a/sys/winnt/winnt.c +++ b/sys/winnt/winnt.c @@ -37,9 +37,13 @@ * */ +/* runtime cursor display control switch */ +boolean win32_cursorblink; + /* globals required within here */ HANDLE ffhandle = (HANDLE) 0; WIN32_FIND_DATA ffd; + typedef HWND(WINAPI *GETCONSOLEWINDOW)(); static HWND GetConsoleHandle(void); static HWND GetConsoleHwnd(void); @@ -581,6 +585,25 @@ BOOL winos_font_support_cp437(HFONT hFont) return allFound; } +int +windows_early_options(window_opt) +const char *window_opt; +{ + /* + * If you return 2, the game will exit before it begins. + * Return 1, to say the option parsed okay. + * Return 0, to say the option was bad. + */ + + if (match_optname(window_opt, "cursorblink", 5, FALSE)) { + win32_cursorblink = TRUE; + return 1; + } else { + raw_printf( + "-%swindows:cursorblink is the only supported option.\n"); + } + return 0; +} #endif /* WIN32 */ -/*winnt.c*/ \ No newline at end of file +/*winnt.c*/ diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index 3001afdd8..233e02ed1 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -18,6 +18,11 @@ #define NHMAP_FONT_NAME TEXT("Terminal") #define MAXWINDOWTEXT 255 +#define CURSOR_BLINK_INTERVAL 1000 // milliseconds +#define CURSOR_HEIGHT 2 // pixels + +#define CUSOR_BLINK FALSE // Set to true for a cursor that blinks + extern short glyph2tile[]; #define TILEBMP_X(ntile) \ @@ -27,8 +32,11 @@ extern short glyph2tile[]; /* map window data */ typedef struct mswin_nethack_map_window { - int map[COLNO][ROWNO]; /* glyph map */ - int bkmap[COLNO][ROWNO]; /* backround glyph map */ + HWND hWnd; /* window */ + + int map[COLNO][ROWNO]; /* glyph map */ + int bkmap[COLNO][ROWNO]; /* backround glyph map */ + boolean mapDirty[COLNO][ROWNO]; /* dirty flag for map */ int mapMode; /* current map mode */ boolean bAsciiMode; /* switch ASCII/tiled mode */ @@ -49,6 +57,16 @@ typedef struct mswin_nethack_map_window { double backScale; /* scaling from source to back buffer */ double frontScale; /* scaling from back to front */ double monitorScale; /* from 96dpi to monitor dpi*/ + + boolean cursorOn; + int yCursor; /* height of cursor inback buffer in pixels */ + + int backWidth; /* back buffer width */ + int backHeight; /* back buffer height */ + HBITMAP hBackBuffer; /* back buffe bitmap */ + HDC backBufferDC; /* back buffer drawing context */ + + HDC tileDC; /* tile drawing context */ } NHMapWindow, *PNHMapWindow; @@ -61,15 +79,22 @@ static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onPaint(HWND hWnd); static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam); static void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut); +static void paint(PNHMapWindow data, int i, int j); +static void dirtyAll(PNHMapWindow data); +static void dirty(PNHMapWindow data, int i, int j); +static void setGlyph(PNHMapWindow data, int i, int j, int fg, int bg); +static void clearAll(PNHMapWindow data); + #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) static void nhglyph2charcolor(short glyph, uchar *ch, int *color); #endif +extern boolean win32_cursorblink; /* from sys\winnt\winnt.c */ HWND mswin_init_map_window() { static int run_once = 0; - HWND ret; + HWND hWnd; RECT rt; if (!run_once) { @@ -85,7 +110,7 @@ mswin_init_map_window() } /* create map window object */ - ret = CreateWindow( + hWnd = CreateWindow( szNHMapWindowClass, /* registered class name */ NULL, /* window name */ WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_CLIPSIBLINGS @@ -98,16 +123,21 @@ mswin_init_map_window() NULL, /* menu handle or child identifier */ GetNHApp()->hApp, /* handle to application instance */ NULL); /* window-creation data */ - if (!ret) { + if (!hWnd) { panic("Cannot create map window"); } /* Set window caption */ - SetWindowText(ret, "Map"); + SetWindowText(hWnd, "Map"); - mswin_apply_window_style(ret); + mswin_apply_window_style(hWnd); - return ret; +#if CURSOR_BLINK + /* set cursor blink timer */ + SetTimer(hWnd, 0, CURSOR_BLINK_INTERVAL, NULL); +#endif + + return hWnd; } void @@ -131,7 +161,7 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) // calculate back buffer scale data->monitorScale = win10_monitor_scale(hWnd); - if (data->bAsciiMode) { + if (data->bAsciiMode || Is_rogue_level(&u.uz)) { data->backScale = data->monitorScale; } else { data->backScale = 1.0; @@ -141,12 +171,7 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) data->xBackTile = (int) (data->tileWidth * data->backScale); data->yBackTile = (int) (data->tileHeight * data->backScale); - if (data->bAsciiMode) { - - /* create font */ - if (data->hMapFont) - DeleteObject(data->hMapFont); - + if (data->bAsciiMode || Is_rogue_level(&u.uz)) { LOGFONT lgfnt; ZeroMemory(&lgfnt, sizeof(lgfnt)); @@ -171,17 +196,14 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) } TEXTMETRIC textMetrics; + HFONT font; while (1) { - data->hMapFont = CreateFontIndirect(&lgfnt); + font = CreateFontIndirect(&lgfnt); - HDC hdc = GetDC(NULL); - HFONT savedFont = SelectObject(hdc, data->hMapFont); + SelectObject(data->backBufferDC, font); - GetTextMetrics(hdc, &textMetrics); - - SelectObject(hdc, savedFont); - ReleaseDC(NULL, hdc); + GetTextMetrics(data->backBufferDC, &textMetrics); if (textMetrics.tmHeight > data->yBackTile) { lgfnt.lfHeight++; @@ -196,6 +218,11 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) break; } + if (data->hMapFont) + DeleteObject(data->hMapFont); + + data->hMapFont = font; + data->bUnicodeFont = winos_font_support_cp437(data->hMapFont); // set tile size to match font metrics @@ -205,24 +232,46 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) } + int backWidth = COLNO * data->xBackTile; + int backHeight = ROWNO * data->yBackTile; + + /* create back buffer */ + + if (data->backWidth != backWidth || data->backHeight != backHeight) { + + HDC frontBufferDC = GetDC(hWnd); + HBITMAP hBackBuffer = CreateCompatibleBitmap(frontBufferDC, backWidth, backHeight); + ReleaseDC(hWnd, frontBufferDC); + + if (data->hBackBuffer != NULL) { + SelectBitmap(data->backBufferDC, hBackBuffer); + DeleteObject(data->hBackBuffer); + } + + data->backWidth = backWidth; + data->backHeight = backHeight; + + SelectBitmap(data->backBufferDC, hBackBuffer); + data->hBackBuffer = hBackBuffer; + } + /* calculate front buffer tile size */ if (wnd_size.cx > 0 && wnd_size.cy > 0 && data->bFitToScreenMode) { double windowAspectRatio = (double) wnd_size.cx / (double) wnd_size.cy; - UINT backWidth = COLNO * data->xBackTile; - UINT backHeight = ROWNO * data->yBackTile; - double backAspectRatio = (double) backWidth / (double) backHeight; + double backAspectRatio = + (double) data->backWidth / (double) data->backHeight; if (windowAspectRatio > backAspectRatio) - data->frontScale = (double) wnd_size.cy / (double) backHeight; + data->frontScale = (double) wnd_size.cy / (double) data->backHeight; else - data->frontScale = (double) wnd_size.cx / (double) backWidth; + data->frontScale = (double) wnd_size.cx / (double) data->backWidth; } else { - if (data->bAsciiMode) { + if (data->bAsciiMode || Is_rogue_level(&u.uz)) { data->frontScale = 1.0; } else { data->frontScale = data->monitorScale; @@ -233,6 +282,13 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) data->xFrontTile = (int) ((double) data->xBackTile * data->frontScale); data->yFrontTile = (int) ((double) data->yBackTile * data->frontScale); + /* calcuate ASCII cursor height */ +#if CURSOR_BLINK + data->yCursor = (int) ((double) CURSOR_HEIGHT * data->backScale); +#else + data->yCursor = data->yBackTile; +#endif + /* set map origin point */ data->map_orig.x = max(0, client_rt.left + (wnd_size.cx - data->xFrontTile * COLNO) / 2); @@ -280,8 +336,10 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) mswin_cliparound(data->xCur, data->yCur); - if (redraw) + if (redraw) { + dirtyAll(data); InvalidateRect(hWnd, NULL, TRUE); + } } /* set map mode */ @@ -509,10 +567,20 @@ MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_DESTROY: if (data->hMapFont) DeleteObject(data->hMapFont); + if (data->hBackBuffer) + DeleteBitmap(data->hBackBuffer); + if (data->backBufferDC) + DeleteDC(data->backBufferDC); free(data); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); break; + case WM_TIMER: + data->cursorOn = !data->cursorOn; + dirty(data, data->xCur, data->yCur); + break; + + default: return DefWindowProc(hWnd, message, wParam, lParam); } @@ -524,25 +592,13 @@ void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; - RECT rt; data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (wParam) { case MSNH_MSG_PRINT_GLYPH: { PMSNHMsgPrintGlyph msg_data = (PMSNHMsgPrintGlyph) lParam; - if ((data->map[msg_data->x][msg_data->y] != msg_data->glyph) - || (data->bkmap[msg_data->x][msg_data->y] != msg_data->bkglyph)) { - data->map[msg_data->x][msg_data->y] = msg_data->glyph; - data->bkmap[msg_data->x][msg_data->y] = msg_data->bkglyph; - - /* invalidate the update area. Erase backround if there - is nothing to paint or we are in text mode */ - nhcoord2display(data, msg_data->x, msg_data->y, &rt); - InvalidateRect(hWnd, &rt, - (((msg_data->glyph == NO_GLYPH) - && (msg_data->bkglyph == NO_GLYPH)) - || data->bAsciiMode || Is_rogue_level(&u.uz))); - } + setGlyph(data, msg_data->x, msg_data->y, + msg_data->glyph, msg_data->bkglyph); } break; case MSNH_MSG_CLIPAROUND: { @@ -589,44 +645,22 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) } } break; - case MSNH_MSG_CLEAR_WINDOW: { - int i, j; - for (i = 0; i < COLNO; i++) - for (j = 0; j < ROWNO; j++) { - data->map[i][j] = NO_GLYPH; - data->bkmap[i][j] = NO_GLYPH; - } - InvalidateRect(hWnd, NULL, TRUE); - } break; + case MSNH_MSG_CLEAR_WINDOW: + clearAll(data); + break; case MSNH_MSG_CURSOR: { PMSNHMsgCursor msg_data = (PMSNHMsgCursor) lParam; - HDC hdc; - RECT rt; - /* move focus rectangle at the cursor postion */ - hdc = GetDC(hWnd); + if (data->xCur != msg_data->x || data->yCur != msg_data->y) { - nhcoord2display(data, data->xCur, data->yCur, &rt); - if (data->bAsciiMode) { - PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, - rt.bottom - rt.top, DSTINVERT); - } else { - DrawFocusRect(hdc, &rt); + dirty(data, data->xCur, data->yCur); + dirty(data, msg_data->x, msg_data->y); + + data->xCur = msg_data->x; + data->yCur = msg_data->y; } - - data->xCur = msg_data->x; - data->yCur = msg_data->y; - - nhcoord2display(data, data->xCur, data->yCur, &rt); - if (data->bAsciiMode) { - PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, - rt.bottom - rt.top, DSTINVERT); - } else { - DrawFocusRect(hdc, &rt); - } - - ReleaseDC(hWnd, hdc); + } break; case MSNH_MSG_GETTEXT: { @@ -666,7 +700,6 @@ void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; - int i, j; UNREFERENCED_PARAMETER(wParam); UNREFERENCED_PARAMETER(lParam); @@ -677,269 +710,287 @@ onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) panic("out of memory"); ZeroMemory(data, sizeof(NHMapWindow)); - for (i = 0; i < COLNO; i++) - for (j = 0; j < ROWNO; j++) { - data->map[i][j] = NO_GLYPH; - data->bkmap[i][j] = NO_GLYPH; - } + + data->hWnd = hWnd; data->bAsciiMode = FALSE; + data->cursorOn = TRUE; data->xFrontTile = GetNHApp()->mapTile_X; data->yFrontTile = GetNHApp()->mapTile_Y; data->tileWidth = GetNHApp()->mapTile_X; data->tileHeight = GetNHApp()->mapTile_Y; + HDC hDC = GetDC(hWnd); + data->backBufferDC = CreateCompatibleDC(hDC); + data->tileDC = CreateCompatibleDC(hDC); + ReleaseDC(hWnd, hDC); + + SelectObject(data->tileDC, GetNHApp()->bmpMapTiles); + SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); + + clearAll(data); + } +static void +paintTile(PNHMapWindow data, int i, int j, RECT * rect) +{ + short ntile; + int t_x, t_y; + int glyph, bkglyph; + int layer; +#ifdef USE_PILEMARK + int color; + unsigned special; + int mgch; +#endif + layer = 0; + glyph = data->map[i][j]; + bkglyph = data->bkmap[i][j]; + + if (bkglyph != NO_GLYPH) { + ntile = glyph2tile[bkglyph]; + t_x = TILEBMP_X(ntile); + t_y = TILEBMP_Y(ntile); + + StretchBlt(data->backBufferDC, rect->left, rect->top, + data->xBackTile, data->yBackTile, data->tileDC, + t_x, t_y, GetNHApp()->mapTile_X, + GetNHApp()->mapTile_Y, SRCCOPY); + layer++; + } + + if ((glyph != NO_GLYPH) && (glyph != bkglyph)) { + ntile = glyph2tile[glyph]; + t_x = TILEBMP_X(ntile); + t_y = TILEBMP_Y(ntile); + + if (layer > 0) { + (*GetNHApp()->lpfnTransparentBlt)( + data->backBufferDC, rect->left, rect->top, + data->xBackTile, data->yBackTile, data->tileDC, t_x, + t_y, GetNHApp()->mapTile_X, + GetNHApp()->mapTile_Y, TILE_BK_COLOR); + } else { + StretchBlt(data->backBufferDC, rect->left, rect->top, + data->xBackTile, data->yBackTile, data->tileDC, + t_x, t_y, GetNHApp()->mapTile_X, + GetNHApp()->mapTile_Y, SRCCOPY); + } + + layer++; + } + +#ifdef USE_PILEMARK + /* rely on NetHack core helper routine */ + (void) mapglyph(data->map[i][j], &mgch, &color, &special, + i, j); + if ((glyph != NO_GLYPH) && (special & MG_PET) +#else + if ((glyph != NO_GLYPH) && glyph_is_pet(glyph) +#endif + && iflags.wc_hilite_pet) { + /* apply pet mark transparently over + pet image */ + HDC hdcPetMark; + HBITMAP bmPetMarkOld; + + /* this is DC for petmark bitmap */ + hdcPetMark = CreateCompatibleDC(data->backBufferDC); + bmPetMarkOld = + SelectObject(hdcPetMark, GetNHApp()->bmpPetMark); + + (*GetNHApp()->lpfnTransparentBlt)( + data->backBufferDC, rect->left, rect->top, + data->xBackTile, data->yBackTile, hdcPetMark, 0, 0, + TILE_X, TILE_Y, TILE_BK_COLOR); + SelectObject(hdcPetMark, bmPetMarkOld); + DeleteDC(hdcPetMark); + } +#ifdef USE_PILEMARK + if ((glyph != NO_GLYPH) && (special & MG_OBJPILE) + && iflags.hilite_pile) { + /* apply pilemark transparently over other image */ + HDC hdcPileMark; + HBITMAP bmPileMarkOld; + + /* this is DC for pilemark bitmap */ + hdcPileMark = CreateCompatibleDC(data->backBufferDC); + bmPileMarkOld = SelectObject(hdcPileMark, + GetNHApp()->bmpPileMark); + + (*GetNHApp()->lpfnTransparentBlt)( + data->backBufferDC, rect->left, rect->top, + data->xBackTile, data->yBackTile, hdcPileMark, 0, 0, + TILE_X, TILE_Y, TILE_BK_COLOR); + SelectObject(hdcPileMark, bmPileMarkOld); + DeleteDC(hdcPileMark); + } +#endif + + if (i == data->xCur && j == data->yCur && data->cursorOn) + DrawFocusRect(data->backBufferDC, rect); +} + + +static void +paintGlyph(PNHMapWindow data, int i, int j, RECT * rect) +{ + if (data->map[i][j] >= 0) { + + char ch; + WCHAR wch; + int color; + unsigned special; + int mgch; + HBRUSH back_brush; + COLORREF OldFg; + + SetBkMode(data->backBufferDC, TRANSPARENT); + + HBRUSH blackBrush = CreateSolidBrush(RGB(0, 0, 0)); + FillRect(data->backBufferDC, rect, blackBrush); + DeleteObject(blackBrush); + + #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) + nhglyph2charcolor(data->map[i][j], &ch, &color); + OldFg = SetTextColor(hDC, nhcolor_to_RGB(color)); + #else + /* rely on NetHack core helper routine */ + (void) mapglyph(data->map[i][j], &mgch, &color, + &special, i, j); + ch = (char) mgch; + if (((special & MG_PET) && iflags.hilite_pet) + || ((special & (MG_DETECT | MG_BW_LAVA)) + && iflags.use_inverse)) { + back_brush = + CreateSolidBrush(nhcolor_to_RGB(CLR_GRAY)); + FillRect(data->backBufferDC, rect, back_brush); + DeleteObject(back_brush); + switch (color) { + case CLR_GRAY: + case CLR_WHITE: + OldFg = SetTextColor( + data->backBufferDC, nhcolor_to_RGB(CLR_BLACK)); + break; + default: + OldFg = + SetTextColor(data->backBufferDC, nhcolor_to_RGB(color)); + } + } else { + OldFg = SetTextColor(data->backBufferDC, nhcolor_to_RGB(color)); + } + #endif + if (data->bUnicodeFont) { + wch = winos_ascii_to_wide(ch); + DrawTextW(data->backBufferDC, &wch, 1, rect, + DT_CENTER | DT_VCENTER | DT_NOPREFIX + | DT_SINGLELINE); + } else { + DrawTextA(data->backBufferDC, &ch, 1, rect, + DT_CENTER | DT_VCENTER | DT_NOPREFIX + | DT_SINGLELINE); + } + + SetTextColor(data->backBufferDC, OldFg); + } + + if (i == data->xCur && j == data->yCur && data->cursorOn) + PatBlt(data->backBufferDC, + rect->left, rect->bottom - data->yCursor, + rect->right - rect->left, + data->yCursor, + DSTINVERT); +} + +static void setGlyph(PNHMapWindow data, int i, int j, int fg, int bg) +{ + if ((data->map[i][j] != fg) || (data->bkmap[i][j] != bg)) { + data->map[i][j] = fg; + data->bkmap[i][j] = bg; + data->mapDirty[i][j] = TRUE; + + RECT rect; + nhcoord2display(data, i, j, &rect); + InvalidateRect(data->hWnd, &rect, FALSE); + } +} + +static void clearAll(PNHMapWindow data) +{ + for (int x = 0; x < COLNO; x++) + for (int y = 0; y < ROWNO; y++) { + data->map[x][y] = NO_GLYPH; + data->bkmap[x][y] = NO_GLYPH; + data->mapDirty[x][y] = TRUE; + } + InvalidateRect(data->hWnd, NULL, FALSE); +} + +static void dirtyAll(PNHMapWindow data) +{ + for (int i = 0; i < COLNO; i++) + for (int j = 0; j < ROWNO; j++) + data->mapDirty[i][j] = TRUE; + + InvalidateRect(data->hWnd, NULL, FALSE); +} + +static void dirty(PNHMapWindow data, int x, int y) +{ + data->mapDirty[x][y] = TRUE; + + RECT rt; + nhcoord2display(data, data->xCur, data->yCur, &rt); + + InvalidateRect(data->hWnd, &rt, FALSE); +} + +static void +paint(PNHMapWindow data, int i, int j) +{ + RECT rect; + + rect.left = i * data->xBackTile; + rect.top = j * data->yBackTile; + rect.right = rect.left + data->xBackTile; + rect.bottom = rect.top + data->yBackTile; + + if (data->bAsciiMode || Is_rogue_level(&u.uz)) { + paintGlyph(data, i, j, &rect); + } else { + paintTile(data, i, j, &rect); + } + + data->mapDirty[i][j] = FALSE; +} + + /* on WM_PAINT */ void onPaint(HWND hWnd) { - PNHMapWindow data; + PNHMapWindow data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); + + /* update back buffer */ + for (int i = 0; i < COLNO; i++) + for (int j = 0; j < ROWNO; j++) + if (data->mapDirty[i][j]) + paint(data, i, j); + PAINTSTRUCT ps; - HDC tileDC; - HGDIOBJ saveBmp; - RECT paint_rt; - int i, j; - - /* get window data */ - data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); - HDC hFrontBufferDC = BeginPaint(hWnd, &ps); - RECT clientRect; - GetClientRect(hWnd, &clientRect); - + /* stretch back buffer onto front buffer window */ int frontWidth = COLNO * data->xFrontTile; int frontHeight = ROWNO * data->yFrontTile; - int backWidth = COLNO * data->xBackTile; - int backHeight = ROWNO * data->yBackTile; - - HBITMAP hBackBufferBitmap = CreateCompatibleBitmap(hFrontBufferDC, backWidth, backHeight); - HDC hBackBufferDC = CreateCompatibleDC(hFrontBufferDC); - HBITMAP hOldBackBuffer = SelectBitmap(hBackBufferDC, hBackBufferBitmap); - - HDC hRenderDC = hBackBufferDC; - - /* calculate paint rectangle */ - if (!IsRectEmpty(&ps.rcPaint)) { - /* calculate paint rectangle */ - paint_rt.left = 0; - paint_rt.right = COLNO; - paint_rt.top = 0; - paint_rt.bottom = ROWNO; - - if (data->bAsciiMode || Is_rogue_level(&u.uz)) { - /* You enter a VERY primitive world! */ - HGDIOBJ oldFont; - - oldFont = SelectObject(hRenderDC, data->hMapFont); - SetBkMode(hRenderDC, TRANSPARENT); - - /* draw the map */ - for (i = paint_rt.left; i < paint_rt.right; i++) - for (j = paint_rt.top; j < paint_rt.bottom; j++) - if (data->map[i][j] >= 0) { - char ch; - WCHAR wch; - RECT glyph_rect; - int color; - unsigned special; - int mgch; - HBRUSH back_brush; - COLORREF OldFg; - - glyph_rect.left = i * data->xBackTile; - glyph_rect.top = j * data->yBackTile; - glyph_rect.right = glyph_rect.left + data->xBackTile; - glyph_rect.bottom = glyph_rect.top + data->yBackTile; - -#if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) - nhglyph2charcolor(data->map[i][j], &ch, &color); - OldFg = SetTextColor(hDC, nhcolor_to_RGB(color)); -#else - /* rely on NetHack core helper routine */ - (void) mapglyph(data->map[i][j], &mgch, &color, - &special, i, j); - ch = (char) mgch; - if (((special & MG_PET) && iflags.hilite_pet) - || ((special & (MG_DETECT | MG_BW_LAVA)) - && iflags.use_inverse)) { - back_brush = - CreateSolidBrush(nhcolor_to_RGB(CLR_GRAY)); - FillRect(hRenderDC, &glyph_rect, back_brush); - DeleteObject(back_brush); - switch (color) { - case CLR_GRAY: - case CLR_WHITE: - OldFg = SetTextColor( - hRenderDC, nhcolor_to_RGB(CLR_BLACK)); - break; - default: - OldFg = - SetTextColor(hRenderDC, nhcolor_to_RGB(color)); - } - } else { - OldFg = SetTextColor(hRenderDC, nhcolor_to_RGB(color)); - } -#endif - if (data->bUnicodeFont) { - wch = winos_ascii_to_wide(ch); - DrawTextW(hRenderDC, &wch, 1, &glyph_rect, - DT_CENTER | DT_VCENTER | DT_NOPREFIX - | DT_SINGLELINE); - } else { - DrawTextA(hRenderDC, &ch, 1, &glyph_rect, - DT_CENTER | DT_VCENTER | DT_NOPREFIX - | DT_SINGLELINE); - } - - SetTextColor(hRenderDC, OldFg); - } - SelectObject(hRenderDC, oldFont); - } else { - short ntile; - int t_x, t_y; - int glyph, bkglyph; - RECT glyph_rect; - int layer; -#ifdef USE_PILEMARK - int color; - unsigned special; - int mgch; -#endif - /* prepare tiles DC for mapping */ - tileDC = CreateCompatibleDC(hRenderDC); - saveBmp = SelectObject(tileDC, GetNHApp()->bmpMapTiles); - - /* draw the map */ - for (i = paint_rt.left; i < paint_rt.right; i++) - for (j = paint_rt.top; j < paint_rt.bottom; j++) { - layer = 0; - glyph = data->map[i][j]; - bkglyph = data->bkmap[i][j]; - - if (bkglyph != NO_GLYPH) { - ntile = glyph2tile[bkglyph]; - t_x = TILEBMP_X(ntile); - t_y = TILEBMP_Y(ntile); - - glyph_rect.left = i * data->xBackTile; - glyph_rect.top = j * data->yBackTile; - glyph_rect.right = glyph_rect.left + data->xBackTile; - glyph_rect.bottom = glyph_rect.top + data->yBackTile; - - StretchBlt(hRenderDC, glyph_rect.left, glyph_rect.top, - data->xBackTile, data->yBackTile, tileDC, - t_x, t_y, GetNHApp()->mapTile_X, - GetNHApp()->mapTile_Y, SRCCOPY); - layer++; - } - - if ((glyph != NO_GLYPH) && (glyph != bkglyph)) { - ntile = glyph2tile[glyph]; - t_x = TILEBMP_X(ntile); - t_y = TILEBMP_Y(ntile); - - glyph_rect.left = i * data->xBackTile; - glyph_rect.top = j * data->yBackTile; - glyph_rect.right = glyph_rect.left + data->xBackTile; - glyph_rect.bottom = glyph_rect.top + data->yBackTile; - - if (layer > 0) { - (*GetNHApp()->lpfnTransparentBlt)( - hRenderDC, glyph_rect.left, glyph_rect.top, - data->xBackTile, data->yBackTile, tileDC, t_x, - t_y, GetNHApp()->mapTile_X, - GetNHApp()->mapTile_Y, TILE_BK_COLOR); - } else { - StretchBlt(hRenderDC, glyph_rect.left, glyph_rect.top, - data->xBackTile, data->yBackTile, tileDC, - t_x, t_y, GetNHApp()->mapTile_X, - GetNHApp()->mapTile_Y, SRCCOPY); - } - - layer++; - } - -#ifdef USE_PILEMARK - /* rely on NetHack core helper routine */ - (void) mapglyph(data->map[i][j], &mgch, &color, &special, - i, j); - if ((glyph != NO_GLYPH) && (special & MG_PET) -#else - if ((glyph != NO_GLYPH) && glyph_is_pet(glyph) -#endif - && iflags.wc_hilite_pet) { - /* apply pet mark transparently over - pet image */ - HDC hdcPetMark; - HBITMAP bmPetMarkOld; - - /* this is DC for petmark bitmap */ - hdcPetMark = CreateCompatibleDC(hRenderDC); - bmPetMarkOld = - SelectObject(hdcPetMark, GetNHApp()->bmpPetMark); - - (*GetNHApp()->lpfnTransparentBlt)( - hRenderDC, glyph_rect.left, glyph_rect.top, - data->xBackTile, data->yBackTile, hdcPetMark, 0, 0, - TILE_X, TILE_Y, TILE_BK_COLOR); - SelectObject(hdcPetMark, bmPetMarkOld); - DeleteDC(hdcPetMark); - } -#ifdef USE_PILEMARK - if ((glyph != NO_GLYPH) && (special & MG_OBJPILE) - && iflags.hilite_pile) { - /* apply pilemark transparently over other image */ - HDC hdcPileMark; - HBITMAP bmPileMarkOld; - - /* this is DC for pilemark bitmap */ - hdcPileMark = CreateCompatibleDC(hRenderDC); - bmPileMarkOld = SelectObject(hdcPileMark, - GetNHApp()->bmpPileMark); - - (*GetNHApp()->lpfnTransparentBlt)( - hRenderDC, glyph_rect.left, glyph_rect.top, - data->xBackTile, data->yBackTile, hdcPileMark, 0, 0, - TILE_X, TILE_Y, TILE_BK_COLOR); - SelectObject(hdcPileMark, bmPileMarkOld); - DeleteDC(hdcPileMark); - } -#endif - } - - SelectObject(tileDC, saveBmp); - DeleteDC(tileDC); - } - - /* draw focus rect */ - paint_rt.left = data->xCur * data->xBackTile; - paint_rt.top = data->yCur * data->yBackTile; - paint_rt.right = paint_rt.left + data->xBackTile; - paint_rt.bottom = paint_rt.top + data->yBackTile; - - if (data->bAsciiMode) { - PatBlt(hRenderDC, paint_rt.left, paint_rt.top, - paint_rt.right - paint_rt.left, - paint_rt.bottom - paint_rt.top, DSTINVERT); - } else { - DrawFocusRect(hRenderDC, &paint_rt); - } - } - StretchBlt(hFrontBufferDC, data->map_orig.x - (data->xPos * data->xFrontTile), data->map_orig.y - (data->yPos * data->yFrontTile), frontWidth, frontHeight, - hBackBufferDC, 0, 0, backWidth, backHeight, SRCCOPY); - - SelectObject(hBackBufferDC, hOldBackBuffer); - DeleteObject(hBackBufferBitmap); - DeleteDC(hBackBufferDC); + data->backBufferDC, 0, 0, data->backWidth, data->backHeight, SRCCOPY); EndPaint(hWnd, &ps); } diff --git a/win/win32/mhmap.h b/win/win32/mhmap.h index cff8a7d5d..695749431 100644 --- a/win/win32/mhmap.h +++ b/win/win32/mhmap.h @@ -15,6 +15,7 @@ void mswin_map_stretch(HWND hWnd, LPSIZE lpsz, BOOL redraw); int mswin_map_mode(HWND hWnd, int mode); #define ROGUE_LEVEL_MAP_MODE MAP_MODE_ASCII12x16 +#define ROGUE_LEVEL_MAP_MODE_FIT_TO_SCREEN MAP_MODE_ASCII_FIT_TO_SCREEN #define DEF_CLIPAROUND_MARGIN 5 #define DEF_CLIPAROUND_AMOUNT 1 diff --git a/win/win32/mhmenu.c b/win/win32/mhmenu.c index 6573f32da..d35c5ef2e 100644 --- a/win/win32/mhmenu.c +++ b/win/win32/mhmenu.c @@ -23,6 +23,9 @@ #define DEFAULT_COLOR_BG_MENU COLOR_WINDOW #define DEFAULT_COLOR_FG_MENU COLOR_WINDOWTEXT +#define CHECK_WIDTH 16 +#define CHECK_HEIGHT 16 + typedef struct mswin_menu_item { int glyph; ANY_P identifier; @@ -62,6 +65,7 @@ typedef struct mswin_nethack_menu_window { HBITMAP bmpChecked; HBITMAP bmpCheckedCount; HBITMAP bmpNotChecked; + HDC bmpDC; BOOL is_active; } NHMenuWindow, *PNHMenuWindow; @@ -268,14 +272,14 @@ mswin_menu_window_select_menu(HWND hWnd, int how, MENU_ITEM_P **_selected, INT_PTR CALLBACK MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - PNHMenuWindow data; - HWND control; - HDC hdc; + PNHMenuWindow data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); + HWND control = GetDlgItem(hWnd, IDC_MENU_TEXT); TCHAR title[MAX_LOADSTRING]; - data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (message) { - case WM_INITDIALOG: + case WM_INITDIALOG: { + + HDC hdc = GetDC(control); data = (PNHMenuWindow) malloc(sizeof(NHMenuWindow)); ZeroMemory(data, sizeof(NHMenuWindow)); data->type = MENU_TYPE_TEXT; @@ -288,12 +292,11 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL_COUNT)); data->bmpNotChecked = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_UNSEL)); + data->bmpDC = CreateCompatibleDC(hdc); data->is_active = FALSE; SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); /* set font for the text cotrol */ - control = GetDlgItem(hWnd, IDC_MENU_TEXT); - hdc = GetDC(control); SendMessage(control, WM_SETFONT, (WPARAM) mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE), (LPARAM) 0); @@ -311,6 +314,7 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) /* set focus to text control for now */ SetFocus(control); + } return FALSE; case WM_MSNH_COMMAND: @@ -501,6 +505,7 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_DESTROY: if (data) { + DeleteDC(data->bmpDC); DeleteObject(data->bmpChecked); DeleteObject(data->bmpCheckedCount); DeleteObject(data->bmpNotChecked); @@ -1015,27 +1020,26 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) if (NHMENU_IS_SELECTABLE(*item)) { char buf[2]; if (data->how != PICK_NONE) { - HGDIOBJ saveBrush; - HBRUSH hbrCheckMark; + HBITMAP bmpCheck; + HBITMAP bmpSaved; switch (item->count) { case -1: - hbrCheckMark = CreatePatternBrush(data->bmpChecked); + bmpCheck = data->bmpChecked; break; case 0: - hbrCheckMark = CreatePatternBrush(data->bmpNotChecked); + bmpCheck = data->bmpNotChecked; break; default: - hbrCheckMark = CreatePatternBrush(data->bmpCheckedCount); + bmpCheck = data->bmpCheckedCount; break; } y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tileYScaled) / 2; - SetBrushOrgEx(lpdis->hDC, x, y, NULL); - saveBrush = SelectObject(lpdis->hDC, hbrCheckMark); - PatBlt(lpdis->hDC, x, y, tileXScaled, tileYScaled, PATCOPY); - SelectObject(lpdis->hDC, saveBrush); - DeleteObject(hbrCheckMark); + bmpSaved = SelectBitmap(data->bmpDC, bmpCheck); + StretchBlt(lpdis->hDC, x, y, tileXScaled, tileYScaled, + data->bmpDC, 0, 0, CHECK_WIDTH, CHECK_HEIGHT, SRCCOPY); + SelectObject(data->bmpDC, bmpSaved); } x += tileXScaled + spacing; diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index fea75b177..c6714bc15 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -813,8 +813,14 @@ mswin_clear_nhwindow(winid wid) && (GetNHApp()->windowlist[wid].win != NULL)) { if (GetNHApp()->windowlist[wid].type == NHW_MAP) { if (Is_rogue_level(&u.uz)) - mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), - ROGUE_LEVEL_MAP_MODE); + if (iflags.wc_map_mode == MAP_MODE_ASCII_FIT_TO_SCREEN || + iflags.wc_map_mode == MAP_MODE_TILES_FIT_TO_SCREEN) + + mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), + ROGUE_LEVEL_MAP_MODE_FIT_TO_SCREEN); + else + mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), + ROGUE_LEVEL_MAP_MODE); else mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), iflags.wc_map_mode);