win32: add dialog for saving/loading with preview images

This commit is contained in:
OV2 2019-09-18 18:04:17 +02:00
parent 87f259c0f5
commit 2e7a345dca
8 changed files with 397 additions and 16 deletions

View File

@ -0,0 +1,281 @@
/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
#include "CSaveLoadWithPreviewDlg.h"
#include "wsnes9x.h"
#include "../snes9x.h"
#include "../ppu.h"
#include "../display.h"
#include <vector>
#include <string>
#include <shlwapi.h>
CSaveLoadWithPreviewDlg::CSaveLoadWithPreviewDlg(bool is_save_dialog)
{
for(int i = 0; i < NUM_DIALOG_SLOTS; i++)
{
previewHbmps[i] = NULL;
}
this->is_save_dialog = is_save_dialog;
}
CSaveLoadWithPreviewDlg::~CSaveLoadWithPreviewDlg()
{
delete_preview_bmps();
}
bool CreatePreviewHbitmap(HBITMAP *hbmp)
{
// create a HBITMAP to store the preview images in 32bit RGB
uint8_t* buffer = NULL;
BITMAPINFO *bm = (BITMAPINFO *)calloc(sizeof(BITMAPINFOHEADER), 1);
bm->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bm->bmiHeader.biWidth = PREVIEW_IMAGE_WIDTH;
bm->bmiHeader.biHeight = -PREVIEW_IMAGE_HEIGHT; // negative is top-down
bm->bmiHeader.biPlanes = 1;
bm->bmiHeader.biBitCount = 32;
bm->bmiHeader.biCompression = BI_RGB;
bm->bmiHeader.biSizeImage = 0;
*hbmp = CreateDIBSection(NULL, bm, DIB_RGB_COLORS, (void**)&buffer, 0, 0);
if(*hbmp == NULL) {
return false;
}
return true;
}
void CSaveLoadWithPreviewDlg::delete_preview_bmps()
{
for(int i = 0; i < NUM_DIALOG_SLOTS; i++)
{
if(previewHbmps[i])
{
DeleteObject(previewHbmps[i]);
}
}
}
bool CSaveLoadWithPreviewDlg::init_preview_bmps()
{
for(int i = 0; i < NUM_DIALOG_SLOTS; i++)
{
if(!CreatePreviewHbitmap(&previewHbmps[i]))
return false;
}
return true;
}
void CSaveLoadWithPreviewDlg::load_slot_image_text(int slot, HWND hDlg)
{
// load the snapshot to receive the saved screenshot
FreezeUnfreezeSlot(slot, FALSE);
// create temporary bitmap storage for screenshot, 16bit RGB
uint8_t* buffer = NULL;
BITMAPINFO *bm = (BITMAPINFO *)calloc(sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD), 1);
bm->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bm->bmiHeader.biWidth = IPPU.RenderedScreenWidth;
bm->bmiHeader.biHeight = -IPPU.RenderedScreenHeight; // negative is top-down
bm->bmiHeader.biPlanes = 1;
bm->bmiHeader.biBitCount = 16;
bm->bmiHeader.biCompression = BI_BITFIELDS;
bm->bmiHeader.biSizeImage = IPPU.RenderedScreenWidth * IPPU.RenderedScreenHeight * 2;
*(unsigned long *)&bm->bmiColors[0] = FIRST_COLOR_MASK_RGB565;
*(unsigned long *)&bm->bmiColors[1] = SECOND_COLOR_MASK_RGB565;
*(unsigned long *)&bm->bmiColors[2] = THIRD_COLOR_MASK_RGB565;
HBITMAP imageBmp = CreateDIBSection(NULL, bm, DIB_RGB_COLORS, (void**)&buffer, 0, 0);
if(imageBmp == NULL)
{
free(bm);
return;
}
int row_bytes = IPPU.RenderedScreenWidth * 2 / 4 * 4; // DIBs always have 4-byte aligned rows
if(IPPU.RenderedScreenWidth * 2 % 4)
row_bytes += 4;
// copy saved screenshot into temporary bitmap
uint16 *screen = GFX.Screen;
for(int h = 0; h < IPPU.RenderedScreenHeight; h++, screen += GFX.RealPPL)
{
uint16_t *row_start = (uint16_t*)(buffer + (h * row_bytes));
for(int w = 0; w < IPPU.RenderedScreenWidth; w++)
{
row_start[w] = screen[w];
}
}
// strech temporary bitmap into HBIMAP for button
HDC cdc = CreateCompatibleDC(GetDC(NULL));
HGDIOBJ old = SelectObject(cdc, previewHbmps[slot]);
int ret = StretchDIBits(cdc, 0, 0, PREVIEW_IMAGE_WIDTH, PREVIEW_IMAGE_HEIGHT, 0, 0, IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight, buffer, bm, DIB_RGB_COLORS, SRCCOPY);
SelectObject(cdc, old);
DeleteDC(cdc);
free(bm);
// set image to button
SendMessage(GetDlgItem(hDlg, IDC_BUTTON_SLOT_1 + slot), BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)previewHbmps[slot]);
// text with filename and last write time
std::wstring static_text(PathFindFileName((wchar_t*)_tFromChar(Memory.ROMFilename)));
// get file time details
char filename[_MAX_PATH + 1];
GetSlotFilename(slot, filename);
HANDLE file_handle = CreateFile(_tFromChar(filename), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(file_handle != INVALID_HANDLE_VALUE)
{
FILETIME ft;
SYSTEMTIME stUTC, stLocal;
// transform from file time to local time
if(GetFileTime(file_handle, NULL, NULL, &ft) &&
FileTimeToSystemTime(&ft, &stUTC) &&
SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal))
{
// reserve space for date and time (both received individually)
std::vector<wchar_t> date_string;
date_string.resize(max(
GetDateFormatEx(LOCALE_NAME_USER_DEFAULT, DATE_AUTOLAYOUT | DATE_LONGDATE, &stLocal, NULL, NULL, 0, NULL),
GetTimeFormatEx(LOCALE_NAME_USER_DEFAULT, 0, &stLocal, NULL, NULL, 0)
));
GetDateFormatEx(LOCALE_NAME_USER_DEFAULT, DATE_AUTOLAYOUT | DATE_LONGDATE, &stLocal, NULL, &date_string[0], 100, NULL);
static_text.append(L"\n").append(&date_string[0]);
GetTimeFormatEx(LOCALE_NAME_USER_DEFAULT, 0, &stLocal, NULL, &date_string[0], 100);
static_text.append(L" ").append(&date_string[0]);
}
}
// set the description text
SetWindowText(GetDlgItem(hDlg, IDC_STATIC_SLOT_1 + slot), static_text.c_str());
}
void CSaveLoadWithPreviewDlg::init_window(HWND hDlg)
{
if(is_save_dialog)
SetWindowText(hDlg, L"Save with preview");
// we need to load snapshots to receive the preview images, so we save the current state,
// load the slots, then reload the backup
std::string backup_filename = S9xGetFilename(".preview_backup", SNAPSHOT_DIR);
// create backup
FreezeUnfreeze(backup_filename.c_str(), true);
int x_pos = 0;
int y_pos = 0;
for(int i = 0; i < NUM_DIALOG_SLOTS; i++)
{
// second row
if(i == NUM_DIALOG_SLOTS / 2)
{
x_pos = 0;
y_pos = PREVIEW_HEIGHT + PREVIEW_TEXT_STATIC_HEIGHT;
}
// create button and static for one slot
CreateWindow(TEXT("BUTTON"), NULL, WS_CHILDWINDOW | WS_VISIBLE | BS_BITMAP, x_pos, y_pos, PREVIEW_WIDHT, PREVIEW_HEIGHT, hDlg, (HMENU)(UINT_PTR)(IDC_BUTTON_SLOT_1 + i), GUI.hInstance, NULL);
HWND hStatic = CreateWindow(TEXT("STATIC"), TEXT(""), WS_CHILDWINDOW | WS_VISIBLE | SS_CENTER, x_pos, y_pos + PREVIEW_HEIGHT, PREVIEW_WIDHT, PREVIEW_TEXT_STATIC_HEIGHT, hDlg, (HMENU)(UINT_PTR)(IDC_STATIC_SLOT_1 + i), GUI.hInstance, NULL);
x_pos += PREVIEW_WIDHT;
// set dialog font to static
HFONT dlg_font = (HFONT)SendMessage(hDlg, WM_GETFONT, 0, 0);
SendMessage(hStatic, WM_SETFONT, (WPARAM)dlg_font, MAKELPARAM(FALSE, 0));
// load one slot
load_slot_image_text(i, hDlg);
}
// resize dialog to fit all buttons and text
int dialog_width = NUM_DIALOG_SLOTS / 2 * PREVIEW_WIDHT;
int dialog_height = 2 * (PREVIEW_HEIGHT + PREVIEW_TEXT_STATIC_HEIGHT) + 40; // +40 for cancel button
// reposition cancel button
RECT rect_cancel, client_rect;
GetWindowRect(GetDlgItem(hDlg, IDCANCEL), &rect_cancel);
POINT topleft = { rect_cancel.left, rect_cancel.top };
ScreenToClient(hDlg, &topleft);
GetClientRect(hDlg, &client_rect);
MoveWindow(GetDlgItem(hDlg, IDCANCEL), dialog_width - (client_rect.right - topleft.x), dialog_height - 30, rect_cancel.right - rect_cancel.left, rect_cancel.bottom - rect_cancel.top, TRUE);
// get monitor dimensions
HMONITOR hm;
MONITORINFO mi;
hm = MonitorFromWindow(GUI.hWnd, MONITOR_DEFAULTTONEAREST);
mi.cbSize = sizeof(mi);
GetMonitorInfo(hm, &mi);
// get title bar and borders
RECT rcMargins = { 0,0,0,0 };
AdjustWindowRectEx(&rcMargins, GetWindowStyle(hDlg), FALSE, GetWindowExStyle(hDlg));
rcMargins.left = abs(rcMargins.left);
rcMargins.top = abs(rcMargins.top);
// add margins to window dimensions and position window in center of screen
dialog_height += rcMargins.top + rcMargins.bottom;
dialog_width += rcMargins.left + rcMargins.right;
int left = (mi.rcWork.right - mi.rcWork.left - dialog_width) / 2;
int top = (mi.rcWork.bottom - mi.rcWork.top - dialog_height) / 2;
SetWindowPos(hDlg, NULL, left, top, dialog_width, dialog_height, SWP_NOZORDER);
// load backup, remove temporary state
FreezeUnfreeze(backup_filename.c_str(), false);
remove(backup_filename.c_str());
}
INT_PTR CALLBACK CSaveLoadWithPreviewDlg::DlgLoadWithPreview(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
CSaveLoadWithPreviewDlg* dlg = (CSaveLoadWithPreviewDlg*)GetWindowLongPtr(hDlg, GWLP_USERDATA);
switch(msg)
{
case WM_INITDIALOG:
{
SetWindowLongPtr(hDlg, GWLP_USERDATA, lParam);
dlg = (CSaveLoadWithPreviewDlg*)lParam;
dlg->init_window(hDlg);
}
return true;
case WM_COMMAND:
{
// return which button was pressed, or -1 for cancel
int id = LOWORD(wParam);
if(id >= IDC_BUTTON_SLOT_1 && id < IDC_BUTTON_SLOT_1 + NUM_DIALOG_SLOTS)
{
EndDialog(hDlg, id - IDC_BUTTON_SLOT_1);
return true;
}
else if(id == IDCANCEL)
{
EndDialog(hDlg, -1);
return true;
}
}
default:
return false;
}
}
int CSaveLoadWithPreviewDlg::show()
{
// disable text and confirm for the duration of the dialog
uint32 save_timeout = Settings.InitialInfoStringTimeout;
bool save_confirm = GUI.ConfirmSaveLoad;
Settings.InitialInfoStringTimeout = 0;
GUI.ConfirmSaveLoad = false;
int ret = -1;
delete_preview_bmps();
if(init_preview_bmps())
{
ret = DialogBoxParam(GUI.hInstance, MAKEINTRESOURCE(IDD_DIALOG_LOAD_PREVIEW), GUI.hWnd, DlgLoadWithPreview, (LPARAM)this);
}
GUI.ConfirmSaveLoad = save_confirm;
Settings.InitialInfoStringTimeout = save_timeout;
return ret;
}

