Created
June 6, 2013 00:32
-
-
Save gszauer/5718451 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define WIN32_LEAN_AND_MEAN | |
#define WIN32_EXTRA_LEAN | |
#include <windows.h> | |
#include <process.h> | |
#include <stdlib.h> | |
#include <gl/gl.h> | |
#include <cmath> | |
#pragma comment(lib, "opengl32.lib") | |
#define OGL_NEAR float(0.1f) | |
#define OGL_FAR float(1000.0f) | |
#define START_FULLSCREEN false | |
#define WINDOW_WIDTH 800 | |
#define WINDOW_HEIGHT 600 | |
#define TARGET_FPS 60 | |
#define WND_CLASSNAME "GLWindow" | |
#define WND_TITLE "OpenGL Enabled Window (Advanced)" | |
#define THROTTLE_FPS 1 | |
#define ENABLE_RESIZE 1 | |
#define MULTITHREADED 1 | |
#define USEOPENGL3X 1 | |
#define FORCE_FORWARDCOMPATABLE 0 | |
HWND hwnd; | |
HINSTANCE hinstance; | |
HGLRC hglrc; | |
unsigned int glMajor; | |
unsigned int glMinor; | |
//////////////////////////////////////////////////////////////////// | |
// Game Hook | |
void Initialize() {} | |
void Update() {} | |
void Render() { | |
glClearColor(0.5f, 0.5f, 0.5f, 1.0f); | |
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); | |
glMatrixMode(GL_MODELVIEW); | |
glPushMatrix(); | |
glLoadIdentity(); | |
glTranslatef(0.0f,0.0f,-6.0f); | |
glBegin(GL_TRIANGLES); | |
glColor3f(1.0f,0.0f,0.0f); | |
glVertex3f( 0.0f, 1.0f, 0.0f); | |
glColor3f(0.0f,1.0f,0.0f); | |
glVertex3f(-1.0f,-1.0f, 1.0f); | |
glColor3f(0.0f,0.0f,1.0f); | |
glVertex3f( 1.0f,-1.0f, 1.0f); | |
glEnd(); | |
glPopMatrix(); | |
} | |
void Shutdown() {} | |
void Resize(int width, int height) { } | |
//////////////////////////////////////////////////////////////////// | |
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); | |
bool CheckIfAlreadyRunning(); | |
void OpenGLUnbindContext(HWND hwnd, HDC hdc, HGLRC hglrc); | |
void OpenGLResetProjection(); | |
HGLRC OpenGLBindContext(HDC hdc); | |
void ToggleFullscreen(bool init = false, bool exit = false); | |
void SetDisplayMode(int width, int height, int bpp, int refreshRate); | |
#if MULTITHREADED | |
unsigned int __stdcall GameThread(void *args); | |
#endif | |
#if USEOPENGL3X | |
typedef HGLRC (APIENTRY * PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hDC, HGLRC hShareContext, const int *attribList); | |
#endif | |
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { | |
if (!hPrevInstance) | |
if (CheckIfAlreadyRunning()) | |
return FALSE; | |
#if THROTTLE_FPS | |
const int SKIP_TICKS = 1000 / TARGET_FPS; | |
DWORD next_game_tick = GetTickCount(); | |
int sleep_time = 0; | |
#endif | |
#if MULTITHREADED | |
const unsigned int signalstart = 0; | |
const unsigned int signalstop = 1; | |
unsigned int gamethreadid; | |
volatile HANDLE hgamesignals[2]; | |
HANDLE hgamethread; | |
hgamesignals[signalstart] = CreateMutex(NULL, TRUE, NULL); | |
hgamesignals[signalstop] = CreateMutex(NULL, TRUE, NULL); | |
#endif | |
MSG msg; HDC hdc; | |
hinstance = hInstance; | |
WNDCLASSEX wndclass; | |
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 = WND_CLASSNAME; | |
RegisterClassEx(&wndclass); | |
RECT windowRect; | |
SetRect(&windowRect, (GetSystemMetrics(SM_CXSCREEN) / 2) - (WINDOW_WIDTH / 2), (GetSystemMetrics(SM_CYSCREEN) / 2) - (WINDOW_HEIGHT / 2), (GetSystemMetrics(SM_CXSCREEN) / 2) + (WINDOW_WIDTH / 2), (GetSystemMetrics(SM_CYSCREEN) / 2) + (WINDOW_HEIGHT / 2)); | |
#if ENABLE_RESIZE | |
AdjustWindowRectEx(&windowRect, WS_VISIBLE | WS_OVERLAPPEDWINDOW, FALSE, 0); | |
hwnd = CreateWindowEx(0, WND_CLASSNAME, WND_TITLE, WS_VISIBLE | WS_OVERLAPPEDWINDOW, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, NULL, NULL, hInstance, szCmdLine); | |
#else | |
AdjustWindowRectEx(&windowRect, WS_VISIBLE | (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX /*| WS_MAXIMIZEBOX*/), FALSE, 0); | |
hwnd = CreateWindowEx(0, WND_CLASSNAME, WND_TITLE, WS_VISIBLE | (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX /*| WS_MAXIMIZEBOX*/), windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, NULL, NULL, hInstance, szCmdLine); | |
#endif | |
hdc = GetDC(hwnd); | |
hglrc = OpenGLBindContext(hdc); | |
#if !MULTITHREADED | |
ToggleFullscreen(true, false); | |
Initialize(); | |
#else | |
wglMakeCurrent(NULL, NULL); | |
hgamethread = (HANDLE)_beginthreadex(NULL, 0, GameThread, (void*)hgamesignals, 0, &gamethreadid); | |
#endif | |
ShowWindow(hwnd, SW_SHOW); | |
UpdateWindow(hwnd); | |
#if !MULTITHREADED | |
OpenGLResetProjection(); | |
#else | |
ReleaseMutex(hgamesignals[signalstart]); | |
#endif | |
while (true) { | |
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { | |
if (msg.message == WM_QUIT) | |
break; | |
TranslateMessage(&msg); | |
DispatchMessage(&msg); | |
} | |
#if !MULTITHREADED | |
#if THROTTLE_FPS | |
next_game_tick += SKIP_TICKS; | |
sleep_time = next_game_tick - GetTickCount(); | |
if(sleep_time >= 0) | |
Sleep(sleep_time); | |
#endif | |
Update(); | |
Render(); | |
SwapBuffers(hdc); | |
#endif | |
} | |
#if !MULTITHREADED | |
Shutdown(); | |
ToggleFullscreen(false, true); | |
#else | |
ReleaseMutex(hgamesignals[signalstop]); | |
WaitForSingleObject(hgamethread, INFINITE); | |
CloseHandle(hgamesignals[signalstart]); | |
CloseHandle(hgamesignals[signalstop]); | |
CloseHandle(hgamethread); | |
wglMakeCurrent(hdc, hglrc); | |
#endif | |
OpenGLUnbindContext(hwnd, hdc, hglrc); | |
return (int)msg.wParam; | |
} | |
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { | |
static bool cursorVisible = true; | |
switch (iMsg) { | |
case WM_CLOSE: | |
DestroyWindow(hwnd); | |
break; | |
case (WM_APP + 1): | |
if (!cursorVisible) { | |
ShowCursor(TRUE); | |
cursorVisible = true; | |
} | |
break; | |
case (WM_APP + 2): | |
if (cursorVisible) { | |
ShowCursor(FALSE); | |
cursorVisible = false; | |
} | |
break; | |
case WM_DESTROY: | |
PostQuitMessage(0); | |
break; | |
case WM_KEYDOWN: | |
case WM_SYSKEYDOWN: | |
#if !MULTITHREADED | |
if (wParam == VK_RETURN) { | |
if ((HIWORD(lParam) & KF_ALTDOWN)) { | |
ToggleFullscreen(); | |
} | |
} else if (wParam == VK_F4) { | |
PostQuitMessage(0); | |
} | |
#endif | |
break; | |
case WM_SIZE: | |
OpenGLResetProjection(); | |
break; | |
case WM_SYSKEYUP: | |
case WM_SYSCHAR: | |
case WM_PAINT: | |
case WM_ERASEBKGND: | |
return 0; | |
} | |
return DefWindowProc(hwnd, iMsg, wParam, lParam); | |
} | |
HGLRC OpenGLBindContext(HDC hdc) { | |
PIXELFORMATDESCRIPTOR pfd; | |
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); | |
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; | |
int pixelFormat = ChoosePixelFormat(hdc, &pfd); | |
SetPixelFormat(hdc, pixelFormat, &pfd); | |
HGLRC context = wglCreateContext(hdc); | |
wglMakeCurrent(hdc, context); | |
glMajor = 1; | |
glMinor = 1; | |
#if USEOPENGL3X | |
float glVersion = float(atof((const char*)glGetString(GL_VERSION))); | |
if (glVersion < 3.0f) | |
return context; | |
int attribs[] = { | |
/*WGL_CONTEXT_MAJOR_VERSION_ARB*/0x2091, 3, | |
/*WGL_CONTEXT_MINOR_VERSION_ARB*/0x2092, 1, | |
/*WGL_CONTEXT_FLAGS_ARB*/0x2094, | |
#if FORCE_FORWARDCOMPATABLE | |
/*WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB*/0x0002, | |
#else | |
0, | |
#endif | |
0, 0 }; | |
glMajor = 3; | |
glMinor = 1; | |
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); | |
HGLRC forwardContext = wglCreateContextAttribsARB(hdc, 0, attribs); | |
wglMakeCurrent(NULL, NULL); | |
wglDeleteContext(context); | |
wglMakeCurrent(hdc, forwardContext); | |
return forwardContext; | |
#else | |
return context; | |
#endif | |
} | |
void OpenGLUnbindContext(HWND hwnd, HDC hdc, HGLRC hglrc) { | |
wglMakeCurrent(NULL, NULL); | |
wglDeleteContext(hglrc); | |
ReleaseDC(hwnd, hdc); | |
} | |
bool CheckIfAlreadyRunning(void) { | |
HWND hWnd = FindWindow(WND_CLASSNAME, WND_TITLE); | |
if (hWnd) { | |
if (IsIconic(hWnd)) | |
ShowWindow(hWnd, SW_RESTORE); | |
SetForegroundWindow(hWnd); | |
return true; | |
} | |
return false; | |
} | |
void ToggleFullscreen(bool init, bool exit) { | |
static bool fullScreen = !START_FULLSCREEN; | |
static RECT windowRect = { 0 }; | |
if (init) { | |
SetRect(&windowRect, (GetSystemMetrics(SM_CXSCREEN) / 2) - (WINDOW_WIDTH / 2), (GetSystemMetrics(SM_CYSCREEN) / 2) - (WINDOW_HEIGHT / 2), (GetSystemMetrics(SM_CXSCREEN) / 2) + (WINDOW_WIDTH / 2), (GetSystemMetrics(SM_CYSCREEN) / 2) + (WINDOW_HEIGHT / 2)); | |
#if ENABLE_RESIZE | |
AdjustWindowRectEx(&windowRect, WS_VISIBLE | WS_OVERLAPPEDWINDOW, FALSE, 0); | |
#else | |
AdjustWindowRectEx(&windowRect, WS_VISIBLE | (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX /*| WS_MAXIMIZEBOX*/), FALSE, 0); | |
#endif | |
} else if (exit) { | |
if (fullScreen) { | |
SetDisplayMode(0, 0, 0, 0); | |
#if ENABLE_RESIZE | |
SetWindowLongPtr(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW); | |
#else | |
SetWindowLongPtr(hwnd, GWL_STYLE, (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX /*| WS_MAXIMIZEBOX*/)); | |
#endif | |
SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); | |
int iWindowWidth = windowRect.right - windowRect.left; | |
int iWindowHeight = windowRect.bottom - windowRect.top; | |
SetWindowPos(hwnd, 0, windowRect.left, windowRect.top, iWindowWidth, iWindowHeight, SWP_NOZORDER); | |
fullScreen = false; | |
} | |
return; | |
} | |
if(!fullScreen) { | |
GetWindowRect(hwnd, &windowRect); | |
HDC hdc = GetDC(hwnd); | |
SetDisplayMode(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), GetDeviceCaps(hdc, BITSPIXEL), GetDeviceCaps(hdc, VREFRESH)); | |
SetWindowLongPtr(hwnd, GWL_STYLE, WS_POPUP); | |
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); | |
SetWindowPos(hwnd, 0, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SWP_NOZORDER); | |
PostMessage(hwnd, WM_APP + 2, 0, 0); | |
ReleaseDC(hwnd, hdc); | |
fullScreen = true; | |
} else { | |
SetDisplayMode(0, 0, 0, 0); | |
#if ENABLE_RESIZE | |
SetWindowLongPtr(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW); | |
#else | |
SetWindowLongPtr(hwnd, GWL_STYLE, (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX /*| WS_MAXIMIZEBOX*/)); | |
#endif | |
SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); | |
int iWindowWidth = windowRect.right - windowRect.left; | |
int iWindowHeight = windowRect.bottom - windowRect.top; | |
SetWindowPos(hwnd, 0, windowRect.left, windowRect.top, iWindowWidth, iWindowHeight, SWP_NOZORDER); | |
PostMessage(hwnd, WM_APP + 1, 0, 0); | |
fullScreen = false; | |
} | |
OpenGLResetProjection(); | |
} | |
void SetDisplayMode(int width, int height, int bpp, int refreshRate) { | |
if(width == 0 && height == 0 && bpp == 0 && refreshRate == 0) { | |
ChangeDisplaySettings(NULL, 0); | |
return; | |
} | |
DEVMODE dm; | |
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; | |
} | |
} | |
} | |
} | |
void OpenGLResetProjection() { | |
RECT window = { 0 }; | |
GetClientRect(hwnd, &window); | |
glViewport(0, 0, window.right - window.left, window.bottom - window.top); | |
float fov = 62.0f; | |
float aspect = (float)(window.right - window.left) / (float)(window.bottom - window.top); | |
float top = OGL_NEAR * float(tanf(fov * 3.14159265f / 360.0f)); | |
float bottom = -1.0f * top; | |
float right = bottom * aspect; | |
float left = top * aspect; | |
glMatrixMode(GL_PROJECTION); | |
glLoadIdentity(); | |
glFrustum(left, right, bottom, top, OGL_NEAR, OGL_FAR); | |
glMatrixMode(GL_MODELVIEW); | |
glLoadIdentity(); | |
Resize(int(window.right - window.left), int(window.bottom - window.top)); | |
} | |
#if MULTITHREADED | |
unsigned int __stdcall GameThread(void *args) { | |
const unsigned int signalstart = 0; | |
const unsigned int signalstop = 1; | |
HANDLE* hgamesignals = (HANDLE*)args; | |
bool returnIsDown = false, returnWasDown = false; | |
bool f4Processed = false; | |
#if THROTTLE_FPS | |
const int SKIP_TICKS = 1000 / TARGET_FPS; | |
DWORD next_game_tick = GetTickCount(); | |
int sleep_time = 0; | |
#endif | |
while (WaitForSingleObject(hgamesignals[signalstart], 0) != WAIT_OBJECT_0) | |
Sleep(10); | |
HDC hdc = GetDC(hwnd); | |
wglMakeCurrent(hdc, hglrc); | |
ToggleFullscreen(true, false); | |
OpenGLResetProjection(); | |
Initialize(); | |
do { | |
#if THROTTLE_FPS | |
next_game_tick += SKIP_TICKS; | |
sleep_time = next_game_tick - GetTickCount(); | |
if(sleep_time >= 0) | |
Sleep(sleep_time); | |
#endif | |
returnIsDown = bool(GetAsyncKeyState(VK_RETURN) != 0); | |
Update(); | |
Render(); | |
SwapBuffers(hdc); | |
if (WaitForSingleObject(hgamesignals[signalstop], 0) == WAIT_OBJECT_0) | |
break; | |
if ((GetAsyncKeyState(VK_LMENU) || GetAsyncKeyState(VK_RMENU)) && (returnIsDown && !returnWasDown)) | |
ToggleFullscreen(); | |
if ((GetAsyncKeyState(VK_LMENU) || GetAsyncKeyState(VK_RMENU)) && (GetAsyncKeyState(VK_F4) && !f4Processed)) { | |
f4Processed = true; | |
PostMessage(hwnd, WM_DESTROY, 0, 0); | |
} | |
returnWasDown = returnIsDown; | |
} while (true); | |
Shutdown(); | |
ToggleFullscreen(false, true); | |
wglMakeCurrent(NULL, NULL); | |
ReleaseDC(hwnd, hdc); | |
ReleaseMutex(hgamesignals[signalstart]); | |
ReleaseMutex(hgamesignals[signalstop]); | |
return 0; | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment