win32_app
This commit is contained in:
270
src/app/app_win32_opengl.c
Normal file
270
src/app/app_win32_opengl.c
Normal file
@@ -0,0 +1,270 @@
|
||||
// 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
|
||||
|
||||
global MU_wglChoosePixelFormatARB *wglChoosePixelFormatARB;
|
||||
global MU_wglCreateContextAttribsARB *wglCreateContextAttribsARB;
|
||||
global MU_wglSwapIntervalEXT *wglSwapIntervalEXT;
|
||||
|
||||
global MU_glGetProcAddress *wgl_get_proc_address;
|
||||
global void *(*gl_get_proc_address)(const char *str);
|
||||
global HMODULE opengl_hmodule;
|
||||
|
||||
global HGLRC(*mu_wglCreateContext)(HDC unnamedParam1);
|
||||
global BOOL(*mu_wglMakeCurrent)(HDC unnamedParam1, HGLRC unnamedParam2);
|
||||
global 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;
|
||||
}
|
||||
Reference in New Issue
Block a user