OSDN Git Service

[Refactor] main-win.cpp処理の分割
[hengbandforosx/hengbandosx.git] / src / main-win.cpp
index 73e0360..294e750 100644 (file)
@@ -3,7 +3,6 @@
  * @brief Windows版固有実装(メインエントリポイント含む)
  * @date 2018/03/16
  * @author Hengband Team
- * @todo main関数を含むファイルの割に長過ぎる。main-win-utils.cなどといった形で分割したい
  * @details
  *
  * <h3>概要</h3>
@@ -82,8 +81,8 @@
 
 #ifdef WINDOWS
 
-#include "cmd-io/cmd-process-screen.h"
 #include "cmd-io/cmd-save.h"
+#include "cmd-visual/cmd-draw.h"
 #include "core/game-play.h"
 #include "core/player-processor.h"
 #include "core/scores.h"
 #include "io/record-play-movie.h"
 #include "io/signal-handlers.h"
 #include "io/write-diary.h"
+#include "main-win/graphics-win.h"
 #include "main-win/main-win-bg.h"
 #include "main-win/main-win-file-utils.h"
 #include "main-win/main-win-mci.h"
 #include "main-win/main-win-menuitem.h"
 #include "main-win/main-win-music.h"
 #include "main-win/main-win-sound.h"
+#include "main-win/main-win-utils.h"
 #include "main/angband-initializer.h"
 #include "main/sound-of-music.h"
 #include "monster-floor/monster-lite.h"
 #include "save/save.h"
-#include "system/angband-version.h"
 #include "system/angband.h"
+#include "system/player-type-definition.h"
 #include "system/system-variables.h"
 #include "term/gameterm.h"
 #include "term/screen-processor.h"
 #include <commdlg.h>
 #include <direct.h>
 
-/*
- * Include the support for loading bitmaps
- */
-#include "term/readdib.h"
-
-/*
- * Available graphic modes
- */
-#define GRAPHICS_NONE 0
-#define GRAPHICS_ORIGINAL 1
-#define GRAPHICS_ADAM_BOLT 2
-#define GRAPHICS_HENGBAND 3
-
-/*
- * Foreground color bits
- */
-#define VID_BLACK 0x00
-#define VID_BLUE 0x01
-#define VID_GREEN 0x02
-#define VID_CYAN 0x03
-#define VID_RED 0x04
-#define VID_MAGENTA 0x05
-#define VID_YELLOW 0x06
-#define VID_WHITE 0x07
-
-/*
- * Bright text
- */
-#define VID_BRIGHT 0x08
-
 /*!
  * @struct term_data
  * @brief ターム情報構造体 / Extra "term" data
@@ -232,16 +203,6 @@ bool game_in_progress = FALSE;
 bool initialized = FALSE;
 
 /*
- * screen paletted, i.e. 256 colors
- */
-bool paletted = FALSE;
-
-/*
- * 16 colors screen, don't use RGB()
- */
-bool colors16 = FALSE;
-
-/*
  * Saved instance handle
  */
 static HINSTANCE hInstance;
@@ -256,14 +217,10 @@ static HBRUSH hbrYellow;
  */
 static HICON hIcon;
 
-/*
- * A palette
- */
-static HPALETTE hPal;
-
 /* bg */
-static int use_bg = 0; //!< 背景使用フラグ、1なら使用。
+bg_mode current_bg_mode = bg_mode::BG_NONE;
 #define DEFAULT_BG_FILENAME "bg.bmp"
+char wallpaper_file[MAIN_WIN_MAX_PATH] = ""; //!< 壁紙ファイル名。
 
 /*!
  * 現在使用中のタイルID(0ならば未使用)
@@ -272,14 +229,14 @@ static int use_bg = 0; //!< 背景使用フラグ、1なら使用。
 static byte current_graphics_mode = 0;
 
 /*
- * The global bitmap
+ * The global tile
  */
-static DIBINIT infGraph;
+static tile_info infGraph;
 
 /*
- * The global bitmap mask
+ * The global tile mask
  */
-static DIBINIT infMask;
+static tile_info infMask;
 
 /*
  * Show sub-windows even when Hengband is not in focus
@@ -324,32 +281,6 @@ static bool paint_rect = FALSE;
 static TERM_LEN mousex = 0, mousey = 0;
 static TERM_LEN oldx, oldy;
 
-/*!
- * @brief The "simple" color values
- * @details
- * See "main-ibm.c" for original table information
- * The entries below are taken from the "color bits" defined above.
- * Note that many of the choices below suck, but so do crappy monitors.
- */
-static BYTE win_pal[256] = {
-    VID_BLACK, /* Dark */
-    VID_WHITE, /* White */
-    VID_CYAN, /* Slate XXX */
-    VID_RED | VID_BRIGHT, /* Orange XXX */
-    VID_RED, /* Red */
-    VID_GREEN, /* Green */
-    VID_BLUE, /* Blue */
-    VID_YELLOW, /* Umber XXX */
-    VID_BLACK | VID_BRIGHT, /* Light Dark */
-    VID_CYAN | VID_BRIGHT, /* Light Slate XXX */
-    VID_MAGENTA, /* Violet XXX */
-    VID_YELLOW | VID_BRIGHT, /* Yellow */
-    VID_MAGENTA | VID_BRIGHT, /* Light Red XXX */
-    VID_GREEN | VID_BRIGHT, /* Light Green */
-    VID_BLUE | VID_BRIGHT, /* Light Blue */
-    VID_YELLOW /* Light Umber XXX */
-};
-
 /*
  * Hack -- define which keys are "special"
  */
