]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CWGLManager.cpp
182c460ceb08b73e89215bda0e1c23aa87e5a305
[irrlicht.git] / source / Irrlicht / CWGLManager.cpp
1 // Copyright (C) 2013 Christian Stehno\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in Irrlicht.h\r
4 \r
5 #include "CWGLManager.h"\r
6 \r
7 #ifdef _IRR_COMPILE_WITH_WGL_MANAGER_\r
8 \r
9 #include "os.h"\r
10 \r
11 #include <GL/gl.h>\r
12 #include <GL/wglext.h>\r
13 \r
14 namespace irr\r
15 {\r
16 namespace video\r
17 {\r
18 \r
19 CWGLManager::CWGLManager()\r
20         : PrimaryContext(SExposedVideoData(0)), PixelFormat(0), libHandle(NULL)\r
21 {\r
22         #ifdef _DEBUG\r
23         setDebugName("CWGLManager");\r
24         #endif\r
25         memset(FunctionPointers, 0, sizeof(FunctionPointers));\r
26 }\r
27 \r
28 CWGLManager::~CWGLManager()\r
29 {\r
30 }\r
31 \r
32 bool CWGLManager::initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& videodata)\r
33 {\r
34         // store params, videoData is set later as it would be overwritten else\r
35         Params=params;\r
36 \r
37         // Create a window to test antialiasing support\r
38         const fschar_t* ClassName = __TEXT("CWGLManager");\r
39         HINSTANCE lhInstance = GetModuleHandle(0);\r
40 \r
41         // Register Class\r
42         WNDCLASSEX wcex;\r
43         wcex.cbSize        = sizeof(WNDCLASSEX);\r
44         wcex.style         = CS_HREDRAW | CS_VREDRAW;\r
45         wcex.lpfnWndProc   = (WNDPROC)DefWindowProc;\r
46         wcex.cbClsExtra    = 0;\r
47         wcex.cbWndExtra    = 0;\r
48         wcex.hInstance     = lhInstance;\r
49         wcex.hIcon         = NULL;\r
50         wcex.hCursor       = LoadCursor(NULL, IDC_ARROW);\r
51         wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);\r
52         wcex.lpszMenuName  = 0;\r
53         wcex.lpszClassName = ClassName;\r
54         wcex.hIconSm       = 0;\r
55         wcex.hIcon         = 0;\r
56         RegisterClassEx(&wcex);\r
57 \r
58         RECT clientSize;\r
59         clientSize.top = 0;\r
60         clientSize.left = 0;\r
61         clientSize.right = Params.WindowSize.Width;\r
62         clientSize.bottom = Params.WindowSize.Height;\r
63 \r
64         DWORD style = WS_POPUP;\r
65         if (!Params.Fullscreen)\r
66                 style = WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;\r
67 \r
68         AdjustWindowRect(&clientSize, style, FALSE);\r
69 \r
70         const s32 realWidth = clientSize.right - clientSize.left;\r
71         const s32 realHeight = clientSize.bottom - clientSize.top;\r
72 \r
73         const s32 windowLeft = (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2;\r
74         const s32 windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2;\r
75 \r
76         HWND temporary_wnd=CreateWindow(ClassName, __TEXT(""), style, windowLeft,\r
77                         windowTop, realWidth, realHeight, NULL, NULL, lhInstance, NULL);\r
78 \r
79         if (!temporary_wnd)\r
80         {\r
81                 os::Printer::log("Cannot create a temporary window.", ELL_ERROR);\r
82                 UnregisterClass(ClassName, lhInstance);\r
83                 return false;\r
84         }\r
85 \r
86         HDC HDc = GetDC(temporary_wnd);\r
87 \r
88         // Set up pixel format descriptor with desired parameters\r
89         PIXELFORMATDESCRIPTOR tmp_pfd = {\r
90                 sizeof(PIXELFORMATDESCRIPTOR),             // Size Of This Pixel Format Descriptor\r
91                 1,                                         // Version Number\r
92                 (DWORD)(PFD_DRAW_TO_WINDOW |               // Format Must Support Window\r
93                 PFD_SUPPORT_OPENGL |                       // Format Must Support OpenGL\r
94                 (Params.Doublebuffer?PFD_DOUBLEBUFFER:0) | // Must Support Double Buffering\r
95                 (Params.Stereobuffer?PFD_STEREO:0)),       // Must Support Stereo Buffer\r
96                 PFD_TYPE_RGBA,                             // Request An RGBA Format\r
97                 Params.Bits,                               // Select Our Color Depth\r
98                 0, 0, 0, 0, 0, 0,                          // Color Bits Ignored\r
99                 0,                                         // No Alpha Buffer\r
100                 0,                                         // Shift Bit Ignored\r
101                 0,                                         // No Accumulation Buffer\r
102                 0, 0, 0, 0,                                    // Accumulation Bits Ignored\r
103                 Params.ZBufferBits,                        // Z-Buffer (Depth Buffer)\r
104                 BYTE(Params.Stencilbuffer ? 1 : 0),        // Stencil Buffer Depth\r
105                 0,                                         // No Auxiliary Buffer\r
106                 PFD_MAIN_PLANE,                            // Main Drawing Layer\r
107                 0,                                         // Reserved\r
108                 0, 0, 0                                    // Layer Masks Ignored\r
109         };\r
110         pfd=tmp_pfd;\r
111 \r
112         for (u32 i=0; i<6; ++i)\r
113         {\r
114                 if (i == 1)\r
115                 {\r
116                         if (Params.Stencilbuffer)\r
117                         {\r
118                                 os::Printer::log("Cannot create a GL device with stencil buffer, disabling stencil shadows.", ELL_WARNING);\r
119                                 Params.Stencilbuffer = false;\r
120                                 pfd.cStencilBits = 0;\r
121                         }\r
122                         else\r
123                                 continue;\r
124                 }\r
125                 else\r
126                 if (i == 2)\r
127                 {\r
128                         pfd.cDepthBits = 24;\r
129                 }\r
130                 else\r
131                 if (i == 3)\r
132                 {\r
133                         if (Params.Bits!=16)\r
134                                 pfd.cDepthBits = 16;\r
135                         else\r
136                                 continue;\r
137                 }\r
138                 else\r
139                 if (i == 4)\r
140                 {\r
141                         // try single buffer\r
142                         if (Params.Doublebuffer)\r
143                                 pfd.dwFlags &= ~PFD_DOUBLEBUFFER;\r
144                         else\r
145                                 continue;\r
146                 }\r
147                 else\r
148                 if (i == 5)\r
149                 {\r
150                         os::Printer::log("Cannot create a GL device context", "No suitable format for temporary window.", ELL_ERROR);\r
151                         ReleaseDC(temporary_wnd, HDc);\r
152                         DestroyWindow(temporary_wnd);\r
153                         UnregisterClass(ClassName, lhInstance);\r
154                         return false;\r
155                 }\r
156 \r
157                 // choose pixelformat\r
158                 PixelFormat = ChoosePixelFormat(HDc, &pfd);\r
159                 if (PixelFormat)\r
160                         break;\r
161         }\r
162 \r
163         SetPixelFormat(HDc, PixelFormat, &pfd);\r
164         os::Printer::log("Create temporary GL rendering context", ELL_DEBUG);\r
165         HGLRC hrc=wglCreateContext(HDc);\r
166         if (!hrc)\r
167         {\r
168                 os::Printer::log("Cannot create a temporary GL rendering context.", ELL_ERROR);\r
169                 ReleaseDC(temporary_wnd, HDc);\r
170                 DestroyWindow(temporary_wnd);\r
171                 UnregisterClass(ClassName, lhInstance);\r
172                 return false;\r
173         }\r
174 \r
175         CurrentContext.OpenGLWin32.HDc = HDc;\r
176         CurrentContext.OpenGLWin32.HRc = hrc;\r
177         CurrentContext.OpenGLWin32.HWnd = temporary_wnd;\r
178 \r
179         if (!activateContext(CurrentContext, false))\r
180         {\r
181                 os::Printer::log("Cannot activate a temporary GL rendering context.", ELL_ERROR);\r
182                 wglDeleteContext(hrc);\r
183                 ReleaseDC(temporary_wnd, HDc);\r
184                 DestroyWindow(temporary_wnd);\r
185                 UnregisterClass(ClassName, lhInstance);\r
186                 return false;\r
187         }\r
188 \r
189         core::stringc wglExtensions;\r
190 #ifdef WGL_ARB_extensions_string\r
191         PFNWGLGETEXTENSIONSSTRINGARBPROC irrGetExtensionsString = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");\r
192         if (irrGetExtensionsString)\r
193                 wglExtensions = irrGetExtensionsString(HDc);\r
194 #elif defined(WGL_EXT_extensions_string)\r
195         PFNWGLGETEXTENSIONSSTRINGEXTPROC irrGetExtensionsString = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT");\r
196         if (irrGetExtensionsString)\r
197                 wglExtensions = irrGetExtensionsString(HDc);\r
198 #endif\r
199         const bool pixel_format_supported = (wglExtensions.find("WGL_ARB_pixel_format") != -1);\r
200         const bool multi_sample_supported = ((wglExtensions.find("WGL_ARB_multisample") != -1) ||\r
201                 (wglExtensions.find("WGL_EXT_multisample") != -1) || (wglExtensions.find("WGL_3DFX_multisample") != -1) );\r
202 #ifdef _DEBUG\r
203         os::Printer::log("WGL_extensions", wglExtensions);\r
204 #endif\r
205 \r
206         // Without a GL context we can't call wglGetProcAddress so store this for later\r
207         FunctionPointers[0] = (void*)wglGetProcAddress("wglCreateContextAttribsARB");\r
208 \r
209 #ifdef WGL_ARB_pixel_format\r
210         PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormat_ARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");\r
211         if (pixel_format_supported && wglChoosePixelFormat_ARB)\r
212         {\r
213                 // This value determines the number of samples used for antialiasing\r
214                 // My experience is that 8 does not show a big\r
215                 // improvement over 4, but 4 shows a big improvement\r
216                 // over 2.\r
217 \r
218                 if (Params.AntiAlias > 32)\r
219                         Params.AntiAlias = 32;\r
220 \r
221                 f32 fAttributes[] = {0.0, 0.0};\r
222                 s32 iAttributes[] =\r
223                 {\r
224                         WGL_DRAW_TO_WINDOW_ARB,1,\r
225                         WGL_SUPPORT_OPENGL_ARB,1,\r
226                         WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB,\r
227                         WGL_COLOR_BITS_ARB,(Params.Bits==32) ? 24 : 15,\r
228                         WGL_ALPHA_BITS_ARB,(Params.Bits==32) ? 8 : 1,\r
229                         WGL_DEPTH_BITS_ARB,Params.ZBufferBits, // 10,11\r
230                         WGL_STENCIL_BITS_ARB,Params.Stencilbuffer ? 1 : 0,\r
231                         WGL_DOUBLE_BUFFER_ARB,Params.Doublebuffer ? 1 : 0,\r
232                         WGL_STEREO_ARB,Params.Stereobuffer ? 1 : 0,\r
233                         WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,\r
234 #ifdef WGL_ARB_multisample\r
235                         WGL_SAMPLES_ARB,Params.AntiAlias, // 20,21\r
236                         WGL_SAMPLE_BUFFERS_ARB, (Params.AntiAlias>0) ? 1 : 0,\r
237 #elif defined(WGL_EXT_multisample)\r
238                         WGL_SAMPLES_EXT,AntiAlias, // 20,21\r
239                         WGL_SAMPLE_BUFFERS_EXT, (Params.AntiAlias>0) ? 1 : 0,\r
240 #elif defined(WGL_3DFX_multisample)\r
241                         WGL_SAMPLES_3DFX,AntiAlias, // 20,21\r
242                         WGL_SAMPLE_BUFFERS_3DFX, (Params.AntiAlias>0) ? 1 : 0,\r
243 #endif\r
244 #ifdef WGL_ARB_framebuffer_sRGB\r
245                         WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, Params.HandleSRGB ? 1:0,\r
246 #elif defined(WGL_EXT_framebuffer_sRGB)\r
247                         WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT, Params.HandleSRGB ? 1:0,\r
248 #endif\r
249 //                      WGL_DEPTH_FLOAT_EXT, 1,\r
250                         0,0,0,0\r
251                 };\r
252                 int iAttrSize = sizeof(iAttributes)/sizeof(int);\r
253                 const bool framebuffer_srgb_supported = ((wglExtensions.find("WGL_ARB_framebuffer_sRGB") != -1) ||\r
254                         (wglExtensions.find("WGL_EXT_framebuffer_sRGB") != -1));\r
255                 if (!framebuffer_srgb_supported)\r
256                 {\r
257                         memmove(&iAttributes[24],&iAttributes[26],sizeof(int)*(iAttrSize-26));\r
258                         iAttrSize -= 2;\r
259                 }\r
260                 if (!multi_sample_supported)\r
261                 {\r
262                         memmove(&iAttributes[20],&iAttributes[24],sizeof(int)*(iAttrSize-24));\r
263                         iAttrSize -= 4;\r
264                 }\r
265 \r
266                 s32 rv=0;\r
267                 // Try to get an acceptable pixel format\r
268                 do\r
269                 {\r
270                         int pixelFormat=0;\r
271                         UINT numFormats=0;\r
272                         const BOOL valid = wglChoosePixelFormat_ARB(HDc,iAttributes,fAttributes,1,&pixelFormat,&numFormats);\r
273 \r
274                         if (valid && numFormats)\r
275                                 rv = pixelFormat;\r
276                         else\r
277                                 iAttributes[21] -= 1;\r
278                 }\r
279                 while(rv==0 && iAttributes[21]>1);\r
280                 if (rv)\r
281                 {\r
282                         PixelFormat=rv;\r
283                         Params.AntiAlias=iAttributes[21];\r
284                 }\r
285         }\r
286         else\r
287 #endif\r
288                 Params.AntiAlias=0;\r
289 \r
290         // this only terminates the temporary HRc\r
291         destroyContext();\r
292         destroySurface();\r
293         terminate();\r
294         DestroyWindow(temporary_wnd);\r
295         UnregisterClass(ClassName, lhInstance);\r
296 \r
297         // now get new window\r
298         CurrentContext.OpenGLWin32.HWnd=videodata.OpenGLWin32.HWnd;\r
299         // get hdc\r
300         if (!(CurrentContext.OpenGLWin32.HDc=GetDC((HWND)videodata.OpenGLWin32.HWnd)))\r
301         {\r
302                 os::Printer::log("Cannot create a GL device context.", ELL_ERROR);\r
303                 return false;\r
304         }\r
305         if (!PrimaryContext.OpenGLWin32.HWnd)\r
306         {\r
307                 PrimaryContext.OpenGLWin32.HWnd=CurrentContext.OpenGLWin32.HWnd;\r
308                 PrimaryContext.OpenGLWin32.HDc=CurrentContext.OpenGLWin32.HDc;\r
309         }\r
310 \r
311         return true;\r
312 }\r
313 \r
314 void CWGLManager::terminate()\r
315 {\r
316         if (CurrentContext.OpenGLWin32.HDc)\r
317                 ReleaseDC((HWND)CurrentContext.OpenGLWin32.HWnd, (HDC)CurrentContext.OpenGLWin32.HDc);\r
318         if (PrimaryContext.OpenGLWin32.HDc && PrimaryContext.OpenGLWin32.HDc == CurrentContext.OpenGLWin32.HDc)\r
319                 memset(&PrimaryContext, 0, sizeof(PrimaryContext));\r
320         memset(&CurrentContext, 0, sizeof(CurrentContext));\r
321         if (libHandle)\r
322                 FreeLibrary(libHandle);\r
323 }\r
324 \r
325 bool CWGLManager::generateSurface()\r
326 {\r
327         HDC HDc = (HDC)CurrentContext.OpenGLWin32.HDc;\r
328         // search for pixel format the simple way\r
329         if (PixelFormat==0 || (!SetPixelFormat(HDc, PixelFormat, &pfd)))\r
330         {\r
331                 for (u32 i=0; i<5; ++i)\r
332                 {\r
333                         if (i == 1)\r
334                         {\r
335                                 if (Params.Stencilbuffer)\r
336                                 {\r
337                                         os::Printer::log("Cannot create a GL device with stencil buffer, disabling stencil shadows.", ELL_WARNING);\r
338                                         Params.Stencilbuffer = false;\r
339                                         pfd.cStencilBits = 0;\r
340                                 }\r
341                                 else\r
342                                         continue;\r
343                         }\r
344                         else\r
345                         if (i == 2)\r
346                         {\r
347                                 pfd.cDepthBits = 24;\r
348                         }\r
349                         if (i == 3)\r
350                         {\r
351                                 if (Params.Bits!=16)\r
352                                         pfd.cDepthBits = 16;\r
353                                 else\r
354                                         continue;\r
355                         }\r
356                         else\r
357                         if (i == 4)\r
358                         {\r
359                                 os::Printer::log("Cannot create a GL device context", "No suitable format.", ELL_ERROR);\r
360                                 return false;\r
361                         }\r
362 \r
363                         // choose pixelformat\r
364                         PixelFormat = ChoosePixelFormat(HDc, &pfd);\r
365                         if (PixelFormat)\r
366                                 break;\r
367                 }\r
368 \r
369                 // set pixel format\r
370                 if (!SetPixelFormat(HDc, PixelFormat, &pfd))\r
371                 {\r
372                         os::Printer::log("Cannot set the pixel format.", ELL_ERROR);\r
373                         return false;\r
374                 }\r
375         }\r
376 \r
377         if (pfd.cAlphaBits != 0)\r
378         {\r
379                 if (pfd.cRedBits == 8)\r
380                         ColorFormat = ECF_A8R8G8B8;\r
381                 else\r
382                         ColorFormat = ECF_A1R5G5B5;\r
383         }\r
384         else\r
385         {\r
386                 if (pfd.cRedBits == 8)\r
387                         ColorFormat = ECF_R8G8B8;\r
388                 else\r
389                         ColorFormat = ECF_R5G6B5;\r
390         }\r
391         os::Printer::log("Pixel Format", core::stringc(PixelFormat).c_str(), ELL_DEBUG);\r
392         return true;\r
393 }\r
394 \r
395 void CWGLManager::destroySurface()\r
396 {\r
397 }\r
398 \r
399 bool CWGLManager::generateContext()\r
400 {\r
401         HDC HDc=(HDC)CurrentContext.OpenGLWin32.HDc;\r
402         HGLRC hrc;\r
403         // create rendering context\r
404 #ifdef WGL_ARB_create_context\r
405         PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs_ARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)FunctionPointers[0];\r
406         if (wglCreateContextAttribs_ARB)\r
407         {\r
408                 // with 3.0 all available profiles should be usable, higher versions impose restrictions\r
409                 // we need at least 1.1\r
410                 const int iAttribs[] =\r
411                 {\r
412                         WGL_CONTEXT_MAJOR_VERSION_ARB, 1,\r
413                         WGL_CONTEXT_MINOR_VERSION_ARB, 1,\r
414 //                      WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB,       // enable to get a debug context (depends on driver if that does anything)\r
415                         0\r
416                 };\r
417                 hrc=wglCreateContextAttribs_ARB(HDc, 0, iAttribs);\r
418         }\r
419         else\r
420 #endif\r
421         hrc=wglCreateContext(HDc);\r
422         os::Printer::log("Irrlicht context");\r
423 \r
424         if (!hrc)\r
425         {\r
426                 os::Printer::log("Cannot create a GL rendering context.", ELL_ERROR);\r
427                 return false;\r
428         }\r
429 \r
430         // set exposed data\r
431         CurrentContext.OpenGLWin32.HRc = hrc;\r
432         if (!PrimaryContext.OpenGLWin32.HRc)\r
433                 PrimaryContext.OpenGLWin32.HRc=CurrentContext.OpenGLWin32.HRc;\r
434 \r
435         return true;\r
436 }\r
437 \r
438 const SExposedVideoData& CWGLManager::getContext() const\r
439 {\r
440         return CurrentContext;\r
441 }\r
442 \r
443 bool CWGLManager::activateContext(const SExposedVideoData& videoData, bool restorePrimaryOnZero)\r
444 {\r
445         if (videoData.OpenGLWin32.HWnd && videoData.OpenGLWin32.HDc && videoData.OpenGLWin32.HRc)\r
446         {\r
447                 if (!wglMakeCurrent((HDC)videoData.OpenGLWin32.HDc, (HGLRC)videoData.OpenGLWin32.HRc))\r
448                 {\r
449                         os::Printer::log("Render Context switch failed.");\r
450                         return false;\r
451                 }\r
452                 CurrentContext=videoData;\r
453         }\r
454         else if (!restorePrimaryOnZero && !videoData.OpenGLWin32.HDc && !videoData.OpenGLWin32.HRc)\r
455         {\r
456                 if (!wglMakeCurrent((HDC)0, (HGLRC)0))\r
457                 {\r
458                         os::Printer::log("Render Context reset failed.");\r
459                         return false;\r
460                 }\r
461                 CurrentContext = videoData;\r
462         }\r
463         // set back to main context\r
464         else if (!videoData.OpenGLWin32.HWnd && CurrentContext.OpenGLWin32.HDc != PrimaryContext.OpenGLWin32.HDc)\r
465         {\r
466                 if (!wglMakeCurrent((HDC)PrimaryContext.OpenGLWin32.HDc, (HGLRC)PrimaryContext.OpenGLWin32.HRc))\r
467                 {\r
468                         os::Printer::log("Render Context switch failed.");\r
469                         return false;\r
470                 }\r
471                 CurrentContext=PrimaryContext;\r
472         }\r
473         return true;\r
474 }\r
475 \r
476 void CWGLManager::destroyContext()\r
477 {\r
478         if (CurrentContext.OpenGLWin32.HRc)\r
479         {\r
480                 if (!wglMakeCurrent((HDC)CurrentContext.OpenGLWin32.HDc, 0))\r
481                         os::Printer::log("Release of render context failed.", ELL_WARNING);\r
482 \r
483                 if (!wglDeleteContext((HGLRC)CurrentContext.OpenGLWin32.HRc))\r
484                         os::Printer::log("Deletion of render context failed.", ELL_WARNING);\r
485                 if (PrimaryContext.OpenGLWin32.HRc==CurrentContext.OpenGLWin32.HRc)\r
486                         PrimaryContext.OpenGLWin32.HRc=0;\r
487                 CurrentContext.OpenGLWin32.HRc=0;\r
488         }\r
489 }\r
490 \r
491 void* CWGLManager::getProcAddress(const std::string &procName)\r
492 {\r
493         void* proc = NULL;\r
494         proc = (void*)wglGetProcAddress(procName.c_str());\r
495         if (!proc) { // Fallback\r
496                 if (!libHandle)\r
497                         libHandle = LoadLibraryA("opengl32.dll");\r
498                 if (libHandle)\r
499                         proc = (void*)GetProcAddress(libHandle, procName.c_str());\r
500         }\r
501         return proc;\r
502 }\r
503 \r
504 bool CWGLManager::swapBuffers()\r
505 {\r
506         return SwapBuffers((HDC)CurrentContext.OpenGLWin32.HDc) == TRUE;\r
507 }\r
508 \r
509 }\r
510 }\r
511 \r
512 #endif\r