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