Created
May 30, 2022 20:53
-
-
Save bplaat/96c7031470ddd6a14f7d6f1c506026a6 to your computer and use it in GitHub Desktop.
Win32 OpenGL 1.0 Example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Win32 OpenGL 1.0 Example | |
// gcc opengl.c -c -o opengl.o && ld -s opengl.o -lkernel32 -luser32 -lgdi32 -lopengl32 -o opengl.exe -e _start && ./opengl | |
// --subsystem windows | |
#define UNICODE | |
#include <windows.h> | |
#include <GL/gl.h> | |
// Window state | |
wchar_t *windowTitle = L"Win32 OpenGL Example"; | |
UINT windowWidth = 1280; | |
UINT windowHeight = 720; | |
#define windowMinWidth 320 | |
#define windowMinHeight 240 | |
UINT windowDpi; | |
UINT windowRealWidth; | |
UINT windowRealHeight; | |
// Dpi helpers | |
#define PROCESS_PER_MONITOR_DPI_AWARE 2 | |
typedef int (STDMETHODCALLTYPE *_SetProcessDpiAwarenessContext)(void *value); | |
typedef int (STDMETHODCALLTYPE *_SetProcessDpiAwareness)(UINT value); | |
typedef BOOL (STDMETHODCALLTYPE *_SetProcessDPIAware)(void); | |
void SetDpiAware(void) { | |
HMODULE huser32 = LoadLibrary(L"user32.dll"); | |
_SetProcessDpiAwarenessContext SetProcessDpiAwarenessContext = (_SetProcessDpiAwarenessContext)GetProcAddress(huser32, "SetProcessDpiAwarenessContext"); | |
if (SetProcessDpiAwarenessContext != NULL) { | |
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); | |
return; | |
} | |
HMODULE hshcore = LoadLibrary(L"shcore.dll"); | |
_SetProcessDpiAwareness SetProcessDpiAwareness = (_SetProcessDpiAwareness)GetProcAddress(hshcore, "SetProcessDpiAwareness"); | |
if (SetProcessDpiAwareness != NULL) { | |
SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); | |
return; | |
} | |
_SetProcessDPIAware SetProcessDPIAware = (_SetProcessDPIAware)GetProcAddress(huser32, "SetProcessDPIAware"); | |
if (SetProcessDPIAware != NULL) SetProcessDPIAware(); | |
} | |
int GetDesktopDpi(void) { | |
HDC hdc = GetDC(HWND_DESKTOP); | |
int dpi = GetDeviceCaps(hdc, LOGPIXELSY); | |
ReleaseDC(HWND_DESKTOP, hdc); | |
return dpi; | |
} | |
typedef BOOL (STDMETHODCALLTYPE *_AdjustWindowRectExForDpi)(RECT *lpRect, UINT dwStyle, BOOL bMenu, UINT dwExStyle, UINT dpi); | |
BOOL AdjustWindowRectExForDpi(RECT *lpRect, UINT dwStyle, BOOL bMenu, UINT dwExStyle, UINT dpi) { | |
HMODULE huser32 = LoadLibrary(L"user32.dll"); | |
_AdjustWindowRectExForDpi AdjustWindowRectExForDpi = (_AdjustWindowRectExForDpi)GetProcAddress(huser32, "AdjustWindowRectExForDpi"); | |
if (AdjustWindowRectExForDpi != NULL) return AdjustWindowRectExForDpi(lpRect, dwStyle, bMenu, dwExStyle, dpi); | |
return AdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle); | |
} | |
// Dwm helpers | |
#define DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 19 | |
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 | |
typedef HRESULT (STDMETHODCALLTYPE *_DwmSetWindowAttribute)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute); | |
void SetWindowImmersiveDarkMode(HWND hwnd, BOOL enabled) { | |
HMODULE hdwmapi = LoadLibrary(L"dwmapi.dll"); | |
_DwmSetWindowAttribute DwmSetWindowAttribute = (_DwmSetWindowAttribute)GetProcAddress(hdwmapi, "DwmSetWindowAttribute"); | |
if (DwmSetWindowAttribute != NULL) { | |
if (FAILED(DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &enabled, sizeof(BOOL)))) { | |
DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, &enabled, sizeof(BOOL)); | |
} | |
} | |
} | |
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { | |
if (msg == WM_DPICHANGED) { | |
windowDpi = HIWORD(wParam); | |
RECT *window_rect = (RECT *)lParam; | |
SetWindowPos(hwnd, NULL, window_rect->left, window_rect->top, window_rect->right - window_rect->left, | |
window_rect->bottom - window_rect->top, SWP_NOZORDER | SWP_NOACTIVATE); | |
return 0; | |
} | |
if (msg == WM_SIZE) { | |
windowRealWidth = LOWORD(lParam); | |
windowRealHeight = HIWORD(lParam); | |
windowWidth = MulDiv(windowRealWidth, USER_DEFAULT_SCREEN_DPI, windowDpi); | |
windowHeight = MulDiv(windowRealHeight, USER_DEFAULT_SCREEN_DPI, windowDpi); | |
wchar_t windowTitleBuffer[512]; | |
wsprintf(windowTitleBuffer, L"%s (%dx%d@%d -> %dx%d)", windowTitle, windowWidth, windowHeight, windowDpi, windowRealWidth, windowRealHeight); | |
SetWindowText(hwnd, windowTitleBuffer); | |
return 0; | |
} | |
if (msg == WM_GETMINMAXINFO) { | |
RECT windowRect = {0}; | |
windowRect.right = MulDiv(windowMinWidth, windowDpi, USER_DEFAULT_SCREEN_DPI); | |
windowRect.bottom = MulDiv(windowMinHeight, windowDpi, USER_DEFAULT_SCREEN_DPI); | |
AdjustWindowRectExForDpi(&windowRect, WS_OVERLAPPEDWINDOW, FALSE, 0, windowDpi); | |
MINMAXINFO *minMaxInfo = (MINMAXINFO *)lParam; | |
minMaxInfo->ptMinTrackSize.x = windowRect.right - windowRect.left; | |
minMaxInfo->ptMinTrackSize.y = windowRect.bottom - windowRect.top; | |
return 0; | |
} | |
if (msg == WM_PAINT) { | |
PAINTSTRUCT ps; | |
BeginPaint(hwnd, &ps); | |
glViewport(0, 0, windowRealWidth, windowRealHeight); | |
glClearColor(0, 0, 0, 1); | |
glClear(GL_COLOR_BUFFER_BIT); | |
glBegin(GL_QUADS); | |
glColor3f(1, 1, 1); | |
glVertex2f(-0.5, 0.5); | |
glColor3f(1, 0, 0); | |
glVertex2f(0.5, 0.5); | |
glColor3f(0, 1, 0); | |
glVertex2f(0.5, -0.5); | |
glColor3f(0, 0, 1); | |
glVertex2f(-0.5, -0.5); | |
glEnd(); | |
glFlush(); | |
SwapBuffers(ps.hdc); | |
EndPaint(hwnd, &ps); | |
return 0; | |
} | |
if (msg == WM_ERASEBKGND) { | |
return FALSE; | |
} | |
if (msg == WM_DESTROY) { | |
PostQuitMessage(0); | |
return 0; | |
} | |
return DefWindowProc(hwnd, msg, wParam, lParam); | |
} | |
void _start(void) { | |
SetDpiAware(); | |
WNDCLASSEX wc = {0}; | |
wc.cbSize = sizeof(WNDCLASSEX); | |
wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; | |
wc.lpfnWndProc = WndProc; | |
wc.hInstance = GetModuleHandle(NULL); | |
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); | |
wc.hCursor = LoadCursor(NULL, IDC_ARROW); | |
wc.lpszClassName = L"opengl-example"; | |
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); | |
RegisterClassEx(&wc); | |
windowDpi = GetDesktopDpi(); | |
windowRealWidth = MulDiv(windowWidth, windowDpi, USER_DEFAULT_SCREEN_DPI); | |
windowRealHeight = MulDiv(windowHeight, windowDpi, USER_DEFAULT_SCREEN_DPI); | |
RECT windowRect; | |
windowRect.left = (GetSystemMetrics(SM_CXSCREEN) - windowRealWidth) / 2; | |
windowRect.top = (GetSystemMetrics(SM_CYSCREEN) - windowRealHeight) / 2; | |
windowRect.right = windowRect.left + windowRealWidth; | |
windowRect.bottom = windowRect.top + windowRealHeight; | |
AdjustWindowRectExForDpi(&windowRect, WS_OVERLAPPEDWINDOW, FALSE, 0, windowDpi); | |
HWND hwnd = CreateWindowEx(0, wc.lpszClassName, windowTitle, WS_OVERLAPPEDWINDOW, | |
windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, | |
NULL, NULL, wc.hInstance, NULL); | |
SetWindowImmersiveDarkMode(hwnd, TRUE); | |
HDC hdc = GetDC(hwnd); | |
PIXELFORMATDESCRIPTOR pixelFormatDesc = {0}; | |
pixelFormatDesc.nSize = sizeof(PIXELFORMATDESCRIPTOR); | |
pixelFormatDesc.nVersion = 1; | |
pixelFormatDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; | |
pixelFormatDesc.iPixelType = PFD_TYPE_RGBA; | |
pixelFormatDesc.cColorBits = 32; | |
pixelFormatDesc.cAlphaBits = 8; | |
pixelFormatDesc.cDepthBits = 24; | |
SetPixelFormat(hdc, ChoosePixelFormat(hdc, &pixelFormatDesc), &pixelFormatDesc); | |
HGLRC renderContext = wglCreateContext(hdc); | |
wglMakeCurrent(hdc, renderContext); | |
ReleaseDC(hwnd, hdc); | |
wchar_t openglInfoBuffer[512]; | |
int length = wsprintf(openglInfoBuffer, L"[INFO] Using %hs on %hs\r\n", glGetString(GL_VERSION), glGetString(GL_RENDERER)); | |
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), openglInfoBuffer, length, NULL, NULL); | |
ShowWindow(hwnd, SW_SHOWDEFAULT); | |
UpdateWindow(hwnd); | |
MSG msg; | |
while(GetMessage(&msg, NULL, 0, 0) > 0) { | |
TranslateMessage(&msg); | |
DispatchMessage(&msg); | |
} | |
ExitProcess(msg.wParam); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment