Skip to content

Instantly share code, notes, and snippets.

@gszauer
Last active May 14, 2025 09:03
Show Gist options
  • Save gszauer/03fa4d1fbd72bfc169f70e78eabe3c4c to your computer and use it in GitHub Desktop.
Save gszauer/03fa4d1fbd72bfc169f70e78eabe3c4c to your computer and use it in GitHub Desktop.
OpenGLInitWin32.cpp
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <ShellScalingAPI.h> // Shcore.lib
#include "glad.h" // OpenGL32.lib
#pragma comment(lib, "OpenGL32.lib")
#pragma comment(linker, "/SUBSYSTEM:WINDOWS")
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define WINDOW_CLASS "OGL_Sample"
#define WINDOW_TITLE "OpenGL Sample"
// Used for setting up a modern OpenGL Context
typedef HGLRC(WINAPI* PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int* attribList);
typedef BOOL(WINAPI* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats);
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
#define WGL_CONTEXT_FLAGS_ARB 0x2094
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001
#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
#define WGL_SUPPORT_OPENGL_ARB 0x2010
#define WGL_DOUBLE_BUFFER_ARB 0x2011
#define WGL_PIXEL_TYPE_ARB 0x2013
#define WGL_COLOR_BITS_ARB 0x2014
#define WGL_DEPTH_BITS_ARB 0x2022
#define WGL_STENCIL_BITS_ARB 0x2023
#define WGL_TYPE_RGBA_ARB 0x202B
#define WGL_SAMPLE_BUFFERS_ARB 0x2041
#define WGL_SAMPLES_ARB 0x2042
// Demo framework
struct WindowData {
HWND hwnd;
HDC hdc;
HGLRC hglrc;
HINSTANCE hInstance; // Window instance
bool closeWindow;
};
void* Initialize(const WindowData& windowData);
void Update(void* userData, float deltatTime);
void Render(void* userData, RECT clientRect);
void Shutdown(void* userData);
// Forward declared callbacks
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow);
// Command line entry point
int main(int argc, char** argv) {
return WinMain(GetModuleHandleA(NULL), NULL, GetCommandLineA(), SW_SHOWDEFAULT);
}
HDC gHdc;
// Windowed entry point
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) {
// Make process DPI aware
HRESULT hr = SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
float dpi = (float)GetDpiForSystem() / 96.0f;
// Two windows. A temp one to create a legacy opengl context, and a real one with a msaa context.
WNDCLASSA wndclass, tmpclass;
ZeroMemory(&wndclass, sizeof(WNDCLASSA));
ZeroMemory(&tmpclass, sizeof(WNDCLASSA));
tmpclass.style = wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
tmpclass.lpfnWndProc = DefWindowProcA;
tmpclass.hInstance = wndclass.hInstance = hInstance;
tmpclass.hIcon = wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
tmpclass.hCursor = wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
tmpclass.hbrBackground = wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wndclass.lpszClassName = WINDOW_CLASS;
tmpclass.lpszClassName = "tmp_gl_context_window";
RegisterClassA(&wndclass);
RegisterClassA(&tmpclass);
// Figure out window size
int windowWidth = (float)WINDOW_WIDTH * dpi;
int windowHeight = (float)WINDOW_HEIGHT * dpi;
RECT rClient;
SetRect(&rClient, 0, 0, windowWidth, windowHeight);
AdjustWindowRect(&rClient, WS_OVERLAPPEDWINDOW | WS_VISIBLE, FALSE);
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
int screenHeight = GetSystemMetrics(SM_CYSCREEN);
windowWidth = rClient.right - rClient.left;
windowHeight = rClient.right - rClient.left;
// Create dummy window
HWND hwnd = CreateWindowA(tmpclass.lpszClassName, (char*)(WINDOW_TITLE), WS_OVERLAPPEDWINDOW,
(screenWidth / 2) - (windowWidth / 2), (screenHeight / 2) - (windowHeight / 2),
windowWidth, windowHeight, NULL, NULL, hInstance, 0);
HDC hdc = GetDC(hwnd);
// Make legacy OpenGL request
PIXELFORMATDESCRIPTOR pfd;
ZeroMemory(&pfd, 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 = 32;
pfd.cDepthBits = 24;
pfd.cStencilBits = 8;
pfd.iLayerType = PFD_MAIN_PLANE;
int pixelFormat = ChoosePixelFormat(hdc, &pfd);
SetPixelFormat(hdc, pixelFormat, &pfd);
HGLRC hglrc = wglCreateContext(hdc);
wglMakeCurrent(hdc, hglrc);
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); // Recognised (Why this and not the function name?)
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
// Delete the legacy context and destroy the temp window
wglMakeCurrent(hdc, NULL);
wglDeleteContext(hglrc);
ReleaseDC(hwnd, hdc);
DestroyWindow(hwnd);
// Create new (final) window
hwnd = CreateWindowA(wndclass.lpszClassName, (char*)(WINDOW_TITLE), WS_OVERLAPPEDWINDOW | WS_VISIBLE,
(screenWidth / 2) - (windowWidth / 2), (screenHeight / 2) - (windowHeight / 2),
windowWidth, windowHeight, NULL, NULL, hInstance, 0);
hdc = GetDC(hwnd);
gHdc = hdc;
// Create a modern OpenGL context
const int iPixelFormatAttribList[] = {
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_COLOR_BITS_ARB, 32,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
WGL_SAMPLE_BUFFERS_ARB,1,
WGL_SAMPLES_ARB,8,
0, 0 // End of attributes list
};
int nPixelFormat = 0;
UINT iNumFormats = 0;
wglChoosePixelFormatARB(hdc, iPixelFormatAttribList, NULL, 1, &nPixelFormat, (UINT*)&iNumFormats);
ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
DescribePixelFormat(hdc, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
SetPixelFormat(hdc, nPixelFormat, &pfd);
const int attributes[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 2,
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
NULL
};
hglrc = wglCreateContextAttribsARB(hdc, NULL, attributes);
wglMakeCurrent(hdc, hglrc);
// Load all extensions
if (!gladLoadGL()) {
exit(-1);
}
// OpenGL is now initialized
WindowData windowData = { 0 };
windowData.hwnd = hwnd;
windowData.hglrc = hglrc;
windowData.hdc = hdc;
windowData.hInstance = hInstance;
windowData.closeWindow = false;
LONG_PTR lptr = (LONG_PTR)(&windowData);
SetWindowLongPtrA(hwnd, GWLP_USERDATA, lptr);
ShowWindow(hwnd, SW_NORMAL);
UpdateWindow(hwnd);
void* userData = Initialize(windowData);
MSG msg;
bool running = true;
bool quit = false;
LARGE_INTEGER timerFrequency;
LARGE_INTEGER thisTick;
LARGE_INTEGER lastTick;
LONGLONG timeDelta;
if (!QueryPerformanceFrequency(&timerFrequency)) {
OutputDebugStringA("WinMain: QueryPerformanceFrequency failed\n");
}
QueryPerformanceCounter(&thisTick);
lastTick = thisTick;
while (!quit) {
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
quit = true;
break;
}
TranslateMessage(&msg);
DispatchMessageA(&msg);
}
if (windowData.closeWindow && running) {
Shutdown(userData);
running = false;
}
else if (running) {
RECT clientRect = {};
GetClientRect(hwnd, &clientRect);
QueryPerformanceCounter(&thisTick);
timeDelta = thisTick.QuadPart - lastTick.QuadPart;
double deltaTime = (double)timeDelta * 1000.0 / (double)timerFrequency.QuadPart;
Update(userData, (float)deltaTime);
Render(userData, clientRect);
lastTick = thisTick;
SwapBuffers(hdc);
Sleep(1); // TODO: VSynch
}
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
switch (iMsg) {
case WM_CLOSE:
{
LONG_PTR lptr = GetWindowLongPtrA(hwnd, GWLP_USERDATA);
WindowData* windowData = (WindowData*)lptr;
windowData->closeWindow = true;
}
DestroyWindow(hwnd);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProcA(hwnd, iMsg, wParam, lParam);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment