Professional Documents
Culture Documents
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#include <float.h>
unsigned int fp_control_state = _controlfp(_EM_INEXACT, _MCW_EM);
#endif
#define WIN32_LEAN_AND_MEAN
#define WIN32_EXTRA_LEAN
#include <windows.h>
#include <windowsx.h>
#include "glad/glad.h"
#include <string>
#include <iostream>
#include <cstdio>
#include <conio.h>
#include "IWindow.h"
#include "matrices.h"
#include "imgui/imgui.h"
#include "imgui/imgui_implementation.h"
#include "imgui/ImGuizmo.h"
RECT windowRect;
RECT clientRect;
RECT borderRect;
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine,
int iCmdShow);
bool CheckIfAlreadyRunning(IWindow* pWindowInstance);
HWND MakeNewWindow(IWindow* pWindowInstance, HINSTANCE hInstance, LPSTR szCmdLine);
HGLRC OpenGLBindContext(HDC hdc);
void OpenGLUnbindContext(HWND hwnd, HDC hdc, HGLRC hglrc);
void UpdateFullscreen(IWindow* pWindowInstance, HWND hwnd, HDC hdc);
void SetDisplayMode(int width, int height, int bpp, int refreshRate);
int WParamToKeydef(WPARAM param, bool shiftDown);
double GetMilliseconds();
#define NO_RESIZE_STYLE (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
WS_MAXIMIZEBOX)
#define NORMAL_STYLE (WS_VISIBLE | WS_OVERLAPPEDWINDOW)
if (pWindowInstance->GetQuitFlag()) {
std::cout << "Something went wrong, could not initialize!\n";
getch();
}
else if (CheckIfAlreadyRunning(pWindowInstance)) {
std::cout << "Error, only one instance of application is allowed to
run\n";
getch();
}
else {
WinMain(GetModuleHandle(NULL), NULL, GetCommandLineA(),
SW_SHOWDEFAULT);
}
return 0;
}
if (CheckIfAlreadyRunning(pWindowInstance)) {
MessageBox(NULL, L"Only one instance of application is allowed to run",
NULL, NULL);
return FALSE;
}
WNDCLASSEX wndclass;
ZeroMemory(&wndclass, sizeof(WNDCLASSEX));
wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wndclass.lpszMenuName = 0;
wndclass.lpszClassName = MAIN_WIN_32_WINDOW_CLASS;
RegisterClassEx(&wndclass);
if (!gladLoadGL()) {
std::cout << "Could not instantiate GLAD OpenGL 2.1 context\n";
exit(-1);
}
else if (GLVersion.major < 2) {
std::cout << "Your system doesn't support OpenGL >= 2!\n";
return -1;
}
std::cout << "OpenGL Context: " << GLVersion.major << ", " << GLVersion.minor
<< "\n";
std::cout << "OpenGL version: " << glGetString(GL_VERSION) << "\n";
std::cout << "GLSL Version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) <<
"\n";
ImGui_Implementation_Init(hwnd);
pWindowInstance->OnInitialize();
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
GetClientRect(hwnd, &clientRect);
GetWindowRect(hwnd, &windowRect);
GetWindowRect(hwnd, &borderRect);
MSG msg;
DWORD next_game_tick = GetTickCount();
int sleep_time = 0;
double lastTime = GetMilliseconds();
double fixed_millis = pWindowInstance->GetFixedFPS() / 1000.0;
double fixed_ellapsed = 0.0;
pWindowInstance->MarkAsShown();
while (!pWindowInstance->GetQuitFlag()) {
// If or while? Not sure if all messages should process at once or not
// Keeping it while for now, but i have serious reservations about
this....
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
ImGui_Implementation_NewFrame();
ImGuizmo::BeginFrame();
if (!fullscreen) {
int windowWidth = borderRect.right - borderRect.left;
int windowHeight = borderRect.bottom - borderRect.top;
int clientWidth = clientRect.right - clientRect.left;
int clientHeight = clientRect.bottom - clientRect.top;
int borderWidth = windowWidth - clientWidth;
int borderHeight = windowHeight - clientHeight;
pWindowInstance->OnUpdate(deltaTime);
fixed_ellapsed += deltaTime;
while (fixed_ellapsed > fixed_millis) {
pWindowInstance->OnFixedUpdate(fixed_millis);
fixed_ellapsed -= fixed_millis;
}
pWindowInstance->OnRender();
ImGui::Render();
SwapBuffers(hdc);
// Regulate FPS
int SKIP_TICKS = 1000 / pWindowInstance->GetTargetFPS();
next_game_tick += SKIP_TICKS;
sleep_time = next_game_tick - GetTickCount();
if (sleep_time >= 0) {
Sleep(sleep_time);
}
}
pWindowInstance->OnShutdown();
ImGui_Implementation_Shutdown();
OpenGLUnbindContext(hwnd, hdc, hglrc);
CleanupMemory(pWindowInstance);
#if _DEBUG
_CrtDumpMemoryLeaks();
#endif
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
ImGui_Implementation_WndProcHandler(hwnd, iMsg, wParam, lParam);
switch (iMsg) {
// Window Lifecycle events
case WM_CLOSE:
DestroyWindow(hwnd);
pWindowInstance->Close();
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
// Handle resize event
case WM_SIZE:
width = LOWORD(lParam);
height = HIWORD(lParam);
GetClientRect(hwnd, &clientRect);
GetWindowRect(hwnd, &borderRect);
pWindowInstance->Resize(width, height);
if (pWindowInstance->WasWindowShown()) {
pWindowInstance->OnResize(width, height);
}
break;
// Handle Mouse Events
case WM_MOUSEMOVE:
if (!ImGui_Implementation_HasMouse()) {
pWindowInstance->OnMouseMove(GET_X_LPARAM(lParam),
GET_Y_LPARAM(lParam));
}
break;
case WM_LBUTTONDOWN:
if (!ImGui_Implementation_HasMouse()) {
//pWindowInstance->OnMouseMove(GET_X_LPARAM(lParam),
GET_Y_LPARAM(lParam));
if (!ImGuizmo::IsUsing() && !ImGuizmo::IsOver()) {
pWindowInstance->OnMouseDown(MOUSE_LEFT);
}
}
break;
case WM_LBUTTONUP:
if (!ImGui_Implementation_HasMouse()) {
//pWindowInstance->OnMouseMove(GET_X_LPARAM(lParam),
GET_Y_LPARAM(lParam));
if (!ImGuizmo::IsUsing()) {
pWindowInstance->OnMouseUp(MOUSE_LEFT);
}
}
break;
case WM_RBUTTONDOWN:
if (!ImGui_Implementation_HasMouse()) {
//pWindowInstance->OnMouseMove(GET_X_LPARAM(lParam),
GET_Y_LPARAM(lParam));
if (!ImGuizmo::IsUsing() && !ImGuizmo::IsOver()) {
pWindowInstance->OnMouseDown(MOUSE_RIGHT);
}
}
break;
case WM_RBUTTONUP:
if (!ImGui_Implementation_HasMouse()) {
//pWindowInstance->OnMouseMove(GET_X_LPARAM(lParam),
GET_Y_LPARAM(lParam));
if (!ImGuizmo::IsUsing()) {
pWindowInstance->OnMouseUp(MOUSE_RIGHT);
}
}
break;
case WM_MBUTTONDOWN:
if (!ImGui_Implementation_HasMouse()) {
//pWindowInstance->OnMouseMove(GET_X_LPARAM(lParam),
GET_Y_LPARAM(lParam));
if (!ImGuizmo::IsUsing() && !ImGuizmo::IsOver()) {
pWindowInstance->OnMouseDown(MOUSE_MIDDLE);
}
}
break;
case WM_MBUTTONUP:
if (!ImGui_Implementation_HasMouse()) {
if (!ImGuizmo::IsOver()) {
pWindowInstance->OnMouseMove(GET_X_LPARAM(lParam),
GET_Y_LPARAM(lParam));
}
if (!ImGuizmo::IsUsing()) {
pWindowInstance->OnMouseUp(MOUSE_MIDDLE);
}
}
break;
// Handle keyboard events
case WM_SYSKEYUP:
break;
case WM_SYSKEYDOWN:
break;
case WM_KEYDOWN:
if (wParam == VK_SHIFT || wParam == VK_LSHIFT || wParam == VK_RSHIFT)
shiftDown = true;
if (wParam == VK_CAPITAL)
capsOn = !capsOn;
if (!ImGui_Implementation_HasKeyboard()) {
pWindowInstance->OnKeyDown(WParamToKeydef(wParam, shiftDown ^
capsOn));
}
break;
case WM_KEYUP:
if (wParam == VK_SHIFT || wParam == VK_LSHIFT || wParam == VK_RSHIFT)
shiftDown = false;
if (!ImGui_Implementation_HasKeyboard()) {
pWindowInstance->OnKeyUp(WParamToKeydef(wParam, shiftDown ^
capsOn));
}
break;
}
if (hWnd) {
if (IsIconic(hWnd)) {
ShowWindow(hWnd, SW_RESTORE);
}
SetForegroundWindow(hWnd);
return true;
}
return false;
}
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 32;
pfd.cStencilBits = 8;
pfd.iLayerType = PFD_MAIN_PLANE;
GetClientRect(hwnd, &clientRect);
GetWindowRect(hwnd, &borderRect);
}
DEVMODE dm;
ZeroMemory(&dm, sizeof(DEVMODE));
dm.dmSize = sizeof(DEVMODE);
int i = 0;
while (EnumDisplaySettings(NULL, i++, &dm)) {
if (dm.dmPelsWidth == width && dm.dmPelsHeight == height &&
dm.dmBitsPerPel == bpp && dm.dmDisplayFrequency == refreshRate) {
if (ChangeDisplaySettings(&dm, CDS_TEST) ==
DISP_CHANGE_SUCCESSFUL) {
ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
return;
}
}
}
}
return KEY_NONE;
}
double GetMilliseconds() {
static LARGE_INTEGER s_frequency;
static BOOL s_use_qpc = QueryPerformanceFrequency(&s_frequency);
if (s_use_qpc) {
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
return (double)((1000LL * now.QuadPart) / s_frequency.QuadPart);
}
else {
return GetTickCount();
}
}