View File

@ -0,0 +1,37 @@
/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
#pragma once
#include "windows.h"
#define NUM_DIALOG_SLOTS 10
#define PREVIEW_IMAGE_WIDTH SNES_WIDTH
#define PREVIEW_IMAGE_HEIGHT SNES_HEIGHT
#define PREVIEW_WIDHT (PREVIEW_IMAGE_WIDTH + 10)
#define PREVIEW_HEIGHT (PREVIEW_IMAGE_HEIGHT + 10)
#define PREVIEW_TEXT_STATIC_HEIGHT 50
class CSaveLoadWithPreviewDlg
{
private:
static INT_PTR CALLBACK DlgLoadWithPreview(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
HBITMAP previewHbmps[NUM_DIALOG_SLOTS];
bool is_save_dialog;
void delete_preview_bmps();
bool init_preview_bmps();
void load_slot_image_text(int slot, HWND hDlg);
void init_window(HWND hDlg);
public:
CSaveLoadWithPreviewDlg(bool is_save_dialog = false);
virtual ~CSaveLoadWithPreviewDlg();
int show();
};

View File

@ -45,6 +45,7 @@
#define IDI_ICON3 161
#define IDI_ICON4 162
#define IDD_DIALOG_HACKS 164
#define IDD_DIALOG_LOAD_PREVIEW 167
#define IDC_DRIVER 1001
#define IDC_BUFLEN 1002
#define IDC_RATE 1003
@ -404,6 +405,8 @@
#define IDC_SFX_CLOCK_SPEED_SPIN 3036
#define IDC_NO_SPRITE_LIMIT 3037
#define IDC_SET_DEFAULTS 3038
#define IDC_BUTTON_SLOT_1 3039
#define IDC_STATIC_SLOT_1 3059
#define ID_FILE_EXIT 40001
#define ID_WINDOW_HIDEMENUBAR 40004
#define ID_FILE_AVI_RECORDING 40005
@ -520,6 +523,8 @@
#define ID_INPUT_BACKGROUNDKEYBOARDHOTKEYS 40176
#define ID_INPUT_DETECTGAMEPADCHANGES 40177
#define ID_EMULATION_HACKS 40178
#define ID_FILE_LOAD_PREVIEW 40179
#define ID_FILE_SAVE_PREVIEW 40180
#define ID_FILE_SAVE0 44000
#define ID_FILE_SAVE1 44001
#define ID_FILE_SAVE2 44002
@ -541,7 +546,7 @@
#define ID_FILE_LOAD7 44027
#define ID_FILE_LOAD8 44028
#define ID_FILE_LOAD9 44029
#define ID_FILE_LOAD_OOPS 44030
#define ID_FILE_LOAD_OOPS 44030
#define ID_FILE_LOAD_FILE 44031
#define IDM_MACSRIFLE_TOGGLE 44032
#define IDC_STATIC -1
@ -550,9 +555,9 @@
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 167
#define _APS_NEXT_COMMAND_VALUE 40179
#define _APS_NEXT_CONTROL_VALUE 3039
#define _APS_NEXT_RESOURCE_VALUE 169
#define _APS_NEXT_COMMAND_VALUE 40181
#define _APS_NEXT_CONTROL_VALUE 3040
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@ -26,6 +26,14 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
// Dialog
//
IDD_DIALOG_LOAD_PREVIEW DIALOGEX 0, 0, 567, 247
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Load with Preview"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
PUSHBUTTON "Cancel",IDCANCEL,510,226,50,14
END
IDD_SOUND_OPTS DIALOGEX 0, 0, 414, 158
STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU
CAPTION "Sound Settings"
@ -753,6 +761,13 @@ BEGIN
TOPMARGIN, 7
BOTTOMMARGIN, 113
END
IDD_DIALOG_LOAD_PREVIEW, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 560
TOPMARGIN, 7
BOTTOMMARGIN, 240
END
END
#endif // APSTUDIO_INVOKED
@ -912,6 +927,8 @@ BEGIN
BEGIN
MENUITEM "Dummy", ID_RECENT_DUMMY, INACTIVE
END
MENUITEM "Load MultiCart...", ID_FILE_LOADMULTICART
MENUITEM SEPARATOR
POPUP "&Save Game Position"
BEGIN
MENUITEM "Slot #&0", ID_FILE_SAVE0
@ -944,7 +961,8 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "&Select File", ID_FILE_LOAD_FILE
END
MENUITEM "Load MultiCart...", ID_FILE_LOADMULTICART
MENUITEM "&Save with Preview", ID_FILE_SAVE_PREVIEW
MENUITEM "&Load with Preview", ID_FILE_LOAD_PREVIEW
MENUITEM SEPARATOR
POPUP "Save Other"
BEGIN
@ -1182,6 +1200,11 @@ BEGIN
0
END
IDD_DIALOG_LOAD_PREVIEW AFX_DIALOG_LAYOUT
BEGIN
0
END
/////////////////////////////////////////////////////////////////////////////
//

View File

@ -438,6 +438,7 @@
<ClInclude Include="cgFunctions.h" />
<ClInclude Include="CGLCG.h" />
<ClInclude Include="cgMini.h" />
<ClInclude Include="CSaveLoadWithPreviewDlg.h" />
<ClInclude Include="COpenGL.h" />
<ClInclude Include="CShaderParamDlg.h" />
<ClInclude Include="CWaveOut.h" />
@ -582,6 +583,7 @@
<ClCompile Include="CDirectDraw.cpp" />
<ClCompile Include="cgFunctions.cpp" />
<ClCompile Include="CGLCG.cpp" />
<ClCompile Include="CSaveLoadWithPreviewDlg.cpp" />
<ClCompile Include="COpenGL.cpp" />
<ClCompile Include="CShaderParamDlg.cpp" />
<ClCompile Include="CWaveOut.cpp" />

View File

@ -285,6 +285,9 @@
<ClInclude Include="..\filter\snes_ntsc_impl.h">
<Filter>Filter</Filter>
</ClInclude>
<ClInclude Include="CSaveLoadWithPreviewDlg.h">
<Filter>GUI</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\bsx.cpp">
@ -626,6 +629,9 @@
<ClCompile Include="..\filter\snes_ntsc.c">
<Filter>Filter</Filter>
</ClCompile>
<ClCompile Include="CSaveLoadWithPreviewDlg.cpp">
<Filter>GUI</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="rsrc\nodrop.cur">
@ -886,4 +892,4 @@
</CustomBuild>
<CustomBuild Include="snes9x.cfg" />
</ItemGroup>
</Project>
</Project>

View File

@ -35,6 +35,7 @@
#include "CCGShader.h"
#include "../shaders/glsl.h"
#include "CShaderParamDlg.h"
#include "CSaveLoadWithPreviewDlg.h"
#include "../snes9x.h"
#include "../memmap.h"
#include "../cpuexec.h"
@ -462,9 +463,6 @@ void DoAVIOpen(const TCHAR* filename);
void DoAVIClose(int reason);
void RestoreGUIDisplay ();
void RestoreSNESDisplay ();
void FreezeUnfreezeDialog(bool8 freeze);
void FreezeUnfreezeSlot(int slot, bool8 freeze);
void FreezeUnfreeze (const char *filename, bool8 freeze);
void CheckDirectoryIsWritable (const char *filename);
static void CheckMenuStates ();
static void ResetFrameTimer ();
@ -2148,6 +2146,14 @@ LRESULT CALLBACK WinProc(
case ID_FILE_LOAD_FILE:
FreezeUnfreezeDialog(FALSE);
break;
case ID_FILE_LOAD_PREVIEW:
{
CSaveLoadWithPreviewDlg dlg;
int slot = dlg.show();
if(slot >= 0)
FreezeUnfreezeSlot(slot, FALSE);
break;
}
case ID_FILE_SAVE0:
FreezeUnfreezeSlot (0, TRUE);
break;
@ -2181,6 +2187,14 @@ LRESULT CALLBACK WinProc(
case ID_FILE_SAVE_FILE:
FreezeUnfreezeDialog(TRUE);
break;
case ID_FILE_SAVE_PREVIEW:
{
CSaveLoadWithPreviewDlg dlg(true);
int slot = dlg.show();
if(slot >= 0)
FreezeUnfreezeSlot(slot, TRUE);
break;
}
case ID_CHEAT_ENTER:
RestoreGUIDisplay ();
while (DialogBox(g_hInst, MAKEINTRESOURCE(IDD_CHEATER), hWnd, DlgCheater) == NC_SEARCHDB)
@ -3608,16 +3622,21 @@ void FreezeUnfreezeDialog(bool8 freeze)
}
}
void GetSlotFilename(int slot, char filename[_MAX_PATH + 1])
{
char ext[_MAX_EXT + 1];
if(slot == -1)
strcpy(ext, ".oops");
else
snprintf(ext, _MAX_EXT, ".%03d", slot);
strcpy(filename, S9xGetFilename(ext, SNAPSHOT_DIR));
}
void FreezeUnfreezeSlot(int slot, bool8 freeze)
{
char filename[_MAX_PATH + 1];
char ext[_MAX_EXT + 1];
if (slot == -1)
strcpy(ext, ".oops");
else
snprintf(ext, _MAX_EXT, ".%03d", slot);
strcpy(filename, S9xGetFilename(ext, SNAPSHOT_DIR));
GetSlotFilename(slot, filename);
FreezeUnfreeze(filename, freeze);
}
@ -3743,6 +3762,9 @@ static void CheckMenuStates ()
for (int i = ID_FILE_LOAD0; i <= ID_FILE_LOAD_FILE; i++)
SetMenuItemInfo(GUI.hMenu, i, FALSE, &mii);
SetMenuItemInfo(GUI.hMenu, ID_FILE_SAVE_PREVIEW, FALSE, &mii);
SetMenuItemInfo(GUI.hMenu, ID_FILE_LOAD_PREVIEW, FALSE, &mii);
SetMenuItemInfo (GUI.hMenu, ID_FILE_RESET, FALSE, &mii);
SetMenuItemInfo (GUI.hMenu, ID_CHEAT_ENTER, FALSE, &mii);
SetMenuItemInfo (GUI.hMenu, ID_CHEAT_SEARCH_MODAL, FALSE, &mii);

View File

@ -26,6 +26,7 @@
#include <dsound.h>
#endif
#include "rsrc/resource.h"
#include "port.h"
#define COUNT(a) (sizeof (a) / sizeof (a[0]))
#define MAX_AUDIO_NAME_LENGTH 1024
@ -458,5 +459,9 @@ int GetFilterScale(RenderFilter filterID);
bool GetFilterHiResSupport(RenderFilter filterID);
const TCHAR * S9xGetDirectoryT (enum s9x_getdirtype);
RECT GetWindowMargins(HWND hwnd, UINT width);
void GetSlotFilename(int slot, char filename[_MAX_PATH + 1]);
void FreezeUnfreezeSlot(int slot, bool8 freeze);
void FreezeUnfreezeDialog(bool8 freeze);
void FreezeUnfreeze(const char *filename, bool8 freeze);
#endif // !defined(SNES9X_H_INCLUDED)