📄 main.c
字号:
#include "shared.h"
#include "commctrl.h"
#include "state.h"
#include "dinput.h"
#include "vfw.h"
#include "stdio.h"
#include "resource.h"
#include "file.h"
#include "audio.h"
#include "input.h"
#include "main.h"
#include "zip.h"
#include "registry.h"
#include "modes.h"
static BMP Bmp;
static HWND hwnd;
static HINSTANCE hInstance;
static HMENU hMenu;
static BOOL RunEmulation = FALSE;
static BOOL Paused = FALSE;
static HANDLE Mutex = NULL;
static unsigned int USER_MESSAGE = 0;
unsigned char BitmapData[256 * 256 * 2];
static HBITMAP hBitmap = NULL;
static char GameName[MAX_PATH] = "";
static unsigned int Frame = 0;
static unsigned int LastTickCount = 0;
static BOOL RecordSound = FALSE;
static BOOL RecordingSound = FALSE;
static BOOL UseDirectDraw = FALSE;
static BOOL DirectDrawAvail= FALSE;
static unsigned int FrameTime[] = {0, 0, 0};
static unsigned int FrameTime60hz[] = {17, 17, 16};
static unsigned int FrameTime50hz[] = {20, 20, 20};
extern short pixel[];
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
WNDCLASS WindowClass;
MSG msg;
int QuitFlag = FALSE;
if (CreateSingleInstance(szCmdLine))
{
// Clear the window class structure
memset(&WindowClass, 0, sizeof(WindowClass));
// Set up window class attributes
WindowClass.style = CS_HREDRAW | CS_VREDRAW; // Window styles
WindowClass.lpfnWndProc = MainWindowProc; // Windows messaging function
WindowClass.hInstance = hInstance; // Application instance
WindowClass.hIcon = LoadIcon(hinstance, MAKEINTRESOURCE(IDI_ICON1)); // Icon to display on title bar
WindowClass.hCursor = LoadCursor(NULL, IDC_ARROW); // Cursor to use over window
WindowClass.hbrBackground = CreateSolidBrush(0); // Colour to use for window background
WindowClass.lpszMenuName = NULL; // Menu to use
WindowClass.lpszClassName = SMS_CLASS_NAME; // Class name
// Register window class
if (!RegisterClass(&WindowClass))
{
// Return unsuccessful
return FALSE;
}
InitRegistryEntries();
LoadRegistryEntries();
// Create the main window for our application
hInstance = hinstance;
hwnd = CreateWindowEx(0, // Extended window style
SMS_CLASS_NAME, // Pointer to registered class name
"SMS Plus", // Pointer to window name
WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, // Window style
0, // X Pos
0, // Y Pos
0, // Width
0, // Height
NULL, // Handle to parent or owner window
NULL, // Handle to menu, or child window
hInstance, // Application instance
NULL); // Pointer to window creation data
// Load the menu to use for the application and set it
hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MENU));
SetMenu(hwnd, hMenu);
InitVRAM();
InitAudio(hwnd, RegistryInfo.SoundFrequency, FREQ_60HZ);
InitInput(hwnd, hInstance);
DirectDrawAvail = InitModes();
if (DirectDrawAvail && RegistryInfo.EnableDirectDraw) UseDirectDraw = ChangeMode(RegistryInfo.FullScreenMode, RegistryInfo.FullScreen);
CheckMenuItem(hMenu, ID_MENU_CONFIG_SCREEN_SMOOTHING, RegistryInfo.ScreenSmoothing? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hMenu, ID_MENU_CONFIG_SOUND_ENABLE, RegistryInfo.EnableSound? MF_CHECKED : MF_UNCHECKED);
EnableMenuItem(hMenu, ID_MENU_CONFIG_SCREEN_FULL, UseDirectDraw? MF_BYCOMMAND | MF_ENABLED : MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem(hMenu, ID_MENU_CONFIG_SCREEN_SMOOTHING, UseDirectDraw? MF_BYCOMMAND | MF_ENABLED : MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem(hMenu, ID_MENU_CONFIG_SOUND_RECORD, RegistryInfo.EnableSound? MF_BYCOMMAND | MF_ENABLED : MF_BYCOMMAND | MF_GRAYED);
if ((!UseDirectDraw || !RegistryInfo.EnableDirectDraw) && (RegistryInfo.ScreenScale == 0))
{
RegistryInfo.ScreenScale = 1;
}
SetFrameTime(RegistryInfo.UpdateFrequency);
SetScreenScale(RegistryInfo.ScreenScale);
SetScreenSmoothing(RegistryInfo.ScreenSmoothing);
SetUpdateFrequency(RegistryInfo.UpdateFrequency);
SetFrameSkip(RegistryInfo.FrameSkip);
SetSoundFrequency(RegistryInfo.SoundFrequency);
SetRegion(RegistryInfo.Region);
CenterWindowInParent(hwnd);
ShowWindow(hwnd, SW_SHOW);
if (strlen(szCmdLine))
{
if (!stricmp(&szCmdLine[strlen(szCmdLine) - 2], "gg") ||
!stricmp(&szCmdLine[strlen(szCmdLine) - 3], "sms") ||
!stricmp(&szCmdLine[strlen(szCmdLine) - 3], ".zip"))
{
OpenROM(szCmdLine);
}
}
}
else
{
QuitFlag = TRUE;
}
// Main program loop
while (QuitFlag == FALSE)
{
unsigned int TickCount;
unsigned int Skip = (Frame % (RegistryInfo.FrameSkip + 1))? 1 : 0;
TickCount = GetTickCount();
if (LastTickCount == 0) LastTickCount = TickCount;
if (TickCount - LastTickCount >= FrameTime[Frame % 3])
{
// Auto frame skip
if (RegistryInfo.FrameSkip == 0)
{
if (TickCount - LastTickCount >= (FrameTime[Frame % 3] * 2)) Skip = TRUE;
}
if (RunEmulation && !Paused)
{
sms_frame(Skip);
if (RegistryInfo.EnableSound) UpdateAudio(snd.buffer, snd.bufsize, Frame);
if (!Skip)
{
UpdatePalette();
UpdateKeyboard();
UpdateSpecialKeys();
UpdateJoysticks();
UpdateRapidFire(Frame);
SendMessage(hwnd, WM_PAINT, 0, 0);
}
}
if ((TickCount - LastTickCount) >= (FrameTime[0] * (NO_OF_AUDIO_BUFFERS / 2)))
{
LastTickCount = 0;
Frame = 0;
}
else
{
LastTickCount = TickCount - ((TickCount - LastTickCount) - FrameTime[Frame % 3]);
Frame++;
}
}
else
{
if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
// GetMessage returning FALSE implies exit message
QuitFlag = TRUE;
}
}
}
}
SaveRegistryEntries();
TidyModes();
TidyInput();
TidyAudio();
system_shutdown();
if (hMenu) DestroyMenu(hMenu);
DestroySingleInstance();
return msg.wParam;
}
LRESULT CALLBACK MainWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
{
HDC hDC;
memset(&Bmp, 0, sizeof(BMP));
Bmp.BitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
Bmp.BitmapInfoHeader.biWidth = 256;
Bmp.BitmapInfoHeader.biHeight = 192;
Bmp.BitmapInfoHeader.biPlanes = 1;
Bmp.BitmapInfoHeader.biBitCount = 8;
Bmp.BitmapInfoHeader.biCompression = BI_RGB;
Bmp.BitmapInfoHeader.biClrUsed = 256;
hDC = GetDC(hwnd);
hBitmap = CreateDIBitmap(hDC, &Bmp.BitmapInfoHeader, 0, &BitmapData[0], (BITMAPINFO *)&Bmp, DIB_PAL_COLORS);
ReleaseDC(hwnd, hDC);
}
break;
case WM_SETFOCUS:
if (UseDirectDraw && RegistryInfo.EnableDirectDraw && FullScreenMode()) FlipToGDISurface(FALSE);
break;
case WM_KILLFOCUS:
if (UseDirectDraw && RegistryInfo.EnableDirectDraw && FullScreenMode()) FlipToGDISurface(TRUE);
break;
case WM_ACTIVATEAPP:
if (wParam)
{
Paused = FALSE;
// Restore Sync (+ Restart Audio)
Frame = 0;
LastTickCount = 0;
// Restore Input
InitInput(hwnd, hInstance);
}
else
{
Paused = TRUE;
StopAudio();
TidyInput();
}
break;
case WM_MOVE:
if (UseDirectDraw && RegistryInfo.EnableDirectDraw && !FullScreenMode()) UpdateModeWindowCoords(hwnd);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_MENU_FILE_OPEN:
SaveSRAM();
OpenROM(NULL);
break;
case ID_MENU_FILE_EXIT:
SendMessage(hwnd, WM_CLOSE, 0, 0);
break;
case ID_MENU_CPU_RESET:
SaveSRAM();
input.system = INPUT_HARD_RESET;
if (RecordSound) RecordingSound = TRUE;
break;
case ID_MENU_CPU_LOAD_STATE:
LoadState();
break;
case ID_MENU_CPU_SAVE_STATE:
SaveState();
break;
case ID_MENU_CONFIG_SCREEN_FULL:
SetScreenScale(RegistryInfo.ScreenScale = 0);
break;
case ID_MENU_CONFIG_SCREEN_X1:
SetScreenScale(RegistryInfo.ScreenScale = 1);
break;
case ID_MENU_CONFIG_SCREEN_X2:
SetScreenScale(RegistryInfo.ScreenScale = 2);
break;
case ID_MENU_CONFIG_SCREEN_X3:
SetScreenScale(RegistryInfo.ScreenScale = 3);
break;
case ID_MENU_CONFIG_UPDATE_50HZ:
SetUpdateFrequency(RegistryInfo.UpdateFrequency = FREQ_50HZ);
break;
case ID_MENU_CONFIG_UPDATE_60HZ:
SetUpdateFrequency(RegistryInfo.UpdateFrequency = FREQ_60HZ);
break;
case ID_MENU_CONFIG_SKIP_AUTO:
SetFrameSkip(RegistryInfo.FrameSkip = 0);
break;
case ID_MENU_CONFIG_SKIP_1:
SetFrameSkip(RegistryInfo.FrameSkip = 1);
break;
case ID_MENU_CONFIG_SKIP_2:
SetFrameSkip(RegistryInfo.FrameSkip = 2);
break;
case ID_MENU_CONFIG_SKIP_3:
SetFrameSkip(RegistryInfo.FrameSkip = 3);
break;
case ID_MENU_CONFIG_SKIP_4:
SetFrameSkip(RegistryInfo.FrameSkip = 4);
break;
case ID_MENU_CONFIG_SCREEN_SMOOTHING:
if (GetMenuState(hMenu, ID_MENU_CONFIG_SCREEN_SMOOTHING, MF_BYCOMMAND) == MF_CHECKED)
{
CheckMenuItem(hMenu, ID_MENU_CONFIG_SCREEN_SMOOTHING, MF_UNCHECKED);
SetScreenSmoothing(RegistryInfo.ScreenSmoothing = FALSE);
}
else
{
CheckMenuItem(hMenu, ID_MENU_CONFIG_SCREEN_SMOOTHING, MF_CHECKED);
SetScreenSmoothing(RegistryInfo.ScreenSmoothing = TRUE);
}
break;
case ID_MENU_CONFIG_SOUND_ENABLE:
if (GetMenuState(hMenu, ID_MENU_CONFIG_SOUND_ENABLE, MF_BYCOMMAND) == MF_CHECKED)
{
RegistryInfo.EnableSound = FALSE;
CheckMenuItem(hMenu, ID_MENU_CONFIG_SOUND_ENABLE, MF_UNCHECKED);
EnableMenuItem(hMenu, ID_MENU_CONFIG_SOUND_RECORD, MF_BYCOMMAND | MF_GRAYED);
}
else
{
RegistryInfo.EnableSound = TRUE;
CheckMenuItem(hMenu, ID_MENU_CONFIG_SOUND_ENABLE, MF_CHECKED);
EnableMenuItem(hMenu, ID_MENU_CONFIG_SOUND_RECORD, MF_BYCOMMAND | MF_ENABLED);
}
break;
case ID_MENU_CONFIG_SOUND_RECORD:
if (GetMenuState(hMenu, ID_MENU_CONFIG_SOUND_RECORD, MF_BYCOMMAND) == MF_CHECKED)
{
RecordSound = FALSE;
RecordingSound = FALSE;
CheckMenuItem(hMenu, ID_MENU_CONFIG_SOUND_RECORD, MF_UNCHECKED);
}
else
{
RecordSound = TRUE;
MessageBox(hwnd, "Sound will begin recording when the\nnext game is loaded, or the CPU is reset.", "Record sound output", MB_OK | MB_ICONEXCLAMATION);
CheckMenuItem(hMenu, ID_MENU_CONFIG_SOUND_RECORD, RecordSound? MF_CHECKED : MF_UNCHECKED);
}
break;
case ID_MENU_CONFIG_SOUND_44100:
SetSoundFrequency(RegistryInfo.SoundFrequency = 44100);
break;
case ID_MENU_CONFIG_SOUND_22050:
// Pick nearest divisible by 50 & 60
SetSoundFrequency(RegistryInfo.SoundFrequency = 22200);
break;
case ID_MENU_CONFIG_SOUND_11025:
// Pick nearest divisible by 50 & 60
SetSoundFrequency(RegistryInfo.SoundFrequency = 11100);
break;
case ID_MENU_CONFIG_REGION_JAPAN:
SetRegion(RegistryInfo.Region = sms.country = TYPE_DOMESTIC);
break;
case ID_MENU_CONFIG_REGION_EUROPEUS:
SetRegion(RegistryInfo.Region = sms.country = TYPE_OVERSEAS);
break;
case ID_MENU_CONFIG_CONTROLS:
DialogBox(hInstance, MAKEINTRESOURCE(IDD_CONTROLS), hwnd, ConfigureControlsProc);
TidyInput();
InitInput(hwnd, hInstance);
break;
case ID_MENU_CONFIG_SETTINGS:
DialogBox(hInstance, MAKEINTRESOURCE(IDD_SETTINGS), hwnd, SettingsProc);
break;
case ID_MENU_HELP_ABOUT:
DialogBox(hInstance, MAKEINTRESOURCE(IDD_ABOUT), hwnd, AboutProc);
break;
default:
return TRUE;
}
break;
case WM_ENTERMENULOOP:
{
char Filename[MAX_PATH];
int Found;
int AppendPos;
wsprintf(Filename, "%s%s", RegistryInfo.SaveStatePath, GetGameName());
Found = CountSaveStateFiles(Filename, &AppendPos);
EnableMenuItem(hMenu, ID_MENU_CPU_LOAD_STATE, Found? (MF_BYCOMMAND | MF_ENABLED) : (MF_BYCOMMAND | MF_GRAYED));
EnableMenuItem(hMenu, ID_MENU_CPU_SAVE_STATE, RunEmulation? (MF_BYCOMMAND | MF_ENABLED) : (MF_BYCOMMAND | MF_GRAYED));
StopAudio();
if (UseDirectDraw && RegistryInfo.EnableDirectDraw && FullScreenMode()) FlipToGDISurface(TRUE);
}
break;
case WM_EXITMENULOOP:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -