Skip to content

Instantly share code, notes, and snippets.

@dwilliamson
Created February 11, 2018 14:49
Show Gist options
  • Save dwilliamson/2262f68021cb71ef37530c5e8678f39f to your computer and use it in GitHub Desktop.
Save dwilliamson/2262f68021cb71ef37530c5e8678f39f to your computer and use it in GitHub Desktop.
Old K-Libs game engine snippet
/*
===============================================================================================
K-Libs, Kernel, WINMAIN.C
-------------------------------------
by Don Williamson, 1999
===============================================================================================
*/
#include <windows.h>
#include "types.h"
#include "resource.h"
#include "utility.h"
#include "memory.h"
#include "timing.h"
#define kMSGLOOP_THREAD 1
#define kMSGLOOP_NORMAL 2
#define kMSGLOOP_POLLED 4
extern uBYTE kSetupMessageLoop(void);
/* --- Private variables --- */
static uBYTE message_loop;
static LPSTR lpCmdGlobal;
static int nShowGlobal;
static HANDLE hThread;
static DWORD nThreadId;
static volatile uBYTE ThreadReady = 0;
/* --- Global variables --- */
HINSTANCE kInstance = 0;
HWND khWnd = 0;
LPSTR kClassName = "K-Lib Class";
int (*main_function)(int argc, char **argv) = NULL;
long (*message_handler)(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) = NULL;
int (*main_loop)(void) = NULL;
void (*abnormal_exit)(void) = NULL;
void (*normal_exit)(void) = NULL;
int (*main_init)(void) = NULL;
/*
==================================================================================================
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Globally used functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
==================================================================================================
*/
long WINAPI MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// Check to see if there is a user-defined message handling function
if (message_handler)
{
long retval;
// The function should return TRUE if the message was processed
retval = message_handler(hWnd, message, wParam, lParam);
if (retval) return (0L);
}
// Decide what to do with the message
switch (message)
{
case (WM_COMMAND):
return (0L);
// Handle the X click to close a window
case (WM_CLOSE):
SendMessage(khWnd, WM_DESTROY, 0, 0);
return (0L);
// Return 0 to the message loop to terminate it
case (WM_DESTROY):
PostQuitMessage(0);
return (0L);
}
// Message has not been catered for so pass onto the default window procedure
return (DefWindowProc(hWnd, message, wParam, lParam));
}
static int InitApplication(void)
{
WNDCLASS wc;
// Setup the needed window class
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(kInstance, NULL);
wc.hInstance = kInstance;
wc.lpfnWndProc = MainWndProc;
wc.lpszClassName = kClassName;
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;
// Attempt to register the class with windows
if (!RegisterClass(&wc)) return (kFALSE);
// Create the application window
khWnd = CreateWindowEx(0, kClassName, kClassName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, kInstance, NULL);
if (khWnd == NULL) return (kFALSE);
// Update the window
UpdateWindow(khWnd);
ShowWindow(khWnd, nShowGlobal);
return (kTRUE);
}
/*
==================================================================================================
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Thread message loop functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
==================================================================================================
*/
DWORD WINAPI ThreadMessageLoop(LPVOID parameter)
{
MSG message;
// Create the window in this thread and continue if successful
if (InitApplication())
{
// Flag that the application can continue processing
ThreadReady = 1;
// Loop infinitely
while (1)
{
// Check to see if there is a message in the queue
if (PeekMessage(&message, NULL, 0, 0, PM_NOREMOVE))
{
// Terminate thread if application message queue terminates
if (!GetMessage(&message, NULL, 0, 0)) return (kTRUE);
// Translate accelerators and pass everything onto the message loop
TranslateMessage(&message);
DispatchMessage(&message);
}
// If not, sit idle until one occurs
else
{
WaitMessage();
}
}
}
// Even though it is not ready, avoid a crashing infinite loop
ThreadReady = 1;
return (kFALSE);
}
int ExecuteApplication_Thread(void)
{
int retval = kFALSE;
// Create the message loop's host thread
hThread = CreateThread(NULL, 0, (LPVOID)&ThreadMessageLoop, NULL, 0, &nThreadId);
if (hThread == NULL) return (kFALSE);
// Wait until the thread creates the application window
while (!ThreadReady) { }
// If a "main" function exists, call it to enter the application
if (main_function)
retval = main_function(__argc, __argv);
// Tell the thread message loop to destroy itself and the window
SendMessage(khWnd, WM_DESTROY, 0, 0);
CloseHandle(hThread);
return (retval);
}
/*
==================================================================================================
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Normal message loop functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
==================================================================================================
*/
int ExecuteApplication_Normal(void)
{
MSG message;
int retval = kFALSE;
// Create the window
if (!InitApplication()) return (kFALSE);
// Execute the init function if one exists
if (main_init)
if (!main_init()) SendMessage(khWnd, WM_DESTROY, 0, 0);
// Loop infinitely
while (1)
{
// Check to see if there are any messages waiting in the queue
if (PeekMessage(&message, NULL, 0, 0, PM_NOREMOVE))
{
// Terminate loop if application message queue terminates
if (!GetMessage(&message, NULL, 0, 0)) return (kTRUE);
// Translate accelerators and pass everything onto the message loop
TranslateMessage(&message);
DispatchMessage(&message);
}
else
{
// If there is a "main_loop" function, call it
if (main_loop)
{
// The "main_loop" function should return FALSE to abort the application
retval = main_loop();
if (retval == 0) SendMessage(khWnd, WM_DESTROY, 0, 0);
}
}
}
return (retval);
}
/*
==================================================================================================
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Polled message loop functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
==================================================================================================
*/
void kPollMessageQueue(void)
{
MSG message;
// Continuously remove all messages until there are none left
while (PeekMessage(&message, khWnd, 0, 0, PM_REMOVE))
{
// Translate accelerators and pass everything onto the message handler
TranslateMessage(&message);
DispatchMessage(&message);
}
}
int ExecuteApplication_Polled(void)
{
int retval = kFALSE;
// Create the application window
if (!InitApplication()) return (kFALSE);
// If a main function exists, call it to enter the application
if (main_function)
retval = main_function(__argc, __argv);
// Destroy the application window
SendMessage(khWnd, WM_DESTROY, 0, 0);
kPollMessageQueue();
return (retval);
}
/*
==================================================================================================
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> WINMAIN <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
==================================================================================================
*/
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
int retval = kFALSE;
// Initialise the K-Lib memory sub-system
if (kInitAllMemory() == kFALSE)
return (kFALSE);
// Obtain the message loop type and quit if required
if ((message_loop = kSetupMessageLoop()) == 0)
{
kCloseAllMemory();
return (kFALSE);
}
// Setup the needed global variables
lpCmdGlobal = lpCmdLine;
nShowGlobal = nCmdShow;
kInstance = hInstance;
// Execute the first block of code unconditionally
__try
{
// Decide where to further the application and it's resources
if (message_loop == kMSGLOOP_THREAD) retval = ExecuteApplication_Thread();
if (message_loop == kMSGLOOP_NORMAL) retval = ExecuteApplication_Normal();
if (message_loop == kMSGLOOP_POLLED) retval = ExecuteApplication_Polled();
}
// The next block is called normally or if an exception occurs
__finally
{
if (AbnormalTermination())
{
// Call the user defined abnormal termination function if one exists
if (abnormal_exit)
abnormal_exit();
}
// Call the user defined normal termination function if one exists
if (normal_exit)
normal_exit();
// Shut down all resources
CloseUtil();
}
// Destroy all created timers
kDestroyAllTimers();
// Shutdown the K-Lib memory sub-system
kCloseAllMemory();
return (retval);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment