|
|
@ -50,23 +50,24 @@ |
|
|
|
/** Height of the canvas. */ |
|
|
|
#define WND_Y_EXTENTS (NUM_ROWS * LED_EXTENT) |
|
|
|
|
|
|
|
|
|
|
|
/* string constants */ |
|
|
|
LPCSTR g_strWindowClass = "BorgSimulatorWindowClass"; |
|
|
|
LPCSTR g_strWindowTitle = "Borg Simulator"; |
|
|
|
|
|
|
|
LPCSTR g_strError = "Error"; |
|
|
|
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."; |
|
|
|
LPCSTR g_strErr = "Error"; |
|
|
|
LPCSTR g_strErrTimerResolution = "Could not retrieve minimum timer resolution."; |
|
|
|
LPCSTR g_strErrRegisterWindow = "Could not register window class."; |
|
|
|
LPCSTR g_strErrCreateWindow = "Could not create window."; |
|
|
|
LPCSTR g_strErrCreateEvent = "Could not create wait event."; |
|
|
|
LPCSTR g_strErrCreateThread = "Could not create display loop thread."; |
|
|
|
LPCSTR g_strErrCreateUITimer = "Could not create UI Timer."; |
|
|
|
|
|
|
|
/** Minimum timer resolution the system is capable of. */ |
|
|
|
UINT g_uResolution; |
|
|
|
|
|
|
|
/** Event object for the multimedia timer (wait() function). */ |
|
|
|
HANDLE g_hWaitEvent; |
|
|
|
|
|
|
|
|
|
|
|
/** Fake port for simulating joystick input. */ |
|
|
|
volatile unsigned char fakeport; |
|
|
|
/** Flag which indicates if wait should jump to the menu if fire is pressed. */ |
|
|
@ -82,7 +83,6 @@ LRESULT CALLBACK simWndProc(HWND hWnd, |
|
|
|
WPARAM wParam, |
|
|
|
LPARAM lParam); |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a new window and makes it visible. |
|
|
|
* @param hInstance Handle of the instance where this window should belong to. |
|
|
@ -133,13 +133,12 @@ HWND simCreateWindow(HINSTANCE hInstance, |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
fprintf(stderr, g_strErrorRegisterWindow); |
|
|
|
fprintf(stderr, g_strErrRegisterWindow); |
|
|
|
} |
|
|
|
|
|
|
|
return hWnd; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Closes windows and unregisters its associated window class. |
|
|
|
* @param lphWnd Pointer to window handle. |
|
|
@ -152,7 +151,6 @@ void simDestroyWindow(HWND hWnd, |
|
|
|
UnregisterClassA(g_strWindowClass, hInstance); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Draws the LED matrix on the given device context. |
|
|
|
* @param hdc The device context where the LED matrix should be drawn on. |
|
|
@ -216,7 +214,6 @@ void simDrawMatrix(HDC hdc) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieves device context from given window, creates a compatible memory |
|
|
|
* device context for double buffering and hands that thing over to |
|
|
@ -411,7 +408,6 @@ LRESULT CALLBACK simWndProc(HWND hWnd, |
|
|
|
return lResult; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Entry point for starting the the display loop in a thread. |
|
|
|
* @param lpParam Free style arguments for the thread function (not used here). |
|
|
@ -423,19 +419,36 @@ DWORD WINAPI simLoop(LPVOID lpParam) |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieves and enforces the minimum timer resolution of the current system. |
|
|
|
* @return Result of the multimedia timer operations. |
|
|
|
*/ |
|
|
|
MMRESULT simSetMinimumTimerResolution() |
|
|
|
{ |
|
|
|
TIMECAPS tc; |
|
|
|
MMRESULT mmresult; |
|
|
|
|
|
|
|
mmresult = timeGetDevCaps(&tc, sizeof(tc)); |
|
|
|
if (mmresult == TIMERR_NOERROR) |
|
|
|
{ |
|
|
|
/* retrieve best resolution and configure timer services accordingly */ |
|
|
|
g_uResolution = min(max(tc.wPeriodMin, 0), tc.wPeriodMax); |
|
|
|
mmresult = timeBeginPeriod(g_uResolution); |
|
|
|
} |
|
|
|
|
|
|
|
return mmresult; |
|
|
|
} |
|
|
|
|
|
|
|
/**
|
|
|
|
* Wait function which utilizes multimedia timers and thread synchronization |
|
|
|
* objects. Although this is much more complicated than calling the Sleep() |
|
|
|
* function, it is also much more precise. |
|
|
|
* @param ms The requested delay in milliseconds. |
|
|
|
* @param uResolution The minimum timer resolution the system is capable of. |
|
|
|
*/ |
|
|
|
void wait(int ms) |
|
|
|
{ |
|
|
|
TIMECAPS tc; |
|
|
|
MMRESULT mmresult; |
|
|
|
MMRESULT mmTimerEventId; |
|
|
|
UINT uResolution; |
|
|
|
|
|
|
|
/* check if fire button is pressed (and if it is, jump to the menu) */ |
|
|
|
if (waitForFire) |
|
|
@ -446,17 +459,8 @@ void wait(int ms) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* retrieve timer resolution capabilities of the current system */ |
|
|
|
mmresult = timeGetDevCaps(&tc, sizeof(tc)); |
|
|
|
if (mmresult == TIMERR_NOERROR) |
|
|
|
{ |
|
|
|
/* retrieve best resolution and configure timer services accordingly */ |
|
|
|
uResolution = min(max(tc.wPeriodMin, 0), tc.wPeriodMax); |
|
|
|
mmresult = timeBeginPeriod(uResolution); |
|
|
|
if (mmresult == TIMERR_NOERROR) |
|
|
|
{ |
|
|
|
/* actually retrieve a multimedia timer */ |
|
|
|
mmTimerEventId = timeSetEvent(ms, uResolution, g_hWaitEvent, 0, |
|
|
|
/* retrieve a multimedia timer */ |
|
|
|
mmTimerEventId = timeSetEvent(ms, g_uResolution, g_hWaitEvent, 0, |
|
|
|
TIME_ONESHOT | TIME_CALLBACK_EVENT_SET); |
|
|
|
if (mmTimerEventId != 0) |
|
|
|
{ |
|
|
@ -467,13 +471,7 @@ void wait(int ms) |
|
|
|
/* relieve the timer from its duties */ |
|
|
|
timeKillEvent(mmTimerEventId); |
|
|
|
} |
|
|
|
|
|
|
|
/* relax timer service constraints */ |
|
|
|
timeEndPeriod (uResolution); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Main function of the windows simulator. |
|
|
@ -495,6 +493,9 @@ int APIENTRY WinMain(HINSTANCE hInstance, |
|
|
|
int nExitCode = 0; |
|
|
|
|
|
|
|
if ((hWnd = simCreateWindow(hInstance, nCmdShow)) != NULL) |
|
|
|
{ |
|
|
|
/* retrieve minimum timer resolution */ |
|
|
|
if (simSetMinimumTimerResolution() == TIMERR_NOERROR) |
|
|
|
{ |
|
|
|
/* event handle for multimedia timer (for the wait() function) */ |
|
|
|
g_hWaitEvent = CreateEventA(NULL, TRUE, FALSE, "Local\\WaitEvent"); |
|
|
@ -504,7 +505,8 @@ int APIENTRY WinMain(HINSTANCE hInstance, |
|
|
|
hLoopThread = CreateThread(NULL, 0, simLoop, NULL, 0, NULL); |
|
|
|
if (hLoopThread != NULL) |
|
|
|
{ |
|
|
|
SetThreadPriority(hLoopThread, THREAD_PRIORITY_TIME_CRITICAL); |
|
|
|
SetThreadPriority(hLoopThread, |
|
|
|
THREAD_PRIORITY_TIME_CRITICAL); |
|
|
|
|
|
|
|
/* issue a UI timer message every 40 ms (roughly 25 fps) */ |
|
|
|
uTimerId = SetTimer(hWnd, 23, 40, NULL); |
|
|
@ -522,14 +524,14 @@ int APIENTRY WinMain(HINSTANCE hInstance, |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
fprintf(stderr, g_strErrorCreateUITimer); |
|
|
|
fprintf(stderr, g_strErrCreateUITimer); |
|
|
|
} |
|
|
|
|
|
|
|
TerminateThread(hLoopThread, 0); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
fprintf(stderr, g_strErrorCreateThread); |
|
|
|
fprintf(stderr, g_strErrCreateThread); |
|
|
|
} |
|
|
|
|
|
|
|
/* relieve wait event object from its duties */ |
|
|
@ -537,14 +539,22 @@ int APIENTRY WinMain(HINSTANCE hInstance, |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
fprintf(stderr, g_strErrorCreateEvent); |
|
|
|
fprintf(stderr, g_strErrCreateEvent); |
|
|
|
} |
|
|
|
|
|
|
|
/* relieve timer resolution constraints */ |
|
|
|
timeEndPeriod(g_uResolution); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
fprintf(stderr, g_strErrTimerResolution); |
|
|
|
} |
|
|
|
|
|
|
|
simDestroyWindow(hWnd, hInstance); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
fprintf(stderr, g_strErrorCreateWindow); |
|
|
|
fprintf(stderr, g_strErrCreateWindow); |
|
|
|
} |
|
|
|
|
|
|
|
return nExitCode; |
|
|
|