1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010-2020 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);
653 _WindowVisible
= false;
654 _Resizable
= resizeable
;
655 _DestroyWindow
= false;
668 // Retrieve the WGL extensions before init the driver.
671 if (_CurrentMode
.OffScreen
)
673 if (!createWindow(mode
)) return false;
676 int width
= mode
.Width
;
677 int height
= mode
.Height
;
680 // TODO: implement for OpenGL ES 1.x
684 SetRect (&rc
, 0, 0, width
, height
);
685 AdjustWindowRectEx (&rc
, GetWindowStyle (_win
), GetMenu (_win
) != NULL
, GetWindowExStyle (_win
));
686 SetWindowPos (_win
, NULL
, 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
689 HDC tempHDC
= GetDC(tmpHWND
);
691 _CurrentMode
.Depth
= uint8(GetDeviceCaps(tempHDC
,BITSPIXEL
));
694 memset(&_pfd
,0,sizeof(_pfd
));
695 _pfd
.nSize
= sizeof(_pfd
);
697 _pfd
.dwFlags
= PFD_DRAW_TO_WINDOW
| PFD_SUPPORT_OPENGL
| PFD_DOUBLEBUFFER
;
698 _pfd
.iPixelType
= PFD_TYPE_RGBA
;
699 _pfd
.cColorBits
= _CurrentMode
.Depth
;
701 // Choose best suited Depth Buffer.
702 if(_CurrentMode
.Depth
<=16)
704 _pfd
.cDepthBits
= 16;
708 _pfd
.cDepthBits
= 24;
711 _pfd
.iLayerType
= PFD_MAIN_PLANE
;
712 int pf
=ChoosePixelFormat(tempHDC
,&_pfd
);
715 nlwarning ("CDriverGL::setDisplay: ChoosePixelFormat failed");
716 DestroyWindow (tmpHWND
);
719 if ( !SetPixelFormat(tempHDC
,pf
,&_pfd
) )
721 nlwarning ("CDriverGL::setDisplay: SetPixelFormat failed");
722 DestroyWindow (tmpHWND
);
727 HGLRC tempGLRC
= wglCreateContext(tempHDC
);
728 if (tempGLRC
== NULL
)
730 DWORD error
= GetLastError ();
731 nlwarning ("CDriverGL::setDisplay: wglCreateContext failed: 0x%x", error
);
732 DestroyWindow (tmpHWND
);
740 // Make the context current
741 if (!wglMakeCurrent(tempHDC
,tempGLRC
))
743 DWORD error
= GetLastError ();
744 nlwarning ("CDriverGL::setDisplay: wglMakeCurrent failed: 0x%x", error
);
745 wglDeleteContext (tempGLRC
);
746 DestroyWindow (tmpHWND
);
754 // Register WGL functions
756 registerEGlExtensions (_Extensions
, tempHDC
);
758 registerWGlExtensions (_Extensions
, tempHDC
);
761 HDC hdc
= wglGetCurrentDC ();
765 DWORD error
= GetLastError ();
766 nlwarning ("CDriverGL::setDisplay: wglGetCurrentDC failed: 0x%x", error
);
767 DestroyWindow (tmpHWND
);
775 // Get ready to query for a suitable pixel format that meets our
776 // minimum requirements.
777 int iattributes
[2*20];
778 float fattributes
[2*20];
781 // Attribute arrays must be "0" terminated - for simplicity, first
782 // just zero-out the array then fill from left to right.
783 for ( int a
= 0; a
< 2*20; a
++ )
789 // Since we are trying to create a pbuffer, the pixel format we
790 // request (and subsequently use) must be "buffer capable".
791 iattributes
[2*niattribs
] = WGL_DRAW_TO_PBUFFER_ARB
;
792 iattributes
[2*niattribs
+1] = true;
795 // We require a minimum of 24-bit depth.
796 iattributes
[2*niattribs
] = WGL_DEPTH_BITS_ARB
;
797 iattributes
[2*niattribs
+1] = 24;
800 // We require a minimum of 8-bits for each R, G, B, and A.
801 iattributes
[2*niattribs
] = WGL_RED_BITS_ARB
;
802 iattributes
[2*niattribs
+1] = 8;
804 iattributes
[2*niattribs
] = WGL_GREEN_BITS_ARB
;
805 iattributes
[2*niattribs
+1] = 8;
807 iattributes
[2*niattribs
] = WGL_BLUE_BITS_ARB
;
808 iattributes
[2*niattribs
+1] = 8;
810 iattributes
[2*niattribs
] = WGL_ALPHA_BITS_ARB
;
811 iattributes
[2*niattribs
+1] = 8;
814 // Now obtain a list of pixel formats that meet these minimum
817 unsigned int nformats
;
818 if ( !nwglChoosePixelFormatARB ( hdc
, iattributes
, fattributes
,
819 20, pformat
, &nformats
) )
821 nlwarning ( "pbuffer creation error: Couldn't find a suitable pixel format." );
822 wglDeleteContext (tempGLRC
);
823 DestroyWindow (tmpHWND
);
827 /* After determining a compatible pixel format, the next step is to create a pbuffer of the
828 chosen format. Fortunately this step is fairly easy, as you merely select one of the formats
829 returned in the list in step #2 and call the function: */
830 int iattributes2
[1] = {0};
831 // int iattributes2[] = {WGL_PBUFFER_LARGEST_ARB, 1, 0};
832 _PBuffer
= nwglCreatePbufferARB( hdc
, pformat
[0], width
, height
, iattributes2
);
833 if (_PBuffer
== NULL
)
835 DWORD error
= GetLastError ();
836 nlwarning ("CDriverGL::setDisplay: wglCreatePbufferARB failed: 0x%x", error
);
837 wglDeleteContext (tempGLRC
);
839 DestroyWindow (tmpHWND
);
847 /* After creating a pbuffer, you may use this functions to determine the dimensions of the pbuffer actually created. */
848 if ( !nwglQueryPbufferARB( _PBuffer
, WGL_PBUFFER_WIDTH_ARB
, (int*)&width
) )
850 DWORD error
= GetLastError ();
851 nlwarning ("CDriverGL::setDisplay: wglQueryPbufferARB failed: 0x%x", error
);
852 wglDeleteContext (tempGLRC
);
853 DestroyWindow (tmpHWND
);
861 if ( !nwglQueryPbufferARB( _PBuffer
, WGL_PBUFFER_HEIGHT_ARB
, (int*)&height
) )
863 DWORD error
= GetLastError ();
864 nlwarning ("CDriverGL::setDisplay: wglQueryPbufferARB failed: 0x%x", error
);
865 wglDeleteContext (tempGLRC
);
866 DestroyWindow (tmpHWND
);
874 _CurrentMode
.Width
= width
;
875 _CurrentMode
.Height
= height
;
877 /* The next step is to create a device context for the newly created pbuffer. To do this,
878 call to the function: */
879 _hDC
= nwglGetPbufferDCARB( _PBuffer
);
882 DWORD error
= GetLastError ();
883 nlwarning ("CDriverGL::setDisplay: wglGetPbufferDCARB failed: 0x%x", error
);
884 nwglDestroyPbufferARB( _PBuffer
);
886 wglDeleteContext (tempGLRC
);
888 DestroyWindow (tmpHWND
);
896 /* The final step of pbuffer creation is to create an OpenGL rendering context and
897 associate it with the handle for the pbuffer's device context created in step #4. This is done as follows */
898 _hRC
= wglCreateContext( _hDC
);
901 DWORD error
= GetLastError ();
902 nlwarning ("CDriverGL::setDisplay: wglCreateContext failed: 0x%x", error
);
903 nwglReleasePbufferDCARB( _PBuffer
, _hDC
);
904 nwglDestroyPbufferARB( _PBuffer
);
905 wglDeleteContext (tempGLRC
);
906 DestroyWindow (tmpHWND
);
915 _CurrentMode
.Depth
= uint8(GetDeviceCaps (_hDC
, BITSPIXEL
));
917 // Destroy the temp gl context
919 if (!eglDestroyContext(_EglDisplay
, _EglContext
);)
921 DWORD error
= GetLastError ();
922 nlwarning ("CDriverGL::setDisplay: wglDeleteContext failed: 0x%x", error
);
925 if (!wglDeleteContext (tempGLRC
))
927 DWORD error
= GetLastError ();
928 nlwarning ("CDriverGL::setDisplay: wglDeleteContext failed: 0x%x", error
);
932 // Destroy the temp windows
933 if (!DestroyWindow (tmpHWND
))
934 nlwarning ("CDriverGL::setDisplay: DestroyWindow failed");
936 /* After a pbuffer has been successfully created you can use it for off-screen rendering. To do
937 so, you'll first need to bind the pbuffer, or more precisely, make its GL rendering context
938 the current context that will interpret all OpenGL commands and state changes. */
939 if (!wglMakeCurrent(_hDC
,_hRC
))
941 DWORD error
= GetLastError ();
942 nlwarning ("CDriverGL::setDisplay: wglMakeCurrent failed: 0x%x", error
);
945 eglDestroyContext(_EglDisplay
, _EglContext
);
947 wglDeleteContext (_hRC
);
948 nwglReleasePbufferDCARB( _PBuffer
, _hDC
);
949 nwglDestroyPbufferARB( _PBuffer
);
952 DestroyWindow (tmpHWND
);
963 if (wnd
== EmptyWindow
)
965 if (!createWindow(mode
))
973 // associate OpenGL driver to window
974 SetWindowLongPtr(_win
, GWLP_USERDATA
, (LONG_PTR
)this);
979 /// release old emitter
980 while (_EventEmitter
.getNumEmitters() != 0)
982 _EventEmitter
.removeEmitter(_EventEmitter
.getEmitter(_EventEmitter
.getNumEmitters() - 1));
985 NLMISC::CWinEventEmitter
*we
= new NLMISC::CWinEventEmitter
;
987 // setup the event emitter, and try to retrieve a direct input interface
988 _EventEmitter
.addEmitter(we
, true /*must delete*/); // the main emitter
990 #elif defined(NL_OS_MAC)
992 if (wnd
== EmptyWindow
)
994 if (!createWindow(mode
))
1001 /* The NSView* extracted from a QWidget using winId() has bounds set to
1002 * (QWidget::x(), QWidget::y(), QWidget::width(), QWidget::height()).
1003 * This causes cocoa to draw at an offset of x(), y() leaving an unhandled
1004 * border in the NSView. The code below fixes this by translating the
1005 * coordinate system of the NSView back to 0,0.
1006 * In my opinion this is an error in Qt since QWidget::x/y() are relative to
1007 * parent and [NSView bounds.origin] is relative to it's own coordinate
1008 * system. This are incompatible notations. Qt should handle the conversion.
1009 * Fixes: #1013 Viewport size when embedding NeL Cocoa view in Qt
1010 * (http://dev.ryzom.com/issues/1013)
1012 NSView
* view
= (NSView
*)wnd
;
1013 if(view
.frame
.origin
.x
!= 0 || view
.frame
.origin
.y
!= 0) {
1014 [view setBoundsOrigin
:view
.frame
.origin
];
1018 // setup opengl settings
1019 NSOpenGLPixelFormatAttribute att
[] =
1021 NSOpenGLPFADoubleBuffer
,
1022 NSOpenGLPFAColorSize
, 24,
1023 NSOpenGLPFADepthSize
, 24,
1024 NSOpenGLPFAAlphaSize
, 8,
1025 NSOpenGLPFAStencilSize
, 8,
1026 NSOpenGLPFANoRecovery
,
1027 NSOpenGLPFAAccelerated
,
1028 NSOpenGLPFABackingStore
,
1032 // put the settings into a format object
1033 NSOpenGLPixelFormat
* format
=
1034 [[NSOpenGLPixelFormat alloc
] initWithAttributes
:att
];
1037 nlerror("cannot create NSOpenGLPixelFormat");
1039 // intially set height/width, further updates through CocoaOpenGLView
1040 _CurrentMode
.Height
= mode
.Height
;
1041 _CurrentMode
.Width
= mode
.Width
;
1043 // create a opengl view with the created format
1044 _glView
= [[CocoaOpenGLView alloc
]
1045 initWithFrame
:NSMakeRect(0, 0, mode
.Width
, mode
.Height
)
1046 pixelFormat
:format
];
1049 nlerror("cannot create view");
1051 // tell the view about the driver so the view is able to update "window" size
1052 [_glView setDriver
:this];
1054 // make the view automatically fit the super view
1055 [_glView setAutoresizingMask
: NSViewHeightSizable
| NSViewWidthSizable
];
1057 // put the open gl view into the dummy view contained in the window
1058 [containerView() addSubview
:_glView
];
1061 [_glView setFrame
: [containerView() frame
]];
1063 // create a opengl context for the view
1064 _ctx
= [_glView openGLContext
];
1067 nlerror("cannot create context");
1069 // free the pixel format object
1072 // let the open gl view handle the input
1073 [[containerView() window
] makeFirstResponder
:_glView
];
1075 // prevents scrambled content in the view before first swap
1079 // Set context as thread context
1080 CGLSetCurrentContext((CGLContextObj
)[_ctx CGLContextObj
]);
1082 _EventEmitter
.init(this, _glView
, _DestroyWindow
);
1084 #elif defined(NL_OS_UNIX)
1086 static int sAttribList16bpp
[] =
1095 GLX_STENCIL_SIZE
, 8,
1099 static int sAttribList24bpp
[] =
1108 GLX_STENCIL_SIZE
, 8,
1112 // first try 24bpp and if that fails 16bpp
1113 XVisualInfo
*visual_info
= glXChooseVisual (_dpy
, DefaultScreen(_dpy
), sAttribList24bpp
);
1114 if (visual_info
== NULL
)
1115 visual_info
= glXChooseVisual(_dpy
, DefaultScreen(_dpy
), sAttribList16bpp
);
1116 if(visual_info
== NULL
)
1118 nlerror("glXChooseVisual() failed");
1121 _visual_info
= visual_info
;
1123 _ctx
= glXCreateContext (_dpy
, visual_info
, None
, GL_TRUE
);
1126 nlerror("glXCreateContext() failed");
1129 if (wnd
== EmptyWindow
)
1131 if (!createWindow(mode
))
1138 XSetWindowAttributes attr
;
1139 attr
.background_pixel
= BlackPixel(_dpy
, DefaultScreen(_dpy
));
1140 attr
.override_redirect
= False
;
1142 int attr_flags
= CWOverrideRedirect
| CWBackPixel
;
1144 XChangeWindowAttributes(_dpy
, _win
, attr_flags
, &attr
);
1147 glXMakeCurrent (_dpy
, _win
, _ctx
);
1148 // XMapRaised (_dpy, _win);
1150 // XMapWindow(_dpy, _win);
1152 _EventEmitter
.init (_dpy
, _win
, this);
1155 // XIfEvent(dpy, &event, WaitForNotify, (char *)this);
1157 #endif // NL_OS_UNIX
1159 // setup OpenGL structures
1160 if (!setupDisplay())
1163 // setup window size and screen mode
1167 if (show
|| !_CurrentMode
.Windowed
)
1173 // --------------------------------------------------
1174 bool CDriverGL::saveScreenMode()
1176 H_AUTO_OGL(CDriverGL_saveScreenMode
)
1180 #if defined(NL_OS_WINDOWS)
1182 // don't need to save it because Windows will use default desktop resolution
1184 #elif defined(NL_OS_MAC)
1186 // no need to store because the screen mode is never really changed
1188 #elif defined(NL_OS_UNIX)
1190 int screen
= DefaultScreen(_dpy
);
1195 // TODO: if using mode switching, save current xrandr mode to _OldSizeID
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 // TODO: if using mode switching, then restore mode from _OldSizeID
1259 if (!res
&& _xrandr_version
> 0)
1261 Window root
= RootWindow(_dpy
, screen
);
1263 XRRScreenConfiguration
*screen_config
= XRRGetScreenInfo(_dpy
, root
);
1267 Rotation saved_rotation
;
1268 SizeID size
= XRRConfigCurrentConfiguration(screen_config
, &saved_rotation
);
1269 if (XRRSetScreenConfig(_dpy
, screen_config
, root
, _OldSizeID
, saved_rotation
, CurrentTime
) == RRSetConfigSuccess
)
1271 nlinfo("3D: Switching back to XRandR mode %d", _OldSizeID
);
1275 XRRFreeScreenConfigInfo(screen_config
);
1279 nlwarning("3D: XRRGetScreenInfo failed");
1283 #endif // HAVE_XRANDR
1285 #if defined(XF86VIDMODE)
1287 if (!res
&& _xvidmode_version
> 0)
1289 XF86VidModeModeInfo info
;
1290 nlinfo("3D: Switching back to original mode");
1293 info
.dotclock
= _OldDotClock
;
1294 info
.hdisplay
= _OldScreenMode
.hdisplay
;
1295 info
.hsyncstart
= _OldScreenMode
.hsyncstart
;
1296 info
.hsyncend
= _OldScreenMode
.hsyncend
;
1297 info
.htotal
= _OldScreenMode
.htotal
;
1298 info
.vdisplay
= _OldScreenMode
.vdisplay
;
1299 info
.vsyncstart
= _OldScreenMode
.vsyncstart
;
1300 info
.vsyncend
= _OldScreenMode
.vsyncend
;
1301 info
.vtotal
= _OldScreenMode
.vtotal
;
1302 info
.flags
= _OldScreenMode
.flags
;
1303 info
.privsize
= _OldScreenMode
.privsize
;
1304 info
.c_private
= _OldScreenMode
.c_private
;
1306 nlinfo("3D: Switching back mode to %dx%d", info
.hdisplay
, info
.vdisplay
);
1307 XF86VidModeSwitchToMode(_dpy
, screen
, &info
);
1308 nlinfo("3D: Switching back viewport to %d,%d",_OldX
, _OldY
);
1309 res
= XF86VidModeSetViewPort(_dpy
, screen
, _OldX
, _OldY
);
1312 #endif // XF86VIDMODE
1314 #endif // NL_OS_WINDOWS
1319 // ***************************************************************************
1322 static sint
modeInfoToFrequency(XF86VidModeModeInfo
*info
)
1324 return (info
->htotal
&& info
->vtotal
) ? (1000 * info
->dotclock
/ (info
->htotal
* info
->vtotal
)) : 0;
1326 #endif // XF86VIDMODE
1328 // ***************************************************************************
1330 bool CDriverGL::setScreenMode(const GfxMode
&mode
)
1332 H_AUTO_OGL(CDriverGL_setScreenMode
)
1336 // if fullscreen, switch back to desktop screen mode
1337 if (!_CurrentMode
.Windowed
)
1338 restoreScreenMode();
1343 // save previous screen mode only if switching from windowed to fullscreen
1344 if (_CurrentMode
.Windowed
)
1347 // if switching exactly to the same screen mode, doesn't change it
1348 GfxMode previousMode
;
1349 if (getCurrentScreenMode(previousMode
)
1350 && mode
.Width
== previousMode
.Width
1351 && mode
.Height
== previousMode
.Height
1352 && mode
.Depth
== previousMode
.Depth
1353 && mode
.Frequency
== previousMode
.Frequency
1354 && mode
.DisplayDevice
== previousMode
.DisplayDevice
)
1357 #if defined(NL_OS_WINDOWS)
1360 memset(&devMode
, 0, sizeof(DEVMODE
));
1361 devMode
.dmSize
= sizeof(DEVMODE
);
1362 devMode
.dmDriverExtra
= 0;
1363 devMode
.dmFields
= DM_PELSWIDTH
| DM_PELSHEIGHT
;
1364 devMode
.dmPelsWidth
= mode
.Width
;
1365 devMode
.dmPelsHeight
= mode
.Height
;
1369 devMode
.dmBitsPerPel
= mode
.Depth
;
1370 devMode
.dmFields
|= DM_BITSPERPEL
;
1373 if(mode
.Frequency
> 0)
1375 devMode
.dmDisplayFrequency
= mode
.Frequency
;
1376 devMode
.dmFields
|= DM_DISPLAYFREQUENCY
;
1379 if (ChangeDisplaySettings(&devMode
, CDS_FULLSCREEN
) != DISP_CHANGE_SUCCESSFUL
)
1381 nlwarning("3D: Fullscreen mode switch failed");
1385 #elif defined(NL_OS_MAC)
1387 // no need to do anything here, on mac os, the screen mode is never changed
1389 #elif defined(NL_OS_UNIX)
1394 // TODO: implement mode switching using xrandr crts
1397 if (!found
&& _xrandr_version
> 0)
1399 int screen
= DefaultScreen(_dpy
);
1400 Window root
= RootWindow(_dpy
, screen
);
1402 XRRScreenConfiguration
*screen_config
= XRRGetScreenInfo(_dpy
, root
);
1406 Rotation saved_rotation
;
1407 SizeID cur_size
= XRRConfigCurrentConfiguration(screen_config
, &saved_rotation
);
1410 XRRScreenSize
*sizes
= XRRConfigSizes(screen_config
, &nsizes
);
1413 for (sint i
= 0; i
< nsizes
; ++i
)
1415 if (sizes
[i
].width
== mode
.Width
&& sizes
[i
].height
== mode
.Height
)
1424 if (XRRSetScreenConfig(_dpy
, screen_config
, root
, size
, saved_rotation
, CurrentTime
) == RRSetConfigSuccess
)
1426 nlinfo("3D: Switching to XRandR mode %d: %dx%d", size
, sizes
[size
].width
, sizes
[size
].height
);
1431 nlwarning("3D: XRRSetScreenConfig failed for mode %d: %dx%d", size
, sizes
[size
].width
, sizes
[size
].height
);
1436 nlwarning("3D: No corresponding screen mode");
1439 XRRFreeScreenConfigInfo(screen_config
);
1443 nlwarning("3D: XRRGetScreenInfo failed");
1447 #endif // HAVE_XRANDR
1449 #if defined(XF86VIDMODE)
1451 if (!found
&& _xvidmode_version
> 0)
1453 // Find the requested mode and use it
1454 XF86VidModeModeInfo
**modes
;
1456 if (XF86VidModeGetAllModeLines(_dpy
, DefaultScreen(_dpy
), &nmodes
, &modes
))
1458 for (int i
= 0; i
< nmodes
; i
++)
1460 const uint16 freq
= modeInfoToFrequency(modes
[i
]);
1462 nldebug("3D: Available mode - %dx%d %d Hz", modes
[i
]->hdisplay
, modes
[i
]->vdisplay
, (int)freq
);
1463 if (modes
[i
]->hdisplay
== mode
.Width
&& modes
[i
]->vdisplay
== mode
.Height
/* && freq == mode.Frequency */)
1465 if (XF86VidModeSwitchToMode(_dpy
, DefaultScreen(_dpy
), modes
[i
]))
1467 nlinfo("3D: XF86VidMode Switching to mode %dx%d", modes
[i
]->hdisplay
, modes
[i
]->vdisplay
);
1468 XF86VidModeSetViewPort(_dpy
, DefaultScreen(_dpy
), 0, 0);
1478 #endif // XF86VIDMODE
1483 #endif // NL_OS_WINDOWS
1488 // ***************************************************************************
1489 bool CDriverGL::createWindow(const GfxMode
&mode
)
1491 H_AUTO_OGL(CDriverGL_createWindow
)
1493 nlWindow window
= EmptyWindow
;
1495 #ifdef NL_OS_WINDOWS
1497 // create the OpenGL window
1498 DWORD dwStyle
= WS_OVERLAPPEDWINDOW
|WS_CLIPCHILDREN
|WS_CLIPSIBLINGS
;
1499 int pos
= CW_USEDEFAULT
;
1500 HWND hwndParent
= HWND_DESKTOP
;
1503 dwStyle
&= ~WS_VISIBLE
;
1507 window
= CreateWindowW(L
"NLClass", L
"NeL Window", dwStyle
,
1508 pos
, pos
, mode
.Width
, mode
.Height
, hwndParent
, NULL
, GetModuleHandle(NULL
), NULL
);
1510 if (window
== EmptyWindow
)
1512 DWORD res
= GetLastError();
1513 nlwarning("CreateWindow failed: %u", res
);
1517 #elif defined(NL_OS_MAC)
1519 // create the menu in the top screen bar
1520 setupApplicationMenu();
1522 // finish the application launching
1523 [NSApp finishLaunching
];
1525 // describe how the window should look like and behave
1526 unsigned int styleMask
= NSTitledWindowMask
| NSClosableWindowMask
|
1527 NSMiniaturizableWindowMask
| NSResizableWindowMask
;
1529 // create a cocoa window with the size provided by the mode parameter
1530 NSWindow
* cocoa_window
= [[NSWindow alloc
]
1531 initWithContentRect
:NSMakeRect(0, 0, mode
.Width
, mode
.Height
)
1532 styleMask
:styleMask backing
:NSBackingStoreBuffered defer
:NO
];
1536 nlerror("cannot create cocoa window");
1540 // create an application delegate
1541 CocoaApplicationDelegate
* appDelegate
=
1542 [[CocoaApplicationDelegate alloc
] initWithDriver
:this];
1544 // set the application delegate, this will handle window/app close events
1545 [NSApp setDelegate
:(id
<NSApplicationDelegate
>)appDelegate
];
1547 // bind the close button of the window to applicationShouldTerminate
1548 id closeButton
= [cocoa_window standardWindowButton
:NSWindowCloseButton
];
1549 [closeButton setAction
:@
selector(applicationShouldTerminate
:)];
1550 [closeButton setTarget
:appDelegate
];
1552 // set the delegate which will handle window move events
1553 [cocoa_window setDelegate
:[[CocoaWindowDelegate alloc
] initWithDriver
:this]];
1555 // set the window to non transparent
1556 [cocoa_window setOpaque
:YES
];
1558 // enable mouse move events, NeL wants them
1559 [cocoa_window setAcceptsMouseMovedEvents
:YES
];
1561 // there are no overlapping subviews, can use the magical optimization :)
1562 [cocoa_window useOptimizedDrawing
:YES
];
1564 // put the window to the front and make it the key window
1565 [cocoa_window makeKeyAndOrderFront
:nil
];
1567 // this is our main window
1568 [cocoa_window makeMainWindow
];
1570 // create a dummy view which works like the window on other platforms
1571 // the open gl view will be created as subview of this one.
1572 window
= [[NSView alloc
]
1573 initWithFrame
:NSMakeRect(0, 0, mode
.Width
, mode
.Height
)];
1575 [cocoa_window setContentView
: (NSView
*)window
];
1577 if(window
== EmptyWindow
)
1579 nldebug("cannot create cocoa view for cocoa window");
1583 #elif defined (NL_OS_UNIX)
1585 if (_visual_info
== NULL
)
1588 nlWindow root
= RootWindow(_dpy
, DefaultScreen(_dpy
));
1590 XSetWindowAttributes attr
;
1591 attr
.background_pixel
= BlackPixel(_dpy
, DefaultScreen(_dpy
));
1592 attr
.colormap
= XCreateColormap(_dpy
, root
, _visual_info
->visual
, AllocNone
);
1593 int attr_flags
= CWBackPixel
| CWColormap
;
1595 window
= XCreateWindow (_dpy
, root
, 0, 0, mode
.Width
, mode
.Height
, 0, _visual_info
->depth
, InputOutput
, _visual_info
->visual
, attr_flags
, &attr
);
1597 if (window
== EmptyWindow
)
1599 nlerror("3D: XCreateWindow() failed");
1603 // normal window type
1604 XChangeProperty(_dpy
, window
, XA_WM_WINDOW_TYPE
, XA_ATOM
, 32, PropModeReplace
, (const unsigned char*)&XA_WM_WINDOW_TYPE_NORMAL
, 1);
1607 XWMHints
*wm_hints
= XAllocWMHints();
1611 wm_hints
->flags
= StateHint
| InputHint
;
1612 wm_hints
->initial_state
= NormalState
;
1613 wm_hints
->input
= True
;
1615 XSetWMHints(_dpy
, window
, wm_hints
);
1620 nlwarning("3D: Couldn't allocate XWMHints");
1624 XClassHint
*class_hints
= XAllocClassHint();
1628 class_hints
->res_name
= (char*)"NeL";
1629 class_hints
->res_class
= (char*)"nel";
1631 XSetClassHint(_dpy
, window
, class_hints
);
1636 nlwarning("3D: Couldn't allocate XClassHint");
1639 #endif // NL_OS_UNIX
1643 _CurrentMode
.Width
= mode
.Width
;
1644 _CurrentMode
.Height
= mode
.Height
;
1646 // Must destroy this window
1647 _DestroyWindow
= true;
1649 setWindowTitle(ucstring("NeL window"));
1656 // ***************************************************************************
1658 bool CDriverGL::destroyWindow()
1660 H_AUTO_OGL(CDriverGL_destroyWindow
)
1664 // make sure window icons are deleted
1665 std::vector
<NLMISC::CBitmap
> bitmaps
;
1666 setWindowIcon(bitmaps
);
1670 if (_EglDisplay
&& _EglContext
)
1672 eglMakeCurrent(_EglDisplay
, _EglSurface
, _EglSurface
, _EglContext
);
1676 eglDestroyContext(_EglDisplay
, _EglContext
);
1680 #elif defined(NL_OS_WINDOWS)
1683 // wglMakeCurrent(NULL,NULL);
1686 wglMakeCurrent(_hDC
, NULL
);
1690 wglDeleteContext(_hRC
);
1696 ReleaseDC(_win
, _hDC
);
1700 #elif defined(NL_OS_MAC)
1702 #elif defined(NL_OS_UNIX)
1704 if (_DestroyWindow
&& _ctx
) // FIXME: _DestroyWindow may need to be removed here as well
1705 glXDestroyContext(_dpy
, _ctx
);
1711 #ifdef NL_OS_WINDOWS
1713 // don't destroy window if it hasn't been created by our driver
1714 if (_win
&& _DestroyWindow
)
1715 DestroyWindow(_win
);
1717 #elif defined(NL_OS_MAC)
1721 [[containerView() window
] release
];
1722 [containerView() release
];
1728 #elif defined (NL_OS_UNIX)
1730 _EventEmitter
.closeIM();
1732 if (_DestroyWindow
&& _win
)
1733 XDestroyWindow(_dpy
, _win
);
1735 // Ungrab the keyboard (probably not necessary);
1736 // XUnmapWindow(_dpy, _win);
1738 XUngrabKeyboard(_dpy
, CurrentTime
);
1747 // ***************************************************************************
1749 CDriverGL::EWindowStyle
CDriverGL::getWindowStyle() const
1751 H_AUTO_OGL(CDriverGL_getWindowStyle
)
1753 if (!_CurrentMode
.Windowed
)
1754 return EWSFullscreen
;
1759 // ***************************************************************************
1761 bool CDriverGL::setWindowStyle(EWindowStyle windowStyle
)
1763 H_AUTO_OGL(CDriverGL_setWindowStyle
)
1765 // don't change window style, if we did not create the window
1766 if (_win
== EmptyWindow
|| !_DestroyWindow
)
1769 if (getWindowStyle() == windowStyle
)
1772 #if defined(NL_OS_WINDOWS)
1774 // get current style
1775 LONG dwStyle
= GetWindowLong(_win
, GWL_STYLE
);
1777 // prepare new style
1778 LONG dwNewStyle
= WS_CLIPCHILDREN
|WS_CLIPSIBLINGS
;
1780 // get window current state
1781 WINDOWPLACEMENT wndpl
;
1782 wndpl
.length
= sizeof(WINDOWPLACEMENT
);
1784 bool isMaximized
= GetWindowPlacement(_win
, &wndpl
) && (wndpl
.showCmd
== SW_SHOWMAXIMIZED
);
1785 bool isVisible
= false;
1787 if (windowStyle
== EWSWindowed
&& !_CurrentMode
.OffScreen
)
1789 dwNewStyle
|= WS_OVERLAPPEDWINDOW
;
1791 // if we can't resize window, remove maximize box and resize anchors
1792 if (!_Resizable
) dwNewStyle
^= WS_MAXIMIZEBOX
|WS_THICKFRAME
;
1794 isVisible
= (dwStyle
& WS_VISIBLE
) != 0;
1796 else if (windowStyle
== EWSFullscreen
)
1799 dwNewStyle
|= WS_POPUP
;
1805 dwNewStyle
|= WS_VISIBLE
;
1807 if (dwStyle
!= dwNewStyle
)
1808 SetWindowLong(_win
, GWL_STYLE
, dwNewStyle
);
1810 // if (windowStyle == EWSMaximized && isVisible && !isMaximized)
1811 // ShowWindow(_hWnd, SW_SHOWMAXIMIZED);
1812 // else if (isMaximized && isVisible)
1813 // ShowWindow(_hWnd, SW_RESTORE);
1815 #elif defined(NL_OS_MAC)
1817 // leave fullscreen mode, enter windowed mode
1818 if (windowStyle
== EWSWindowed
&& [containerView() isInFullScreenMode
])
1820 // disable manual setting of back buffer size, cocoa handles this
1821 // automatically as soon as the view gets resized
1822 CGLError error
= CGLDisable((CGLContextObj
)[_ctx CGLContextObj
],
1823 kCGLCESurfaceBackingSize
);
1825 if (error
!= kCGLNoError
)
1826 nlerror("cannot disable kCGLCESurfaceBackingSize (%s)",
1827 CGLErrorString(error
));
1829 // pull the view back from fullscreen restoring window options
1830 [containerView() exitFullScreenModeWithOptions
:nil
];
1832 // let the gl view receive key events
1833 [[containerView() window
] makeFirstResponder
:_glView
];
1835 // bring the window containing the gl view to the front
1836 [[containerView() window
] makeKeyAndOrderFront
:nil
];
1839 // enter fullscreen, leave windowed mode
1840 else if (windowStyle
== EWSFullscreen
&& ![containerView() isInFullScreenMode
])
1842 // enable manual back buffer size for mode setting in fullscreen
1843 CGLError error
= CGLEnable((CGLContextObj
)[_ctx CGLContextObj
],
1844 kCGLCESurfaceBackingSize
);
1846 if (error
!= kCGLNoError
)
1847 nlerror("cannot enable kCGLCESurfaceBackingSize (%s)",
1848 CGLErrorString(error
));
1850 // put the view in fullscreen mode, hiding the dock but enabling the menubar
1851 // to pop up if the mouse hits the top screen border.
1852 // NOTE: withOptions:nil disables <CMD>+<Tab> application switching!
1853 #ifdef NL_MAC_VERSION_10_6_UP
1854 [containerView() enterFullScreenMode
:[NSScreen mainScreen
] withOptions
:
1855 [NSDictionary dictionaryWithObjectsAndKeys
:
1856 [NSNumber numberWithInt
:
1857 NSApplicationPresentationHideDock
|
1858 NSApplicationPresentationAutoHideMenuBar
],
1859 NSFullScreenModeApplicationPresentationOptions
, nil
]];
1862 TODO check if simply using NSView enterFullScreenMode is a good idea.
1863 the context can be set to full screen as well, performance differences?
1866 // let the gl view receive key events
1867 [[containerView() window
] makeFirstResponder
:_glView
];
1870 #elif defined(NL_OS_UNIX)
1872 XWindowAttributes attr
;
1873 XGetWindowAttributes(_dpy
, _win
, &attr
);
1875 // if window is mapped use events else properties
1876 if (attr
.map_state
!= IsUnmapped
)
1878 // Toggle fullscreen
1880 xev
.xclient
.type
= ClientMessage
;
1881 xev
.xclient
.serial
= 0;
1882 xev
.xclient
.send_event
= True
;
1883 xev
.xclient
.display
= _dpy
;
1884 xev
.xclient
.window
= _win
;
1885 xev
.xclient
.message_type
= XA_WM_STATE
;
1886 xev
.xclient
.format
= 32;
1887 xev
.xclient
.data
.l
[0] = windowStyle
== EWSFullscreen
? _NET_WM_STATE_ADD
:_NET_WM_STATE_REMOVE
;
1888 xev
.xclient
.data
.l
[1] = XA_WM_STATE_FULLSCREEN
;
1889 xev
.xclient
.data
.l
[2] = 0;
1890 xev
.xclient
.data
.l
[3] = 1; // 1 for Application, 2 for Page or Taskbar, 0 for old source
1891 xev
.xclient
.data
.l
[4] = 0;
1892 if (!XSendEvent(_dpy
, XDefaultRootWindow(_dpy
), False
, SubstructureRedirectMask
| SubstructureNotifyMask
, &xev
))
1894 nlwarning("3D: Failed to toggle to fullscreen");
1900 if (windowStyle
== EWSFullscreen
)
1902 // set state property to fullscreen
1903 XChangeProperty(_dpy
, _win
, XA_WM_STATE
, XA_ATOM
, 32, PropModeReplace
, (const unsigned char*)&XA_WM_STATE_FULLSCREEN
, 1);
1907 // delete state property
1908 XDeleteProperty(_dpy
, _win
, XA_WM_STATE
);
1912 #endif // NL_OS_WINDOWS
1914 _CurrentMode
.Windowed
= (windowStyle
== EWSWindowed
);
1919 bool CDriverGL::getMonitorByName(const std::string
&name
, sint32
&x
, sint32
&y
, uint32
&w
, uint32
&h
) const
1924 int screen
= DefaultScreen(_dpy
);
1927 if (_xrandr_version
>= 105)
1930 XRRMonitorInfo
*monitor
= XRRGetMonitors(_dpy
, RootWindow(_dpy
, screen
), 1, &nmonitors
);
1934 for(sint i
= 0; i
< nmonitors
; ++i
)
1936 char* pname
= XGetAtomName(_dpy
, monitor
[i
].name
);
1937 found
= (nlstricmp(pname
, name
) == 0);
1944 w
= monitor
[i
].width
;
1945 h
= monitor
[i
].height
;
1951 XRRFreeMonitors(monitor
);
1955 XRRScreenResources
*resources
= XRRGetScreenResourcesCurrent(_dpy
, RootWindow(_dpy
, screen
));
1957 resources
= XRRGetScreenResources(_dpy
, RootWindow(_dpy
, screen
));
1959 for(uint i
= 0; i
< resources
->noutput
; ++i
)
1961 XRROutputInfo
*output
= XRRGetOutputInfo(_dpy
, resources
, resources
->outputs
[i
]);
1965 if (output
->crtc
&& output
->connection
== RR_Connected
&& nlstricmp(name
, output
->name
) == 0)
1968 XRRCrtcInfo
*crtc
= XRRGetCrtcInfo(_dpy
, resources
, output
->crtc
);
1975 // TODO: test rotation
1976 if (crtc
->rotation
== RR_Rotate_0
|| crtc
->rotation
== RR_Rotate_180
)
1987 XRRFreeCrtcInfo(crtc
);
1991 XRRFreeOutputInfo(output
);
1997 XRRFreeScreenResources(resources
);
2003 // --------------------------------------------------
2004 bool CDriverGL::setMode(const GfxMode
& amode
)
2006 H_AUTO_OGL(CDriverGL_setMode
);
2008 // don't modify window or screen if managed by a 3rd party library
2009 if (!_DestroyWindow
)
2013 const GfxMode
&mode
= amode
;
2016 #if defined(NL_OS_WINDOWS)
2017 // save relative cursor
2022 BOOL cursorPosOk
= isSystemCursorInClientArea()
2023 && GetCursorPos(&cursorPos
)
2024 && ScreenToClient(_win
, &cursorPos
);
2026 // FIXME: this probably needs to use _CurrentMode instead of mode
2027 sint curX
= (sint
)cursorPos
.x
* (sint
)mode
.Width
;
2028 sint curY
= (sint
)cursorPos
.y
* (sint
)mode
.Height
;
2032 GfxMode mode
= amode
;
2037 if (!getCurrentScreenMode(current
))
2038 nlinfo("3D: XrandR: Reading active monitor info failed");
2040 sint newX
= _WindowX
;
2041 sint newY
= _WindowY
;
2043 // make sure resolution matches requested or currently active monitor's resolution
2044 mode
.Width
= current
.Width
;
2045 mode
.Height
= current
.Height
;
2046 if (!mode
.DisplayDevice
.empty())
2048 uint newW
= current
.Width
;
2049 uint newH
= current
.Height
;
2050 if (getMonitorByName(mode
.DisplayDevice
, newX
, newY
, newW
, newH
))
2057 nlinfo("3D: XrandR: Reading requested monitor '%s' info failed, using '%s'", mode
.DisplayDevice
.c_str(), current
.DisplayDevice
.c_str());
2058 mode
.DisplayDevice
= current
.DisplayDevice
;
2062 // switching monitors.
2063 // first move mouse pointer to target monitor and then move window.
2064 // if window is visible, then also restore mouse relative position.
2065 if (!mode
.DisplayDevice
.empty() && mode
.DisplayDevice
!= current
.DisplayDevice
)
2067 int screen
= DefaultScreen(_dpy
);
2068 Window root
= RootWindow(_dpy
, screen
);
2069 uint mouseX
= mode
.Width
/ 2;
2070 uint mouseY
= mode
.Height
/ 2;
2072 XWindowAttributes xwa
;
2073 XGetWindowAttributes(_dpy
, _win
, &xwa
);
2074 if (xwa
.map_state
!= IsUnmapped
)
2078 sint root_x
, root_y
, win_x
, win_y
;
2081 Bool res
= XQueryPointer(_dpy
, _win
, &root_win
, &child_win
, &root_x
, &root_y
, &win_x
, &win_y
, &mask
);
2084 mouseX
= (uint
)((float)win_x
* mode
.Width
/ current
.Width
);
2085 mouseY
= (uint
)((float)win_y
* mode
.Height
/ current
.Height
);
2089 XWarpPointer(_dpy
, None
, root
, None
, None
, None
, None
, newX
+ mouseX
, newY
+ mouseY
);
2090 XMoveWindow(_dpy
, _win
, newX
, newY
);
2097 if (!setScreenMode(mode
))
2100 _CurrentMode
.Depth
= mode
.Depth
;
2101 _CurrentMode
.Frequency
= mode
.Frequency
;
2102 _CurrentMode
.DisplayDevice
= mode
.DisplayDevice
;
2104 // when changing window style, it's possible system change window size too
2105 setWindowStyle(mode
.Windowed
? EWSWindowed
: EWSFullscreen
);
2106 setWindowPos(_WindowX
, _WindowY
);
2107 setWindowSize(mode
.Width
, mode
.Height
);
2109 switch (_CurrentMode
.Depth
)
2111 case 16: _ColorDepth
= ColorDepth16
; break;
2113 case 32: _ColorDepth
= ColorDepth32
; break;
2116 #if defined(NL_OS_WINDOWS)
2117 // restore relative cursor
2120 cursorPos
.x
= curX
/ (sint
)mode
.Width
;
2121 cursorPos
.y
= curY
/ (sint
)mode
.Height
;
2122 ClientToScreen(_win
, &cursorPos
);
2123 SetCursorPos(cursorPos
.x
, cursorPos
.y
);
2127 // set color depth for custom cursor
2135 #ifdef NL_MAC_VERSION_10_6_UP
2137 /// helper to extract bits per pixel value from screen mode, only 16 or 32 bits
2138 static int bppFromDisplayMode(CGDisplayModeRef mode
)
2140 CFStringRef pixelEncoding
= CGDisplayModeCopyPixelEncoding(mode
);
2142 if(CFStringCompare(pixelEncoding
, CFSTR(IO32BitDirectPixels
),
2143 kCFCompareCaseInsensitive
) == kCFCompareEqualTo
)
2146 else if(CFStringCompare(pixelEncoding
, CFSTR(IO16BitDirectPixels
),
2147 kCFCompareCaseInsensitive
) == kCFCompareEqualTo
)
2155 long GetDictionaryLong(CFDictionaryRef theDict
, const void* key
)
2159 numRef
= (CFNumberRef
)CFDictionaryGetValue(theDict
, key
);
2161 CFNumberGetValue(numRef
, kCFNumberLongType
, &value
);
2165 // some macros to make code more readable.
2166 #define GetModeWidth(mode) GetDictionaryLong((mode), kCGDisplayWidth)
2167 #define GetModeHeight(mode) GetDictionaryLong((mode), kCGDisplayHeight)
2168 #define GetModeBitsPerPixel(mode) GetDictionaryLong((mode), kCGDisplayBitsPerPixel)
2174 // --------------------------------------------------
2175 bool CDriverGL::getModes(std::vector
<GfxMode
> &modes
)
2177 H_AUTO_OGL(CDriverGL_getModes
)
2179 #ifdef NL_OS_WINDOWS
2182 while (EnumDisplaySettings (NULL
, modeIndex
, &devMode
))
2184 // Keep only 16 and 32 bits
2185 if ((devMode
.dmBitsPerPel
== 16 ) || (devMode
.dmBitsPerPel
== 32))
2189 mode
.Width
= (uint16
)devMode
.dmPelsWidth
;
2190 mode
.Height
= (uint16
)devMode
.dmPelsHeight
;
2191 mode
.Depth
= (uint8
)devMode
.dmBitsPerPel
;
2192 mode
.Frequency
= devMode
.dmDisplayFrequency
;
2193 modes
.push_back (mode
);
2200 #elif defined(NL_OS_MAC)
2202 static const CGDisplayCount kMaxDisplays
= 16;
2203 CGDirectDisplayID display
[kMaxDisplays
];
2204 CGDisplayCount numDisplays
;
2206 CGDisplayErr err
= CGGetActiveDisplayList(kMaxDisplays
, display
, &numDisplays
);
2207 if(err
!= CGDisplayNoErr
)
2209 nlwarning("Cannot get displays (%d)", err
);
2213 // nldebug("3D: %d displays found", (int)numDisplays);
2215 for (CGDisplayCount i
= 0; i
< numDisplays
; ++i
)
2217 CGDirectDisplayID dspy
= display
[i
];
2219 #ifdef NL_MAC_VERSION_10_6_UP
2220 CFArrayRef modeList
= CGDisplayCopyAllDisplayModes(dspy
, NULL
);
2222 CFArrayRef modeList
= CGDisplayAvailableModes(dspy
);
2225 if (modeList
== NULL
)
2227 nlwarning("Display is invalid");
2231 for (CFIndex j
= 0; j
< CFArrayGetCount(modeList
); ++j
)
2233 #ifdef NL_MAC_VERSION_10_6_UP
2234 CGDisplayModeRef mode
= (CGDisplayModeRef
)CFArrayGetValueAtIndex(modeList
, j
);
2235 uint8 bpp
= bppFromDisplayMode(mode
);
2237 CFDictionaryRef mode
= (CFDictionaryRef
)CFArrayGetValueAtIndex(modeList
, j
);
2238 uint8 bpp
= (uint8
)GetModeBitsPerPixel(mode
);
2243 #ifdef NL_MAC_VERSION_10_6_UP
2244 uint16 w
= CGDisplayModeGetWidth(mode
);
2245 uint16 h
= CGDisplayModeGetHeight(mode
);
2247 uint16 w
= (uint16
)GetModeWidth(mode
);
2248 uint16 h
= (uint16
)GetModeHeight(mode
);
2257 // Frequency stays at 0 because on mac cocoa, display resolution
2258 // is never really changed. if rendering res < display res,
2259 // cocoa interpolates and keeps the display at it's original res.
2261 modes
.push_back (mode
);
2263 // nldebug(" Display 0x%x: Mode %dx%d, %d BPP", dspy, w, h, bpp);
2267 #ifdef NL_MAC_VERSION_10_6_UP
2268 CFRelease(modeList
);
2272 #elif defined (NL_OS_UNIX)
2276 nlwarning("3D: Unable to list modes because Display is NULL, did you forget to call init() ?");
2281 int screen
= DefaultScreen(_dpy
);
2283 #if defined(HAVE_XRANDR)
2284 if (_xrandr_version
>= 105)
2288 XRRMonitorInfo
*monitor
= XRRGetMonitors(_dpy
, RootWindow(_dpy
, screen
), 1, &nmonitors
);
2289 for(sint i
= 0; i
< nmonitors
; ++i
)
2291 char * name
= XGetAtomName(_dpy
, monitor
[i
].name
);
2293 mode
.DisplayDevice
= name
;
2294 mode
.Width
= monitor
[i
].width
;
2295 mode
.Height
= monitor
[i
].height
;
2297 modes
.push_back(mode
);
2300 XRRFreeMonitors(monitor
);
2304 XRRScreenResources
*resources
= XRRGetScreenResourcesCurrent(_dpy
, RootWindow(_dpy
, screen
));
2306 resources
= XRRGetScreenResources(_dpy
, RootWindow(_dpy
, screen
));
2308 std::map
<int, int> resourceModeMap
;
2309 for(sint i
= 0; i
< resources
->nmode
; ++i
)
2310 resourceModeMap
.insert(std::make_pair(resources
->modes
[i
].id
, i
));
2312 for(sint i
= 0; i
< resources
->noutput
; ++i
)
2314 XRROutputInfo
*output
= XRRGetOutputInfo(_dpy
, resources
, resources
->outputs
[i
]);
2318 if (output
->crtc
&& output
->connection
== RR_Connected
)
2321 XRRCrtcInfo
*crtc
= XRRGetCrtcInfo(_dpy
, resources
, output
->crtc
);
2324 std::map
<int,int>::const_iterator it
= resourceModeMap
.find(crtc
->mode
);
2325 if (it
!= resourceModeMap
.end())
2328 mode
.DisplayDevice
= output
->name
;
2329 mode
.Width
= resources
->modes
[it
->second
].width
;
2330 mode
.Height
= resources
->modes
[it
->second
].height
;
2333 modes
.push_back(mode
);
2335 XRRFreeCrtcInfo(crtc
);
2338 XRRFreeOutputInfo(output
);
2341 XRRFreeScreenResources(resources
);
2343 found
= modes
.size() > 0;
2344 if (!found
&& _xrandr_version
>= 100)
2346 XRRScreenConfiguration
*screen_config
= XRRGetScreenInfo(_dpy
, RootWindow(_dpy
, screen
));
2350 // retrieve the list of resolutions
2352 XRRScreenSize
*sizes
= XRRConfigSizes(screen_config
, &nsizes
);
2356 // nldebug("3D: %d available XRandR modes:", nsizes);
2357 for (sint i
= 0; i
< nsizes
; ++i
)
2361 mode
.Width
= sizes
[i
].width
;
2362 mode
.Height
= sizes
[i
].height
;
2365 modes
.push_back(mode
);
2366 // nldebug("3D: Mode %d: %dx%d", i, mode.Width, mode.Height);
2373 nlwarning("3D: No XRandR modes available");
2376 XRRFreeScreenConfigInfo(screen_config
);
2380 nlwarning("3D: XRRGetScreenInfo failed");
2386 if (!found
&& _xvidmode_version
> 0)
2389 XF86VidModeModeInfo
**ms
;
2390 if (XF86VidModeGetAllModeLines(_dpy
, screen
, &nmodes
, &ms
))
2392 // nlinfo("3D: %d available XF86VidMode modes:", nmodes);
2393 for (int j
= 0; j
< nmodes
; j
++)
2397 mode
.Width
= (uint16
)ms
[j
]->hdisplay
;
2398 mode
.Height
= (uint16
)ms
[j
]->vdisplay
;
2399 mode
.Frequency
= modeInfoToFrequency(ms
[j
]);
2400 // nlinfo("3D: Mode %d: %dx%d, %d Hz", j, mode.Width, mode.Height, mode.Frequency);
2401 modes
.push_back (mode
);
2407 nlwarning("3D: XF86VidModeGetAllModeLines failed");
2410 #endif // XF86VIDMODE
2414 // Add current screen mode
2416 mode
.Width
= DisplayWidth(_dpy
, screen
);
2417 mode
.Height
= DisplayHeight(_dpy
, screen
);
2419 modes
.push_back(mode
);
2426 // --------------------------------------------------
2427 bool CDriverGL::getCurrentScreenMode(GfxMode
&mode
)
2429 H_AUTO_OGL(CDriverGL_getCurrentScreenMode
)
2431 #ifdef NL_OS_WINDOWS
2434 devmode
.dmSize
= sizeof(DEVMODE
);
2435 devmode
.dmDriverExtra
= 0;
2436 EnumDisplaySettings(NULL
, ENUM_CURRENT_SETTINGS
, &devmode
);
2438 mode
.Windowed
= _CurrentMode
.Windowed
;
2439 mode
.OffScreen
= false;
2440 mode
.Depth
= (uint8
)devmode
.dmBitsPerPel
;
2441 mode
.Frequency
= devmode
.dmDisplayFrequency
;
2442 mode
.Width
= (uint16
)devmode
.dmPelsWidth
;
2443 mode
.Height
= (uint16
)devmode
.dmPelsHeight
;
2444 mode
.AntiAlias
= _CurrentMode
.AntiAlias
;
2446 #elif defined(NL_OS_MAC)
2448 // the sceen with the menu bar
2449 NSScreen
* screen
= [[NSScreen screens
] objectAtIndex
:0];
2451 mode
.OffScreen
= false;
2453 mode
.Depth
= NSBitsPerPixelFromDepth([screen depth
]);
2455 // in fullscreen mode
2456 if([containerView() isInFullScreenMode
])
2458 // return the size of the back buffer (like having switched monitor mode)
2459 mode
.Windowed
= false;
2460 mode
.Width
= _backBufferWidth
;
2461 mode
.Height
= _backBufferHeight
;
2467 // return the size of the screen with menu bar
2468 mode
.Windowed
= true;
2469 mode
.Width
= (uint16
)[screen frame
].size
.width
;
2470 mode
.Height
= (uint16
)[screen frame
].size
.height
;
2473 #elif defined(NL_OS_UNIX)
2476 int screen
= DefaultScreen(_dpy
);
2483 // get window position so we can compare monitors (or mouse position if window not visible yet)
2484 XWindowAttributes xwa
;
2485 XGetWindowAttributes(_dpy
, _win
, &xwa
);
2486 if (xwa
.map_state
!= IsUnmapped
)
2488 XTranslateCoordinates(_dpy
, _win
, xwa
.root
, xwa
.x
, xwa
.y
, &x
, &y
, &child
);
2492 sint rx
, ry
, wx
, wy
;
2494 Bool res
= XQueryPointer(_dpy
, RootWindow(_dpy
, screen
), &child
, &child
, &rx
, &ry
, &wx
, &wy
, &mask
);
2502 if (_xrandr_version
>= 105)
2505 XRRMonitorInfo
*monitor
= XRRGetMonitors(_dpy
, RootWindow(_dpy
, screen
), 1, &nmonitors
);
2508 sint bestMatch
= -1;
2509 for(sint i
= 0; i
< nmonitors
; ++i
)
2511 if ((x
>= monitor
[i
].x
&& x
< (monitor
[i
].x
+ monitor
[i
].width
) &&
2512 y
>= monitor
[i
].y
&& y
< (monitor
[i
].y
+ monitor
[i
].height
)) ||
2513 (monitor
[i
].primary
&& bestMatch
== -1))
2519 // best match or primary monitor
2520 if (bestMatch
!= -1)
2523 char* pname
= XGetAtomName(_dpy
, monitor
[bestMatch
].name
);
2524 mode
.DisplayDevice
= pname
;
2525 mode
.Width
= monitor
[bestMatch
].width
;
2526 mode
.Height
= monitor
[bestMatch
].height
;
2527 mode
.Windowed
= _CurrentMode
.Windowed
;
2528 mode
.OffScreen
= false;
2529 mode
.Depth
= (uint
) DefaultDepth(_dpy
, screen
);
2534 XRRFreeMonitors(monitor
);
2539 XRRScreenResources
*resources
= XRRGetScreenResourcesCurrent(_dpy
, RootWindow(_dpy
, screen
));
2541 resources
= XRRGetScreenResources(_dpy
, RootWindow(_dpy
, screen
));
2543 for(uint i
= 0; i
< resources
->noutput
; ++i
)
2545 XRROutputInfo
*output
= XRRGetOutputInfo(_dpy
, resources
, resources
->outputs
[i
]);
2549 if (output
->crtc
&& output
->connection
== RR_Connected
)
2551 XRRCrtcInfo
*crtc
= XRRGetCrtcInfo(_dpy
, resources
, output
->crtc
);
2557 // TODO: test rotation
2558 if (crtc
->rotation
== RR_Rotate_0
|| crtc
->rotation
== RR_Rotate_180
)
2560 width
= crtc
->width
;
2561 height
= crtc
->height
;
2565 width
= crtc
->height
;
2566 height
= crtc
->width
;
2569 if (x
>= crtc
->x
&& y
>= crtc
->y
&& x
< (crtc
->x
+ width
) && y
< (crtc
->y
+ height
))
2572 mode
.DisplayDevice
= output
->name
;
2574 mode
.Height
= height
;
2575 mode
.Windowed
= _CurrentMode
.Windowed
;
2576 mode
.OffScreen
= false;
2577 mode
.Depth
= (uint
) DefaultDepth(_dpy
, screen
);
2581 XRRFreeCrtcInfo(crtc
);
2585 XRRFreeOutputInfo(output
);
2591 XRRFreeScreenResources(resources
);
2594 if (!found
&& _xrandr_version
> 0)
2596 XRRScreenConfiguration
*screen_config
= XRRGetScreenInfo(_dpy
, RootWindow(_dpy
, screen
));
2601 XRRScreenSize
*sizes
= XRRConfigSizes(screen_config
, &nsizes
);
2604 Rotation cur_rotation
;
2605 SizeID size
= XRRConfigCurrentConfiguration(screen_config
, &cur_rotation
);
2607 mode
.Windowed
= _CurrentMode
.Windowed
;
2608 mode
.OffScreen
= false;
2609 mode
.Depth
= (uint
) DefaultDepth(_dpy
, screen
);
2611 mode
.Width
= sizes
[size
].width
;
2612 mode
.Height
= sizes
[size
].height
;
2616 nlinfo("3D: Current XRandR mode %d: %dx%d, %dbit", size
, mode
.Width
, mode
.Height
, mode
.Depth
);
2620 nlwarning("3D: No XRandR modes available");
2623 XRRFreeScreenConfigInfo(screen_config
);
2627 nlwarning("3D: XRRGetScreenInfo failed");
2631 #endif // HAVE_XRANDR
2635 if (!found
&& _xvidmode_version
> 0)
2638 XF86VidModeModeLine xmode
;
2640 if (XF86VidModeGetModeLine(_dpy
, screen
, &pixelClock
, &xmode
))
2642 mode
.Windowed
= _CurrentMode
.Windowed
;
2643 mode
.OffScreen
= false;
2644 mode
.Depth
= (uint
) DefaultDepth(_dpy
, screen
);
2645 mode
.Frequency
= 1000 * pixelClock
/ (xmode
.htotal
* xmode
.vtotal
) ;
2646 mode
.Width
= xmode
.hdisplay
;
2647 mode
.Height
= xmode
.vdisplay
;
2648 nlinfo("3D: Current XF86VidMode mode: %dx%d, %d Hz, %dbit", mode
.Width
, mode
.Height
, mode
.Frequency
, mode
.Depth
);
2654 nlwarning("3D: XF86VidModeGetModeLine failed, cannot get current video mode");
2658 #endif // XF86VidMode
2662 mode
.Windowed
= _CurrentMode
.Windowed
;
2663 mode
.OffScreen
= _CurrentMode
.OffScreen
;
2664 mode
.Depth
= (uint
) DefaultDepth(_dpy
, screen
);
2666 mode
.Width
= DisplayWidth(_dpy
, screen
);
2667 mode
.Height
= DisplayHeight(_dpy
, screen
);
2671 nldebug("Current mode: %dx%d, %d Hz, %dbit", mode
.Width
, mode
.Height
, mode
.Frequency
, mode
.Depth
);
2674 #endif // NL_OS_UNIX
2679 // --------------------------------------------------
2680 void CDriverGL::setWindowTitle(const ucstring
&title
)
2682 H_AUTO_OGL(CDriverGL_setWindowTitle
)
2684 if (_win
== EmptyWindow
)
2687 #ifdef NL_OS_WINDOWS
2689 if (!SetWindowTextW(_win
, (WCHAR
*)title
.c_str()))
2691 nlwarning("SetWindowText failed: %s", formatErrorMessage(getLastError()).c_str());
2694 #elif defined(NL_OS_MAC)
2696 [[containerView() window
] setTitle
:
2697 [NSString stringWithUTF8String
:title
.toUtf8().c_str()]];
2699 #elif defined (NL_OS_UNIX)
2701 #ifdef X_HAVE_UTF8_STRING
2703 Xutf8SetWMProperties (_dpy
, _win
, (char*)title
.toUtf8().c_str(), (char*)title
.toUtf8().c_str(), NULL
, 0, NULL
, NULL
, NULL
);
2705 // standard properties
2706 XTextProperty text_property
;
2707 if (XStringListToTextProperty((char**)&title
.toUtf8().c_str(), 1, &text_property
) != 0)
2709 XSetWMProperties (_dpy
, _win
, &text_property
, &text_property
, NULL
, 0, NULL
, NULL
, NULL
);
2713 nlwarning("3D: Can't convert title to TextProperty");
2717 #endif // NL_OS_WINDOWS
2720 // ***************************************************************************
2721 void CDriverGL::setWindowPos(sint32 x
, sint32 y
)
2723 H_AUTO_OGL(CDriverGL_setWindowPos
)
2728 if (_win
== EmptyWindow
|| !_CurrentMode
.Windowed
)
2731 #ifdef NL_OS_WINDOWS
2733 // save relative cursor
2735 BOOL cursorPosOk
= isSystemCursorInClientArea()
2736 && GetCursorPos(&cursorPos
)
2737 && ScreenToClient(_win
, &cursorPos
);
2739 SetWindowPos(_win
, NULL
, x
, y
, 0, 0, /*SWP_NOZORDER | SWP_NOACTIVATE |*/ SWP_NOSIZE
);
2743 ClientToScreen(_win
, &cursorPos
);
2744 SetCursorPos(cursorPos
.x
, cursorPos
.y
);
2747 #elif defined(NL_OS_MAC)
2748 // get the rect (position, size) of the screen with menu bar
2749 NSRect screenRect
= [[[NSScreen screens
] objectAtIndex
:0] frame
];
2751 // get the rect (position, size) of the window
2752 NSRect windowRect
= [[containerView() window
] frame
];
2754 // convert y from NeL coordinates to cocoa coordinates
2755 y
= screenRect
.size
.height
- y
;
2757 // tell cocoa to move the window
2758 [[containerView() window
] setFrameTopLeftPoint
:NSMakePoint(x
, y
)];
2760 #elif defined (NL_OS_UNIX)
2762 if (_CurrentMode
.Windowed
)
2764 // first time requesting decoration sizes
2765 if (_WindowX
&& _WindowY
&& !_DecorationWidth
&& !_DecorationHeight
&& _WndActive
)
2767 _DecorationWidth
= -1;
2768 _DecorationHeight
= -1;
2770 XMoveWindow(_dpy
, _win
, x
, y
);
2773 #endif // NL_OS_WINDOWS
2776 // ***************************************************************************
2777 void CDriverGL::showWindow(bool show
)
2779 H_AUTO_OGL(CDriverGL_showWindow
)
2781 // don't change window visibility, if we didn't create the window
2782 if (_win
== EmptyWindow
|| !_DestroyWindow
)
2785 _WindowVisible
= show
;
2787 #ifdef NL_OS_WINDOWS
2789 ShowWindow (_win
, show
? SW_SHOW
:SW_HIDE
);
2791 #elif defined(NL_OS_MAC)
2793 // TODO: Missing Mac Implementation for showWindow
2795 #elif defined (NL_OS_UNIX)
2799 XMapRaised(_dpy
, _win
);
2801 // fix window position if windows manager want to impose them
2802 setWindowPos(_WindowX
, _WindowY
);
2806 XUnmapWindow(_dpy
, _win
);
2809 #endif // NL_OS_WINDOWS
2812 // --------------------------------------------------
2813 emptyProc
CDriverGL::getWindowProc()
2815 H_AUTO_OGL(CDriverGL_getWindowProc
)
2817 return (emptyProc
)GlWndProc
;
2820 // --------------------------------------------------
2821 bool CDriverGL::createContext()
2826 if (_CurrentMode
.AntiAlias
> -1)
2828 if (_CurrentMode
.AntiAlias
== 0)
2834 samples
= _CurrentMode
.AntiAlias
;
2838 EGLint attribList
[] =
2845 EGL_STENCIL_SIZE
, 8,
2846 // EGL_SAMPLE_BUFFERS, _CurrentMode.AntiAlias > -1 ? 1:0,
2847 // EGL_SAMPLES, samples,
2848 EGL_RENDERABLE_TYPE
,
2854 _EglDisplay
= EGL_NO_DISPLAY
; // eglGetDisplay(_hDC);
2856 if (_EglDisplay
== EGL_NO_DISPLAY
)
2858 _EglDisplay
= eglGetDisplay(EGL_DEFAULT_DISPLAY
);
2860 if (_EglDisplay
== EGL_NO_DISPLAY
)
2862 nlwarning("3D: failed to get display 0x%x", eglGetError());
2868 EGLint majorVersion
;
2869 EGLint minorVersion
;
2871 if (!eglInitialize(_EglDisplay
, &majorVersion
, &minorVersion
))
2876 const char *extensions
= eglQueryString(_EglDisplay
, EGL_EXTENSIONS
);
2882 if (!eglGetConfigs(_EglDisplay
, NULL
, 0, &numConfigs
))
2888 EGLConfig config
= NULL
;
2890 if (!eglChooseConfig(_EglDisplay
, attribList
, &config
, 1, &numConfigs
))
2896 _EglSurface
= eglCreateWindowSurface(_EglDisplay
, config
, (EGLNativeWindowType
)_win
, NULL
);
2898 if (_EglSurface
== EGL_NO_SURFACE
)
2903 // Create a GL context
2904 EGLint contextAttribs
[] =
2906 EGL_CONTEXT_CLIENT_VERSION
, 1,
2910 _EglContext
= eglCreateContext(_EglDisplay
, config
, EGL_NO_CONTEXT
, contextAttribs
);
2912 if (_EglContext
== EGL_NO_CONTEXT
)
2917 // Make the context current
2918 if (!eglMakeCurrent(_EglDisplay
, _EglSurface
, _EglSurface
, _EglContext
))
2922 #elif defined(NL_OS_WINDOWS)
2924 _CurrentMode
.Depth
= uint8(GetDeviceCaps(_hDC
,BITSPIXEL
));
2926 wglMakeCurrent(_hDC
,NULL
);
2928 memset(&_pfd
,0,sizeof(_pfd
));
2929 _pfd
.nSize
= sizeof(_pfd
);
2931 _pfd
.dwFlags
= PFD_DRAW_TO_WINDOW
| PFD_SUPPORT_OPENGL
| PFD_DOUBLEBUFFER
;
2932 _pfd
.iPixelType
= PFD_TYPE_RGBA
;
2933 _pfd
.cColorBits
= _CurrentMode
.Depth
;
2934 // Choose best suited Depth Buffer.
2935 if(_CurrentMode
.Depth
<= 16)
2937 _pfd
.cDepthBits
= 16;
2941 _pfd
.cDepthBits
= 24;
2942 _pfd
.cAlphaBits
= 8;
2943 _pfd
.cStencilBits
= 8;
2945 _pfd
.iLayerType
= PFD_MAIN_PLANE
;
2946 int pf
=ChoosePixelFormat(_hDC
,&_pfd
);
2952 if ( !SetPixelFormat(_hDC
,pf
,&_pfd
) )
2956 _hRC
=wglCreateContext(_hDC
);
2958 wglMakeCurrent(_hDC
,_hRC
);
2964 // --------------------------------------------------
2965 bool CDriverGL::activate()
2967 H_AUTO_OGL(CDriverGL_activate
);
2969 if (_win
== EmptyWindow
)
2974 EGLContext ctx
= eglGetCurrentContext();
2976 if (ctx
!= _EglContext
)
2978 // Make the context current
2979 if (!eglMakeCurrent(_EglDisplay
, _EglSurface
, _EglSurface
, _EglContext
))
2985 #elif defined(NL_OS_WINDOWS)
2987 HGLRC hglrc
= wglGetCurrentContext();
2990 wglMakeCurrent(_hDC
, _hRC
);
2992 #elif defined(NL_OS_MAC)
2994 if([NSOpenGLContext currentContext
] != _ctx
)
2995 [_ctx makeCurrentContext
];
2997 #elif defined (NL_OS_UNIX)
2999 GLXContext nctx
= glXGetCurrentContext();
3001 if (nctx
!= NULL
&& nctx
!= _ctx
)
3002 glXMakeCurrent(_dpy
, _win
, _ctx
);
3004 #endif // USE_OPENGLES
3009 // --------------------------------------------------
3010 IDriver::TMessageBoxId
CDriverGL::systemMessageBox (const char* message
, const char* title
, IDriver::TMessageBoxType type
, TMessageBoxIcon icon
)
3012 H_AUTO_OGL(CDriverGL_systemMessageBox
)
3013 #ifdef NL_OS_WINDOWS
3014 switch (::MessageBoxW(NULL
, nlUtf8ToWide(message
), nlUtf8ToWide(title
), ((type
== retryCancelType
) ? MB_RETRYCANCEL
:
3015 (type
==yesNoCancelType
)?MB_YESNOCANCEL
:
3016 (type
==okCancelType
)?MB_OKCANCEL
:
3017 (type
==abortRetryIgnoreType
)?MB_ABORTRETRYIGNORE
:
3018 (type
==yesNoType
)?MB_YESNO
|MB_ICONQUESTION
:MB_OK
)|
3020 ((icon
==handIcon
)?MB_ICONHAND
:
3021 (icon
==questionIcon
)?MB_ICONQUESTION
:
3022 (icon
==exclamationIcon
)?MB_ICONEXCLAMATION
:
3023 (icon
==asteriskIcon
)?MB_ICONASTERISK
:
3024 (icon
==warningIcon
)?MB_ICONWARNING
:
3025 (icon
==errorIcon
)?MB_ICONERROR
:
3026 (icon
==informationIcon
)?MB_ICONINFORMATION
:
3027 (icon
==stopIcon
)?MB_ICONSTOP
:0)))
3045 #else // NL_OS_WINDOWS
3046 // TODO: if user did not launch from console, then program "freezes" without explanation or possibility to continue
3047 //IDriver::systemMessageBox (message, title, type, icon);
3049 printf("%s:%s\n", title
, message
);
3050 nlwarning("%s: %s", title
, message
);
3051 #endif // NL_OS_WINDOWS
3055 void CDriverGL::getWindowSize(uint32
&width
, uint32
&height
)
3057 H_AUTO_OGL(CDriverGL_getWindowSize
)
3059 if (_CurrentMode
.OffScreen
)
3061 #ifdef NL_OS_WINDOWS
3063 #ifndef USE_OPENGLES
3066 nwglQueryPbufferARB( _PBuffer
, WGL_PBUFFER_WIDTH_ARB
, (int*)&width
);
3067 nwglQueryPbufferARB( _PBuffer
, WGL_PBUFFER_HEIGHT_ARB
, (int*)&height
);
3076 if([containerView() isInFullScreenMode
])
3078 width
= _backBufferWidth
;
3079 height
= _backBufferHeight
;
3083 width
= _CurrentMode
.Width
;
3084 height
= _CurrentMode
.Height
;
3088 void CDriverGL::setWindowSize(uint32 width
, uint32 height
)
3090 H_AUTO_OGL(CDriverGL_setWindowSize
)
3092 if (_win
== EmptyWindow
)
3095 #if defined(NL_OS_WINDOWS)
3097 // resize the window
3099 SetRect (&rc
, 0, 0, width
, height
);
3100 AdjustWindowRectEx(&rc
, GetWindowStyle(_win
), GetMenu(_win
) != NULL
, GetWindowExStyle(_win
));
3101 UINT flags
= SWP_NOZORDER
| SWP_NOACTIVATE
;
3102 // set position to (0, 0) if fullscreen
3103 if (_CurrentMode
.Windowed
)
3104 flags
|= SWP_NOMOVE
;
3105 SetWindowPos(_win
, NULL
, 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, flags
);
3107 // init window width and height
3109 GetClientRect(_win
, &clientRect
);
3110 _CurrentMode
.Width
= uint16(clientRect
.right
-clientRect
.left
);
3111 _CurrentMode
.Height
= uint16(clientRect
.bottom
-clientRect
.top
);
3112 GetWindowRect(_win
, &clientRect
);
3113 _WindowX
= clientRect
.left
;
3114 _WindowY
= clientRect
.top
;
3116 #elif defined(NL_OS_MAC)
3118 // for fullscreen mode, adjust the back buffer size to desired resolution
3119 if([containerView() isInFullScreenMode
])
3121 // disable and re-enable fullscreen
3122 // fixes #1062 (http://dev.ryzom.com/issues/1062)
3123 setWindowStyle(EWSWindowed
);
3124 setWindowStyle(EWSFullscreen
);
3126 // set the back buffer manually to match the desired rendering resolution
3127 GLint dim
[2] = { (GLint
)width
, (GLint
)height
};
3128 CGLError error
= CGLSetParameter(
3129 (CGLContextObj
)[_ctx CGLContextObj
],
3130 kCGLCPSurfaceBackingSize
, dim
);
3132 if(error
!= kCGLNoError
)
3133 nlerror("cannot set kCGLCPSurfaceBackingSize parameter (%s)",
3134 CGLErrorString(error
));
3136 _backBufferHeight
= height
;
3137 _backBufferWidth
= width
;
3141 // only change the window size if the driver created the window itself
3144 // get the windows current frame
3145 NSRect rect
= [[containerView() window
] frame
];
3147 // convert the desired content size to window size
3148 rect
= [[containerView() window
] frameRectForContentRect
:
3149 NSMakeRect(rect
.origin
.x
, rect
.origin
.y
, width
, height
)];
3151 // update window dimensions
3152 [[containerView() window
] setFrame
:rect display
:YES
];
3156 #elif defined(NL_OS_UNIX)
3160 // Update WM hints (disallow resizing)
3161 XSizeHints
*size_hints
= XAllocSizeHints();
3163 size_hints
->flags
= PMinSize
| PMaxSize
;
3164 size_hints
->min_width
= width
;
3165 size_hints
->min_height
= height
;
3166 size_hints
->max_width
= width
;
3167 size_hints
->max_height
= height
;
3169 XSetWMNormalHints(_dpy
, _win
, size_hints
);
3174 // XSetWMNormalHints(_dpy, _win, StdHints);
3177 if (width
!= _CurrentMode
.Width
|| height
!= _CurrentMode
.Height
)
3179 // resize the window
3180 XResizeWindow(_dpy
, _win
, width
, height
);
3182 _CurrentMode
.Width
= width
;
3183 _CurrentMode
.Height
= height
;
3186 #endif // NL_OS_WINDOWS
3189 void CDriverGL::getWindowPos(sint32
&x
, sint32
&y
)
3191 H_AUTO_OGL(CDriverGL_getWindowPos
)
3193 // Off-screen rendering ?
3194 if (_CurrentMode
.OffScreen
)
3205 // --------------------------------------------------
3206 bool CDriverGL::isActive()
3208 H_AUTO_OGL(CDriverGL_isActive
)
3210 if (_win
== EmptyWindow
)
3215 #ifdef NL_OS_WINDOWS
3217 res
= (IsWindow(_win
) != FALSE
);
3219 #elif defined(NL_OS_MAC)
3220 // TODO: Missing Mac Implementation for isActive (always true if a window is set)
3221 #elif defined (NL_OS_UNIX)
3223 // check if our window is still active
3224 XWindowAttributes attr
;
3225 Status status
= XGetWindowAttributes(_dpy
, _win
, &attr
);
3227 res
= (status
== 1);
3229 #endif // NL_OS_UNIX
3234 // ***************************************************************************
3235 bool CDriverGL::setMonitorColorProperties (const CMonitorColorProperties
&properties
)
3237 H_AUTO_OGL(CDriverGL_setMonitorColorProperties
)
3239 #ifdef NL_OS_WINDOWS
3242 HDC dc
= CreateDCA ("DISPLAY", NULL
, NULL
, NULL
);
3248 // For each composant
3250 for( c
=0; c
<3; c
++ )
3253 for( i
=0; i
<256; i
++ )
3256 float value
= (float)i
/ 256;
3259 value
= (float) max (0.0f
, (value
-0.5f
) * (float) pow (3.f
, properties
.Contrast
[c
]) + 0.5f
);
3262 value
= (float) pow (value
, (properties
.Gamma
[c
]>0) ? 1 - 3 * properties
.Gamma
[c
] / 4 : 1 - properties
.Gamma
[c
] );
3265 value
= value
+ properties
.Luminosity
[c
] / 2.f
;
3266 ramp
[i
+(c
<<8)] = (WORD
)min ((int)65535, max (0, (int)(value
* 65535)));
3271 bool result
= SetDeviceGammaRamp (dc
, ramp
) != FALSE
;
3274 ReleaseDC (NULL
, dc
);
3281 nlwarning ("(CDriverGL::setMonitorColorProperties): can't create DC");
3284 #elif defined(NL_OS_MAC)
3285 // TODO for Mac: implement CDriverGL::setMonitorColorProperties
3286 nlwarning ("CDriverGL::setMonitorColorProperties not implemented");
3288 #elif defined (NL_OS_UNIX)
3289 // TODO for Linux: implement CDriverGL::setMonitorColorProperties
3290 nlwarning ("CDriverGL::setMonitorColorProperties not implemented");
3298 void CDriverGL::setupApplicationMenu()
3301 NSMenuItem
* menuItem
;
3305 // get the applications name from it's process info
3306 appName
= [[NSProcessInfo processInfo
] processName
];
3308 // create an empty menu object
3309 menu
= [[NSMenu alloc
] initWithTitle
:@
""];
3311 // add the about menu item
3312 title
= [@
"About " stringByAppendingString
:appName
];
3313 [menu addItemWithTitle
:title
3314 action
:@
selector(orderFrontStandardAboutPanel
:) keyEquivalent
:@
""];
3317 [menu addItem
:[NSMenuItem separatorItem
]];
3319 // add the hide application menu item
3320 title
= [@
"Hide " stringByAppendingString
:appName
];
3321 [menu addItemWithTitle
:title
3322 action
:@
selector(hide
:) keyEquivalent
:@
"h"];
3324 // add the hide others menu item
3325 menuItem
= [menu addItemWithTitle
:@
"Hide Others"
3326 action
:@
selector(hideOtherApplications
:) keyEquivalent
:@
"h"];
3327 [menuItem setKeyEquivalentModifierMask
:(NSAlternateKeyMask
|NSCommandKeyMask
)];
3329 // add the show all menu item
3330 [menu addItemWithTitle
:@
"Show All"
3331 action
:@
selector(unhideAllApplications
:) keyEquivalent
:@
""];
3334 [menu addItem
:[NSMenuItem separatorItem
]];
3337 TODO on quit send EventDestroyWindowId
3339 // add the quit menu item
3340 title
= [@
"Quit " stringByAppendingString
:appName
];
3341 [menu addItemWithTitle
:title
3342 action
:@
selector(terminate
:) keyEquivalent
:@
"q"];
3344 // create an empty menu item and put the new menu into it as a subitem
3345 menuItem
= [[NSMenuItem alloc
] initWithTitle
:@
""
3346 action
:nil keyEquivalent
:@
""];
3347 [menuItem setSubmenu
:menu
];
3349 // create a menu for the application
3350 [NSApp setMainMenu
:[[NSMenu alloc
] initWithTitle
:@
""]];
3352 // attach the new menu to the applications menu
3353 [[NSApp mainMenu
] addItem
:menuItem
];
3357 bool CDriverGL::copyTextToClipboard(const std::string
&text
)
3359 return _EventEmitter
.copyTextToClipboard(text
);
3362 bool CDriverGL::pasteTextFromClipboard(std::string
&text
)
3364 return _EventEmitter
.pasteTextFromClipboard(text
);
3367 #ifdef NL_OS_WINDOWS
3369 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
)
3371 CBitmap src
= bitmap
;
3373 // resample bitmap if necessary
3374 if (src
.getWidth() != iconWidth
|| src
.getHeight() != iconHeight
)
3376 src
.resample(iconWidth
, iconHeight
);
3379 colorBm
.resize(iconWidth
, iconHeight
, CBitmap::RGBA
);
3380 const CRGBA
*srcColorPtr
= (CRGBA
*) &(src
.getPixels()[0]);
3381 const CRGBA
*srcColorPtrLast
= srcColorPtr
+ (iconWidth
* iconHeight
);
3382 CRGBA
*destColorPtr
= (CRGBA
*) &(colorBm
.getPixels()[0]);
3383 static uint8 alphaThreshold
= 127;
3386 destColorPtr
->modulateFromColor(*srcColorPtr
, col
);
3387 std::swap(destColorPtr
->R
, destColorPtr
->B
);
3391 while (srcColorPtr
!= srcColorPtrLast
);
3393 HBITMAP colorHbm
= NULL
;
3394 HBITMAP maskHbm
= NULL
;
3396 if (iconDepth
== 16)
3398 std::vector
<uint16
> colorBm16(iconWidth
* iconHeight
);
3399 const CRGBA
*src32
= (const CRGBA
*) &colorBm
.getPixels(0)[0];
3401 for (uint k
= 0; k
< colorBm16
.size(); ++k
)
3403 colorBm16
[k
] = ((uint16
)(src32
[k
].R
&0xf8)>>3) | ((uint16
)(src32
[k
].G
&0xfc)<<3) | ((uint16
)(src32
[k
].B
& 0xf8)<<8);
3406 colorHbm
= CreateBitmap(iconWidth
, iconHeight
, 1, 16, &colorBm16
[0]);
3407 std::vector
<uint8
> bitMask((iconWidth
* iconHeight
+ 7) / 8, 0);
3409 for (uint k
= 0;k
< colorBm16
.size(); ++k
)
3411 if (src32
[k
].A
<= alphaThreshold
)
3413 bitMask
[k
/ 8] |= (0x80 >> (k
& 7));
3417 maskHbm
= CreateBitmap(iconWidth
, iconHeight
, 1, 1, &bitMask
[0]);
3421 colorHbm
= CreateBitmap(iconWidth
, iconHeight
, 1, 32, &colorBm
.getPixels(0)[0]);
3422 maskHbm
= CreateBitmap(iconWidth
, iconHeight
, 1, 32, &colorBm
.getPixels(0)[0]);
3426 iconInfo
.fIcon
= cursor
? FALSE
:TRUE
;
3427 iconInfo
.xHotspot
= (DWORD
) hotSpotX
;
3428 iconInfo
.yHotspot
= (DWORD
) hotSpotY
;
3429 iconInfo
.hbmMask
= maskHbm
;
3430 iconInfo
.hbmColor
= colorHbm
;
3432 if (colorHbm
&& maskHbm
)
3434 icon
= CreateIconIndirect(&iconInfo
);
3438 if (colorHbm
) DeleteObject(colorHbm
);
3439 if (maskHbm
) DeleteObject(maskHbm
);
3444 #elif defined(NL_OS_MAC)
3446 #elif defined(NL_OS_UNIX)
3448 bool CDriverGL::convertBitmapToIcon(const NLMISC::CBitmap
&bitmap
, std::vector
<long> &icon
)
3450 // get bitmap width and height
3451 uint width
= bitmap
.getWidth();
3452 uint height
= bitmap
.getHeight();
3454 // icon position for bitmap
3455 uint pos
= (uint
)icon
.size();
3457 // extend icon_data size for bitmap
3458 icon
.resize(pos
+ 2 + width
*height
);
3460 // set bitmap width and height
3461 icon
[pos
++] = width
;
3462 icon
[pos
++] = height
;
3464 // convert RGBA to ARGB
3465 CObjectVector
<uint8
> pixels
= bitmap
.getPixels();
3466 for(uint j
= 0; j
< pixels
.size(); j
+=4)
3467 icon
[pos
++] = pixels
[j
] << 16 | pixels
[j
+1] << 8 | pixels
[j
+2] | pixels
[j
+3] << 24;