// first load the opengl loading functions fn b32 w32_load_wgl_fns(void); // then create opengl context for window fn b32 w32_create_opengl_context(HDC window_handle_dc, i32 opengl_major, i32 opengl_minor); // then you can use this to load opengl functions - // either pass this to glad or load them manually fn void *w32_load_opengl_fn(const char *proc); // compile time options #define W32_OPENGL_DEBUG 1 #define W32_ENABLE_MULTISAMPLING 1 // Symbols taken from GLFW // // Executables (but not DLLs) exporting this symbol with this value will be // automatically directed to the high-performance GPU on Nvidia Optimus systems // with up-to-date drivers // __declspec(dllexport) DWORD NvOptimusEnablement = 1; // Executables (but not DLLs) exporting this symbol with this value will be // automatically directed to the high-performance GPU on AMD PowerXpress systems // with up-to-date drivers // __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; typedef HGLRC MU_wglCreateContext(HDC unnamedParam1); typedef BOOL MU_wglMakeCurrent(HDC unnamedParam1, HGLRC unnamedParam2); typedef BOOL MU_wglDeleteContext(HGLRC unnamedParam1); typedef void *MU_glGetProcAddress(const char *); typedef const char *MU_wglGetExtensionsStringARB(HDC hdc); typedef BOOL MU_wglChoosePixelFormatARB(HDC hdc, const int *piAttribIList, const float *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); typedef HGLRC MU_wglCreateContextAttribsARB(HDC hDC, HGLRC hshareContext, const int *attribList); typedef BOOL MU_wglSwapIntervalEXT(int interval); #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_TYPE_RGBA_ARB 0x202B #define WGL_COLOR_BITS_ARB 0x2014 #define WGL_DEPTH_BITS_ARB 0x2022 #define WGL_STENCIL_BITS_ARB 0x2023 #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 #define WGL_CONTEXT_FLAGS_ARB 0x2094 #define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 #define WGL_SAMPLE_BUFFERS_ARB 0x2041 #define WGL_SAMPLES_ARB 0x2042 gb MU_wglChoosePixelFormatARB *wglChoosePixelFormatARB; gb MU_wglCreateContextAttribsARB *wglCreateContextAttribsARB; gb MU_wglSwapIntervalEXT *wglSwapIntervalEXT; gb MU_glGetProcAddress *wgl_get_proc_address; gb void *(*gl_get_proc_address)(const char *str); gb HMODULE opengl_hmodule; gb HGLRC(*mu_wglCreateContext)(HDC unnamedParam1); gb BOOL(*mu_wglMakeCurrent)(HDC unnamedParam1, HGLRC unnamedParam2); gb BOOL(*mu_wglDeleteContext)(HGLRC unnamedParam1); // compares src string with dstlen characters from dst, returns 1 if they are equal, 0 if not fn int w32_are_strings_equal(const char *src, const char *dst, size_t dstlen) { while (*src && dstlen-- && *dst) { if (*src++ != *dst++) { return 0; } } return (dstlen && *src == *dst) || (!dstlen && *src == 0); } fn void *w32_load_opengl_fn(const char *proc) { void *func = wgl_get_proc_address(proc); if (!func) { func = GetProcAddress(opengl_hmodule, proc); } return func; } fn b32 w32_load_wgl_fns(void) { HMODULE opengl32 = LoadLibraryA("opengl32"); assert(opengl32); if (opengl32) { opengl_hmodule = opengl32; wgl_get_proc_address = (MU_glGetProcAddress *)GetProcAddress(opengl32, "wglGetProcAddress"); gl_get_proc_address = w32_load_opengl_fn; mu_wglCreateContext = (MU_wglCreateContext *)GetProcAddress(opengl32, "wglCreateContext"); mu_wglMakeCurrent = (MU_wglMakeCurrent *)GetProcAddress(opengl32, "wglMakeCurrent"); mu_wglDeleteContext = (MU_wglDeleteContext *)GetProcAddress(opengl32, "wglDeleteContext"); } if (opengl32 == NULL || mu_wglCreateContext == NULL || gl_get_proc_address == NULL || mu_wglMakeCurrent == NULL || mu_wglDeleteContext == NULL) { assert(!"Failed to load Opengl wgl functions from opengl32.lib"); } // to get WGL functions we need valid GL context, so create dummy window for dummy GL contetx HWND dummy = CreateWindowExW( 0, L"STATIC", L"DummyWindow", WS_OVERLAPPED, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL); assert(dummy && "Failed to create dummy window"); HDC dc = GetDC(dummy); assert(dc && "Failed to get device context for dummy window"); PIXELFORMATDESCRIPTOR desc = {0}; { desc.nSize = sizeof(desc); desc.nVersion = 1; desc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; desc.iPixelType = PFD_TYPE_RGBA; desc.cColorBits = 24; }; int format = ChoosePixelFormat(dc, &desc); if (!format) { assert(!"Cannot choose OpenGL pixel format for dummy window!"); } int ok = DescribePixelFormat(dc, format, sizeof(desc), &desc); assert(ok && "Failed to describe OpenGL pixel format"); // reason to create dummy window is that SetPixelFormat can be called only once for the window if (!SetPixelFormat(dc, format, &desc)) { assert(!"Cannot set OpenGL pixel format for dummy window!"); } HGLRC rc = mu_wglCreateContext(dc); assert(rc && "Failed to create OpenGL context for dummy window"); ok = mu_wglMakeCurrent(dc, rc); assert(ok && "Failed to make current OpenGL context for dummy window"); // https://www.khronos.org/registry/OpenGL/extensions/ARB/WGL_ARB_extensions_string.txt MU_wglGetExtensionsStringARB *wglGetExtensionsStringARB = (MU_wglGetExtensionsStringARB *)gl_get_proc_address("wglGetExtensionsStringARB"); if (!wglGetExtensionsStringARB) { assert(!"OpenGL does not support WGL_ARB_extensions_string extension!"); } const char *ext = wglGetExtensionsStringARB(dc); assert(ext && "Failed to get OpenGL WGL extension string"); const char *start = ext; for (;;) { while (*ext != 0 && *ext != ' ') { ext++; } size_t length = ext - start; if (w32_are_strings_equal("WGL_ARB_pixel_format", start, length)) { // https://www.khronos.org/registry/OpenGL/extensions/ARB/WGL_ARB_pixel_format.txt wglChoosePixelFormatARB = (MU_wglChoosePixelFormatARB *)gl_get_proc_address("wglChoosePixelFormatARB"); } else if (w32_are_strings_equal("WGL_ARB_create_context", start, length)) { // https://www.khronos.org/registry/OpenGL/extensions/ARB/WGL_ARB_create_context.txt wglCreateContextAttribsARB = (MU_wglCreateContextAttribsARB *)gl_get_proc_address("wglCreateContextAttribsARB"); } else if (w32_are_strings_equal("WGL_EXT_swap_control", start, length)) { // https://www.khronos.org/registry/OpenGL/extensions/EXT/WGL_EXT_swap_control.txt wglSwapIntervalEXT = (MU_wglSwapIntervalEXT *)gl_get_proc_address("wglSwapIntervalEXT"); } if (*ext == 0) { break; } ext++; start = ext; } if (!wglChoosePixelFormatARB || !wglCreateContextAttribsARB || !wglSwapIntervalEXT) { assert(!"OpenGL does not support required WGL extensions for modern context!"); } BOOL ok_b = mu_wglMakeCurrent(NULL, NULL); assert(ok_b); ok_b = mu_wglDeleteContext(rc); assert(ok_b); ok = ReleaseDC(dummy, dc); assert(ok); ok_b = DestroyWindow(dummy); assert(ok_b); return true; } fn b32 w32_create_opengl_context(HDC window_handle_dc, i32 opengl_major, i32 opengl_minor) { // set pixel format for OpenGL context int attrib[] = { WGL_DRAW_TO_WINDOW_ARB, true, WGL_SUPPORT_OPENGL_ARB, true, WGL_DOUBLE_BUFFER_ARB, true, WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, WGL_COLOR_BITS_ARB, 32, WGL_DEPTH_BITS_ARB, 24, WGL_STENCIL_BITS_ARB, 8, // uncomment for sRGB framebuffer, from WGL_ARB_framebuffer_sRGB extension // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_framebuffer_sRGB.txt // WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, GL_TRUE, // uncomment for multisampeld framebuffer, from WGL_ARB_multisample extension // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_multisample.txt #if W32_ENABLE_MULTISAMPLING WGL_SAMPLE_BUFFERS_ARB, 1, WGL_SAMPLES_ARB, 4, // 4x MSAA #endif 0, }; int format; UINT formats; if (!wglChoosePixelFormatARB(window_handle_dc, attrib, 0, 1, &format, &formats) || formats == 0) { assert(!"OpenGL does not support required pixel format!"); } PIXELFORMATDESCRIPTOR desc = {0}; desc.nSize = sizeof(desc); int ok = DescribePixelFormat(window_handle_dc, format, sizeof(desc), &desc); assert(ok && "Failed to describe OpenGL pixel format"); if (!SetPixelFormat(window_handle_dc, format, &desc)) { assert(!"Cannot set OpenGL selected pixel format!"); } // create modern OpenGL context { int attrib[] = { WGL_CONTEXT_MAJOR_VERSION_ARB, opengl_major, WGL_CONTEXT_MINOR_VERSION_ARB, opengl_minor, WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, #if W32_OPENGL_DEBUG WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB, #endif 0, }; HGLRC rc = wglCreateContextAttribsARB(window_handle_dc, 0, attrib); assert(rc && "Cannot create modern OpenGL context! OpenGL version not supported?"); BOOL ok = mu_wglMakeCurrent(window_handle_dc, rc); assert(ok && "Failed to make current OpenGL context"); } return true; }