@@ -530,9 +461,9 @@ static void save_prefs(void)
     strcpy(buf, use_pause_music_inactive ? "1" : "0");
     WritePrivateProfileString("Angband", "MusicPauseInactive", buf, ini_file);
 
-    strcpy(buf, use_bg ? "1" : "0");
+    sprintf(buf, "%d", current_bg_mode);
     WritePrivateProfileString("Angband", "BackGround", buf, ini_file);
-    WritePrivateProfileString("Angband", "BackGroundBitmap", bg_bitmap_file[0] != '\0' ? bg_bitmap_file : DEFAULT_BG_FILENAME, ini_file);
+    WritePrivateProfileString("Angband", "BackGroundBitmap", wallpaper_file[0] != '\0' ? wallpaper_file : DEFAULT_BG_FILENAME, ini_file);
 
     int path_length = strlen(ANGBAND_DIR) - 4; /* \libの4文字分を削除 */
     char tmp[1024] = "";
@@ -633,8 +564,8 @@ static void load_prefs(void)
     arg_sound = (GetPrivateProfileInt("Angband", "Sound", 0, ini_file) != 0);
     arg_music = (GetPrivateProfileInt("Angband", "Music", 0, ini_file) != 0);
     use_pause_music_inactive = (GetPrivateProfileInt("Angband", "MusicPauseInactive", 0, ini_file) != 0);
-    use_bg = GetPrivateProfileInt("Angband", "BackGround", 0, ini_file);
-    GetPrivateProfileString("Angband", "BackGroundBitmap", DEFAULT_BG_FILENAME, bg_bitmap_file, 1023, ini_file);
+    current_bg_mode = static_cast<bg_mode>(GetPrivateProfileInt("Angband", "BackGround", 0, ini_file));
+    GetPrivateProfileString("Angband", "BackGroundBitmap", DEFAULT_BG_FILENAME, wallpaper_file, 1023, ini_file);
     GetPrivateProfileString("Angband", "SaveFile", "", savefile, 1023, ini_file);
 
     int n = strncmp(".\\", savefile, 2);
@@ -652,92 +583,6 @@ static void load_prefs(void)
     }
 }
 
-/*
- * Create the new global palette based on the bitmap palette
- * (if any), and the standard 16 entry palette derived from
- * "win_clr[]" which is used for the basic 16 Angband colors.
- *
- * This function is never called before all windows are ready.
- *
- * This function returns FALSE if the new palette could not be
- * prepared, which should normally be a fatal error.  XXX XXX
- *
- * Note that only some machines actually use a "palette".
- */
-static int new_palette(void)
-{
-    int i, nEntries;
-    int pLogPalSize;
-    int lppeSize;
-    LPLOGPALETTE pLogPal;
-    LPPALETTEENTRY lppe;
-    term_data *td;
-    if (!paletted)
-        return TRUE;
-
-    lppeSize = 0;
-    lppe = NULL;
-    nEntries = 0;
-
-    HPALETTE hBmPal = static_cast<HPALETTE>(infGraph.hPalette);
-    if (hBmPal) {
-        lppeSize = 256 * sizeof(PALETTEENTRY);
-        lppe = (LPPALETTEENTRY)std::malloc(lppeSize);
-        nEntries = GetPaletteEntries(hBmPal, 0, 255, lppe);
-        if ((nEntries == 0) || (nEntries > 220)) {
-            plog(_("画面を16ビットか24ビットカラーモードにして下さい。", "Please switch to high- or true-color mode."));
-            std::free(lppe);
-            return FALSE;
-        }
-    }
-
-    pLogPalSize = sizeof(LOGPALETTE) + (nEntries + 16) * sizeof(PALETTEENTRY);
-    pLogPal = (LPLOGPALETTE)std::malloc(pLogPalSize);
-    pLogPal->palVersion = 0x300;
-    pLogPal->palNumEntries = nEntries + 16;
-    for (i = 0; i < nEntries; i++) {
-        pLogPal->palPalEntry[i] = lppe[i];
-    }
-
-    for (i = 0; i < 16; i++) {
-        LPPALETTEENTRY p;
-        p = &(pLogPal->palPalEntry[i + nEntries]);
-        p->peRed = GetRValue(win_clr[i]);
-        p->peGreen = GetGValue(win_clr[i]);
-        p->peBlue = GetBValue(win_clr[i]);
-        p->peFlags = PC_NOCOLLAPSE;
-    }
-
-    if (lppe)
-        std::free(lppe);
-
-    HPALETTE hNewPal = CreatePalette(pLogPal);
-    if (!hNewPal)
-        quit(_("パレットを作成できません!", "Cannot create palette!"));
-
-    std::free(pLogPal);
-    td = &data[0];
-    HDC hdc = GetDC(td->w);
-    SelectPalette(hdc, hNewPal, 0);
-    i = RealizePalette(hdc);
-    ReleaseDC(td->w, hdc);
-    if (i == 0)
-        quit(_("パレットをシステムエントリにマップできません!", "Cannot realize palette!"));
-
-    for (i = 1; i < MAX_TERM_DATA; i++) {
-        td = &data[i];
-        hdc = GetDC(td->w);
-        SelectPalette(hdc, hNewPal, 0);
-        ReleaseDC(td->w, hdc);
-    }
-
-    if (hPal)
-        DeleteObject(hPal);
-
-    hPal = hNewPal;
-    return TRUE;
-}
-
 /*!
  * @brief グラフィクスを初期化する / Initialize graphics
  * @details
@@ -748,9 +593,13 @@ static int new_palette(void)
  */
 static bool init_graphics(void)
 {
-    char buf[1024];
+    char buf[MAIN_WIN_MAX_PATH];
     BYTE wid, hgt, twid, thgt, ox, oy;
     concptr name;
+    concptr name_mask = NULL;
+
+    infGraph.delete_bitmap();
+    infMask.delete_bitmap();
 
     if (arg_graphics == GRAPHICS_ADAM_BOLT) {
         wid = 16;
@@ -760,6 +609,7 @@ static bool init_graphics(void)
         ox = 0;
         oy = 0;
         name = "16X16.BMP";
+        name_mask = "mask.bmp";
 
         ANGBAND_GRAF = "new";
     } else if (arg_graphics == GRAPHICS_HENGBAND) {
@@ -770,6 +620,7 @@ static bool init_graphics(void)
         ox = 0;
         oy = 0;
         name = "32X32.BMP";
+        name_mask = "mask32.bmp";
 
         ANGBAND_GRAF = "ne2";
     } else {
@@ -784,7 +635,8 @@ static bool init_graphics(void)
     }
 
     path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_GRAF, name);
