Skip to content

Instantly share code, notes, and snippets.

@stillwwater
Created November 17, 2023 04:44
Show Gist options
  • Save stillwwater/b5f8c659979fb6f9657239b833432d54 to your computer and use it in GitHub Desktop.
Save stillwwater/b5f8c659979fb6f9657239b833432d54 to your computer and use it in GitHub Desktop.
Create a modern OpenGL context on Windows
// Initializes an OpenGL device context for a given window.
void
gl_create_context(HWND hwnd)
{
HDC hdc;
HGLRC hglrc;
int pfd_index;
PIXELFORMATDESCRIPTOR pfd, device_pfd;
// in order to load a modern opengl context we first need to load an old
// opengl using a dummy window and use it to query the extension to load a
// modern context.
WNDCLASSA wndclass = {0};
wndclass.lpfnWndProc = DefWindowProcA;
wndclass.hInstance = GetModuleHandleA(NULL);
wndclass.lpszClassName = "WNDWGLLOADER";
RegisterClassA(&wndclass);
HWND glwnd = CreateWindowA("WNDWGLLOADER", "",
CS_OWNDC, 0, 0, 0, 0, NULL, NULL, wndclass.hInstance, NULL);
if (!glwnd) {
fprintf(stderr, "Failed to create dummy GL window (0x%lX)", GetLastError());
}
ZeroMemory(&pfd, sizeof(pfd));
// we're doing this again later, for now all we care about is a PFD that
// supports opengl
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cAlphaBits = 8;
pfd.cDepthBits = 24;
pfd.cStencilBits = 8;
pfd.iLayerType = PFD_MAIN_PLANE;
hdc = GetDC(glwnd);
pfd_index = ChoosePixelFormat(hdc, &pfd);
DescribePixelFormat(hdc, pfd_index, sizeof(device_pfd), &device_pfd);
if (!SetPixelFormat(hdc, pfd_index, &device_pfd)) {
fprintf(stderr, "Failed to find a suitable pixel format for the graphics context (0x%lX).", GetLastError());
}
// create opengl device context for the current window
hglrc = wglCreateContext(hdc);
if (!wglMakeCurrent(hdc, hglrc)) {
fprintf(stderr, "Failed to create an opengl context (0x%lX).", GetLastError());
}
// load the extensions we need in order to load the real context
wglCreateContextAttribsARB = (wglCreateContextAttribsARB_t *)wglGetProcAddress("wglCreateContextAttribsARB");
wglChoosePixelFormatARB = (wglChoosePixelFormatARB_t *)wglGetProcAddress("wglChoosePixelFormatARB");
wglSwapIntervalEXT = (wglSwapIntervalEXT_t *)wglGetProcAddress("wglSwapIntervalEXT");
if (!wglCreateContextAttribsARB || !wglChoosePixelFormatARB) {
fprintf(stderr, "Failed to load opengl extensions");
}
wglMakeCurrent(hdc, 0);
wglDeleteContext(hglrc);
ReleaseDC(glwnd, hdc);
DestroyWindow(glwnd);
if (wglSwapIntervalEXT)
wglSwapIntervalEXT(1);
opengl32_dll = LoadLibraryA("opengl32.dll");
if (!opengl32_dll) {
fprintf(stderr, "Missing opengl32.dll (0x%lX)", GetLastError());
}
// do it for real this time
hdc = GetDC(hwnd);
ZeroMemory(&pfd, sizeof pfd);
int pf_attribs[] = {
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_COLOR_BITS_ARB, 32,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
0,
};
int context_attribs[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, MV_MIN_GL_MAJOR_VERSION,
WGL_CONTEXT_MINOR_VERSION_ARB, MV_MIN_GL_MINOR_VERSION,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0,
} ;
UINT n_formats;
wglChoosePixelFormatARB(hdc, pf_attribs, NULL, 1, &pfd_index, &n_formats);
if (n_formats == 0) {
fprintf(stderr, "No suitable pixel format returned by wglChoosePixelFormatARB.");
}
DescribePixelFormat(hdc, pfd_index, sizeof(pfd), &pfd);
if (!SetPixelFormat(hdc, pfd_index, &pfd)) {
fprintf(stderr, "Failed to find a suitable pixel format for the graphics context (0x%lX).", GetLastError());
}
hglrc = wglCreateContextAttribsARB(hdc, 0, context_attribs);
if (!wglMakeCurrent(hdc, hglrc)) {
fprintf(stderr, "Failed to create an opengl context (0x%lX).", GetLastError());
}
ReleaseDC(hwnd, hdc);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment