|
|
@ -55,8 +55,11 @@ LPCSTR g_strWindowClass = "BorgSimulatorWindowClass"; |
|
|
|
LPCSTR g_strWindowTitle = "Borg Simulator"; |
|
|
|
|
|
|
|
LPCSTR g_strError = "Error"; |
|
|
|
LPCSTR g_strErrorRegisterWindow = "Error: Could not register window class."; |
|
|
|
LPCSTR g_strErrorCreateWindow = "Error: Could not create window."; |
|
|
|
LPCSTR g_strErrorRegisterWindow = "Could not register window class."; |
|
|
|
LPCSTR g_strErrorCreateWindow = "Could not create window."; |
|
|
|
LPCSTR g_strErrorCreateEvent = "Could not create wait event."; |
|
|
|
LPCSTR g_strErrorCreateThread = "Could not create display loop thread."; |
|
|
|
LPCSTR g_strErrorCreateUITimer = "Could not create UI Timer."; |
|
|
|
|
|
|
|
|
|
|
|
/** Event object for the multimedia timer (wait() function). */ |
|
|
@ -114,21 +117,27 @@ BOOL simCreateWindow(HWND *lphWnd, |
|
|
|
HINSTANCE hInstance, |
|
|
|
int nCmdShow) |
|
|
|
{ |
|
|
|
BOOL bSuccess = FALSE; |
|
|
|
|
|
|
|
/* ensure that the client area has the right proportions */ |
|
|
|
RECT rectMin = {0, 0, WND_X_EXTENTS * 1.5 - 1, WND_Y_EXTENTS * 1.5 - 1}; |
|
|
|
AdjustWindowRect(&rectMin, WS_OVERLAPPEDWINDOW & ~(WS_OVERLAPPED), FALSE); |
|
|
|
|
|
|
|
/* create window and retrieve its handle */ |
|
|
|
*lphWnd = CreateWindow(g_strWindowClass, g_strWindowTitle, |
|
|
|
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, |
|
|
|
WND_X_EXTENTS * 2, WND_Y_EXTENTS * 2, HWND_DESKTOP, |
|
|
|
NULL, hInstance, NULL); |
|
|
|
rectMin.right - rectMin.left, rectMin.bottom - rectMin.top, |
|
|
|
HWND_DESKTOP, NULL, hInstance, NULL); |
|
|
|
|
|
|
|
/* mske it visible */ |
|
|
|
/* make it visible */ |
|
|
|
if (*lphWnd != NULL) |
|
|
|
{ |
|
|
|
ShowWindow(*lphWnd, nCmdShow); |
|
|
|
UpdateWindow(*lphWnd); |
|
|
|
return TRUE; |
|
|
|
bSuccess = TRUE; |
|
|
|
} |
|
|
|
|
|
|
|
return FALSE; |
|
|
|
return bSuccess; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -201,8 +210,8 @@ void simDisplay(HWND hWnd) |
|
|
|
/* retrieve window dimensions */ |
|
|
|
if (GetClientRect(hWnd, &rect)) |
|
|
|
{ |
|
|
|
int const cx = rect.right - rect.left; |
|
|
|
int const cy = rect.bottom - rect.top; |
|
|
|
int const cx = rect.right; |
|
|
|
int const cy = rect.bottom; |
|
|
|
|
|
|
|
/* retrieve device context */ |
|
|
|
if ((hdc = GetDC(hWnd)) != NULL) |
|
|
@ -225,7 +234,7 @@ void simDisplay(HWND hWnd) |
|
|
|
hBmp = CreateCompatibleBitmap(hdc, cx, cy); |
|
|
|
if (hBmp != NULL) |
|
|
|
{ |
|
|
|
/* ...and selct that into that DC */ |
|
|
|
/* ...and select that into that DC */ |
|
|
|
hOldBmp = (HBITMAP)SelectObject(hMemDc, hBmp); |
|
|
|
|
|
|
|
/* finally *sigh* draw the LED matrix */ |
|
|
@ -257,17 +266,30 @@ LRESULT CALLBACK simWndProc(HWND hWnd, |
|
|
|
WPARAM wParam, |
|
|
|
LPARAM lParam) |
|
|
|
{ |
|
|
|
LRESULT lResult = 0; |
|
|
|
PAINTSTRUCT ps; |
|
|
|
HDC hdc; |
|
|
|
LPMINMAXINFO lpminmax; |
|
|
|
|
|
|
|
/* minimum size of the window's client area */ |
|
|
|
RECT rectMin = {0, 0, WND_X_EXTENTS - 1, WND_Y_EXTENTS - 1}; |
|
|
|
|
|
|
|
switch (msg) |
|
|
|
{ |
|
|
|
/* enforce minimum window size */ |
|
|
|
case WM_GETMINMAXINFO: |
|
|
|
/* minimum size applies to client area */ |
|
|
|
AdjustWindowRect(&rectMin, GetWindowLongA(hWnd, GWL_STYLE), |
|
|
|
GetMenu(hWnd) != NULL); |
|
|
|
|
|
|
|
/* actually set minimum and maximum size */ |
|
|
|
lpminmax = (LPMINMAXINFO)lParam; |
|
|
|
lpminmax->ptMinTrackSize.x = WND_X_EXTENTS * 2; |
|
|
|
lpminmax->ptMinTrackSize.y = WND_Y_EXTENTS * 2; |
|
|
|
lpminmax->ptMinTrackSize.x = rectMin.right - rectMin.left; |
|
|
|
lpminmax->ptMinTrackSize.y = rectMin.bottom - rectMin.top; |
|
|
|
lpminmax->ptMaxTrackSize.x = GetSystemMetrics(SM_CXMAXTRACK); |
|
|
|
lpminmax->ptMaxTrackSize.y = GetSystemMetrics(SM_CYMAXTRACK); |
|
|
|
lpminmax->ptMaxSize.x = GetSystemMetrics(SM_CXMAXTRACK); |
|
|
|
lpminmax->ptMaxSize.y = GetSystemMetrics(SM_CYMAXTRACK); |
|
|
|
break; |
|
|
|
|
|
|
|
/* paint window contents */ |
|
|
@ -310,7 +332,7 @@ LRESULT CALLBACK simWndProc(HWND hWnd, |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
return DefWindowProcA(hWnd, msg, wParam, lParam); |
|
|
|
lResult = DefWindowProcA(hWnd, msg, wParam, lParam); |
|
|
|
break; |
|
|
|
} |
|
|
|
break; |
|
|
@ -340,7 +362,7 @@ LRESULT CALLBACK simWndProc(HWND hWnd, |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
return DefWindowProcA(hWnd, msg, wParam, lParam); |
|
|
|
lResult = DefWindowProcA(hWnd, msg, wParam, lParam); |
|
|
|
break; |
|
|
|
} |
|
|
|
break; |
|
|
@ -348,6 +370,7 @@ LRESULT CALLBACK simWndProc(HWND hWnd, |
|
|
|
/* refresh the LED matrix every 40 ms */ |
|
|
|
case WM_TIMER: |
|
|
|
simDisplay(hWnd); |
|
|
|
UpdateWindow(hWnd); |
|
|
|
break; |
|
|
|
|
|
|
|
/* quit application */ |
|
|
@ -357,11 +380,11 @@ LRESULT CALLBACK simWndProc(HWND hWnd, |
|
|
|
|
|
|
|
/* Windows' default handler */ |
|
|
|
default: |
|
|
|
return DefWindowProcA(hWnd, msg, wParam, lParam); |
|
|
|
lResult = DefWindowProcA(hWnd, msg, wParam, lParam); |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
return lResult; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -391,8 +414,10 @@ void wait(int ms) |
|
|
|
UINT uResolution; |
|
|
|
|
|
|
|
/* check if fire button is pressed (and if it is, jump to the menu) */ |
|
|
|
if (waitForFire) { |
|
|
|
if (fakeport & 0x01) { |
|
|
|
if (waitForFire) |
|
|
|
{ |
|
|
|
if (fakeport & 0x01) |
|
|
|
{ |
|
|
|
longjmp(newmode_jmpbuf, 43); |
|
|
|
} |
|
|
|
} |
|
|
@ -407,12 +432,13 @@ void wait(int ms) |
|
|
|
if (mmresult == TIMERR_NOERROR) |
|
|
|
{ |
|
|
|
/* actually retrieve a multimedia timer */ |
|
|
|
mmTimerEventId = timeSetEvent(ms, uResolution, g_hWaitEvent, NULL, |
|
|
|
TIME_ONESHOT | TIME_CALLBACK_EVENT_PULSE); |
|
|
|
if (mmTimerEventId != NULL) |
|
|
|
mmTimerEventId = timeSetEvent(ms, uResolution, g_hWaitEvent, 0, |
|
|
|
TIME_ONESHOT | TIME_CALLBACK_EVENT_SET); |
|
|
|
if (mmTimerEventId != 0) |
|
|
|
{ |
|
|
|
/* now halt until that timer pulses our wait event object */ |
|
|
|
WaitForSingleObject(g_hWaitEvent, INFINITE); |
|
|
|
ResetEvent(g_hWaitEvent); |
|
|
|
|
|
|
|
/* relieve the timer from its duties */ |
|
|
|
timeKillEvent(mmTimerEventId); |
|
|
@ -441,58 +467,79 @@ int APIENTRY WinMain(HINSTANCE hInstance, |
|
|
|
WNDCLASS wc; |
|
|
|
HWND hWnd; |
|
|
|
MSG msg; |
|
|
|
HANDLE hThread; |
|
|
|
HANDLE hLoopThread; |
|
|
|
UINT_PTR uTimerId; |
|
|
|
int nExitCode = 0; |
|
|
|
|
|
|
|
/* regster window class (with nice black background!) */ |
|
|
|
/* register window class (with nice black background!) and create window */ |
|
|
|
if (simRegisterWindowClass(&wc, hInstance)) |
|
|
|
{ |
|
|
|
/* actually create the window and make it visible */ |
|
|
|
if (simCreateWindow(&hWnd, hInstance, nCmdShow)) |
|
|
|
{ |
|
|
|
/* event handle for multimedia timer (for the wait() function) */ |
|
|
|
g_hWaitEvent = CreateEventA(NULL, FALSE, FALSE, "Local\\WaitEvent"); |
|
|
|
g_hWaitEvent = CreateEventA(NULL, TRUE, FALSE, "Local\\WaitEvent"); |
|
|
|
if (g_hWaitEvent != NULL) |
|
|
|
{ |
|
|
|
/* start the display loop thread */ |
|
|
|
hThread = CreateThread(NULL, 0, simLoop, NULL, 0, NULL); |
|
|
|
if (hThread != NULL) |
|
|
|
hLoopThread = CreateThread(NULL, 0, simLoop, NULL, 0, NULL); |
|
|
|
if (hLoopThread != NULL) |
|
|
|
{ |
|
|
|
/* ensure that the display loop stays responsive */ |
|
|
|
SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST); |
|
|
|
SetThreadPriority(hLoopThread, THREAD_PRIORITY_HIGHEST); |
|
|
|
|
|
|
|
/* issue a UI timer message every 40 ms (roughly 25 fps) */ |
|
|
|
/* NOTE: this has nothing to do with the multimedia timer */ |
|
|
|
uTimerId = SetTimer(hWnd, 23, 40, NULL); |
|
|
|
if (uTimerId != NULL) |
|
|
|
if (uTimerId != 0) |
|
|
|
{ |
|
|
|
/* standard Windows(R) message loop */ |
|
|
|
/* (runs as long as the window hasn't been closed) */ |
|
|
|
while (GetMessageA(&msg, NULL, 0, 0)) |
|
|
|
{ |
|
|
|
TranslateMessage(&msg); |
|
|
|
DispatchMessageA(&msg); |
|
|
|
} |
|
|
|
nExitCode = msg.wParam; |
|
|
|
|
|
|
|
/* remove that UI timer */ |
|
|
|
KillTimer(hWnd, uTimerId); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
MessageBoxA(HWND_DESKTOP, g_strErrorCreateUITimer, |
|
|
|
g_strError, MB_OK | MB_ICONERROR); |
|
|
|
} |
|
|
|
|
|
|
|
/* stop the display loop */ |
|
|
|
TerminateThread(hThread, 0); |
|
|
|
TerminateThread(hLoopThread, 0); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
MessageBoxA(HWND_DESKTOP, g_strErrorCreateThread, |
|
|
|
g_strError, MB_OK | MB_ICONERROR); |
|
|
|
} |
|
|
|
|
|
|
|
/* relieve wait event object from its duties */ |
|
|
|
CloseHandle(g_hWaitEvent); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
MessageBoxA(HWND_DESKTOP, g_strErrorCreateEvent, |
|
|
|
g_strError, MB_OK | MB_ICONERROR); |
|
|
|
} |
|
|
|
|
|
|
|
return msg.wParam; |
|
|
|
DestroyWindow(hWnd); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
MessageBoxA(HWND_DESKTOP, g_strErrorCreateWindow, |
|
|
|
g_strError, MB_OK | MB_ICONERROR); |
|
|
|
} |
|
|
|
MessageBoxA(HWND_DESKTOP, g_strErrorCreateWindow, g_strError, MB_OK); |
|
|
|
|
|
|
|
UnregisterClassA(g_strWindowClass, hInstance); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
MessageBoxA(HWND_DESKTOP, g_strErrorRegisterWindow, |
|
|
|
g_strError, MB_OK | MB_ICONERROR); |
|
|
|
} |
|
|
|
MessageBoxA(HWND_DESKTOP, g_strErrorRegisterWindow, g_strError, MB_OK); |
|
|
|
|
|
|
|
return 0; |
|
|
|
return nExitCode; |
|
|
|
} |
|
|
|
|
|
|
|
/*@}*/ |
|
|
|