-    if (!ReadDIB(data[0].w, buf, &infGraph)) {
+    infGraph.hBitmap = read_graphic(buf);
+    if (!infGraph.hBitmap) {
         plog_fmt(_("ビットマップ '%s' を読み込めません。", "Cannot read bitmap file '%s'"), name);
         return FALSE;
     }
@@ -796,29 +648,17 @@ static bool init_graphics(void)
     infGraph.OffsetX = ox;
     infGraph.OffsetY = oy;
 
-    if (arg_graphics == GRAPHICS_ADAM_BOLT) {
-        path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_GRAF, "mask.bmp");
-        if (!ReadDIB(data[0].w, buf, &infMask)) {
-            plog_fmt("Cannot read bitmap file '%s'", buf);
-            return FALSE;
-        }
-    }
-
-    if (arg_graphics == GRAPHICS_HENGBAND) {
-        path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_GRAF, "mask32.bmp");
-        if (!ReadDIB(data[0].w, buf, &infMask)) {
+    if (name_mask) {
+        path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_GRAF, name_mask);
+        infMask.hBitmap = read_graphic(buf);
+        if (!infMask.hBitmap) {
             plog_fmt("Cannot read bitmap file '%s'", buf);
             return FALSE;
         }
     }
 
-    if (!new_palette()) {
-        plog(_("パレットを実現できません!", "Cannot activate palette!"));
-        return FALSE;
-    }
-
     current_graphics_mode = arg_graphics;
-    return current_graphics_mode != 0;
+    return (current_graphics_mode != GRAPHICS_NONE);
 }
 
 /*
@@ -849,6 +689,18 @@ static void init_sound(void)
     }
 }
 
+/*!
+ * @brief Change sound mode
+ * @param new_mode bool
+ */
+static void change_sound_mode(bool new_mode)
+{
+    use_sound = new_mode;
+    if (use_sound) {
+        init_sound();
+    }
+}
+
 /*
  * Initialize background
  */
@@ -864,6 +716,42 @@ static void init_background(void)
 }
 
 /*!
+ * @brief Change background mode
+ * @param new_mode bg_mode
+ * @param show_error trueに設定した場合のみ、エラーダイアログを表示する
+ * @param force_redraw trueの場合、モード変更に関わらずウインドウを再描画する
+ * @retval true success
+ * @retval false failed
+ */
+static bool change_bg_mode(bg_mode new_mode, bool show_error = false, bool force_redraw = false)
+{
+    bg_mode old_bg_mode = current_bg_mode;
+    current_bg_mode = new_mode;
+    if (current_bg_mode != bg_mode::BG_NONE) {
+        init_background();
+        if (!load_bg(wallpaper_file)) {
+            current_bg_mode = bg_mode::BG_NONE;
+            if (show_error)
+                plog_fmt(_("壁紙用ファイル '%s' を読み込めません。", "Can't load the image file '%s'."), wallpaper_file);
+        }
+    } else {
+        delete_bg();
+    }
+
+    const bool mode_changed = (current_bg_mode != old_bg_mode);
+    if (mode_changed || force_redraw) {
+        // 全ウインドウ再描画
+        for (int i = 0; i < MAX_TERM_DATA; i++) {
+            term_data *td = &data[i];
+            if (td->visible)
+                InvalidateRect(td->w, NULL, FALSE);
+        }
+    }
+
+    return (current_bg_mode == new_mode);
+}
+
+/*!
  * @brief Resize a window
  */
 static void term_window_resize(term_data *td)
