1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2010 Robert TIMM (rti) <mail@rtti.de>
6 // Copyright (C) 2014 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
7 // Copyright (C) 2014-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
9 // This program is free software: you can redistribute it and/or modify
10 // it under the terms of the GNU Affero General Public License as
11 // published by the Free Software Foundation, either version 3 of the
12 // License, or (at your option) any later version.
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU Affero General Public License for more details.
19 // You should have received a copy of the GNU Affero General Public License
20 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "stdopengl.h"
23 #include "driver_opengl.h"
24 #include "driver_opengl_extension.h"
25 #include "driver_opengl_vertex_buffer_hard.h"
27 // by default, we disable the windows menu keys (F10, ALT and ALT+SPACE key doesn't freeze or open the menu)
28 #define NL_DISABLE_MENU
31 # import "mac/cocoa_window_delegate.h"
32 # import "mac/cocoa_application_delegate.h"
33 # import <OpenGL/OpenGL.h>
34 #elif defined (NL_OS_UNIX)
36 # include <X11/extensions/Xrandr.h>
37 # endif // HAVE_XRANDR
39 # include <X11/extensions/Xrender.h>
40 # endif // HAVE_XRENDER
41 # include <X11/Xatom.h>
42 # define _NET_WM_STATE_REMOVE 0
43 # define _NET_WM_STATE_ADD 1
46 #include "nel/3d/u_driver.h"
47 #include "nel/misc/file.h"
50 using namespace NLMISC
;
60 namespace NLDRIVERGLES
{
62 namespace NLDRIVERGL
{
68 bool GlWndProc(CDriverGL
*driver
, HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
75 if(message
== WM_SIZE
)
77 if (driver
->_CurrentMode
.Windowed
)
80 GetClientRect (driver
->_win
, &rect
);
83 driver
->_CurrentMode
.Width
= (uint16
)(rect
.right
-rect
.left
);
84 driver
->_CurrentMode
.Height
= (uint16
)(rect
.bottom
-rect
.top
);
87 else if(message
== WM_MOVE
)
89 if (driver
->_CurrentMode
.Windowed
)
92 GetWindowRect (hWnd
, &rect
);
93 driver
->_WindowX
= rect
.left
;
94 driver
->_WindowY
= rect
.top
;
97 else if (message
== WM_ACTIVATE
)
99 WORD fActive
= LOWORD(wParam
);
100 if (fActive
== WA_INACTIVE
)
102 driver
->_WndActive
= false;
106 driver
->_WndActive
= true;
109 else if ((message
== WM_SETFOCUS
) || (message
== WM_KILLFOCUS
))
113 driver
->_WindowFocus
= (message
== WM_SETFOCUS
);
117 bool trapMessage
= false;
118 if (driver
->_EventEmitter
.getNumEmitters() > 0)
120 CWinEventEmitter
*we
= NLMISC::safe_cast
<CWinEventEmitter
*>(driver
->_EventEmitter
.getEmitter(0));
121 // Process the message by the emitter
123 trapMessage
= we
->processMessage (hWnd
, message
, wParam
, lParam
);
128 static LRESULT CALLBACK
WndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
130 H_AUTO_OGL(DriverGL_WndProc
);
132 // Get the driver pointer..
133 CDriverGL
*pDriver
=(CDriverGL
*)GetWindowLongPtr (hWnd
, GWLP_USERDATA
);
134 bool trapMessage
= false;
137 trapMessage
= GlWndProc (pDriver
, hWnd
, message
, wParam
, lParam
);
140 // we don't want Windows to erase background
141 if (message
== WM_ERASEBKGND
)
146 if (message
== WM_SYSCOMMAND
)
150 #ifdef NL_DISABLE_MENU
151 // disable menu (F10, ALT and ALT+SPACE key doesn't freeze or open the menu)
153 #endif // NL_DISABLE_MENU
155 // Screensaver Trying To Start?
158 // Monitor Trying To Enter Powersave?
159 case SC_MONITORPOWER
:
161 // Prevent From Happening
169 // disable menu (default ALT-F4 behavior is disabled)
170 if (message
== WM_CLOSE
)
172 if(pDriver
&& pDriver
->ExitFunc
)
178 #ifndef NL_DISABLE_MENU
179 // if we don't disable menu, alt F4 make a direct exit else we discard the message
181 #endif // NL_DISABLE_MENU
187 // https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-unichar
188 if (message
== WM_UNICHAR
)
189 return (wParam
== UNICODE_NOCHAR
);
192 return trapMessage
? 0 : DefWindowProcW(hWnd
, message
, wParam
, lParam
);
195 #elif defined (NL_OS_MAC)
197 bool GlWndProc(CDriverGL
*driver
, const void* e
)
199 H_AUTO_OGL(GlWndProc
)
204 NSEvent
* event
= [NSEvent eventWithEventRef
:e
];
205 // NSLog(@"NSEvent in GlWndProc %@", event);
207 return driver
->_EventEmitter
.processMessage(event
);
210 #elif defined (NL_OS_UNIX)
212 static Atom XA_WM_STATE
= 0;
213 static Atom XA_WM_STATE_FULLSCREEN
= 0;
214 static Atom XA_WM_ICON
= 0;
215 static Atom XA_WM_WINDOW_TYPE
= 0;
216 static Atom XA_WM_WINDOW_TYPE_NORMAL
= 0;
217 static Atom XA_FRAME_EXTENTS
= 0;
219 sint
nelXErrorsHandler(Display
*dpy
, XErrorEvent
*e
)
222 XGetErrorText(dpy
, e
->error_code
, buf
, sizeof(buf
));
223 nlwarning("3D: XError: %s", buf
);
227 bool GlWndProc(CDriverGL
*driver
, XEvent
&e
)
229 H_AUTO_OGL(GlWndProc
)
234 // nlinfo("3D: glop %d %d", e.type, e.xmap.window);
236 // disable menu (default ALT-F4 behavior is disabled)
241 if(driver
&& driver
->ExitFunc
)
247 #ifndef NL_DISABLE_MENU
248 // if we don't disable menu, alt F4 make a direct exit else we discard the message
250 #endif // NL_DISABLE_MENU
255 driver
->_WndActive
= true;
259 driver
->_WndActive
= false;
263 // nlwarning("Expose event");
266 case ConfigureNotify
:
268 if (driver
->_CurrentMode
.Windowed
&& driver
->_WndActive
)
270 // first time setting decoration sizes
271 if ((driver
->_DecorationWidth
== -1) || (driver
->_DecorationWidth
== 0))
273 Atom type_return
= 0;
274 int format_return
= 0;
275 unsigned long nitems_return
= 0;
276 unsigned long bytes_after_return
= 0;
279 int status
= XGetWindowProperty(driver
->_dpy
, driver
->_win
, XA_FRAME_EXTENTS
, 0, 4, False
, XA_CARDINAL
, &type_return
, &format_return
, &nitems_return
, &bytes_after_return
, (unsigned char**)&data
);
281 // succeeded to retrieve decoration size
282 if (status
== Success
&& type_return
== XA_CARDINAL
&& format_return
== 32 && nitems_return
== 4 && data
)
284 driver
->_DecorationWidth
= data
[0];
285 driver
->_DecorationHeight
= data
[2];
289 // use difference between current position and previous one (set by application)
290 driver
->_DecorationWidth
= e
.xconfigure
.x
- driver
->_WindowX
;
291 driver
->_DecorationHeight
= e
.xconfigure
.y
- driver
->_WindowY
;
294 // don't allow negative decoration sizes
295 if (driver
->_DecorationWidth
< 0) driver
->_DecorationWidth
= 0;
296 if (driver
->_DecorationHeight
< 0) driver
->_DecorationHeight
= 0;
299 driver
->_CurrentMode
.Width
= e
.xconfigure
.width
;
300 driver
->_CurrentMode
.Height
= e
.xconfigure
.height
;
301 driver
->_WindowX
= e
.xconfigure
.x
- driver
->_DecorationWidth
;
302 driver
->_WindowY
= e
.xconfigure
.y
- driver
->_DecorationHeight
;
309 driver
->_WindowFocus
= true;
310 return driver
->_EventEmitter
.processMessage(e
);
315 driver
->_WindowFocus
= false;
316 return driver
->_EventEmitter
.processMessage(e
);
321 // Process the message by the emitter
322 return driver
->_EventEmitter
.processMessage(e
);
330 // ***************************************************************************
331 bool CDriverGL::init (uintptr_t windowIcon
, emptyProc exitFunc
)
333 H_AUTO_OGL(CDriverGL_init
)
344 memset(&wc
,0,sizeof(wc
));
345 wc
.style
= CS_HREDRAW
| CS_VREDRAW
;//| CS_DBLCLKS;
346 wc
.lpfnWndProc
= (WNDPROC
)WndProc
;
349 wc
.hInstance
= GetModuleHandleW(NULL
);
350 wc
.hIcon
= (HICON
)windowIcon
;
351 wc
.hCursor
= _DefaultCursor
;
352 wc
.hbrBackground
= WHITE_BRUSH
;
353 wc
.lpszClassName
= L
"NLClass";
354 wc
.lpszMenuName
= NULL
;
355 if ( !RegisterClassW(&wc
) )
362 // Backup monitor color parameters
363 HDC dc
= CreateDCA ("DISPLAY", NULL
, NULL
, NULL
);
366 _NeedToRestoreGammaRamp
= GetDeviceGammaRamp (dc
, _GammaRampBackuped
) != FALSE
;
369 ReleaseDC (NULL
, dc
);
373 nlwarning ("(CDriverGL::init): can't create DC");
376 // ati specific : try to retrieve driver version
377 retrieveATIDriverVersion();
378 #elif defined(NL_OS_MAC)
380 nlunreferenced(windowIcon
);
382 // autorelease pool for memory management
383 _autoreleasePool
= [[NSAutoreleasePool alloc
] init
];
385 // init the application object
386 [NSApplication sharedApplication
];
388 #elif defined (NL_OS_UNIX)
390 nlunreferenced(windowIcon
);
392 _dpy
= XOpenDisplay(NULL
);
396 nlerror ("XOpenDisplay failed on '%s'", getenv("DISPLAY"));
400 nldebug("3D: XOpenDisplay on '%s' OK", getenv("DISPLAY"));
407 sint xrandr_major
, xrandr_minor
;
408 if (XRRQueryVersion(_dpy
, &xrandr_major
, &xrandr_minor
))
410 _xrandr_version
= xrandr_major
* 100 + xrandr_minor
;
411 nlinfo("3D: XRandR %d.%d found", xrandr_major
, xrandr_minor
);
413 #endif // HAVE_XRANDR
415 _xvidmode_version
= 0;
418 sint event
= 0, error
= -1, vm_major
= 0, vm_minor
= 0;
419 if (XF86VidModeQueryExtension(_dpy
, &event
, &error
) && XF86VidModeQueryVersion(_dpy
, &vm_major
, &vm_minor
))
421 _xvidmode_version
= vm_major
* 100 + vm_minor
;
422 nlinfo("3D: XF86VidMode %d.%d found", vm_major
, vm_minor
);
426 _xrender_version
= 0;
429 sint xrender_major
, xrender_event
, xrender_error
;
430 if (XQueryExtension(_dpy
, "RENDER", &xrender_major
, &xrender_event
, &xrender_error
) &&
431 XRenderQueryExtension(_dpy
, &xrender_event
, &xrender_error
))
433 sint xrender_minor
= 0;
434 XRenderQueryVersion(_dpy
, &xrender_major
, &xrender_minor
);
435 _xrender_version
= xrender_major
* 100 + xrender_minor
;
436 nlinfo("3D: XRender %d.%d found", xrender_major
, xrender_minor
);
438 #endif // HAVE_XRENDER
440 nldebug("3D: Available X Extensions:");
444 // list all supported extensions
445 sint nextensions
= 0;
446 char **extensions
= XListExtensions(_dpy
, &nextensions
);
448 for(sint i
= 0; i
< nextensions
; ++i
)
450 if(i
%5==0) DebugLog
->displayRaw("3D: ");
451 DebugLog
->displayRaw(NLMISC::toString("%s ", extensions
[i
]).c_str());
452 if(i
%5==4) DebugLog
->displayRaw("\n");
455 DebugLog
->displayRaw("\n");
457 XFreeExtensionList(extensions
);
460 // set default X errors handler
461 XSetErrorHandler(nelXErrorsHandler
);
464 XA_WM_STATE
= XInternAtom(_dpy
, "_NET_WM_STATE", False
);
465 XA_WM_STATE_FULLSCREEN
= XInternAtom(_dpy
, "_NET_WM_STATE_FULLSCREEN", False
);
466 XA_WM_ICON
= XInternAtom(_dpy
, "_NET_WM_ICON", False
);
467 XA_WM_WINDOW_TYPE
= XInternAtom(_dpy
, "_NET_WM_WINDOW_TYPE", False
);
468 XA_WM_WINDOW_TYPE_NORMAL
= XInternAtom(_dpy
, "_NET_WM_WINDOW_TYPE_NORMAL", False
);
469 XA_FRAME_EXTENTS
= XInternAtom(_dpy
, "_NET_FRAME_EXTENTS", False
);
476 // ***************************************************************************
477 bool CDriverGL::unInit()
479 H_AUTO_OGL(CDriverGL_unInit
)
481 if (!_CurrentMode
.Windowed
)
486 _CurrentMode
.Windowed
= true;
492 // Off-screen rendering ?
495 nwglReleasePbufferDCARB(_PBuffer
, _hDC
);
496 nwglDestroyPbufferARB(_PBuffer
);
501 if (_Registered
&& !UnregisterClassW(L
"NLClass", GetModuleHandle(NULL
)))
503 nlwarning("Can't unregister NLClass");
507 // Restore monitor color parameters
508 if (_NeedToRestoreGammaRamp
)
510 HDC dc
= CreateDCA("DISPLAY", NULL
, NULL
, NULL
);
513 if (!SetDeviceGammaRamp(dc
, _GammaRampBackuped
))
514 nlwarning("(CDriverGL::release): SetDeviceGammaRamp failed");
521 nlwarning("(CDriverGL::release): can't create DC");
525 #elif defined(NL_OS_MAC)
527 [_autoreleasePool release
];
529 #elif defined (NL_OS_UNIX)
531 // restore default X errors handler
532 XSetErrorHandler(NULL
);
545 void CDriverGL::setWindowIcon(const std::vector
<NLMISC::CBitmap
> &bitmaps
)
547 if (_win
== EmptyWindow
)
550 #if defined(NL_OS_WINDOWS)
552 static HICON winIconBig
= NULL
;
553 static HICON winIconSmall
= NULL
;
557 DestroyIcon(winIconBig
);
563 DestroyIcon(winIconSmall
);
567 sint smallIndex
= -1;
568 uint smallWidth
= GetSystemMetrics(SM_CXSMICON
);
569 uint smallHeight
= GetSystemMetrics(SM_CYSMICON
);
572 uint bigWidth
= GetSystemMetrics(SM_CXICON
);
573 uint bigHeight
= GetSystemMetrics(SM_CYICON
);
575 // find icons with the exact size
576 for(uint i
= 0; i
< bitmaps
.size(); ++i
)
578 if (smallIndex
== -1 && bitmaps
[i
].getWidth() == smallWidth
&& bitmaps
[i
].getHeight() == smallHeight
)
581 if (bigIndex
== -1 && bitmaps
[i
].getWidth() == bigWidth
&& bitmaps
[i
].getHeight() == bigHeight
)
585 // find icons with taller size (we will resize them)
586 for(uint i
= 0; i
< bitmaps
.size(); ++i
)
588 if (smallIndex
== -1 && bitmaps
[i
].getWidth() >= smallWidth
&& bitmaps
[i
].getHeight() >= smallHeight
)
591 if (bigIndex
== -1 && bitmaps
[i
].getWidth() >= bigWidth
&& bitmaps
[i
].getHeight() >= bigHeight
)
596 convertBitmapToIcon(bitmaps
[smallIndex
], winIconSmall
, smallWidth
, smallHeight
, 32);
599 convertBitmapToIcon(bitmaps
[bigIndex
], winIconBig
, bigWidth
, bigHeight
, 32);
603 SendMessageA(_win
, WM_SETICON
, 0 /* ICON_SMALL */, (LPARAM
)winIconSmall
);
604 SendMessageA(_win
, WM_SETICON
, 1 /* ICON_BIG */, (LPARAM
)winIconBig
);
608 SendMessageA(_win
, WM_SETICON
, 0 /* ICON_SMALL */, (LPARAM
)winIconSmall
);
609 SendMessageA(_win
, WM_SETICON
, 1 /* ICON_BIG */, (LPARAM
)winIconSmall
);
612 #elif defined(NL_OS_MAC)
614 // nothing to do, on Mac OS X, only windows representing a file have icons
616 #elif defined(NL_OS_UNIX)
618 std::vector
<long> icon_data
;
620 if (!bitmaps
.empty())
622 // process each bitmap
623 for(uint i
= 0; i
< bitmaps
.size(); ++i
)
625 convertBitmapToIcon(bitmaps
[i
], icon_data
);
629 if (!icon_data
.empty())
631 // change window icon
632 XChangeProperty(_dpy
, _win
, XA_WM_ICON
, XA_CARDINAL
, 32, PropModeReplace
, (const unsigned char *) &icon_data
[0], icon_data
.size());
636 // delete window icon if no bitmap is available
637 XDeleteProperty(_dpy
, _win
, XA_WM_ICON
);
640 #endif // NL_OS_WINDOWS
643 // --------------------------------------------------
644 bool CDriverGL::setDisplay(nlWindow wnd
, const GfxMode
&mode
, bool show
, bool resizeable
)
646 H_AUTO_OGL(CDriverGL_setDisplay
)
649 NLMISC::INelContext::getInstance().setWindowedApplication(true);
655 _WindowVisible
= false;
656 _Resizable
= resizeable
;
657 _DestroyWindow
= false;
670 // Retrieve the WGL extensions before init the driver.
673 if (_CurrentMode
.OffScreen
)
675 if (!createWindow(mode
)) return false;
678 int width
= mode
.Width
;
679 int height
= mode
.Height
;
682 // TODO: implement for OpenGL ES 1.x
686 SetRect (&rc
, 0, 0, width
, height
);
687 AdjustWindowRectEx (&rc
, GetWindowStyle (_win
), GetMenu (_win
) != NULL
, GetWindowExStyle (_win
));
688 SetWindowPos (_win
, NULL
, 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
691 HDC tempHDC
= GetDC(tmpHWND
);
693 _CurrentMode
.Depth
= uint8(GetDeviceCaps(tempHDC
,BITSPIXEL
));
696 memset(&_pfd
,0,sizeof(_pfd
));
697 _pfd
.nSize
= sizeof(_pfd
);
699 _pfd
.dwFlags
= PFD_DRAW_TO_WINDOW
| PFD_SUPPORT_OPENGL
| PFD_DOUBLEBUFFER
;
700 _pfd
.iPixelType
= PFD_TYPE_RGBA
;
701 _pfd
.cColorBits
= _CurrentMode
.Depth
;
703 // Choose best suited Depth Buffer.
704 if(_CurrentMode
.Depth
<=16)
706 _pfd
.cDepthBits
= 16;
710 _pfd
.cDepthBits
= 24;
713 _pfd
.iLayerType
= PFD_MAIN_PLANE
;
714 int pf
=ChoosePixelFormat(tempHDC
,&_pfd
);
717 nlwarning ("CDriverGL::setDisplay: ChoosePixelFormat failed");
718 DestroyWindow (tmpHWND
);
721 if ( !SetPixelFormat(tempHDC
,pf
,&_pfd
) )
723 nlwarning ("CDriverGL::setDisplay: SetPixelFormat failed");
724 DestroyWindow (tmpHWND
);
729 HGLRC tempGLRC
= wglCreateContext(tempHDC
);
730 if (tempGLRC
== NULL
)
732 DWORD error
= GetLastError ();
733 nlwarning ("CDriverGL::setDisplay: wglCreateContext failed: 0x%x", error
);
734 DestroyWindow (tmpHWND
);
742 // Make the context current
743 if (!wglMakeCurrent(tempHDC
,tempGLRC
))
745 DWORD error
= GetLastError ();
746 nlwarning ("CDriverGL::setDisplay: wglMakeCurrent failed: 0x%x", error
);
747 wglDeleteContext (tempGLRC
);
748 DestroyWindow (tmpHWND
);
756 // Register WGL functions
758 registerEGlExtensions (_Extensions
, tempHDC
);
760 registerWGlExtensions (_Extensions
, tempHDC
);
763 HDC hdc
= wglGetCurrentDC ();
767 DWORD error
= GetLastError ();
768 nlwarning ("CDriverGL::setDisplay: wglGetCurrentDC failed: 0x%x", error
);
769 DestroyWindow (tmpHWND
);
777 // Get ready to query for a suitable pixel format that meets our
778 // minimum requirements.
779 int iattributes
[2*20];
780 float fattributes
[2*20];
783 // Attribute arrays must be "0" terminated - for simplicity, first
784 // just zero-out the array then fill from left to right.
785 for ( int a
= 0; a
< 2*20; a
++ )
791 // Since we are trying to create a pbuffer, the pixel format we
792 // request (and subsequently use) must be "buffer capable".
793 iattributes
[2*niattribs
] = WGL_DRAW_TO_PBUFFER_ARB
;
794 iattributes
[2*niattribs
+1] = true;
797 // We require a minimum of 24-bit depth.
798 iattributes
[2*niattribs
] = WGL_DEPTH_BITS_ARB
;
799 iattributes
[2*niattribs
+1] = 24;
802 // We require a minimum of 8-bits for each R, G, B, and A.
803 iattributes
[2*niattribs
] = WGL_RED_BITS_ARB
;
804 iattributes
[2*niattribs
+1] = 8;
806 iattributes
[2*niattribs
] = WGL_GREEN_BITS_ARB
;
807 iattributes
[2*niattribs
+1] = 8;
809 iattributes
[2*niattribs
] = WGL_BLUE_BITS_ARB
;
810 iattributes
[2*niattribs
+1] = 8;
812 iattributes
[2*niattribs
] = WGL_ALPHA_BITS_ARB
;
813 iattributes
[2*niattribs
+1] = 8;
816 // Now obtain a list of pixel formats that meet these minimum
819 unsigned int nformats
;
820 if ( !nwglChoosePixelFormatARB ( hdc
, iattributes
, fattributes
,
821 20, pformat
, &nformats
) )
823 nlwarning ( "pbuffer creation error: Couldn't find a suitable pixel format." );
824 wglDeleteContext (tempGLRC
);
825 DestroyWindow (tmpHWND
);
829 /* After determining a compatible pixel format, the next step is to create a pbuffer of the
830 chosen format. Fortunately this step is fairly easy, as you merely select one of the formats
831 returned in the list in step #2 and call the function: */
832 int iattributes2
[1] = {0};
833 // int iattributes2[] = {WGL_PBUFFER_LARGEST_ARB, 1, 0};
834 _PBuffer
= nwglCreatePbufferARB( hdc
, pformat
[0], width
, height
, iattributes2
);
835 if (_PBuffer
== NULL
)
837 DWORD error
= GetLastError ();
838 nlwarning ("CDriverGL::setDisplay: wglCreatePbufferARB failed: 0x%x", error
);
839 wglDeleteContext (tempGLRC
);
841 DestroyWindow (tmpHWND
);
849 /* After creating a pbuffer, you may use this functions to determine the dimensions of the pbuffer actually created. */
850 if ( !nwglQueryPbufferARB( _PBuffer
, WGL_PBUFFER_WIDTH_ARB
, (int*)&width
) )
852 DWORD error
= GetLastError ();
853 nlwarning ("CDriverGL::setDisplay: wglQueryPbufferARB failed: 0x%x", error
);
854 wglDeleteContext (tempGLRC
);
855 DestroyWindow (tmpHWND
);
863 if ( !nwglQueryPbufferARB( _PBuffer
, WGL_PBUFFER_HEIGHT_ARB
, (int*)&height
) )
865 DWORD error
= GetLastError ();
866 nlwarning ("CDriverGL::setDisplay: wglQueryPbufferARB failed: 0x%x", error
);
867 wglDeleteContext (tempGLRC
);
868 DestroyWindow (tmpHWND
);
876 _CurrentMode
.Width
= width
;
877 _CurrentMode
.Height
= height
;
879 /* The next step is to create a device context for the newly created pbuffer. To do this,
880 call to the function: */
881 _hDC
= nwglGetPbufferDCARB( _PBuffer
);
884 DWORD error
= GetLastError ();
885 nlwarning ("CDriverGL::setDisplay: wglGetPbufferDCARB failed: 0x%x", error
);
886 nwglDestroyPbufferARB( _PBuffer
);
888 wglDeleteContext (tempGLRC
);
890 DestroyWindow (tmpHWND
);
898 /* The final step of pbuffer creation is to create an OpenGL rendering context and
899 associate it with the handle for the pbuffer's device context created in step #4. This is done as follows */
900 _hRC
= wglCreateContext( _hDC
);
903 DWORD error
= GetLastError ();
904 nlwarning ("CDriverGL::setDisplay: wglCreateContext failed: 0x%x", error
);
905 nwglReleasePbufferDCARB( _PBuffer
, _hDC
);
906 nwglDestroyPbufferARB( _PBuffer
);
907 wglDeleteContext (tempGLRC
);
908 DestroyWindow (tmpHWND
);
917 _CurrentMode
.Depth
= uint8(GetDeviceCaps (_hDC
, BITSPIXEL
));
919 // Destroy the temp gl context
921 if (!eglDestroyContext(_EglDisplay
, _EglContext
);)
923 DWORD error
= GetLastError ();
924 nlwarning ("CDriverGL::setDisplay: wglDeleteContext failed: 0x%x", error
);
927 if (!wglDeleteContext (tempGLRC
))
929 DWORD error
= GetLastError ();
930 nlwarning ("CDriverGL::setDisplay: wglDeleteContext failed: 0x%x", error
);
934 // Destroy the temp windows
935 if (!DestroyWindow (tmpHWND
))
936 nlwarning ("CDriverGL::setDisplay: DestroyWindow failed");
938 /* After a pbuffer has been successfully created you can use it for off-screen rendering. To do
939 so, you'll first need to bind the pbuffer, or more precisely, make its GL rendering context
940 the current context that will interpret all OpenGL commands and state changes. */
941 if (!wglMakeCurrent(_hDC
,_hRC
))
943 DWORD error
= GetLastError ();
944 nlwarning ("CDriverGL::setDisplay: wglMakeCurrent failed: 0x%x", error
);
947 eglDestroyContext(_EglDisplay
, _EglContext
);
949 wglDeleteContext (_hRC
);
950 nwglReleasePbufferDCARB( _PBuffer
, _hDC
);
951 nwglDestroyPbufferARB( _PBuffer
);
954 DestroyWindow (tmpHWND
);
965 if (wnd
== EmptyWindow
)
967 if (!createWindow(mode
))
975 // associate OpenGL driver to window
976 SetWindowLongPtr(_win
, GWLP_USERDATA
, (LONG_PTR
)this);
981 /// release old emitter
982 while (_EventEmitter
.getNumEmitters() != 0)
984 _EventEmitter
.removeEmitter(_EventEmitter
.getEmitter(_EventEmitter
.getNumEmitters() - 1));
987 NLMISC::CWinEventEmitter
*we
= new NLMISC::CWinEventEmitter
;
989 // setup the event emitter, and try to retrieve a direct input interface
990 _EventEmitter
.addEmitter(we
, true /*must delete*/); // the main emitter
992 #elif defined(NL_OS_MAC)
994 if (wnd
== EmptyWindow
)
996 if (!createWindow(mode
))
1003 /* The NSView* extracted from a QWidget using winId() has bounds set to
1004 * (QWidget::x(), QWidget::y(), QWidget::width(), QWidget::height()).
1005 * This causes cocoa to draw at an offset of x(), y() leaving an unhandled
1006 * border in the NSView. The code below fixes this by translating the
1007 * coordinate system of the NSView back to 0,0.
1008 * In my opinion this is an error in Qt since QWidget::x/y() are relative to
1009 * parent and [NSView bounds.origin] is relative to it's own coordinate
1010 * system. This are incompatible notations. Qt should handle the conversion.
1011 * Fixes: #1013 Viewport size when embedding NeL Cocoa view in Qt
1012 * (http://dev.ryzom.com/issues/1013)
1014 NSView
* view
= (NSView
*)wnd
;
1015 if(view
.frame
.origin
.x
!= 0 || view
.frame
.origin
.y
!= 0) {
1016 [view setBoundsOrigin
:view
.frame
.origin
];
1020 // setup opengl settings
1021 NSOpenGLPixelFormatAttribute att
[] =
1023 NSOpenGLPFADoubleBuffer
,
1024 NSOpenGLPFAColorSize
, 24,
1025 NSOpenGLPFADepthSize
, 24,
1026 NSOpenGLPFAAlphaSize
, 8,
1027 NSOpenGLPFAStencilSize
, 8,
1028 NSOpenGLPFANoRecovery
,
1029 NSOpenGLPFAAccelerated
,
1030 NSOpenGLPFABackingStore
,
1034 // put the settings into a format object
1035 NSOpenGLPixelFormat
* format
=
1036 [[NSOpenGLPixelFormat alloc
] initWithAttributes
:att
];
1039 nlerror("cannot create NSOpenGLPixelFormat");
1041 // intially set height/width, further updates through CocoaOpenGLView
1042 _CurrentMode
.Height
= mode
.Height
;
1043 _CurrentMode
.Width
= mode
.Width
;
1045 // create a opengl view with the created format
1046 _glView
= [[CocoaOpenGLView alloc
]
1047 initWithFrame
:NSMakeRect(0, 0, mode
.Width
, mode
.Height
)
1048 pixelFormat
:format
];
1051 nlerror("cannot create view");
1053 // tell the view about the driver so the view is able to update "window" size
1054 [_glView setDriver
:this];
1056 // make the view automatically fit the super view
1057 [_glView setAutoresizingMask
: NSViewHeightSizable
| NSViewWidthSizable
];
1059 // put the open gl view into the dummy view contained in the window
1060 [containerView() addSubview
:_glView
];
1063 [_glView setFrame
: [containerView() frame
]];
1065 // create a opengl context for the view
1066 _ctx
= [_glView openGLContext
];
1069 nlerror("cannot create context");
1071 // free the pixel format object
1074 // let the open gl view handle the input
1075 [[containerView() window
] makeFirstResponder
:_glView
];
1077 // prevents scrambled content in the view before first swap
1081 // Set context as thread context
1082 CGLSetCurrentContext((CGLContextObj
)[_ctx CGLContextObj
]);
1084 _EventEmitter
.init(this, _glView
, _DestroyWindow
);
1086 #elif defined(NL_OS_UNIX)
1088 static int sAttribList16bpp
[] =
1097 GLX_STENCIL_SIZE
, 8,
1101 static int sAttribList24bpp
[] =
1110 GLX_STENCIL_SIZE
, 8,
1114 // first try 24bpp and if that fails 16bpp
1115 XVisualInfo
*visual_info
= glXChooseVisual (_dpy
, DefaultScreen(_dpy
), sAttribList24bpp
);
1116 if (visual_info
== NULL
)
1117 visual_info
= glXChooseVisual(_dpy
, DefaultScreen(_dpy
), sAttribList16bpp
);
1118 if(visual_info
== NULL
)
1120 nlerror("glXChooseVisual() failed");
1123 _visual_info
= visual_info
;
1125 _ctx
= glXCreateContext (_dpy
, visual_info
, None
, GL_TRUE
);
1128 nlerror("glXCreateContext() failed");
1131 if (wnd
== EmptyWindow
)
1133 if (!createWindow(mode
))
1140 XSetWindowAttributes attr
;
1141 attr
.background_pixel
= BlackPixel(_dpy
, DefaultScreen(_dpy
));
1142 attr
.override_redirect
= False
;
1144 int attr_flags
= CWOverrideRedirect
| CWBackPixel
;
1146 XChangeWindowAttributes(_dpy
, _win
, attr_flags
, &attr
);
1149 glXMakeCurrent (_dpy
, _win
, _ctx
);
1150 // XMapRaised (_dpy, _win);
1152 // XMapWindow(_dpy, _win);
1154 _EventEmitter
.init (_dpy
, _win
, this);
1157 // XIfEvent(dpy, &event, WaitForNotify, (char *)this);
1159 #endif // NL_OS_UNIX
1161 // setup OpenGL structures
1162 if (!setupDisplay())
1165 // setup window size and screen mode
1169 if (show
|| !_CurrentMode
.Windowed
)
1175 // --------------------------------------------------
1176 bool CDriverGL::saveScreenMode()
1178 H_AUTO_OGL(CDriverGL_saveScreenMode
)
1182 #if defined(NL_OS_WINDOWS)
1184 // don't need to save it because Windows will use default desktop resolution
1186 #elif defined(NL_OS_MAC)
1188 // no need to store because the screen mode is never really changed
1190 #elif defined(NL_OS_UNIX)
1192 int screen
= DefaultScreen(_dpy
);
1197 if (!res
&& _xrandr_version
> 0)
1199 XRRScreenConfiguration
*screen_config
= XRRGetScreenInfo(_dpy
, RootWindow(_dpy
, screen
));
1203 Rotation saved_rotation
;
1204 _OldSizeID
= XRRConfigCurrentConfiguration(screen_config
, &saved_rotation
);
1205 nlinfo("3D: current XRandR mode %d", _OldSizeID
);
1206 XRRFreeScreenConfigInfo(screen_config
);
1212 nlwarning("3D: XRRGetScreenInfo failed");
1216 #endif // HAVE_XRANDR
1218 #if defined(XF86VIDMODE)
1220 if (!res
&& _xvidmode_version
> 0)
1222 // Store old mode in order to restore it when leaving fullscreen
1223 memset(&_OldScreenMode
, 0, sizeof(XF86VidModeModeLine
));
1224 XF86VidModeGetModeLine(_dpy
, screen
, &_OldDotClock
, &_OldScreenMode
);
1225 res
= XF86VidModeGetViewPort(_dpy
, screen
, &_OldX
, &_OldY
);
1228 #endif // XF86VIDMODE
1230 #endif // NL_OS_WINDOWS
1235 // --------------------------------------------------
1236 bool CDriverGL::restoreScreenMode()
1238 H_AUTO_OGL(CDriverGL_restoreScreenMode
)
1242 #if defined(NL_OS_WINDOWS)
1244 res
= (ChangeDisplaySettings(NULL
, 0) == DISP_CHANGE_SUCCESSFUL
);
1246 #elif defined(NL_OS_MAC)
1248 // no need to restore because the screen mode was never really changed
1251 #elif defined(NL_OS_UNIX)
1253 int screen
= DefaultScreen(_dpy
);
1257 if (!res
&& _xrandr_version
> 0)
1259 Window root
= RootWindow(_dpy
, screen
);
1261 XRRScreenConfiguration
*screen_config
= XRRGetScreenInfo(_dpy
, root
);
1265 Rotation saved_rotation
;
1266 SizeID size
= XRRConfigCurrentConfiguration(screen_config
, &saved_rotation
);
1267 if (XRRSetScreenConfig(_dpy
, screen_config
, root
, _OldSizeID
, saved_rotation
, CurrentTime
) == RRSetConfigSuccess
)
1269 nlinfo("3D: Switching back to XRandR mode %d", _OldSizeID
);
1273 XRRFreeScreenConfigInfo(screen_config
);
1277 nlwarning("3D: XRRGetScreenInfo failed");
1281 #endif // HAVE_XRANDR
1283 #if defined(XF86VIDMODE)
1285 if (!res
&& _xvidmode_version
> 0)
1287 XF86VidModeModeInfo info
;
1288 nlinfo("3D: Switching back to original mode");
1291 info
.dotclock
= _OldDotClock
;
1292 info
.hdisplay
= _OldScreenMode
.hdisplay
;
1293 info
.hsyncstart
= _OldScreenMode
.hsyncstart
;
1294 info
.hsyncend
= _OldScreenMode
.hsyncend
;
1295 info
.htotal
= _OldScreenMode
.htotal
;
1296 info
.vdisplay
= _OldScreenMode
.vdisplay
;
1297 info
.vsyncstart
= _OldScreenMode
.vsyncstart
;
1298 info
.vsyncend
= _OldScreenMode
.vsyncend
;
1299 info
.vtotal
= _OldScreenMode
.vtotal
;
1300 info
.flags
= _OldScreenMode
.flags
;
1301 info
.privsize
= _OldScreenMode
.privsize
;
1302 info
.c_private
= _OldScreenMode
.c_private
;
1304 nlinfo("3D: Switching back mode to %dx%d", info
.hdisplay
, info
.vdisplay
);
1305 XF86VidModeSwitchToMode(_dpy
, screen
, &info
);
1306 nlinfo("3D: Switching back viewport to %d,%d",_OldX
, _OldY
);
1307 res
= XF86VidModeSetViewPort(_dpy
, screen
, _OldX
, _OldY
);
1310 #endif // XF86VIDMODE
1312 #endif // NL_OS_WINDOWS
1317 // ***************************************************************************
1320 static sint
modeInfoToFrequency(XF86VidModeModeInfo
*info
)
1322 return (info
->htotal
&& info
->vtotal
) ? (1000 * info
->dotclock
/ (info
->htotal
* info
->vtotal
)) : 0;
1324 #endif // XF86VIDMODE
1326 // ***************************************************************************
1328 bool CDriverGL::setScreenMode(const GfxMode
&mode
)
1330 H_AUTO_OGL(CDriverGL_setScreenMode
)
1334 // if fullscreen, switch back to desktop screen mode
1335 if (!_CurrentMode
.Windowed
)
1336 restoreScreenMode();
1341 // save previous screen mode only if switching from windowed to fullscreen
1342 if (_CurrentMode
.Windowed
)
1345 // if switching exactly to the same screen mode, doesn't change it
1346 GfxMode previousMode
;
1347 if (getCurrentScreenMode(previousMode
)
1348 && mode
.Width
== previousMode
.Width
1349 && mode
.Height
== previousMode
.Height
1350 && mode
.Depth
== previousMode
.Depth
1351 && mode
.Frequency
== previousMode
.Frequency
)
1354 #if defined(NL_OS_WINDOWS)
1357 memset(&devMode
, 0, sizeof(DEVMODE
));
1358 devMode
.dmSize
= sizeof(DEVMODE
);
1359 devMode
.dmDriverExtra
= 0;
1360 devMode
.dmFields
= DM_PELSWIDTH
| DM_PELSHEIGHT
;
1361 devMode
.dmPelsWidth
= mode
.Width
;
1362 devMode
.dmPelsHeight
= mode
.Height
;
1366 devMode
.dmBitsPerPel
= mode
.Depth
;
1367 devMode
.dmFields
|= DM_BITSPERPEL
;
1370 if(mode
.Frequency
> 0)
1372 devMode
.dmDisplayFrequency
= mode
.Frequency
;
1373 devMode
.dmFields
|= DM_DISPLAYFREQUENCY
;
1376 if (ChangeDisplaySettings(&devMode
, CDS_FULLSCREEN
) != DISP_CHANGE_SUCCESSFUL
)
1378 nlwarning("3D: Fullscreen mode switch failed");
1382 #elif defined(NL_OS_MAC)
1384 // no need to do anything here, on mac os, the screen mode is never changed
1386 #elif defined(NL_OS_UNIX)
1392 if (!found
&& _xrandr_version
> 0)
1394 int screen
= DefaultScreen(_dpy
);
1395 Window root
= RootWindow(_dpy
, screen
);
1397 XRRScreenConfiguration
*screen_config
= XRRGetScreenInfo(_dpy
, root
);
1401 Rotation saved_rotation
;
1402 SizeID cur_size
= XRRConfigCurrentConfiguration(screen_config
, &saved_rotation
);
1405 XRRScreenSize
*sizes
= XRRConfigSizes(screen_config
, &nsizes
);
1408 for (sint i
= 0; i
< nsizes
; ++i
)
1410 if (sizes
[i
].width
== mode
.Width
&& sizes
[i
].height
== mode
.Height
)
1419 if (XRRSetScreenConfig(_dpy
, screen_config
, root
, size
, saved_rotation
, CurrentTime
) == RRSetConfigSuccess
)
1421 nlinfo("3D: Switching to XRandR mode %d: %dx%d", size
, sizes
[size
].width
, sizes
[size
].height
);
1426 nlwarning("3D: XRRSetScreenConfig failed for mode %d: %dx%d", size
, sizes
[size
].width
, sizes
[size
].height
);
1431 nlwarning("3D: No corresponding screen mode");
1434 XRRFreeScreenConfigInfo(screen_config
);
1438 nlwarning("3D: XRRGetScreenInfo failed");
1442 #endif // HAVE_XRANDR
1444 #if defined(XF86VIDMODE)
1446 if (!found
&& _xvidmode_version
> 0)
1448 // Find the requested mode and use it
1449 XF86VidModeModeInfo
**modes
;
1451 if (XF86VidModeGetAllModeLines(_dpy
, DefaultScreen(_dpy
), &nmodes
, &modes
))
1453 for (int i
= 0; i
< nmodes
; i
++)
1455 const uint16 freq
= modeInfoToFrequency(modes
[i
]);
1457 nldebug("3D: Available mode - %dx%d %d Hz", modes
[i
]->hdisplay
, modes
[i
]->vdisplay
, (int)freq
);
1458 if (modes
[i
]->hdisplay
== mode
.Width
&& modes
[i
]->vdisplay
== mode
.Height
/* && freq == mode.Frequency */)
1460 if (XF86VidModeSwitchToMode(_dpy
, DefaultScreen(_dpy
), modes
[i
]))
1462 nlinfo("3D: XF86VidMode Switching to mode %dx%d", modes
[i
]->hdisplay
, modes
[i
]->vdisplay
);
1463 XF86VidModeSetViewPort(_dpy
, DefaultScreen(_dpy
), 0, 0);
1473 #endif // XF86VIDMODE
1478 #endif // NL_OS_WINDOWS
1483 // ***************************************************************************
1484 bool CDriverGL::createWindow(const GfxMode
&mode
)
1486 H_AUTO_OGL(CDriverGL_createWindow
)
1488 nlWindow window
= EmptyWindow
;
1490 #ifdef NL_OS_WINDOWS
1492 // create the OpenGL window
1493 DWORD dwStyle
= WS_OVERLAPPEDWINDOW
|WS_CLIPCHILDREN
|WS_CLIPSIBLINGS
;
1494 int pos
= CW_USEDEFAULT
;
1495 HWND hwndParent
= HWND_DESKTOP
;
1498 dwStyle
&= ~WS_VISIBLE
;
1502 window
= CreateWindowW(L
"NLClass", L
"NeL Window", dwStyle
,
1503 pos
, pos
, mode
.Width
, mode
.Height
, hwndParent
, NULL
, GetModuleHandle(NULL
), NULL
);
1505 if (window
== EmptyWindow
)
1507 DWORD res
= GetLastError();
1508 nlwarning("CreateWindow failed: %u", res
);
1512 #elif defined(NL_OS_MAC)
1514 // create the menu in the top screen bar
1515 setupApplicationMenu();
1517 // finish the application launching
1518 [NSApp finishLaunching
];
1520 // describe how the window should look like and behave
1521 unsigned int styleMask
= NSTitledWindowMask
| NSClosableWindowMask
|
1522 NSMiniaturizableWindowMask
| NSResizableWindowMask
;
1524 // create a cocoa window with the size provided by the mode parameter
1525 NSWindow
* cocoa_window
= [[NSWindow alloc
]
1526 initWithContentRect
:NSMakeRect(0, 0, mode
.Width
, mode
.Height
)
1527 styleMask
:styleMask backing
:NSBackingStoreBuffered defer
:NO
];
1531 nlerror("cannot create cocoa window");
1535 // create an application delegate
1536 CocoaApplicationDelegate
* appDelegate
=
1537 [[CocoaApplicationDelegate alloc
] initWithDriver
:this];
1539 // set the application delegate, this will handle window/app close events
1540 [NSApp setDelegate
:(id
<NSApplicationDelegate
>)appDelegate
];
1542 // bind the close button of the window to applicationShouldTerminate
1543 id closeButton
= [cocoa_window standardWindowButton
:NSWindowCloseButton
];
1544 [closeButton setAction
:@
selector(applicationShouldTerminate
:)];
1545 [closeButton setTarget
:appDelegate
];
1547 // set the delegate which will handle window move events
1548 [cocoa_window setDelegate
:[[CocoaWindowDelegate alloc
] initWithDriver
:this]];
1550 // set the window to non transparent
1551 [cocoa_window setOpaque
:YES
];
1553 // enable mouse move events, NeL wants them
1554 [cocoa_window setAcceptsMouseMovedEvents
:YES
];
1556 // there are no overlapping subviews, can use the magical optimization :)
1557 [cocoa_window useOptimizedDrawing
:YES
];
1559 // put the window to the front and make it the key window
1560 [cocoa_window makeKeyAndOrderFront
:nil
];
1562 // this is our main window
1563 [cocoa_window makeMainWindow
];
1565 // create a dummy view which works like the window on other platforms
1566 // the open gl view will be created as subview of this one.
1567 window
= [[NSView alloc
]
1568 initWithFrame
:NSMakeRect(0, 0, mode
.Width
, mode
.Height
)];
1570 [cocoa_window setContentView
: (NSView
*)window
];
1572 if(window
== EmptyWindow
)
1574 nldebug("cannot create cocoa view for cocoa window");
1578 #elif defined (NL_OS_UNIX)
1580 if (_visual_info
== NULL
)
1583 nlWindow root
= RootWindow(_dpy
, DefaultScreen(_dpy
));
1585 XSetWindowAttributes attr
;
1586 attr
.background_pixel
= BlackPixel(_dpy
, DefaultScreen(_dpy
));
1587 attr
.colormap
= XCreateColormap(_dpy
, root
, _visual_info
->visual
, AllocNone
);
1588 int attr_flags
= CWBackPixel
| CWColormap
;
1590 window
= XCreateWindow (_dpy
, root
, 0, 0, mode
.Width
, mode
.Height
, 0, _visual_info
->depth
, InputOutput
, _visual_info
->visual
, attr_flags
, &attr
);
1592 if (window
== EmptyWindow
)
1594 nlerror("3D: XCreateWindow() failed");
1598 // normal window type
1599 XChangeProperty(_dpy
, window
, XA_WM_WINDOW_TYPE
, XA_ATOM
, 32, PropModeReplace
, (const unsigned char*)&XA_WM_WINDOW_TYPE_NORMAL
, 1);
1602 XWMHints
*wm_hints
= XAllocWMHints();
1606 wm_hints
->flags
= StateHint
| InputHint
;
1607 wm_hints
->initial_state
= NormalState
;
1608 wm_hints
->input
= True
;
1610 XSetWMHints(_dpy
, window
, wm_hints
);
1615 nlwarning("3D: Couldn't allocate XWMHints");
1619 XClassHint
*class_hints
= XAllocClassHint();
1623 class_hints
->res_name
= (char*)"NeL";
1624 class_hints
->res_class
= (char*)"nel";
1626 XSetClassHint(_dpy
, window
, class_hints
);
1631 nlwarning("3D: Couldn't allocate XClassHint");
1634 #endif // NL_OS_UNIX
1638 _CurrentMode
.Width
= mode
.Width
;
1639 _CurrentMode
.Height
= mode
.Height
;
1641 // Must destroy this window
1642 _DestroyWindow
= true;
1644 setWindowTitle(ucstring("NeL window"));
1651 // ***************************************************************************
1653 bool CDriverGL::destroyWindow()
1655 H_AUTO_OGL(CDriverGL_destroyWindow
)
1659 // make sure window icons are deleted
1660 std::vector
<NLMISC::CBitmap
> bitmaps
;
1661 setWindowIcon(bitmaps
);
1665 if (_EglDisplay
&& _EglContext
)
1667 eglMakeCurrent(_EglDisplay
, _EglSurface
, _EglSurface
, _EglContext
);
1671 eglDestroyContext(_EglDisplay
, _EglContext
);
1675 #elif defined(NL_OS_WINDOWS)
1678 // wglMakeCurrent(NULL,NULL);
1681 wglMakeCurrent(_hDC
, NULL
);
1685 wglDeleteContext(_hRC
);
1691 ReleaseDC(_win
, _hDC
);
1695 #elif defined(NL_OS_MAC)
1697 #elif defined(NL_OS_UNIX)
1699 if (_DestroyWindow
&& _ctx
) // FIXME: _DestroyWindow may need to be removed here as well
1700 glXDestroyContext(_dpy
, _ctx
);
1706 #ifdef NL_OS_WINDOWS
1708 // don't destroy window if it hasn't been created by our driver
1709 if (_win
&& _DestroyWindow
)
1710 DestroyWindow(_win
);
1712 #elif defined(NL_OS_MAC)
1716 [[containerView() window
] release
];
1717 [containerView() release
];
1723 #elif defined (NL_OS_UNIX)
1725 _EventEmitter
.closeIM();
1727 if (_DestroyWindow
&& _win
)
1728 XDestroyWindow(_dpy
, _win
);
1730 // Ungrab the keyboard (probably not necessary);
1731 // XUnmapWindow(_dpy, _win);
1733 XUngrabKeyboard(_dpy
, CurrentTime
);
1742 // ***************************************************************************
1744 CDriverGL::EWindowStyle
CDriverGL::getWindowStyle() const
1746 H_AUTO_OGL(CDriverGL_getWindowStyle
)
1748 if (!_CurrentMode
.Windowed
)
1749 return EWSFullscreen
;
1754 // ***************************************************************************
1756 bool CDriverGL::setWindowStyle(EWindowStyle windowStyle
)
1758 H_AUTO_OGL(CDriverGL_setWindowStyle
)
1760 // don't change window style, if we did not create the window
1761 if (_win
== EmptyWindow
|| !_DestroyWindow
)
1764 if (getWindowStyle() == windowStyle
)
1767 #if defined(NL_OS_WINDOWS)
1769 // get current style
1770 LONG dwStyle
= GetWindowLong(_win
, GWL_STYLE
);
1772 // prepare new style
1773 LONG dwNewStyle
= WS_CLIPCHILDREN
|WS_CLIPSIBLINGS
;
1775 // get window current state
1776 WINDOWPLACEMENT wndpl
;
1777 wndpl
.length
= sizeof(WINDOWPLACEMENT
);
1779 bool isMaximized
= GetWindowPlacement(_win
, &wndpl
) && (wndpl
.showCmd
== SW_SHOWMAXIMIZED
);
1780 bool isVisible
= false;
1782 if (windowStyle
== EWSWindowed
&& !_CurrentMode
.OffScreen
)
1784 dwNewStyle
|= WS_OVERLAPPEDWINDOW
;
1786 // if we can't resize window, remove maximize box and resize anchors
1787 if (!_Resizable
) dwNewStyle
^= WS_MAXIMIZEBOX
|WS_THICKFRAME
;
1789 isVisible
= (dwStyle
& WS_VISIBLE
) != 0;
1791 else if (windowStyle
== EWSFullscreen
)
1794 dwNewStyle
|= WS_POPUP
;
1800 dwNewStyle
|= WS_VISIBLE
;
1802 if (dwStyle
!= dwNewStyle
)
1803 SetWindowLong(_win
, GWL_STYLE
, dwNewStyle
);
1805 // if (windowStyle == EWSMaximized && isVisible && !isMaximized)
1806 // ShowWindow(_hWnd, SW_SHOWMAXIMIZED);
1807 // else if (isMaximized && isVisible)
1808 // ShowWindow(_hWnd, SW_RESTORE);
1810 #elif defined(NL_OS_MAC)
1812 // leave fullscreen mode, enter windowed mode
1813 if (windowStyle
== EWSWindowed
&& [containerView() isInFullScreenMode
])
1815 // disable manual setting of back buffer size, cocoa handles this
1816 // automatically as soon as the view gets resized
1817 CGLError error
= CGLDisable((CGLContextObj
)[_ctx CGLContextObj
],
1818 kCGLCESurfaceBackingSize
);
1820 if (error
!= kCGLNoError
)
1821 nlerror("cannot disable kCGLCESurfaceBackingSize (%s)",
1822 CGLErrorString(error
));
1824 // pull the view back from fullscreen restoring window options
1825 [containerView() exitFullScreenModeWithOptions
:nil
];
1827 // let the gl view receive key events
1828 [[containerView() window
] makeFirstResponder
:_glView
];
1830 // bring the window containing the gl view to the front
1831 [[containerView() window
] makeKeyAndOrderFront
:nil
];
1834 // enter fullscreen, leave windowed mode
1835 else if (windowStyle
== EWSFullscreen
&& ![containerView() isInFullScreenMode
])
1837 // enable manual back buffer size for mode setting in fullscreen
1838 CGLError error
= CGLEnable((CGLContextObj
)[_ctx CGLContextObj
],
1839 kCGLCESurfaceBackingSize
);
1841 if (error
!= kCGLNoError
)
1842 nlerror("cannot enable kCGLCESurfaceBackingSize (%s)",
1843 CGLErrorString(error
));
1845 // put the view in fullscreen mode, hiding the dock but enabling the menubar
1846 // to pop up if the mouse hits the top screen border.
1847 // NOTE: withOptions:nil disables <CMD>+<Tab> application switching!
1848 #ifdef NL_MAC_VERSION_10_6_UP
1849 [containerView() enterFullScreenMode
:[NSScreen mainScreen
] withOptions
:
1850 [NSDictionary dictionaryWithObjectsAndKeys
:
1851 [NSNumber numberWithInt
:
1852 NSApplicationPresentationHideDock
|
1853 NSApplicationPresentationAutoHideMenuBar
],
1854 NSFullScreenModeApplicationPresentationOptions
, nil
]];
1857 TODO check if simply using NSView enterFullScreenMode is a good idea.
1858 the context can be set to full screen as well, performance differences?
1861 // let the gl view receive key events
1862 [[containerView() window
] makeFirstResponder
:_glView
];
1865 #elif defined(NL_OS_UNIX)
1867 XWindowAttributes attr
;
1868 XGetWindowAttributes(_dpy
, _win
, &attr
);
1870 // if window is mapped use events else properties
1871 if (attr
.map_state
!= IsUnmapped
)
1873 // Toggle fullscreen
1875 xev
.xclient
.type
= ClientMessage
;
1876 xev
.xclient
.serial
= 0;
1877 xev
.xclient
.send_event
= True
;
1878 xev
.xclient
.display
= _dpy
;
1879 xev
.xclient
.window
= _win
;
1880 xev
.xclient
.message_type
= XA_WM_STATE
;
1881 xev
.xclient
.format
= 32;
1882 xev
.xclient
.data
.l
[0] = windowStyle
== EWSFullscreen
? _NET_WM_STATE_ADD
:_NET_WM_STATE_REMOVE
;
1883 xev
.xclient
.data
.l
[1] = XA_WM_STATE_FULLSCREEN
;
1884 xev
.xclient
.data
.l
[2] = 0;
1885 xev
.xclient
.data
.l
[3] = 1; // 1 for Application, 2 for Page or Taskbar, 0 for old source
1886 xev
.xclient
.data
.l
[4] = 0;
1887 if (!XSendEvent(_dpy
, XDefaultRootWindow(_dpy
), False
, SubstructureRedirectMask
| SubstructureNotifyMask
, &xev
))
1889 nlwarning("3D: Failed to toggle to fullscreen");
1895 if (windowStyle
== EWSFullscreen
)
1897 // set state property to fullscreen
1898 XChangeProperty(_dpy
, _win
, XA_WM_STATE
, XA_ATOM
, 32, PropModeReplace
, (const unsigned char*)&XA_WM_STATE_FULLSCREEN
, 1);
1902 // delete state property
1903 XDeleteProperty(_dpy
, _win
, XA_WM_STATE
);
1907 #endif // NL_OS_WINDOWS
1909 _CurrentMode
.Windowed
= (windowStyle
== EWSWindowed
);
1914 // --------------------------------------------------
1915 bool CDriverGL::setMode(const GfxMode
& mode
)
1917 H_AUTO_OGL(CDriverGL_setMode
);
1919 // don't modify window or screen if managed by a 3rd party library
1920 if (!_DestroyWindow
)
1923 #if defined(NL_OS_WINDOWS)
1924 // save relative cursor
1929 BOOL cursorPosOk
= isSystemCursorInClientArea()
1930 && GetCursorPos(&cursorPos
)
1931 && ScreenToClient(_win
, &cursorPos
);
1932 sint curX
= (sint
)cursorPos
.x
* (sint
)mode
.Width
;
1933 sint curY
= (sint
)cursorPos
.y
* (sint
)mode
.Height
;
1936 if (!setScreenMode(mode
))
1939 // when changing window style, it's possible system change window size too
1940 setWindowStyle(mode
.Windowed
? EWSWindowed
: EWSFullscreen
);
1943 _CurrentMode
.Depth
= mode
.Depth
;
1945 setWindowSize(mode
.Width
, mode
.Height
);
1946 setWindowPos(_WindowX
, _WindowY
);
1948 switch (_CurrentMode
.Depth
)
1950 case 16: _ColorDepth
= ColorDepth16
; break;
1952 case 32: _ColorDepth
= ColorDepth32
; break;
1955 #if defined(NL_OS_WINDOWS)
1956 // restore relative cursor
1959 cursorPos
.x
= curX
/ (sint
)mode
.Width
;
1960 cursorPos
.y
= curY
/ (sint
)mode
.Height
;
1961 ClientToScreen(_win
, &cursorPos
);
1962 SetCursorPos(cursorPos
.x
, cursorPos
.y
);
1966 // set color depth for custom cursor
1974 #ifdef NL_MAC_VERSION_10_6_UP
1976 /// helper to extract bits per pixel value from screen mode, only 16 or 32 bits
1977 static int bppFromDisplayMode(CGDisplayModeRef mode
)
1979 CFStringRef pixelEncoding
= CGDisplayModeCopyPixelEncoding(mode
);
1981 if(CFStringCompare(pixelEncoding
, CFSTR(IO32BitDirectPixels
),
1982 kCFCompareCaseInsensitive
) == kCFCompareEqualTo
)
1985 else if(CFStringCompare(pixelEncoding
, CFSTR(IO16BitDirectPixels
),
1986 kCFCompareCaseInsensitive
) == kCFCompareEqualTo
)
1994 long GetDictionaryLong(CFDictionaryRef theDict
, const void* key
)
1998 numRef
= (CFNumberRef
)CFDictionaryGetValue(theDict
, key
);
2000 CFNumberGetValue(numRef
, kCFNumberLongType
, &value
);
2004 // some macros to make code more readable.
2005 #define GetModeWidth(mode) GetDictionaryLong((mode), kCGDisplayWidth)
2006 #define GetModeHeight(mode) GetDictionaryLong((mode), kCGDisplayHeight)
2007 #define GetModeBitsPerPixel(mode) GetDictionaryLong((mode), kCGDisplayBitsPerPixel)
2013 // --------------------------------------------------
2014 bool CDriverGL::getModes(std::vector
<GfxMode
> &modes
)
2016 H_AUTO_OGL(CDriverGL_getModes
)
2018 #ifdef NL_OS_WINDOWS
2021 while (EnumDisplaySettings (NULL
, modeIndex
, &devMode
))
2023 // Keep only 16 and 32 bits
2024 if ((devMode
.dmBitsPerPel
== 16 ) || (devMode
.dmBitsPerPel
== 32))
2028 mode
.Width
= (uint16
)devMode
.dmPelsWidth
;
2029 mode
.Height
= (uint16
)devMode
.dmPelsHeight
;
2030 mode
.Depth
= (uint8
)devMode
.dmBitsPerPel
;
2031 mode
.Frequency
= devMode
.dmDisplayFrequency
;
2032 modes
.push_back (mode
);
2039 #elif defined(NL_OS_MAC)
2041 static const CGDisplayCount kMaxDisplays
= 16;
2042 CGDirectDisplayID display
[kMaxDisplays
];
2043 CGDisplayCount numDisplays
;
2045 CGDisplayErr err
= CGGetActiveDisplayList(kMaxDisplays
, display
, &numDisplays
);
2046 if(err
!= CGDisplayNoErr
)
2048 nlwarning("Cannot get displays (%d)", err
);
2052 // nldebug("3D: %d displays found", (int)numDisplays);
2054 for (CGDisplayCount i
= 0; i
< numDisplays
; ++i
)
2056 CGDirectDisplayID dspy
= display
[i
];
2058 #ifdef NL_MAC_VERSION_10_6_UP
2059 CFArrayRef modeList
= CGDisplayCopyAllDisplayModes(dspy
, NULL
);
2061 CFArrayRef modeList
= CGDisplayAvailableModes(dspy
);
2064 if (modeList
== NULL
)
2066 nlwarning("Display is invalid");
2070 for (CFIndex j
= 0; j
< CFArrayGetCount(modeList
); ++j
)
2072 #ifdef NL_MAC_VERSION_10_6_UP
2073 CGDisplayModeRef mode
= (CGDisplayModeRef
)CFArrayGetValueAtIndex(modeList
, j
);
2074 uint8 bpp
= bppFromDisplayMode(mode
);
2076 CFDictionaryRef mode
= (CFDictionaryRef
)CFArrayGetValueAtIndex(modeList
, j
);
2077 uint8 bpp
= (uint8
)GetModeBitsPerPixel(mode
);
2082 #ifdef NL_MAC_VERSION_10_6_UP
2083 uint16 w
= CGDisplayModeGetWidth(mode
);
2084 uint16 h
= CGDisplayModeGetHeight(mode
);
2086 uint16 w
= (uint16
)GetModeWidth(mode
);
2087 uint16 h
= (uint16
)GetModeHeight(mode
);
2096 // Frequency stays at 0 because on mac cocoa, display resolution
2097 // is never really changed. if rendering res < display res,
2098 // cocoa interpolates and keeps the display at it's original res.
2100 modes
.push_back (mode
);
2102 // nldebug(" Display 0x%x: Mode %dx%d, %d BPP", dspy, w, h, bpp);
2106 #ifdef NL_MAC_VERSION_10_6_UP
2107 CFRelease(modeList
);
2111 #elif defined (NL_OS_UNIX)
2115 nlwarning("3D: Unable to list modes because Display is NULL, did you forget to call init() ?");
2120 int screen
= DefaultScreen(_dpy
);
2122 #if defined(HAVE_XRANDR)
2123 if (!found
&& _xrandr_version
>= 100)
2125 XRRScreenConfiguration
*screen_config
= XRRGetScreenInfo(_dpy
, RootWindow(_dpy
, screen
));
2129 // retrieve the list of resolutions
2131 XRRScreenSize
*sizes
= XRRConfigSizes(screen_config
, &nsizes
);
2135 // nldebug("3D: %d available XRandR modes:", nsizes);
2136 for (sint i
= 0; i
< nsizes
; ++i
)
2140 mode
.Width
= sizes
[i
].width
;
2141 mode
.Height
= sizes
[i
].height
;
2144 modes
.push_back(mode
);
2145 // nldebug("3D: Mode %d: %dx%d", i, mode.Width, mode.Height);
2152 nlwarning("3D: No XRandR modes available");
2155 XRRFreeScreenConfigInfo(screen_config
);
2159 nlwarning("3D: XRRGetScreenInfo failed");
2165 if (!found
&& _xvidmode_version
> 0)
2168 XF86VidModeModeInfo
**ms
;
2169 if (XF86VidModeGetAllModeLines(_dpy
, screen
, &nmodes
, &ms
))
2171 // nlinfo("3D: %d available XF86VidMode modes:", nmodes);
2172 for (int j
= 0; j
< nmodes
; j
++)
2176 mode
.Width
= (uint16
)ms
[j
]->hdisplay
;
2177 mode
.Height
= (uint16
)ms
[j
]->vdisplay
;
2178 mode
.Frequency
= modeInfoToFrequency(ms
[j
]);
2179 // nlinfo("3D: Mode %d: %dx%d, %d Hz", j, mode.Width, mode.Height, mode.Frequency);
2180 modes
.push_back (mode
);
2186 nlwarning("3D: XF86VidModeGetAllModeLines failed");
2189 #endif // XF86VIDMODE
2193 // Add current screen mode
2195 mode
.Width
= DisplayWidth(_dpy
, screen
);
2196 mode
.Height
= DisplayHeight(_dpy
, screen
);
2198 modes
.push_back(mode
);
2205 // --------------------------------------------------
2206 bool CDriverGL::getCurrentScreenMode(GfxMode
&mode
)
2208 H_AUTO_OGL(CDriverGL_getCurrentScreenMode
)
2210 #ifdef NL_OS_WINDOWS
2213 devmode
.dmSize
= sizeof(DEVMODE
);
2214 devmode
.dmDriverExtra
= 0;
2215 EnumDisplaySettings(NULL
, ENUM_CURRENT_SETTINGS
, &devmode
);
2217 mode
.Windowed
= _CurrentMode
.Windowed
;
2218 mode
.OffScreen
= false;
2219 mode
.Depth
= (uint8
)devmode
.dmBitsPerPel
;
2220 mode
.Frequency
= devmode
.dmDisplayFrequency
;
2221 mode
.Width
= (uint16
)devmode
.dmPelsWidth
;
2222 mode
.Height
= (uint16
)devmode
.dmPelsHeight
;
2223 mode
.AntiAlias
= _CurrentMode
.AntiAlias
;
2225 #elif defined(NL_OS_MAC)
2227 // the sceen with the menu bar
2228 NSScreen
* screen
= [[NSScreen screens
] objectAtIndex
:0];
2230 mode
.OffScreen
= false;
2232 mode
.Depth
= NSBitsPerPixelFromDepth([screen depth
]);
2234 // in fullscreen mode
2235 if([containerView() isInFullScreenMode
])
2237 // return the size of the back buffer (like having switched monitor mode)
2238 mode
.Windowed
= false;
2239 mode
.Width
= _backBufferWidth
;
2240 mode
.Height
= _backBufferHeight
;
2246 // return the size of the screen with menu bar
2247 mode
.Windowed
= true;
2248 mode
.Width
= (uint16
)[screen frame
].size
.width
;
2249 mode
.Height
= (uint16
)[screen frame
].size
.height
;
2252 #elif defined(NL_OS_UNIX)
2255 int screen
= DefaultScreen(_dpy
);
2259 if (!found
&& _xrandr_version
> 0)
2261 XRRScreenConfiguration
*screen_config
= XRRGetScreenInfo(_dpy
, RootWindow(_dpy
, screen
));
2266 XRRScreenSize
*sizes
= XRRConfigSizes(screen_config
, &nsizes
);
2269 Rotation cur_rotation
;
2270 SizeID size
= XRRConfigCurrentConfiguration(screen_config
, &cur_rotation
);
2272 mode
.Windowed
= _CurrentMode
.Windowed
;
2273 mode
.OffScreen
= false;
2274 mode
.Depth
= (uint
) DefaultDepth(_dpy
, screen
);
2276 mode
.Width
= sizes
[size
].width
;
2277 mode
.Height
= sizes
[size
].height
;
2281 nlinfo("3D: Current XRandR mode %d: %dx%d, %dbit", size
, mode
.Width
, mode
.Height
, mode
.Depth
);
2285 nlwarning("3D: No XRandR modes available");
2288 XRRFreeScreenConfigInfo(screen_config
);
2292 nlwarning("3D: XRRGetScreenInfo failed");
2296 #endif // HAVE_XRANDR
2300 if (!found
&& _xvidmode_version
> 0)
2303 XF86VidModeModeLine xmode
;
2305 if (XF86VidModeGetModeLine(_dpy
, screen
, &pixelClock
, &xmode
))
2307 mode
.Windowed
= _CurrentMode
.Windowed
;
2308 mode
.OffScreen
= false;
2309 mode
.Depth
= (uint
) DefaultDepth(_dpy
, screen
);
2310 mode
.Frequency
= 1000 * pixelClock
/ (xmode
.htotal
* xmode
.vtotal
) ;
2311 mode
.Width
= xmode
.hdisplay
;
2312 mode
.Height
= xmode
.vdisplay
;
2313 nlinfo("3D: Current XF86VidMode mode: %dx%d, %d Hz, %dbit", mode
.Width
, mode
.Height
, mode
.Frequency
, mode
.Depth
);
2319 nlwarning("3D: XF86VidModeGetModeLine failed, cannot get current video mode");
2323 #endif // XF86VidMode
2327 mode
.Windowed
= _CurrentMode
.Windowed
;
2328 mode
.OffScreen
= _CurrentMode
.OffScreen
;
2329 mode
.Depth
= (uint
) DefaultDepth(_dpy
, screen
);
2331 mode
.Width
= DisplayWidth(_dpy
, screen
);
2332 mode
.Height
= DisplayHeight(_dpy
, screen
);
2336 nldebug("Current mode: %dx%d, %d Hz, %dbit", mode
.Width
, mode
.Height
, mode
.Frequency
, mode
.Depth
);
2339 #endif // NL_OS_UNIX
2344 // --------------------------------------------------
2345 void CDriverGL::setWindowTitle(const ucstring
&title
)
2347 H_AUTO_OGL(CDriverGL_setWindowTitle
)
2349 if (_win
== EmptyWindow
)
2352 #ifdef NL_OS_WINDOWS
2354 if (!SetWindowTextW(_win
, (WCHAR
*)title
.c_str()))
2356 nlwarning("SetWindowText failed: %s", formatErrorMessage(getLastError()).c_str());
2359 #elif defined(NL_OS_MAC)
2361 [[containerView() window
] setTitle
:
2362 [NSString stringWithUTF8String
:title
.toUtf8().c_str()]];
2364 #elif defined (NL_OS_UNIX)
2366 #ifdef X_HAVE_UTF8_STRING
2368 Xutf8SetWMProperties (_dpy
, _win
, (char*)title
.toUtf8().c_str(), (char*)title
.toUtf8().c_str(), NULL
, 0, NULL
, NULL
, NULL
);
2370 // standard properties
2371 XTextProperty text_property
;
2372 if (XStringListToTextProperty((char**)&title
.toUtf8().c_str(), 1, &text_property
) != 0)
2374 XSetWMProperties (_dpy
, _win
, &text_property
, &text_property
, NULL
, 0, NULL
, NULL
, NULL
);
2378 nlwarning("3D: Can't convert title to TextProperty");
2382 #endif // NL_OS_WINDOWS
2385 // ***************************************************************************
2386 void CDriverGL::setWindowPos(sint32 x
, sint32 y
)
2388 H_AUTO_OGL(CDriverGL_setWindowPos
)
2393 if (_win
== EmptyWindow
|| !_CurrentMode
.Windowed
)
2396 #ifdef NL_OS_WINDOWS
2398 // save relative cursor
2400 BOOL cursorPosOk
= isSystemCursorInClientArea()
2401 && GetCursorPos(&cursorPos
)
2402 && ScreenToClient(_win
, &cursorPos
);
2404 SetWindowPos(_win
, NULL
, x
, y
, 0, 0, /*SWP_NOZORDER | SWP_NOACTIVATE |*/ SWP_NOSIZE
);
2408 ClientToScreen(_win
, &cursorPos
);
2409 SetCursorPos(cursorPos
.x
, cursorPos
.y
);
2412 #elif defined(NL_OS_MAC)
2413 // get the rect (position, size) of the screen with menu bar
2414 NSRect screenRect
= [[[NSScreen screens
] objectAtIndex
:0] frame
];
2416 // get the rect (position, size) of the window
2417 NSRect windowRect
= [[containerView() window
] frame
];
2419 // convert y from NeL coordinates to cocoa coordinates
2420 y
= screenRect
.size
.height
- y
;
2422 // tell cocoa to move the window
2423 [[containerView() window
] setFrameTopLeftPoint
:NSMakePoint(x
, y
)];
2425 #elif defined (NL_OS_UNIX)
2427 if (_CurrentMode
.Windowed
)
2429 // first time requesting decoration sizes
2430 if (_WindowX
&& _WindowY
&& !_DecorationWidth
&& !_DecorationHeight
&& _WndActive
)
2432 _DecorationWidth
= -1;
2433 _DecorationHeight
= -1;
2436 XMoveWindow(_dpy
, _win
, x
, y
);
2439 #endif // NL_OS_WINDOWS
2442 // ***************************************************************************
2443 void CDriverGL::showWindow(bool show
)
2445 H_AUTO_OGL(CDriverGL_showWindow
)
2447 // don't change window visibility, if we didn't create the window
2448 if (_win
== EmptyWindow
|| !_DestroyWindow
)
2451 _WindowVisible
= show
;
2453 #ifdef NL_OS_WINDOWS
2455 ShowWindow (_win
, show
? SW_SHOW
:SW_HIDE
);
2457 #elif defined(NL_OS_MAC)
2459 // TODO: Missing Mac Implementation for showWindow
2461 #elif defined (NL_OS_UNIX)
2465 XMapRaised(_dpy
, _win
);
2467 // fix window position if windows manager want to impose them
2468 setWindowPos(_WindowX
, _WindowY
);
2472 XUnmapWindow(_dpy
, _win
);
2475 #endif // NL_OS_WINDOWS
2478 // --------------------------------------------------
2479 emptyProc
CDriverGL::getWindowProc()
2481 H_AUTO_OGL(CDriverGL_getWindowProc
)
2483 return (emptyProc
)GlWndProc
;
2486 // --------------------------------------------------
2487 bool CDriverGL::createContext()
2492 if (_CurrentMode
.AntiAlias
> -1)
2494 if (_CurrentMode
.AntiAlias
== 0)
2500 samples
= _CurrentMode
.AntiAlias
;
2504 EGLint attribList
[] =
2511 EGL_STENCIL_SIZE
, 8,
2512 // EGL_SAMPLE_BUFFERS, _CurrentMode.AntiAlias > -1 ? 1:0,
2513 // EGL_SAMPLES, samples,
2514 EGL_RENDERABLE_TYPE
,
2520 _EglDisplay
= EGL_NO_DISPLAY
; // eglGetDisplay(_hDC);
2522 if (_EglDisplay
== EGL_NO_DISPLAY
)
2524 _EglDisplay
= eglGetDisplay(EGL_DEFAULT_DISPLAY
);
2526 if (_EglDisplay
== EGL_NO_DISPLAY
)
2528 nlwarning("3D: failed to get display 0x%x", eglGetError());
2534 EGLint majorVersion
;
2535 EGLint minorVersion
;
2537 if (!eglInitialize(_EglDisplay
, &majorVersion
, &minorVersion
))
2542 const char *extensions
= eglQueryString(_EglDisplay
, EGL_EXTENSIONS
);
2548 if (!eglGetConfigs(_EglDisplay
, NULL
, 0, &numConfigs
))
2554 EGLConfig config
= NULL
;
2556 if (!eglChooseConfig(_EglDisplay
, attribList
, &config
, 1, &numConfigs
))
2562 _EglSurface
= eglCreateWindowSurface(_EglDisplay
, config
, (EGLNativeWindowType
)_win
, NULL
);
2564 if (_EglSurface
== EGL_NO_SURFACE
)
2569 // Create a GL context
2570 EGLint contextAttribs
[] =
2572 EGL_CONTEXT_CLIENT_VERSION
, 1,
2576 _EglContext
= eglCreateContext(_EglDisplay
, config
, EGL_NO_CONTEXT
, contextAttribs
);
2578 if (_EglContext
== EGL_NO_CONTEXT
)
2583 // Make the context current
2584 if (!eglMakeCurrent(_EglDisplay
, _EglSurface
, _EglSurface
, _EglContext
))
2588 #elif defined(NL_OS_WINDOWS)
2590 _CurrentMode
.Depth
= uint8(GetDeviceCaps(_hDC
,BITSPIXEL
));
2592 wglMakeCurrent(_hDC
,NULL
);
2594 memset(&_pfd
,0,sizeof(_pfd
));
2595 _pfd
.nSize
= sizeof(_pfd
);
2597 _pfd
.dwFlags
= PFD_DRAW_TO_WINDOW
| PFD_SUPPORT_OPENGL
| PFD_DOUBLEBUFFER
;
2598 _pfd
.iPixelType
= PFD_TYPE_RGBA
;
2599 _pfd
.cColorBits
= _CurrentMode
.Depth
;
2600 // Choose best suited Depth Buffer.
2601 if(_CurrentMode
.Depth
<= 16)
2603 _pfd
.cDepthBits
= 16;
2607 _pfd
.cDepthBits
= 24;
2608 _pfd
.cAlphaBits
= 8;
2609 _pfd
.cStencilBits
= 8;
2611 _pfd
.iLayerType
= PFD_MAIN_PLANE
;
2612 int pf
=ChoosePixelFormat(_hDC
,&_pfd
);
2618 if ( !SetPixelFormat(_hDC
,pf
,&_pfd
) )
2622 _hRC
=wglCreateContext(_hDC
);
2624 wglMakeCurrent(_hDC
,_hRC
);
2630 // --------------------------------------------------
2631 bool CDriverGL::activate()
2633 H_AUTO_OGL(CDriverGL_activate
);
2635 if (_win
== EmptyWindow
)
2640 EGLContext ctx
= eglGetCurrentContext();
2642 if (ctx
!= _EglContext
)
2644 // Make the context current
2645 if (!eglMakeCurrent(_EglDisplay
, _EglSurface
, _EglSurface
, _EglContext
))
2651 #elif defined(NL_OS_WINDOWS)
2653 HGLRC hglrc
= wglGetCurrentContext();
2656 wglMakeCurrent(_hDC
, _hRC
);
2658 #elif defined(NL_OS_MAC)
2660 if([NSOpenGLContext currentContext
] != _ctx
)
2661 [_ctx makeCurrentContext
];
2663 #elif defined (NL_OS_UNIX)
2665 GLXContext nctx
= glXGetCurrentContext();
2667 if (nctx
!= NULL
&& nctx
!= _ctx
)
2668 glXMakeCurrent(_dpy
, _win
, _ctx
);
2670 #endif // USE_OPENGLES
2675 // --------------------------------------------------
2676 IDriver::TMessageBoxId
CDriverGL::systemMessageBox (const char* message
, const char* title
, IDriver::TMessageBoxType type
, TMessageBoxIcon icon
)
2678 H_AUTO_OGL(CDriverGL_systemMessageBox
)
2679 #ifdef NL_OS_WINDOWS
2680 switch (::MessageBoxW(NULL
, nlUtf8ToWide(message
), nlUtf8ToWide(title
), ((type
== retryCancelType
) ? MB_RETRYCANCEL
:
2681 (type
==yesNoCancelType
)?MB_YESNOCANCEL
:
2682 (type
==okCancelType
)?MB_OKCANCEL
:
2683 (type
==abortRetryIgnoreType
)?MB_ABORTRETRYIGNORE
:
2684 (type
==yesNoType
)?MB_YESNO
|MB_ICONQUESTION
:MB_OK
)|
2686 ((icon
==handIcon
)?MB_ICONHAND
:
2687 (icon
==questionIcon
)?MB_ICONQUESTION
:
2688 (icon
==exclamationIcon
)?MB_ICONEXCLAMATION
:
2689 (icon
==asteriskIcon
)?MB_ICONASTERISK
:
2690 (icon
==warningIcon
)?MB_ICONWARNING
:
2691 (icon
==errorIcon
)?MB_ICONERROR
:
2692 (icon
==informationIcon
)?MB_ICONINFORMATION
:
2693 (icon
==stopIcon
)?MB_ICONSTOP
:0)))
2711 #else // NL_OS_WINDOWS
2712 // TODO: if user did not launch from console, then program "freezes" without explanation or possibility to continue
2713 //IDriver::systemMessageBox (message, title, type, icon);
2715 printf("%s:%s\n", title
, message
);
2716 nlwarning("%s: %s", title
, message
);
2717 #endif // NL_OS_WINDOWS
2721 void CDriverGL::getWindowSize(uint32
&width
, uint32
&height
)
2723 H_AUTO_OGL(CDriverGL_getWindowSize
)
2725 if (_CurrentMode
.OffScreen
)
2727 #ifdef NL_OS_WINDOWS
2729 #ifndef USE_OPENGLES
2732 nwglQueryPbufferARB( _PBuffer
, WGL_PBUFFER_WIDTH_ARB
, (int*)&width
);
2733 nwglQueryPbufferARB( _PBuffer
, WGL_PBUFFER_HEIGHT_ARB
, (int*)&height
);
2742 if([containerView() isInFullScreenMode
])
2744 width
= _backBufferWidth
;
2745 height
= _backBufferHeight
;
2749 width
= _CurrentMode
.Width
;
2750 height
= _CurrentMode
.Height
;
2754 void CDriverGL::setWindowSize(uint32 width
, uint32 height
)
2756 H_AUTO_OGL(CDriverGL_setWindowSize
)
2758 if (_win
== EmptyWindow
)
2761 #if defined(NL_OS_WINDOWS)
2763 // resize the window
2765 SetRect (&rc
, 0, 0, width
, height
);
2766 AdjustWindowRectEx(&rc
, GetWindowStyle(_win
), GetMenu(_win
) != NULL
, GetWindowExStyle(_win
));
2767 UINT flags
= SWP_NOZORDER
| SWP_NOACTIVATE
;
2768 // set position to (0, 0) if fullscreen
2769 if (_CurrentMode
.Windowed
)
2770 flags
|= SWP_NOMOVE
;
2771 SetWindowPos(_win
, NULL
, 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, flags
);
2773 // init window width and height
2775 GetClientRect(_win
, &clientRect
);
2776 _CurrentMode
.Width
= uint16(clientRect
.right
-clientRect
.left
);
2777 _CurrentMode
.Height
= uint16(clientRect
.bottom
-clientRect
.top
);
2778 GetWindowRect(_win
, &clientRect
);
2779 _WindowX
= clientRect
.left
;
2780 _WindowY
= clientRect
.top
;
2782 #elif defined(NL_OS_MAC)
2784 // for fullscreen mode, adjust the back buffer size to desired resolution
2785 if([containerView() isInFullScreenMode
])
2787 // disable and re-enable fullscreen
2788 // fixes #1062 (http://dev.ryzom.com/issues/1062)
2789 setWindowStyle(EWSWindowed
);
2790 setWindowStyle(EWSFullscreen
);
2792 // set the back buffer manually to match the desired rendering resolution
2793 GLint dim
[2] = { (GLint
)width
, (GLint
)height
};
2794 CGLError error
= CGLSetParameter(
2795 (CGLContextObj
)[_ctx CGLContextObj
],
2796 kCGLCPSurfaceBackingSize
, dim
);
2798 if(error
!= kCGLNoError
)
2799 nlerror("cannot set kCGLCPSurfaceBackingSize parameter (%s)",
2800 CGLErrorString(error
));
2802 _backBufferHeight
= height
;
2803 _backBufferWidth
= width
;
2807 // only change the window size if the driver created the window itself
2810 // get the windows current frame
2811 NSRect rect
= [[containerView() window
] frame
];
2813 // convert the desired content size to window size
2814 rect
= [[containerView() window
] frameRectForContentRect
:
2815 NSMakeRect(rect
.origin
.x
, rect
.origin
.y
, width
, height
)];
2817 // update window dimensions
2818 [[containerView() window
] setFrame
:rect display
:YES
];
2822 #elif defined(NL_OS_UNIX)
2826 // Update WM hints (disallow resizing)
2827 XSizeHints
*size_hints
= XAllocSizeHints();
2829 size_hints
->flags
= PMinSize
| PMaxSize
;
2830 size_hints
->min_width
= width
;
2831 size_hints
->min_height
= height
;
2832 size_hints
->max_width
= width
;
2833 size_hints
->max_height
= height
;
2835 XSetWMNormalHints(_dpy
, _win
, size_hints
);
2840 // XSetWMNormalHints(_dpy, _win, StdHints);
2843 if (width
!= _CurrentMode
.Width
|| height
!= _CurrentMode
.Height
)
2845 // resize the window
2846 XResizeWindow(_dpy
, _win
, width
, height
);
2848 _CurrentMode
.Width
= width
;
2849 _CurrentMode
.Height
= height
;
2852 #endif // NL_OS_WINDOWS
2855 void CDriverGL::getWindowPos(sint32
&x
, sint32
&y
)
2857 H_AUTO_OGL(CDriverGL_getWindowPos
)
2859 // Off-screen rendering ?
2860 if (_CurrentMode
.OffScreen
)
2871 // --------------------------------------------------
2872 bool CDriverGL::isActive()
2874 H_AUTO_OGL(CDriverGL_isActive
)
2876 if (_win
== EmptyWindow
)
2881 #ifdef NL_OS_WINDOWS
2883 res
= (IsWindow(_win
) != FALSE
);
2885 #elif defined(NL_OS_MAC)
2886 // TODO: Missing Mac Implementation for isActive (always true if a window is set)
2887 #elif defined (NL_OS_UNIX)
2889 // check if our window is still active
2890 XWindowAttributes attr
;
2891 Status status
= XGetWindowAttributes(_dpy
, _win
, &attr
);
2893 res
= (status
== 1);
2895 #endif // NL_OS_UNIX
2900 // ***************************************************************************
2901 bool CDriverGL::setMonitorColorProperties (const CMonitorColorProperties
&properties
)
2903 H_AUTO_OGL(CDriverGL_setMonitorColorProperties
)
2905 #ifdef NL_OS_WINDOWS
2908 HDC dc
= CreateDCA ("DISPLAY", NULL
, NULL
, NULL
);
2914 // For each composant
2916 for( c
=0; c
<3; c
++ )
2919 for( i
=0; i
<256; i
++ )
2922 float value
= (float)i
/ 256;
2925 value
= (float) max (0.0f
, (value
-0.5f
) * (float) pow (3.f
, properties
.Contrast
[c
]) + 0.5f
);
2928 value
= (float) pow (value
, (properties
.Gamma
[c
]>0) ? 1 - 3 * properties
.Gamma
[c
] / 4 : 1 - properties
.Gamma
[c
] );
2931 value
= value
+ properties
.Luminosity
[c
] / 2.f
;
2932 ramp
[i
+(c
<<8)] = (WORD
)min ((int)65535, max (0, (int)(value
* 65535)));
2937 bool result
= SetDeviceGammaRamp (dc
, ramp
) != FALSE
;
2940 ReleaseDC (NULL
, dc
);
2947 nlwarning ("(CDriverGL::setMonitorColorProperties): can't create DC");
2950 #elif defined(NL_OS_MAC)
2951 // TODO for Mac: implement CDriverGL::setMonitorColorProperties
2952 nlwarning ("CDriverGL::setMonitorColorProperties not implemented");
2954 #elif defined (NL_OS_UNIX)
2955 // TODO for Linux: implement CDriverGL::setMonitorColorProperties
2956 nlwarning ("CDriverGL::setMonitorColorProperties not implemented");
2964 void CDriverGL::setupApplicationMenu()
2967 NSMenuItem
* menuItem
;
2971 // get the applications name from it's process info
2972 appName
= [[NSProcessInfo processInfo
] processName
];
2974 // create an empty menu object
2975 menu
= [[NSMenu alloc
] initWithTitle
:@
""];
2977 // add the about menu item
2978 title
= [@
"About " stringByAppendingString
:appName
];
2979 [menu addItemWithTitle
:title
2980 action
:@
selector(orderFrontStandardAboutPanel
:) keyEquivalent
:@
""];
2983 [menu addItem
:[NSMenuItem separatorItem
]];
2985 // add the hide application menu item
2986 title
= [@
"Hide " stringByAppendingString
:appName
];
2987 [menu addItemWithTitle
:title
2988 action
:@
selector(hide
:) keyEquivalent
:@
"h"];
2990 // add the hide others menu item
2991 menuItem
= [menu addItemWithTitle
:@
"Hide Others"
2992 action
:@
selector(hideOtherApplications
:) keyEquivalent
:@
"h"];
2993 [menuItem setKeyEquivalentModifierMask
:(NSAlternateKeyMask
|NSCommandKeyMask
)];
2995 // add the show all menu item
2996 [menu addItemWithTitle
:@
"Show All"
2997 action
:@
selector(unhideAllApplications
:) keyEquivalent
:@
""];
3000 [menu addItem
:[NSMenuItem separatorItem
]];
3003 TODO on quit send EventDestroyWindowId
3005 // add the quit menu item
3006 title
= [@
"Quit " stringByAppendingString
:appName
];
3007 [menu addItemWithTitle
:title
3008 action
:@
selector(terminate
:) keyEquivalent
:@
"q"];
3010 // create an empty menu item and put the new menu into it as a subitem
3011 menuItem
= [[NSMenuItem alloc
] initWithTitle
:@
""
3012 action
:nil keyEquivalent
:@
""];
3013 [menuItem setSubmenu
:menu
];
3015 // create a menu for the application
3016 [NSApp setMainMenu
:[[NSMenu alloc
] initWithTitle
:@
""]];
3018 // attach the new menu to the applications menu
3019 [[NSApp mainMenu
] addItem
:menuItem
];
3023 bool CDriverGL::copyTextToClipboard(const std::string
&text
)
3025 return _EventEmitter
.copyTextToClipboard(text
);
3028 bool CDriverGL::pasteTextFromClipboard(std::string
&text
)
3030 return _EventEmitter
.pasteTextFromClipboard(text
);
3033 #ifdef NL_OS_WINDOWS
3035 bool CDriverGL::convertBitmapToIcon(const NLMISC::CBitmap
&bitmap
, HICON
&icon
, uint iconWidth
, uint iconHeight
, uint iconDepth
, const NLMISC::CRGBA
&col
, sint hotSpotX
, sint hotSpotY
, bool cursor
)
3037 CBitmap src
= bitmap
;
3039 // resample bitmap if necessary
3040 if (src
.getWidth() != iconWidth
|| src
.getHeight() != iconHeight
)
3042 src
.resample(iconWidth
, iconHeight
);
3045 colorBm
.resize(iconWidth
, iconHeight
, CBitmap::RGBA
);
3046 const CRGBA
*srcColorPtr
= (CRGBA
*) &(src
.getPixels()[0]);
3047 const CRGBA
*srcColorPtrLast
= srcColorPtr
+ (iconWidth
* iconHeight
);
3048 CRGBA
*destColorPtr
= (CRGBA
*) &(colorBm
.getPixels()[0]);
3049 static uint8 alphaThreshold
= 127;
3052 destColorPtr
->modulateFromColor(*srcColorPtr
, col
);
3053 std::swap(destColorPtr
->R
, destColorPtr
->B
);
3057 while (srcColorPtr
!= srcColorPtrLast
);
3059 HBITMAP colorHbm
= NULL
;
3060 HBITMAP maskHbm
= NULL
;
3062 if (iconDepth
== 16)
3064 std::vector
<uint16
> colorBm16(iconWidth
* iconHeight
);
3065 const CRGBA
*src32
= (const CRGBA
*) &colorBm
.getPixels(0)[0];
3067 for (uint k
= 0; k
< colorBm16
.size(); ++k
)
3069 colorBm16
[k
] = ((uint16
)(src32
[k
].R
&0xf8)>>3) | ((uint16
)(src32
[k
].G
&0xfc)<<3) | ((uint16
)(src32
[k
].B
& 0xf8)<<8);
3072 colorHbm
= CreateBitmap(iconWidth
, iconHeight
, 1, 16, &colorBm16
[0]);
3073 std::vector
<uint8
> bitMask((iconWidth
* iconHeight
+ 7) / 8, 0);
3075 for (uint k
= 0;k
< colorBm16
.size(); ++k
)
3077 if (src32
[k
].A
<= alphaThreshold
)
3079 bitMask
[k
/ 8] |= (0x80 >> (k
& 7));
3083 maskHbm
= CreateBitmap(iconWidth
, iconHeight
, 1, 1, &bitMask
[0]);
3087 colorHbm
= CreateBitmap(iconWidth
, iconHeight
, 1, 32, &colorBm
.getPixels(0)[0]);
3088 maskHbm
= CreateBitmap(iconWidth
, iconHeight
, 1, 32, &colorBm
.getPixels(0)[0]);
3092 iconInfo
.fIcon
= cursor
? FALSE
:TRUE
;
3093 iconInfo
.xHotspot
= (DWORD
) hotSpotX
;
3094 iconInfo
.yHotspot
= (DWORD
) hotSpotY
;
3095 iconInfo
.hbmMask
= maskHbm
;
3096 iconInfo
.hbmColor
= colorHbm
;
3098 if (colorHbm
&& maskHbm
)
3100 icon
= CreateIconIndirect(&iconInfo
);
3104 if (colorHbm
) DeleteObject(colorHbm
);
3105 if (maskHbm
) DeleteObject(maskHbm
);
3110 #elif defined(NL_OS_MAC)
3112 #elif defined(NL_OS_UNIX)
3114 bool CDriverGL::convertBitmapToIcon(const NLMISC::CBitmap
&bitmap
, std::vector
<long> &icon
)
3116 // get bitmap width and height
3117 uint width
= bitmap
.getWidth();
3118 uint height
= bitmap
.getHeight();
3120 // icon position for bitmap
3121 uint pos
= (uint
)icon
.size();
3123 // extend icon_data size for bitmap
3124 icon
.resize(pos
+ 2 + width
*height
);
3126 // set bitmap width and height
3127 icon
[pos
++] = width
;
3128 icon
[pos
++] = height
;
3130 // convert RGBA to ARGB
3131 CObjectVector
<uint8
> pixels
= bitmap
.getPixels();
3132 for(uint j
= 0; j
< pixels
.size(); j
+=4)
3133 icon
[pos
++] = pixels
[j
] << 16 | pixels
[j
+1] << 8 | pixels
[j
+2] | pixels
[j
+3] << 24;