cae  0.0.0
Cross-API graphics engine
Loading...
Searching...
No Matches
WGLContext.cpp
Go to the documentation of this file.
1#ifdef _WIN32
2
4
5#include "Utils/Logger.hpp"
6
7#include <stdexcept>
8
9typedef HGLRC(WINAPI *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *);
10typedef const char *(WINAPI *PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC);
11
12#ifndef WGL_CONTEXT_MAJOR_VERSION_ARB
13#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
14#endif
15#ifndef WGL_CONTEXT_MINOR_VERSION_ARB
16#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
17#endif
18#ifndef WGL_CONTEXT_FLAGS_ARB
19#define WGL_CONTEXT_FLAGS_ARB 0x2094
20#endif
21#ifndef WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB
22#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
23#endif
24#ifndef WGL_CONTEXT_PROFILE_MASK_ARB
25#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
26#endif
27#ifndef WGL_CONTEXT_CORE_PROFILE_BIT_ARB
28#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
29#endif
30
31static HMODULE g_opengl32 = nullptr;
32
33static void *win32GetGLProc(const char *name)
34{
35 auto *proc = (void *)wglGetProcAddress(name);
36
37 if (proc == nullptr || proc == reinterpret_cast<void *>(0x1) || proc == reinterpret_cast<void *>(0x2) ||
38 proc == reinterpret_cast<void *>(0x3) || proc == reinterpret_cast<void *>(-1))
39 {
40 if (g_opengl32 == nullptr)
41 {
42 g_opengl32 = LoadLibraryA("opengl32.dll");
43 }
44
45 proc = (void *)GetProcAddress(g_opengl32, name);
46 }
47
48 return proc;
49}
50
51cae::WGLContext::~WGLContext()
52{
53 if (m_hglrc != nullptr)
54 {
55 wglMakeCurrent(nullptr, nullptr);
56 wglDeleteContext(m_hglrc);
57 }
58 if ((m_hdc != nullptr) && (m_hwnd != nullptr))
59 {
60 ReleaseDC(m_hwnd, m_hdc);
61 }
62}
63
64void cae::WGLContext::initialize(const NativeWindowHandle &window)
65{
66 m_hwnd = static_cast<HWND>(window.window);
67 m_hdc = GetDC(m_hwnd);
68 if (m_hdc == nullptr)
69 {
70 throw std::runtime_error("Failed to get HDC from HWND");
71 }
72
73 PIXELFORMATDESCRIPTOR pfd{};
74 pfd.nSize = sizeof(pfd);
75 pfd.nVersion = 1;
76 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
77 pfd.iPixelType = PFD_TYPE_RGBA;
78 pfd.cColorBits = 32;
79 pfd.cDepthBits = 24;
80 pfd.iLayerType = PFD_MAIN_PLANE;
81
82 const int pf = ChoosePixelFormat(m_hdc, &pfd);
83 if (pf == 0)
84 {
85 throw std::runtime_error("Failed to choose pixel format");
86 }
87 if (SetPixelFormat(m_hdc, pf, &pfd) == 0)
88 {
89 throw std::runtime_error("Failed to set pixel format");
90 }
91
92 const HGLRC tempContext = wglCreateContext(m_hdc);
93 if (tempContext == nullptr)
94 {
95 throw std::runtime_error("Failed to create temporary WGL context");
96 }
97 if (wglMakeCurrent(m_hdc, tempContext) == 0)
98 {
99 throw std::runtime_error("Failed to make temporary context current");
100 }
101
102 const auto wglCreateContextAttribsARB =
103 reinterpret_cast<PFNWGLCREATECONTEXTATTRIBSARBPROC>(wglGetProcAddress("wglCreateContextAttribsARB"));
104
105 if (wglCreateContextAttribsARB != nullptr)
106 {
107 const int attribs[] = {WGL_CONTEXT_MAJOR_VERSION_ARB,
108 4,
109 WGL_CONTEXT_MINOR_VERSION_ARB,
110 6,
111 WGL_CONTEXT_FLAGS_ARB,
112 WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
113 WGL_CONTEXT_PROFILE_MASK_ARB,
114 WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
115 0};
116
117 const HGLRC modernContext = wglCreateContextAttribsARB(m_hdc, nullptr, attribs);
118 if (modernContext == nullptr)
119 {
120 throw std::runtime_error("Failed to create modern WGL context");
121 }
122
123 wglMakeCurrent(nullptr, nullptr);
124 wglDeleteContext(tempContext);
125
126 m_hglrc = modernContext;
127 if (wglMakeCurrent(m_hdc, m_hglrc) == 0)
128 {
129 throw std::runtime_error("Failed to make modern WGL context current");
130 }
131 }
132 else
133 {
134 utl::Logger::log("wglCreateContextAttribsARB not available, using legacy context\n", utl::LogLevel::WARNING);
135 m_hglrc = tempContext;
136 }
137
138 if (wglGetCurrentContext() != m_hglrc)
139 {
140 throw std::runtime_error("Current WGL context is not the one just created");
141 }
142 if (const int version = gladLoadGLContext(&gl, reinterpret_cast<GLADloadfunc>(win32GetGLProc)); version == 0)
143 {
144 throw std::runtime_error("Failed to initialize GLAD MX (Windows)");
145 }
146 if (gl.Enable != nullptr)
147 {
148 gl.Enable(GL_DEBUG_OUTPUT);
149#ifdef CAE_DEBUG
150 gl.DebugMessageCallback([](GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
151 const GLchar *message, const void *userParam)
152 { utl::Logger::log("[GL DEBUG] " + std::string(message), utl::LogLevel::WARNING); },
153 nullptr);
154#endif
155 }
156}
157
158void cae::WGLContext::swapBuffers()
159{
160 if (m_hdc != nullptr)
161 {
162 SwapBuffers(m_hdc);
163 }
164}
165
166void cae::WGLContext::setVSyncEnabled(const bool enabled)
167{
168 using PFNWGLSWAPINTERVALEXTPROC = BOOL(WINAPI *)(int);
169 static auto wglSwapIntervalEXT =
170 reinterpret_cast<PFNWGLSWAPINTERVALEXTPROC>(wglGetProcAddress("wglSwapIntervalEXT"));
171 if (wglSwapIntervalEXT != nullptr)
172 {
173 wglSwapIntervalEXT(enabled ? 1 : 0);
174 }
175}
176
177#endif
This file contains the Logger class.
This file contains the WGLContext class declaration.
static void log(const std::string &message, const LogLevel &logLevel)
Log a message with a specific log level.
Definition Logger.hpp:71