Skip to content

Instantly share code, notes, and snippets.

@seece

seece/system.cpp Secret

Created May 14, 2017 12:44
Show Gist options
  • Save seece/1f67da14d69b9c8a75a7e6839abf8e72 to your computer and use it in GitHub Desktop.
Save seece/1f67da14d69b9c8a75a7e6839abf8e72 to your computer and use it in GitHub Desktop.
WinAPI window creation and key input handling example
#include "logger.h"
#include "deka.h"
#include "system.h"
#include "util.h"
#include <cstdlib>
#ifdef DEBUG
#include "GLDebug.h"
#endif
#include "gl/eksgl.h"
bool system_running;
int window_width = 0;
int window_height = 0;
struct Window {
HDC deviceContext;
HWND handle;
HGLRC renderingContext;
WNDCLASSEX windowClass;
bool fullscreen;
};
#define DEKA_KEY_AMOUNT (256)
namespace {
bool keyDown[DEKA_KEY_AMOUNT];
bool keyHit[DEKA_KEY_AMOUNT];
bool mouseLeft = false;
bool mouseRight = false;
int frames_rendered;
int mousex;
int mousey;
int mousedeltaz;
const char* gl_extension_string = "";
LARGE_INTEGER programStartTime;
LARGE_INTEGER counterFrequency;
}
bool system_gl_ext_supported(const char* name)
{
return strstr((const char *)gl_extension_string, name) != NULL;
}
LRESULT CALLBACK WndProc(HWND windowHandle, UINT message, WPARAM wParam, LPARAM lParam) {
if (message == WM_DESTROY) {
PostQuitMessage(0);
return 0;
} else
return DefWindowProc(windowHandle, message, wParam, lParam);
}
// Lifted from GIGAENGINE code.
static Window create_window(int width, int height, bool fullscreen, bool vsync)
{
window_width = width;
window_height = height;
Window win = { 0 };
auto& windowClass = win.windowClass;
win.fullscreen = fullscreen;
windowClass.cbSize = sizeof(windowClass);
windowClass.hInstance = GetModuleHandle(0);
windowClass.style = CS_OWNDC;
windowClass.hIcon = LoadIcon(windowClass.hInstance, MAKEINTRESOURCE(129));
windowClass.lpfnWndProc = WndProc;
windowClass.lpszClassName = "klassy klass";
ZeroMemory(keyDown, DEKA_KEY_AMOUNT * sizeof(bool));
RegisterClassEx(&windowClass);
HWND temporaryWindow = CreateWindowEx(WS_EX_APPWINDOW, "klassy klass", "temp", WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX, 0, 0, 0, 0, 0, 0, windowClass.hInstance, 0);
HDC temporaryDeviceContext = GetDC(temporaryWindow);
PIXELFORMATDESCRIPTOR pixelFormat = { 0 };
pixelFormat.nSize = sizeof(pixelFormat);
pixelFormat.nVersion = 1;
pixelFormat.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pixelFormat.cColorBits = 32;
pixelFormat.cDepthBits = 24;
SetPixelFormat(temporaryDeviceContext, ChoosePixelFormat(temporaryDeviceContext, &pixelFormat), &pixelFormat);
HGLRC temporaryRenderingContext = wglCreateContext(temporaryDeviceContext);
wglMakeCurrent(temporaryDeviceContext, temporaryRenderingContext);
const char* extensions = (const char*)glGetString(GL_EXTENSIONS);
int ext_string_length = strlen(extensions) + 1;
gl_extension_string = new const char[ext_string_length];
memcpy((void*)gl_extension_string, extensions, ext_string_length);
const int formatAttributes[] =
{
WGL_DRAW_TO_WINDOW_ARB, 1,
WGL_SUPPORT_OPENGL_ARB, 1,
WGL_ACCELERATION_ARB, 0x2027,
WGL_DOUBLE_BUFFER_ARB, 1,
WGL_PIXEL_TYPE_ARB, 0x202B,
WGL_COLOR_BITS_ARB, 32,
WGL_DEPTH_BITS_ARB, 24,
0
};
const int contextAttributes[] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
WGL_CONTEXT_MINOR_VERSION_ARB, 2,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
//WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
#ifdef DEBUG
WGL_CONTEXT_FLAGS_ARB, 0 | WGL_CONTEXT_DEBUG_BIT_ARB,
#endif
0
};
int format, formatcount;
RECT windowArea = { 0, 0, width, height };
DWORD displayFlags = WS_POPUP;
if (fullscreen) {
DEVMODE dev = { 0 };
dev.dmSize = sizeof(DEVMODE);
dev.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
dev.dmPelsWidth = width;
dev.dmPelsHeight = height;
dev.dmBitsPerPel = 32;
ChangeDisplaySettings(&dev, CDS_FULLSCREEN);
} else {
displayFlags = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_BORDER;
//displayFlags = WS_POPUP ; // useful for frame dumping
AdjustWindowRect(&windowArea, displayFlags, 0);
windowArea.right -= windowArea.left;
windowArea.bottom -= windowArea.top;
windowArea.left = (GetSystemMetrics(SM_CXSCREEN) - windowArea.right) / 2;
windowArea.top = (GetSystemMetrics(SM_CYSCREEN) - windowArea.bottom) / 2;
}
win.handle = CreateWindowEx(WS_EX_APPWINDOW,
"klassy klass",
DEKA_DEMO_NAME,
displayFlags,
windowArea.left,
windowArea.top,
windowArea.right,
windowArea.bottom,
0,
0,
windowClass.hInstance,
0);
win.deviceContext = GetDC(win.handle);
((PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"))(win.deviceContext, formatAttributes, 0, 1, &format, (UINT*)&formatcount);
SetPixelFormat(win.deviceContext, format, &pixelFormat);
win.renderingContext = ((PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"))(win.deviceContext, 0, contextAttributes);
if (win.renderingContext == NULL) {
die("Couldn't create context.");
}
wglMakeCurrent(win.deviceContext, win.renderingContext);
wglDeleteContext(temporaryRenderingContext);
ReleaseDC(temporaryWindow, temporaryDeviceContext);
DestroyWindow(temporaryWindow);
MSG message;
while (PeekMessage(&message, 0, 0, 0, PM_REMOVE));
/*
if (ogl_LoadFunctions() == ogl_LOAD_FAILED) {
die("Couldn't init OpenGL functions!");
}
*/
int failed = load_gl_functions();
if (failed > 0) {
trace("Failed to load %d GL functions.", failed);
}
trace("Vendor : %s\nRenderer : %s\nOpenGL version : %s\nGLSL version : %s\n",
glGetString(GL_VENDOR),
glGetString(GL_RENDERER),
glGetString(GL_VERSION),
glGetString(GL_SHADING_LANGUAGE_VERSION));
/*
int major = -1;
int minor = -1;
glGetIntegerv(GL_MAJOR_VERSION, &major);
glGetIntegerv(GL_MINOR_VERSION, &minor);
trace("GL %d.%d\n", major, minor);
*/
ShowWindow(win.handle, SW_SHOW);
glViewport(0, 0, width, height);
glClearColor(.0f, .0f, .0f, .0f);
glClear(GL_COLOR_BUFFER_BIT);
SwapBuffers(win.deviceContext);
return win;
}
static Window current_window;
bool system_init(int width, int height, bool fullscreen, bool vsync)
{
#ifdef DEBUG
const char* datadir = "data";
SetCurrentDirectory(datadir);
trace("Changed working dir to %s", datadir);
#endif
QueryPerformanceFrequency(&counterFrequency);
QueryPerformanceCounter(&programStartTime);
srand(static_cast<unsigned int>(programStartTime.QuadPart));
//current_window = create_window(1280, 720, false, false);
current_window = create_window(width, height, fullscreen, vsync);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
SwapBuffers(current_window.deviceContext);
#ifdef DEBUG
setupDebugOutput();
#endif
frames_rendered = 0;
system_running = true;
return true;
}
double system_get_time()
{
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
return (now.QuadPart - programStartTime.QuadPart) / static_cast<double>(counterFrequency.QuadPart);
}
unsigned long long system_get_millis()
{
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
return (now.QuadPart - programStartTime.QuadPart) * 1000 / counterFrequency.QuadPart;
}
bool system_cleanup()
{
trace("system_cleanup");
if (current_window.fullscreen)
ChangeDisplaySettings(0, 0);
wglMakeCurrent(0, 0);
wglDeleteContext(current_window.renderingContext);
ReleaseDC(current_window.handle, current_window.deviceContext);
DestroyWindow(current_window.handle);
UnregisterClass("klassy klass", GetModuleHandle(0));
return true;
}
// Max number of keypresses per frame is 128.
#define CHAR_BUFFER_SIZE (128)
static unsigned char charbuffer[CHAR_BUFFER_SIZE];
static int charbuffer_pos;
static void add_input_character(unsigned char c) {
if (charbuffer_pos < CHAR_BUFFER_SIZE) {
charbuffer[charbuffer_pos++] = c;
}
}
int system_poll_input_char(unsigned short* out_c) {
if (charbuffer_pos > 0) {
*out_c = charbuffer[charbuffer_pos--];
}
return charbuffer_pos;
}
void system_update()
{
frames_rendered++;
MSG message;
ZeroMemory(keyHit, DEKA_KEY_AMOUNT * sizeof(bool));
mousedeltaz = 0;
charbuffer_pos = 0;
while (PeekMessage(&message, 0, 0, 0, PM_REMOVE)) {
TranslateMessage(&message);
DispatchMessage(&message);
WPARAM wParam = message.wParam;
switch (message.message) {
case WM_QUIT:
system_running = false;
break;
case WM_KEYDOWN:
keyHit[wParam] = keyDown[wParam] = true;
break;
case WM_KEYUP:
keyDown[wParam] = false;
break;
case WM_LBUTTONDOWN:
mouseLeft = true;
break;
case WM_LBUTTONUP:
mouseLeft = false;
break;
case WM_RBUTTONDOWN:
mouseRight = true;
break;
case WM_RBUTTONUP:
mouseRight = false;
break;
case WM_MOUSEMOVE:
mousex = int(message.lParam) % 65536;
mousey = int(message.lParam) / 65536;
break;
case WM_MOUSEWHEEL:
mousedeltaz += GET_WHEEL_DELTA_WPARAM(wParam);
break;
case WM_CHAR:
// You can also use ToAscii()+GetKeyboardState() to retrieve characters.
if (wParam > 0 && wParam < 0x10000) {
//io.AddInputCharacter((unsigned short)wParam);
// FIXME this might be broken?
add_input_character((unsigned short)wParam);
}
break;
case WM_PAINT:
/*HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint(current_window.handle, &ps);
//wglMakeCurrent(hdc, current_window.renderingContext);
//scene.Render(); //
//SwapBuffers(hdc);
//wglMakeCurrent(hdc, 0);
EndPaint(current_window.handle, &ps);*/
break;
}
}
}
void system_draw()
{
SwapBuffers(current_window.deviceContext);
}
bool system_key_down(int code)
{
passert(code >= 0);
passert(code < DEKA_KEY_AMOUNT);
return keyDown[code];
}
bool system_key_hit(int code)
{
passert(code >= 0);
passert(code < DEKA_KEY_AMOUNT);
return keyHit[code];
}
MousePos system_mouse_pos()
{
return { mousex, mousey, mousedeltaz };
}
bool system_mouse_down(int button)
{
if (button == 0)
{
return mouseLeft;
}
if (button == 1)
{
return mouseRight;
}
#ifdef DEBUG
die("invalid mouse button %d", button);
#endif
return false;
}
void* system_get_window_handle()
{
return (void*)current_window.handle;
}
HDC system_get_device_context()
{
return current_window.deviceContext;
}
#pragma once
#define WIN32_LEAN_AND_MEAN
#define WIN32_EXTRA_LEAN
#include <Windows.h> // for VK key codes
extern int window_width;
extern int window_height;
struct MousePos {
int x, y;
int dz; // wheel movement
};
// main loop runs as long as this is true
extern bool system_running;
bool system_init(int width, int height, bool fullscreen, bool vsync);
bool system_cleanup();
void system_update();
void system_draw();
// These use WinAPI virtual key codes, e.g. VK_ESCAPE
bool system_key_down(int code);
bool system_key_hit(int code);
MousePos system_mouse_pos(); // returns the mouse position in pixels
bool system_mouse_down(int button); // 0 = left, 1 = right
int system_poll_input_char(unsigned short* out_c); // returns the number of input characters left in buffer
bool system_gl_ext_supported(const char* name);
double system_get_time();
unsigned long long system_get_millis();
void* system_get_window_handle(); // cast to HWND manually
HDC system_get_device_context();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment