1 // Copyright (C) 2013 Christian Stehno
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in Irrlicht.h
5 #include "CWGLManager.h"
7 #ifdef _IRR_COMPILE_WITH_WGL_MANAGER_
12 #include <GL/wglext.h>
19 CWGLManager::CWGLManager() :
20 PrimaryContext(SExposedVideoData(0)), PixelFormat(0), libHandle(NULL
)
23 setDebugName("CWGLManager");
25 memset(FunctionPointers
, 0, sizeof(FunctionPointers
));
28 CWGLManager::~CWGLManager()
32 bool CWGLManager::initialize(const SIrrlichtCreationParameters
¶ms
, const SExposedVideoData
&videodata
)
34 // store params, videoData is set later as it would be overwritten else
37 // Create a window to test antialiasing support
38 const fschar_t
*ClassName
= __TEXT("CWGLManager");
39 HINSTANCE lhInstance
= GetModuleHandle(0);
43 wcex
.cbSize
= sizeof(WNDCLASSEX
);
44 wcex
.style
= CS_HREDRAW
| CS_VREDRAW
;
45 wcex
.lpfnWndProc
= (WNDPROC
)DefWindowProc
;
48 wcex
.hInstance
= lhInstance
;
50 wcex
.hCursor
= LoadCursor(NULL
, IDC_ARROW
);
51 wcex
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
52 wcex
.lpszMenuName
= 0;
53 wcex
.lpszClassName
= ClassName
;
55 RegisterClassEx(&wcex
);
60 clientSize
.right
= Params
.WindowSize
.Width
;
61 clientSize
.bottom
= Params
.WindowSize
.Height
;
63 DWORD style
= WS_POPUP
;
64 if (!Params
.Fullscreen
)
65 style
= WS_SYSMENU
| WS_BORDER
| WS_CAPTION
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
;
67 AdjustWindowRect(&clientSize
, style
, FALSE
);
69 const s32 realWidth
= clientSize
.right
- clientSize
.left
;
70 const s32 realHeight
= clientSize
.bottom
- clientSize
.top
;
72 const s32 windowLeft
= (GetSystemMetrics(SM_CXSCREEN
) - realWidth
) / 2;
73 const s32 windowTop
= (GetSystemMetrics(SM_CYSCREEN
) - realHeight
) / 2;
75 HWND temporary_wnd
= CreateWindow(ClassName
, __TEXT(""), style
, windowLeft
,
76 windowTop
, realWidth
, realHeight
, NULL
, NULL
, lhInstance
, NULL
);
79 os::Printer::log("Cannot create a temporary window.", ELL_ERROR
);
80 UnregisterClass(ClassName
, lhInstance
);
84 HDC HDc
= GetDC(temporary_wnd
);
86 // Set up pixel format descriptor with desired parameters
87 PIXELFORMATDESCRIPTOR tmp_pfd
= {
88 sizeof(PIXELFORMATDESCRIPTOR
), // Size Of This Pixel Format Descriptor
90 (DWORD
)(PFD_DRAW_TO_WINDOW
| // Format Must Support Window
91 PFD_SUPPORT_OPENGL
| // Format Must Support OpenGL
92 (Params
.Doublebuffer
? PFD_DOUBLEBUFFER
: 0) | // Must Support Double Buffering
93 (Params
.Stereobuffer
? PFD_STEREO
: 0)), // Must Support Stereo Buffer
94 PFD_TYPE_RGBA
, // Request An RGBA Format
95 Params
.Bits
, // Select Our Color Depth
96 0, 0, 0, 0, 0, 0, // Color Bits Ignored
98 0, // Shift Bit Ignored
99 0, // No Accumulation Buffer
100 0, 0, 0, 0, // Accumulation Bits Ignored
101 Params
.ZBufferBits
, // Z-Buffer (Depth Buffer)
102 BYTE(Params
.Stencilbuffer
? 1 : 0), // Stencil Buffer Depth
103 0, // No Auxiliary Buffer
104 PFD_MAIN_PLANE
, // Main Drawing Layer
106 0, 0, 0 // Layer Masks Ignored
110 for (u32 i
= 0; i
< 6; ++i
) {
112 if (Params
.Stencilbuffer
) {
113 os::Printer::log("Cannot create a GL device with stencil buffer, disabling stencil shadows.", ELL_WARNING
);
114 Params
.Stencilbuffer
= false;
115 pfd
.cStencilBits
= 0;
121 if (Params
.Bits
!= 16)
127 if (Params
.Doublebuffer
)
128 pfd
.dwFlags
&= ~PFD_DOUBLEBUFFER
;
132 os::Printer::log("Cannot create a GL device context", "No suitable format for temporary window.", ELL_ERROR
);
133 ReleaseDC(temporary_wnd
, HDc
);
134 DestroyWindow(temporary_wnd
);
135 UnregisterClass(ClassName
, lhInstance
);
139 // choose pixelformat
140 PixelFormat
= ChoosePixelFormat(HDc
, &pfd
);
145 SetPixelFormat(HDc
, PixelFormat
, &pfd
);
146 os::Printer::log("Create temporary GL rendering context", ELL_DEBUG
);
147 HGLRC hrc
= wglCreateContext(HDc
);
149 os::Printer::log("Cannot create a temporary GL rendering context.", ELL_ERROR
);
150 ReleaseDC(temporary_wnd
, HDc
);
151 DestroyWindow(temporary_wnd
);
152 UnregisterClass(ClassName
, lhInstance
);
156 CurrentContext
.OpenGLWin32
.HDc
= HDc
;
157 CurrentContext
.OpenGLWin32
.HRc
= hrc
;
158 CurrentContext
.OpenGLWin32
.HWnd
= temporary_wnd
;
160 if (!activateContext(CurrentContext
, false)) {
161 os::Printer::log("Cannot activate a temporary GL rendering context.", ELL_ERROR
);
162 wglDeleteContext(hrc
);
163 ReleaseDC(temporary_wnd
, HDc
);
164 DestroyWindow(temporary_wnd
);
165 UnregisterClass(ClassName
, lhInstance
);
169 core::stringc wglExtensions
;
170 #ifdef WGL_ARB_extensions_string
171 PFNWGLGETEXTENSIONSSTRINGARBPROC irrGetExtensionsString
= (PFNWGLGETEXTENSIONSSTRINGARBPROC
)wglGetProcAddress("wglGetExtensionsStringARB");
172 if (irrGetExtensionsString
)
173 wglExtensions
= irrGetExtensionsString(HDc
);
174 #elif defined(WGL_EXT_extensions_string)
175 PFNWGLGETEXTENSIONSSTRINGEXTPROC irrGetExtensionsString
= (PFNWGLGETEXTENSIONSSTRINGEXTPROC
)wglGetProcAddress("wglGetExtensionsStringEXT");
176 if (irrGetExtensionsString
)
177 wglExtensions
= irrGetExtensionsString(HDc
);
179 const bool pixel_format_supported
= (wglExtensions
.find("WGL_ARB_pixel_format") != -1);
180 const bool multi_sample_supported
= ((wglExtensions
.find("WGL_ARB_multisample") != -1) ||
181 (wglExtensions
.find("WGL_EXT_multisample") != -1) || (wglExtensions
.find("WGL_3DFX_multisample") != -1));
182 if (params
.DriverDebug
)
183 os::Printer::log("WGL_extensions", wglExtensions
);
185 // Without a GL context we can't call wglGetProcAddress so store this for later
186 FunctionPointers
[0] = (void *)wglGetProcAddress("wglCreateContextAttribsARB");
188 #ifdef WGL_ARB_pixel_format
189 PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormat_ARB
= (PFNWGLCHOOSEPIXELFORMATARBPROC
)wglGetProcAddress("wglChoosePixelFormatARB");
190 if (pixel_format_supported
&& wglChoosePixelFormat_ARB
) {
191 // This value determines the number of samples used for antialiasing
192 // My experience is that 8 does not show a big
193 // improvement over 4, but 4 shows a big improvement
196 if (Params
.AntiAlias
> 32)
197 Params
.AntiAlias
= 32;
199 f32 fAttributes
[] = {0.0, 0.0};
200 s32 iAttributes
[] = {
201 WGL_DRAW_TO_WINDOW_ARB
, 1,
202 WGL_SUPPORT_OPENGL_ARB
, 1,
203 WGL_ACCELERATION_ARB
, WGL_FULL_ACCELERATION_ARB
,
204 WGL_COLOR_BITS_ARB
, (Params
.Bits
== 32) ? 24 : 15,
205 WGL_ALPHA_BITS_ARB
, (Params
.Bits
== 32) ? 8 : 1,
206 WGL_DEPTH_BITS_ARB
, Params
.ZBufferBits
, // 10,11
207 WGL_STENCIL_BITS_ARB
, Params
.Stencilbuffer
? 1 : 0,
208 WGL_DOUBLE_BUFFER_ARB
, Params
.Doublebuffer
? 1 : 0,
209 WGL_STEREO_ARB
, Params
.Stereobuffer
? 1 : 0,
210 WGL_PIXEL_TYPE_ARB
, WGL_TYPE_RGBA_ARB
,
211 #ifdef WGL_ARB_multisample
212 WGL_SAMPLES_ARB
, Params
.AntiAlias
, // 20,21
213 WGL_SAMPLE_BUFFERS_ARB
, (Params
.AntiAlias
> 0) ? 1 : 0,
214 #elif defined(WGL_EXT_multisample)
215 WGL_SAMPLES_EXT
, AntiAlias
, // 20,21
216 WGL_SAMPLE_BUFFERS_EXT
, (Params
.AntiAlias
> 0) ? 1 : 0,
217 #elif defined(WGL_3DFX_multisample)
218 WGL_SAMPLES_3DFX
, AntiAlias
, // 20,21
219 WGL_SAMPLE_BUFFERS_3DFX
, (Params
.AntiAlias
> 0) ? 1 : 0,
221 // WGL_DEPTH_FLOAT_EXT, 1,
224 int iAttrSize
= sizeof(iAttributes
) / sizeof(int);
225 if (!multi_sample_supported
) {
226 memmove(&iAttributes
[20], &iAttributes
[24], sizeof(int) * (iAttrSize
- 24));
231 // Try to get an acceptable pixel format
235 const BOOL valid
= wglChoosePixelFormat_ARB(HDc
, iAttributes
, fAttributes
, 1, &pixelFormat
, &numFormats
);
237 if (valid
&& numFormats
)
240 iAttributes
[21] -= 1;
241 } while (rv
== 0 && iAttributes
[21] > 1);
244 Params
.AntiAlias
= iAttributes
[21];
248 Params
.AntiAlias
= 0;
250 // this only terminates the temporary HRc
254 DestroyWindow(temporary_wnd
);
255 UnregisterClass(ClassName
, lhInstance
);
257 // now get new window
258 CurrentContext
.OpenGLWin32
.HWnd
= videodata
.OpenGLWin32
.HWnd
;
260 if (!(CurrentContext
.OpenGLWin32
.HDc
= GetDC((HWND
)videodata
.OpenGLWin32
.HWnd
))) {
261 os::Printer::log("Cannot create a GL device context.", ELL_ERROR
);
264 if (!PrimaryContext
.OpenGLWin32
.HWnd
) {
265 PrimaryContext
.OpenGLWin32
.HWnd
= CurrentContext
.OpenGLWin32
.HWnd
;
266 PrimaryContext
.OpenGLWin32
.HDc
= CurrentContext
.OpenGLWin32
.HDc
;
272 void CWGLManager::terminate()
274 if (CurrentContext
.OpenGLWin32
.HDc
)
275 ReleaseDC((HWND
)CurrentContext
.OpenGLWin32
.HWnd
, (HDC
)CurrentContext
.OpenGLWin32
.HDc
);
276 if (PrimaryContext
.OpenGLWin32
.HDc
&& PrimaryContext
.OpenGLWin32
.HDc
== CurrentContext
.OpenGLWin32
.HDc
)
277 memset(&PrimaryContext
, 0, sizeof(PrimaryContext
));
278 memset(&CurrentContext
, 0, sizeof(CurrentContext
));
280 FreeLibrary(libHandle
);
283 bool CWGLManager::generateSurface()
285 HDC HDc
= (HDC
)CurrentContext
.OpenGLWin32
.HDc
;
286 // search for pixel format the simple way
287 if (PixelFormat
== 0 || (!SetPixelFormat(HDc
, PixelFormat
, &pfd
))) {
288 for (u32 i
= 0; i
< 5; ++i
) {
290 if (Params
.Stencilbuffer
) {
291 os::Printer::log("Cannot create a GL device with stencil buffer, disabling stencil shadows.", ELL_WARNING
);
292 Params
.Stencilbuffer
= false;
293 pfd
.cStencilBits
= 0;
300 if (Params
.Bits
!= 16)
305 os::Printer::log("Cannot create a GL device context", "No suitable format.", ELL_ERROR
);
309 // choose pixelformat
310 PixelFormat
= ChoosePixelFormat(HDc
, &pfd
);
316 if (!SetPixelFormat(HDc
, PixelFormat
, &pfd
)) {
317 os::Printer::log("Cannot set the pixel format.", ELL_ERROR
);
322 if (pfd
.cAlphaBits
!= 0) {
323 if (pfd
.cRedBits
== 8)
324 ColorFormat
= ECF_A8R8G8B8
;
326 ColorFormat
= ECF_A1R5G5B5
;
328 if (pfd
.cRedBits
== 8)
329 ColorFormat
= ECF_R8G8B8
;
331 ColorFormat
= ECF_R5G6B5
;
333 os::Printer::log("Pixel Format", core::stringc(PixelFormat
).c_str(), ELL_DEBUG
);
337 void CWGLManager::destroySurface()
341 bool CWGLManager::generateContext()
343 HDC HDc
= (HDC
)CurrentContext
.OpenGLWin32
.HDc
;
345 // create rendering context
346 #ifdef WGL_ARB_create_context
347 PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs_ARB
= (PFNWGLCREATECONTEXTATTRIBSARBPROC
)FunctionPointers
[0];
348 if (wglCreateContextAttribs_ARB
) {
349 // with 3.0 all available profiles should be usable, higher versions impose restrictions
350 // we need at least 1.1
351 const int iAttribs
[] = {
352 WGL_CONTEXT_MAJOR_VERSION_ARB
, 1,
353 WGL_CONTEXT_MINOR_VERSION_ARB
, 1,
354 // WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB, // enable to get a debug context (depends on driver if that does anything)
357 hrc
= wglCreateContextAttribs_ARB(HDc
, 0, iAttribs
);
360 hrc
= wglCreateContext(HDc
);
361 os::Printer::log("Irrlicht context");
364 os::Printer::log("Cannot create a GL rendering context.", ELL_ERROR
);
369 CurrentContext
.OpenGLWin32
.HRc
= hrc
;
370 if (!PrimaryContext
.OpenGLWin32
.HRc
)
371 PrimaryContext
.OpenGLWin32
.HRc
= CurrentContext
.OpenGLWin32
.HRc
;
376 const SExposedVideoData
&CWGLManager::getContext() const
378 return CurrentContext
;
381 bool CWGLManager::activateContext(const SExposedVideoData
&videoData
, bool restorePrimaryOnZero
)
383 if (videoData
.OpenGLWin32
.HWnd
&& videoData
.OpenGLWin32
.HDc
&& videoData
.OpenGLWin32
.HRc
) {
384 if (!wglMakeCurrent((HDC
)videoData
.OpenGLWin32
.HDc
, (HGLRC
)videoData
.OpenGLWin32
.HRc
)) {
385 os::Printer::log("Render Context switch failed.");
388 CurrentContext
= videoData
;
389 } else if (!restorePrimaryOnZero
&& !videoData
.OpenGLWin32
.HDc
&& !videoData
.OpenGLWin32
.HRc
) {
390 if (!wglMakeCurrent((HDC
)0, (HGLRC
)0)) {
391 os::Printer::log("Render Context reset failed.");
394 CurrentContext
= videoData
;
396 // set back to main context
397 else if (!videoData
.OpenGLWin32
.HWnd
&& CurrentContext
.OpenGLWin32
.HDc
!= PrimaryContext
.OpenGLWin32
.HDc
) {
398 if (!wglMakeCurrent((HDC
)PrimaryContext
.OpenGLWin32
.HDc
, (HGLRC
)PrimaryContext
.OpenGLWin32
.HRc
)) {
399 os::Printer::log("Render Context switch (back to main) failed.");
402 CurrentContext
= PrimaryContext
;
407 void CWGLManager::destroyContext()
409 if (CurrentContext
.OpenGLWin32
.HRc
) {
410 if (!wglMakeCurrent((HDC
)CurrentContext
.OpenGLWin32
.HDc
, 0))
411 os::Printer::log("Release of render context failed.", ELL_WARNING
);
413 if (!wglDeleteContext((HGLRC
)CurrentContext
.OpenGLWin32
.HRc
))
414 os::Printer::log("Deletion of render context failed.", ELL_WARNING
);
415 if (PrimaryContext
.OpenGLWin32
.HRc
== CurrentContext
.OpenGLWin32
.HRc
)
416 PrimaryContext
.OpenGLWin32
.HRc
= 0;
417 CurrentContext
.OpenGLWin32
.HRc
= 0;
421 void *CWGLManager::getProcAddress(const std::string
&procName
)
424 proc
= (void *)wglGetProcAddress(procName
.c_str());
425 if (!proc
) { // Fallback
427 libHandle
= LoadLibraryA("opengl32.dll");
429 proc
= (void *)GetProcAddress(libHandle
, procName
.c_str());
434 bool CWGLManager::swapBuffers()
436 return SwapBuffers((HDC
)CurrentContext
.OpenGLWin32
.HDc
) == TRUE
;