@@ -980,48 +868,29 @@ static errr term_user_win(int n)
     return 0;
 }
 
+static void refresh_color_table()
+{
+    for (int i = 0; i < 256; i++) {
+        byte rv = angband_color_table[i][1];
+        byte gv = angband_color_table[i][2];
+        byte bv = angband_color_table[i][3];
+        win_clr[i] = PALETTERGB(rv, gv, bv);
+    }
+}
+
 /*
  * React to global changes
  */
 static errr term_xtra_win_react(player_type *player_ptr)
 {
-    if (colors16) {
-        for (int i = 0; i < 256; i++) {
-            win_pal[i] = angband_color_table[i][0];
-        }
-    } else {
-        COLORREF code;
-        byte rv, gv, bv;
-        bool change = FALSE;
-        for (int i = 0; i < 256; i++) {
-            rv = angband_color_table[i][1];
-            gv = angband_color_table[i][2];
-            bv = angband_color_table[i][3];
-            code = PALETTERGB(rv, gv, bv);
-            if (win_clr[i] != code) {
-                change = TRUE;
-                win_clr[i] = code;
-            }
-        }
-
-        if (change)
-            (void)new_palette();
-    }
-
-    use_sound = arg_sound;
-    if (use_sound) {
-        init_sound();
-    }
-
-    if (use_graphics != (arg_graphics > 0)) {
-        if (arg_graphics && !init_graphics()) {
-            plog(_("グラフィックスを初期化できません!", "Cannot initialize graphics!"));
-            arg_graphics = GRAPHICS_NONE;
-        }
+    refresh_color_table();
 
-        use_graphics = (arg_graphics > 0);
-        reset_visuals(player_ptr);
+    if (arg_graphics && !init_graphics()) {
+        plog(_("グラフィックスを初期化できません!", "Cannot initialize graphics!"));
+        arg_graphics = GRAPHICS_NONE;
     }
+    use_graphics = (arg_graphics > 0);
+    reset_visuals(player_ptr);
 
     for (int i = 0; i < MAX_TERM_DATA; i++) {
         term_type *old = Term;
@@ -1092,7 +961,7 @@ static errr term_xtra_win_clear(void)
     SelectObject(hdc, td->font_id);
     ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
 
-    if (use_bg) {
+    if (current_bg_mode != bg_mode::BG_NONE) {
         rc.left = 0;
         rc.top = 0;
         draw_bg(hdc, &rc);
@@ -1269,7 +1138,7 @@ static errr term_wipe_win(int x, int y, int n)
     HDC hdc = GetDC(td->w);
     SetBkColor(hdc, RGB(0, 0, 0));
     SelectObject(hdc, td->font_id);
-    if (use_bg)
+    if (current_bg_mode != bg_mode::BG_NONE)
         draw_bg(hdc, &rc);
     else
         ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
@@ -1303,28 +1172,19 @@ static errr term_text_win(int x, int y, int n, TERM_COLOR a, concptr s)
         init_done = TRUE;
     }
 
-    RECT rc;
-    rc.left = x * td->tile_wid + td->size_ow1;
-    rc.right = rc.left + n * td->tile_wid;
-    rc.top = y * td->tile_hgt + td->size_oh1;
-    rc.bottom = rc.top + td->tile_hgt;
+    RECT rc{ static_cast<LONG>(x * td->tile_wid + td->size_ow1), static_cast<LONG>(y * td->tile_hgt + td->size_oh1),
+        static_cast<LONG>(rc.left + n * td->tile_wid), static_cast<LONG>(rc.top + td->tile_hgt) };
 
     HDC hdc = GetDC(td->w);
     SetBkColor(hdc, RGB(0, 0, 0));
-    if (colors16) {
-        SetTextColor(hdc, PALETTEINDEX(win_pal[a]));
-    } else if (paletted) {
-        SetTextColor(hdc, win_clr[a & 0x0F]);
-    } else {
-        SetTextColor(hdc, win_clr[a]);
-    }
+    SetTextColor(hdc, win_clr[a]);
 
     SelectObject(hdc, td->font_id);
-    if (use_bg)
+    if (current_bg_mode != bg_mode::BG_NONE)
         SetBkMode(hdc, TRANSPARENT);
 
     ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
-    if (use_bg)
+    if (current_bg_mode != bg_mode::BG_NONE)
         draw_bg(hdc, &rc);
 
     rc.left += ((td->tile_wid - td->font_wid) / 2);
@@ -1644,7 +1504,6 @@ static void init_windows(void)
         ShowWindow(td->w, SW_SHOW);
 
     SetWindowPos(td->w, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
-    (void)new_palette();
     hbrYellow = CreateSolidBrush(win_clr[TERM_YELLOW]);
     (void)term_xtra_win_flush();
 }
@@ -1666,9 +1525,6 @@ static void setup_menus(void)
         EnableMenuItem(hm, IDM_FILE_SAVE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
     }
 
-    EnableMenuItem(hm, IDM_FILE_SCORE, MF_BYCOMMAND | MF_ENABLED);
-    EnableMenuItem(hm, IDM_FILE_EXIT, MF_BYCOMMAND | MF_ENABLED);
-
     for (int i = 0; i < MAX_TERM_DATA; i++) {
         EnableMenuItem(hm, IDM_WINDOW_VIS_0 + i, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
         CheckMenuItem(hm, IDM_WINDOW_VIS_0 + i, (data[i].visible ? MF_CHECKED : MF_UNCHECKED));
@@ -1719,15 +1575,8 @@ static void setup_menus(void)
             EnableMenuItem(hm, IDM_WINDOW_D_HGT_0 + i, MF_BYCOMMAND | MF_ENABLED);
         }
     }
-    EnableMenuItem(hm, IDM_WINDOW_KEEP_SUBWINDOWS, MF_BYCOMMAND | MF_ENABLED);
     CheckMenuItem(hm, IDM_WINDOW_KEEP_SUBWINDOWS, (keep_subwindows ? MF_CHECKED : MF_UNCHECKED));
 
-    EnableMenuItem(hm, IDM_OPTIONS_NO_GRAPHICS, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
-    EnableMenuItem(hm, IDM_OPTIONS_OLD_GRAPHICS, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
-    EnableMenuItem(hm, IDM_OPTIONS_NEW_GRAPHICS, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
-    EnableMenuItem(hm, IDM_OPTIONS_BIGTILE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
-    EnableMenuItem(hm, IDM_OPTIONS_SOUND, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
-
     CheckMenuItem(hm, IDM_OPTIONS_NO_GRAPHICS, (arg_graphics == GRAPHICS_NONE ? MF_CHECKED : MF_UNCHECKED));
     CheckMenuItem(hm, IDM_OPTIONS_OLD_GRAPHICS, (arg_graphics == GRAPHICS_ORIGINAL ? MF_CHECKED : MF_UNCHECKED));
     CheckMenuItem(hm, IDM_OPTIONS_NEW_GRAPHICS, (arg_graphics == GRAPHICS_ADAM_BOLT ? MF_CHECKED : MF_UNCHECKED));
@@ -1736,13 +1585,11 @@ static void setup_menus(void)
     CheckMenuItem(hm, IDM_OPTIONS_MUSIC, (arg_music ? MF_CHECKED : MF_UNCHECKED));
     CheckMenuItem(hm, IDM_OPTIONS_MUSIC_PAUSE_INACTIVE, (use_pause_music_inactive ? MF_CHECKED : MF_UNCHECKED));
     CheckMenuItem(hm, IDM_OPTIONS_SOUND, (arg_sound ? MF_CHECKED : MF_UNCHECKED));
-    CheckMenuItem(hm, IDM_OPTIONS_BG, (use_bg ? MF_CHECKED : MF_UNCHECKED));
-
-    EnableMenuItem(hm, IDM_OPTIONS_NO_GRAPHICS, MF_ENABLED);
-    EnableMenuItem(hm, IDM_OPTIONS_OLD_GRAPHICS, MF_ENABLED);
-    EnableMenuItem(hm, IDM_OPTIONS_NEW_GRAPHICS, MF_ENABLED);
-    EnableMenuItem(hm, IDM_OPTIONS_BIGTILE, MF_ENABLED);
-    EnableMenuItem(hm, IDM_OPTIONS_SOUND, MF_ENABLED);
+    CheckMenuItem(hm, IDM_OPTIONS_NO_BG, ((current_bg_mode == bg_mode::BG_NONE) ? MF_CHECKED : MF_UNCHECKED));
+    CheckMenuItem(hm, IDM_OPTIONS_BG, ((current_bg_mode == bg_mode::BG_ONE) ? MF_CHECKED : MF_UNCHECKED));
+    CheckMenuItem(hm, IDM_OPTIONS_PRESET_BG, ((current_bg_mode == bg_mode::BG_PRESET) ? MF_CHECKED : MF_UNCHECKED));
+    // TODO IDM_OPTIONS_PRESET_BG を有効にする
+    EnableMenuItem(hm, IDM_OPTIONS_PRESET_BG, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
 }
 
 /*
@@ -2037,24 +1884,16 @@ static void process_menus(player_type *player_ptr, WORD wCmd)
     case IDM_OPTIONS_NO_GRAPHICS: {
         if (arg_graphics != GRAPHICS_NONE) {
             arg_graphics = GRAPHICS_NONE;
-
-            if (inkey_flag) {
-                term_xtra_win_react(player_ptr);
-                term_key_push(KTRL('R'));
-            }
+            if (game_in_progress)
+                do_cmd_redraw(player_ptr);
         }
         break;
     }
     case IDM_OPTIONS_OLD_GRAPHICS: {
         if (arg_graphics != GRAPHICS_ORIGINAL) {
             arg_graphics = GRAPHICS_ORIGINAL;
-
-            if (inkey_flag) {
-                term_xtra_win_react(player_ptr);
-                term_key_push(KTRL('R'));
-            } else if (!init_graphics()) {
-                arg_graphics = GRAPHICS_NONE;
-            }
+            if (game_in_progress)
+                do_cmd_redraw(player_ptr);
         }
 
         break;
@@ -2062,13 +1901,8 @@ static void process_menus(player_type *player_ptr, WORD wCmd)
     case IDM_OPTIONS_NEW_GRAPHICS: {
         if (arg_graphics != GRAPHICS_ADAM_BOLT) {
             arg_graphics = GRAPHICS_ADAM_BOLT;
-
-            if (inkey_flag) {
-                term_xtra_win_react(player_ptr);
-                term_key_push(KTRL('R'));
-            } else if (!init_graphics()) {
-                arg_graphics = GRAPHICS_NONE;
-            }
+            if (game_in_progress)
+                do_cmd_redraw(player_ptr);
         }
 
         break;
@@ -2076,13 +1910,8 @@ static void process_menus(player_type *player_ptr, WORD wCmd)
     case IDM_OPTIONS_NEW2_GRAPHICS: {
         if (arg_graphics != GRAPHICS_HENGBAND) {
             arg_graphics = GRAPHICS_HENGBAND;
-
-            if (inkey_flag) {
-                term_xtra_win_react(player_ptr);
-                term_key_push(KTRL('R'));
-            } else if (!init_graphics()) {
-                arg_graphics = GRAPHICS_NONE;
-            }
+            if (game_in_progress)
+                do_cmd_redraw(player_ptr);
         }
 
         break;
@@ -2113,62 +1942,42 @@ static void process_menus(player_type *player_ptr, WORD wCmd)
     }
     case IDM_OPTIONS_SOUND: {
         arg_sound = !arg_sound;
-        if (inkey_flag)
-            term_xtra_win_react(player_ptr);
+        change_sound_mode(arg_sound);
         break;
     }
-    case IDM_OPTIONS_BG: {
-        use_bg = !(use_bg > 0);
-        if (use_bg) {
-            init_background();
-            use_bg = init_bg();
-        } else {
-            delete_bg();
-        }
-
-        td = &data[0];
-        InvalidateRect(td->w, NULL, TRUE);
+    case IDM_OPTIONS_NO_BG: {
+        change_bg_mode(bg_mode::BG_NONE);
+        break;
+    }
+    case IDM_OPTIONS_PRESET_BG: {
+        change_bg_mode(bg_mode::BG_PRESET);
         break;
     }
+    case IDM_OPTIONS_BG: {
+        if (change_bg_mode(bg_mode::BG_ONE))
+            break;
+        // 壁紙の設定に失敗した(ファイルが存在しない等)場合、壁紙に使うファイルを選択させる
+    }
+        [[fallthrough]]; /* Fall through */
     case IDM_OPTIONS_OPEN_BG: {
         memset(&ofn, 0, sizeof(ofn));
         ofn.lStructSize = sizeof(ofn);
         ofn.hwndOwner = data[0].w;
         ofn.lpstrFilter = "Image Files (*.bmp;*.png;*.jpg;*.jpeg;)\0*.bmp;*.png;*.jpg;*.jpeg;\0";
         ofn.nFilterIndex = 1;
-        ofn.lpstrFile = bg_bitmap_file;
+        ofn.lpstrFile = wallpaper_file;
         ofn.nMaxFile = 1023;
         ofn.lpstrInitialDir = NULL;
         ofn.lpstrTitle = _("壁紙を選んでね。", "Choose wall paper.");
         ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
 
         if (GetOpenFileName(&ofn)) {
-            init_background();
-            use_bg = init_bg();
-
-            td = &data[0];
-            InvalidateRect(td->w, NULL, TRUE);
+            change_bg_mode(bg_mode::BG_ONE, true, true);
         }
         break;
     }
     case IDM_DUMP_SCREEN_HTML: {
-        static char buf[1024] = "";
-        memset(&ofn, 0, sizeof(ofn));
-        ofn.lStructSize = sizeof(ofn);
-        ofn.hwndOwner = data[0].w;
-        ofn.lpstrFilter = "HTML Files (*.html)\0*.html\0";
-        ofn.nFilterIndex = 1;
-        ofn.lpstrFile = buf;
-        ofn.nMaxFile = 1023;
-        ofn.lpstrDefExt = "html";
-        ofn.lpstrInitialDir = NULL;
-        ofn.lpstrTitle = _("HTMLでスクリーンダンプを保存", "Save screen dump as HTML.");
-        ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
-
-        if (GetSaveFileName(&ofn)) {
-            do_cmd_save_screen_html_aux(buf, 0);
-        }
-
+        save_screen_as_html(data[0].w);
         break;
     }
     }
@@ -2298,7 +2107,7 @@ static void handle_app_active(HWND hWnd, UINT uMsg, WPARAM wParam, [[maybe_unuse
 }
 
 /*!
- * @todo WNDCLASSに影響があるのでplayer_type*の追加は保留
+ * @brief メインウインドウ用ウインドウプロシージャ
  */
 LRESULT PASCAL AngbandWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
@@ -2394,7 +2203,7 @@ LRESULT PASCAL AngbandWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam
         for (int i = 0; i < dy; i++) {
 #ifdef JP
             char *s;
-            char **scr = data[0].t.scr->c;
+            const auto &scr = data[0].t.scr->c;
 
             C_MAKE(s, (dx + 1), char);
             strncpy(s, &scr[oy + i][ox], dx);
@@ -2563,24 +2372,6 @@ LRESULT PASCAL AngbandWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam
 
         break;
     }
-    case WM_PALETTECHANGED: {
-        if ((HWND)wParam == hWnd)
-            return 0;
-    }
-        [[fallthrough]]; /* Fall through */
-    case WM_QUERYNEWPALETTE: {
-        if (!paletted)
-            return 0;
-
-        HDC hdc = GetDC(hWnd);
-        SelectPalette(hdc, hPal, FALSE);
-        int i = RealizePalette(hdc);
-        if (i)
-            InvalidateRect(hWnd, NULL, TRUE);
-
-        ReleaseDC(hWnd, hdc);
-        return 0;
-    }
     case WM_ACTIVATE: {
         if (!wParam || HIWORD(lParam))
             break;
@@ -2623,7 +2414,7 @@ LRESULT PASCAL AngbandWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam
 }
 
 /*!
- * @todo WNDCLASSに影響があるのでplayer_type*の追加は保留
+ * @brief サブウインドウ用ウインドウプロシージャ
  */
 LRESULT PASCAL AngbandListProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
@@ -2704,24 +2495,6 @@ LRESULT PASCAL AngbandListProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara
             term_keypress(wParam);
         return 0;
     }
-    case WM_PALETTECHANGED: {
-        if ((HWND)wParam == hWnd)
-            return FALSE;
-    }
-        [[fallthrough]]; /* Fall through */
-    case WM_QUERYNEWPALETTE: {
-        if (!paletted)
-            return 0;
-
-        HDC hdc = GetDC(hWnd);
-        SelectPalette(hdc, hPal, FALSE);
-        int i = RealizePalette(hdc);
-        if (i)
-            InvalidateRect(hWnd, NULL, TRUE);
-
-        ReleaseDC(hWnd, hdc);
-        return 0;
-    }
     case WM_NCLBUTTONDOWN: {
         if (wParam == HTCLOSE)
             wParam = HTSYSMENU;
@@ -2748,11 +2521,7 @@ LRESULT PASCAL AngbandListProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara
 static void hack_plog(concptr str)
 {
     if (str) {
-#ifdef JP
-        MessageBox(NULL, str, "警告!", MB_ICONEXCLAMATION | MB_OK);
-#else
-        MessageBox(NULL, str, "Warning", MB_ICONEXCLAMATION | MB_OK);
-#endif
+        MessageBoxW(NULL, to_wchar(str).wc_str(), _(L"警告!", L"Warning"), MB_ICONEXCLAMATION | MB_OK);
     }
 }
 
@@ -2762,11 +2531,7 @@ static void hack_plog(concptr str)
 static void hack_quit(concptr str)
 {
     if (str) {
-#ifdef JP
-        MessageBox(NULL, str, "エラー!", MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP);
-#else
-        MessageBox(NULL, str, "Error", MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP);
-#endif
+        MessageBoxW(NULL, to_wchar(str).wc_str(), _(L"エラー!", L"Error"), MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP);
     }
 
     UnregisterClass(AppName, hInstance);
@@ -2782,11 +2547,7 @@ static void hack_quit(concptr str)
 static void hook_plog(concptr str)
 {
     if (str) {
-#ifdef JP
-        MessageBox(data[0].w, str, "警告!", MB_ICONEXCLAMATION | MB_OK);
-#else
-        MessageBox(data[0].w, str, "Warning", MB_ICONEXCLAMATION | MB_OK);
-#endif
+        MessageBoxW(data[0].w, to_wchar(str).wc_str(), _(L"警告!", L"Warning"), MB_ICONEXCLAMATION | MB_OK);
     }
 }
 
@@ -2796,11 +2557,7 @@ static void hook_plog(concptr str)
 static void hook_quit(concptr str)
 {
     if (str) {
-#ifdef JP
-        MessageBox(data[0].w, str, "エラー!", MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP);
-#else
-        MessageBox(data[0].w, str, "Error", MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP);
-#endif
+        MessageBoxW(data[0].w, to_wchar(str).wc_str(), _(L"エラー!", L"Error"), MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP);
     }
 
     save_prefs();
@@ -2813,20 +2570,12 @@ static void hook_quit(concptr str)
         data[i].w = 0;
     }
 
-    if (infGraph.hPalette)
-        DeleteObject(infGraph.hPalette);
-    if (infGraph.hBitmap)
-        DeleteObject(infGraph.hBitmap);
-    if (infMask.hPalette)
-        DeleteObject(infMask.hPalette);
-    if (infMask.hBitmap)
-        DeleteObject(infMask.hBitmap);
+    infGraph.delete_bitmap();
+    infMask.delete_bitmap();
 
     DeleteObject(hbrYellow);
     finalize_bg();
-
-    if (hPal)
-        DeleteObject(hPal);
+    finalize_graphics();
 
     UnregisterClass(AppName, hInstance);
     if (hIcon)
@@ -2912,35 +2661,15 @@ static spoiler_output_status create_debug_spoiler(LPSTR cmd_line)
 }
 
 /*!
- * @todo よく見るとhMutexはちゃんと使われていない……?
- * @brief (Windows固有)変愚蛮怒が起動済かどうかのチェック
- */
-static bool is_already_running(void)
-{
-    HANDLE hMutex;
-    hMutex = CreateMutex(NULL, TRUE, VERSION_NAME);
-    if (GetLastError() == ERROR_ALREADY_EXISTS) {
-        return TRUE;
-    }
-
-    return FALSE;
-}
-
-/*!
  * @brief (Windows固有)Windowsアプリケーションとしてのエントリポイント
  */
-int WINAPI WinMain(_In_ HINSTANCE hInst, _In_opt_ HINSTANCE hPrevInst, _In_ LPSTR lpCmdLine, _In_ int nCmdShow)
+int WINAPI WinMain(_In_ HINSTANCE hInst, _In_opt_ HINSTANCE hPrevInst, _In_ LPSTR lpCmdLine, [[maybe_unused]] _In_ int nCmdShow)
 {
-    WNDCLASS wc;
-    HDC hdc;
-    MSG msg;
-
     setlocale(LC_ALL, "ja_JP");
-    (void)nCmdShow;
     hInstance = hInst;
     if (is_already_running()) {
-        MessageBox(
-            NULL, _("変愚蛮怒はすでに起動しています。", "Hengband is already running."), _("エラー!", "Error"), MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP);
+        MessageBoxW(
+            NULL, _(L"変愚蛮怒はすでに起動しています。", L"Hengband is already running."), _(L"エラー!", L"Error"), MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP);
         return FALSE;
     }
 
@@ -2962,6 +2691,7 @@ int WINAPI WinMain(_In_ HINSTANCE hInst, _In_opt_ HINSTANCE hPrevInst, _In_ LPST
     }
 
     if (hPrevInst == NULL) {
+        WNDCLASS wc;
         wc.style = CS_CLASSDC;
         wc.lpfnWndProc = AngbandWndProc;
         wc.cbClsExtra = 0;
@@ -2997,29 +2727,15 @@ int WINAPI WinMain(_In_ HINSTANCE hInst, _In_opt_ HINSTANCE hPrevInst, _In_ LPST
         ignore_key[ignore_key_list[i]] = TRUE;
     }
 
-    hdc = GetDC(NULL);
-    colors16 = (GetDeviceCaps(hdc, BITSPIXEL) == 4);
-    paletted = ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) ? TRUE : FALSE);
-    ReleaseDC(NULL, hdc);
-
-    for (int i = 0; i < 256; i++) {
-        byte rv = angband_color_table[i][1];
-        byte gv = angband_color_table[i][2];
-        byte bv = angband_color_table[i][3];
-        win_clr[i] = PALETTERGB(rv, gv, bv);
-        angband_color_table[i][0] = win_pal[i];
+    HDC hdc = GetDC(NULL);
+    if (GetDeviceCaps(hdc, BITSPIXEL) <= 8) {
+        quit(_("画面を16ビット以上のカラーモードにして下さい。", "Please switch to High Color (16-bit) or higher color mode."));
     }
+    ReleaseDC(NULL, hdc);
 
+    refresh_color_table();
     init_windows();
-    if (use_bg) {
-        init_background();
-        use_bg = init_bg();
-    }
-
-    use_music = arg_music;
-    if (use_music) {
-        init_music();
-    }
+    change_bg_mode(current_bg_mode, true);
 
     plog_aux = hook_plog;
     quit_aux = hook_quit;
@@ -3052,6 +2768,14 @@ int WINAPI WinMain(_In_ HINSTANCE hInst, _In_opt_ HINSTANCE hPrevInst, _In_ LPST
     check_for_save_file(p_ptr, lpCmdLine);
     prt(_("[ファイル] メニューの [新規] または [開く] を選択してください。", "[Choose 'New' or 'Open' from the 'File' menu]"), 23, _(8, 17));
     term_fresh();
+
+    change_sound_mode(arg_sound);
+    use_music = arg_music;
+    if (use_music) {
+        init_music();
+    }
+
+    MSG msg;
     while (GetMessage(&msg, NULL, 0, 0)) {
         TranslateMessage(&msg);
         DispatchMessage(&msg);