234 lines
5.5 KiB
C++
234 lines
5.5 KiB
C++
#include "Framework.h"
|
|
|
|
#define DEFAULT_FRAMERATE 60
|
|
#define DEFAULT_WIDTH 800
|
|
#define DEFAULT_HEIGHT 600
|
|
|
|
// Reference to ourselves - primarily used to access the message handler correctly
|
|
// This is initialised in the constructor
|
|
Framework * _thisFramework = NULL;
|
|
|
|
// Forward declaration of our window procedure
|
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
|
|
|
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
|
|
_In_opt_ HINSTANCE hPrevInstance,
|
|
_In_ LPWSTR lpCmdLine,
|
|
_In_ int nCmdShow)
|
|
{
|
|
UNREFERENCED_PARAMETER(hPrevInstance);
|
|
UNREFERENCED_PARAMETER(lpCmdLine);
|
|
|
|
// We can only run if an instance of a class that inherits from Framework
|
|
// has been created
|
|
if (_thisFramework)
|
|
{
|
|
return _thisFramework->Run(hInstance, nCmdShow);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
Framework::Framework() : Framework(DEFAULT_WIDTH, DEFAULT_HEIGHT)
|
|
{
|
|
}
|
|
|
|
Framework::Framework(unsigned int width, unsigned int height)
|
|
{
|
|
_thisFramework = this;
|
|
_width = width;
|
|
_height = height;
|
|
}
|
|
|
|
Framework::~Framework()
|
|
{
|
|
}
|
|
|
|
int Framework::Run(HINSTANCE hInstance, int nCmdShow)
|
|
{
|
|
int returnValue;
|
|
|
|
_hInstance = hInstance;
|
|
if (!InitialiseMainWindow(nCmdShow))
|
|
{
|
|
return -1;
|
|
}
|
|
returnValue = MainLoop();
|
|
Shutdown();
|
|
return returnValue;
|
|
}
|
|
|
|
// Main program loop.
|
|
|
|
int Framework::MainLoop()
|
|
{
|
|
MSG msg;
|
|
HACCEL hAccelTable = LoadAccelerators(_hInstance, MAKEINTRESOURCE(IDC_GRAPHICS2));
|
|
LARGE_INTEGER counterFrequency;
|
|
LARGE_INTEGER nextTime;
|
|
LARGE_INTEGER currentTime;
|
|
LARGE_INTEGER lastTime;
|
|
bool updateFlag = true;
|
|
|
|
// Initialise timer
|
|
QueryPerformanceFrequency(&counterFrequency);
|
|
DWORD msPerFrame = (DWORD)(counterFrequency.QuadPart / DEFAULT_FRAMERATE);
|
|
double timeFactor = 1.0 / counterFrequency.QuadPart;
|
|
QueryPerformanceCounter(&nextTime);
|
|
lastTime = nextTime;
|
|
|
|
// Main message loop:
|
|
msg.message = WM_NULL;
|
|
while (msg.message != WM_QUIT)
|
|
{
|
|
if (updateFlag)
|
|
{
|
|
QueryPerformanceCounter(¤tTime);
|
|
_timeSpan = (currentTime.QuadPart - lastTime.QuadPart) * timeFactor;
|
|
lastTime = currentTime;
|
|
Update();
|
|
updateFlag = false;
|
|
}
|
|
QueryPerformanceCounter(¤tTime);
|
|
// Is it time to render the frame?
|
|
if (currentTime.QuadPart > nextTime.QuadPart)
|
|
{
|
|
Render();
|
|
// Set time for next frame
|
|
nextTime.QuadPart += msPerFrame;
|
|
// If we get more than a frame ahead, allow one to be dropped
|
|
// Otherwise, we will never catch up if we let the error accumulate
|
|
// and message handling will suffer
|
|
if (nextTime.QuadPart < currentTime.QuadPart)
|
|
{
|
|
nextTime.QuadPart = currentTime.QuadPart + msPerFrame;
|
|
}
|
|
updateFlag = true;
|
|
}
|
|
else
|
|
{
|
|
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
|
|
{
|
|
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return (int)msg.wParam;
|
|
}
|
|
|
|
// Register the window class, create the window and
|
|
// create the bitmap that we will use for rendering
|
|
|
|
bool Framework::InitialiseMainWindow(int nCmdShow)
|
|
{
|
|
#define MAX_LOADSTRING 100
|
|
|
|
WCHAR windowTitle[MAX_LOADSTRING];
|
|
WCHAR windowClass[MAX_LOADSTRING];
|
|
|
|
LoadStringW(_hInstance, IDS_APP_TITLE, windowTitle, MAX_LOADSTRING);
|
|
LoadStringW(_hInstance, IDC_GRAPHICS2, windowClass, MAX_LOADSTRING);
|
|
|
|
WNDCLASSEXW wcex;
|
|
wcex.cbSize = sizeof(WNDCLASSEX);
|
|
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
|
wcex.lpfnWndProc = WndProc;
|
|
wcex.cbClsExtra = 0;
|
|
wcex.cbWndExtra = 0;
|
|
wcex.hInstance = _hInstance;
|
|
wcex.hIcon = LoadIcon(_hInstance, MAKEINTRESOURCE(IDI_GRAPHICS2));
|
|
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
|
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
|
wcex.lpszMenuName = nullptr;
|
|
wcex.lpszClassName = windowClass;
|
|
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
|
|
if (!RegisterClassExW(&wcex))
|
|
{
|
|
MessageBox(0, L"Unable to register window class", 0, 0);
|
|
return false;
|
|
}
|
|
|
|
// Now work out how large the window needs to be for our required client window size
|
|
RECT windowRect = { 0, 0, static_cast<LONG>(_width), static_cast<LONG>(_height) };
|
|
AdjustWindowRect(&windowRect, WS_OVERLAPPEDWINDOW, FALSE);
|
|
_width = windowRect.right - windowRect.left;
|
|
_height = windowRect.bottom - windowRect.top;
|
|
|
|
_hWnd = CreateWindowW(windowClass,
|
|
windowTitle,
|
|
WS_OVERLAPPEDWINDOW,
|
|
CW_USEDEFAULT, CW_USEDEFAULT, _width, _height,
|
|
nullptr, nullptr, _hInstance, nullptr);
|
|
if (!_hWnd)
|
|
{
|
|
MessageBox(0, L"Unable to create window", 0, 0);
|
|
return false;
|
|
}
|
|
if (!Initialise())
|
|
{
|
|
return false;
|
|
}
|
|
ShowWindow(_hWnd, nCmdShow);
|
|
UpdateWindow(_hWnd);
|
|
return true;
|
|
}
|
|
|
|
// The WndProc for the current window. This cannot be a method, but we can
|
|
// redirect all messages to a method.
|
|
|
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (_thisFramework != NULL)
|
|
{
|
|
// If framework is started, then we can call our own message proc
|
|
return _thisFramework->MsgProc(hWnd, message, wParam, lParam);
|
|
}
|
|
else
|
|
{
|
|
// otherwise, we just pass control to the default message proc
|
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
}
|
|
}
|
|
|
|
// Our main WndProc
|
|
|
|
LRESULT Framework::MsgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (message)
|
|
{
|
|
case WM_PAINT:
|
|
break;
|
|
|
|
case WM_KEYDOWN:
|
|
OnKeyDown(wParam);
|
|
return 0;
|
|
|
|
case WM_KEYUP:
|
|
OnKeyUp(wParam);
|
|
return 0;
|
|
|
|
case WM_DESTROY:
|
|
PostQuitMessage(0);
|
|
break;
|
|
|
|
case WM_MOVE:
|
|
Render();
|
|
break;
|
|
|
|
case WM_SIZE:
|
|
_width = LOWORD(lParam);
|
|
_height = HIWORD(lParam);
|
|
OnResize(wParam);
|
|
Render();
|
|
break;
|
|
|
|
default:
|
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
}
|
|
return 0;
|
|
}
|
|
|