Show bonus/malus timer text if available
[ryzomcore.git] / nel / src / 3d / driver / opengl / driver_opengl_window.cpp
blob163f64843a6907b1da0e88a37c0a27310312a340
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
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>
8 //
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
30 #ifdef NL_OS_MAC
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)
35 # ifdef HAVE_XRANDR
36 # include <X11/extensions/Xrandr.h>
37 # endif // HAVE_XRANDR
38 # ifdef HAVE_XRENDER
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
44 #endif // NL_OS_UNIX
46 #include "nel/3d/u_driver.h"
47 #include "nel/misc/file.h"
49 using namespace std;
50 using namespace NLMISC;
52 #ifdef DEBUG_NEW
53 #define new DEBUG_NEW
54 #endif
56 namespace NL3D {
58 #ifdef NL_STATIC
59 #ifdef USE_OPENGLES
60 namespace NLDRIVERGLES {
61 #else
62 namespace NLDRIVERGL {
63 #endif
64 #endif
66 #ifdef NL_OS_WINDOWS
68 bool GlWndProc(CDriverGL *driver, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
70 H_AUTO_OGL(GlWndProc)
72 if (!driver)
73 return false;
75 if(message == WM_SIZE)
77 if (driver->_CurrentMode.Windowed)
79 RECT rect;
80 GetClientRect (driver->_win, &rect);
82 // Setup gl viewport
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)
91 RECT rect;
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;
104 else
106 driver->_WndActive = true;
109 else if ((message == WM_SETFOCUS) || (message == WM_KILLFOCUS))
111 if (driver != NULL)
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
122 we->setHWnd(hWnd);
123 trapMessage = we->processMessage (hWnd, message, wParam, lParam);
125 return trapMessage;
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;
135 if (pDriver != NULL)
137 trapMessage = GlWndProc (pDriver, hWnd, message, wParam, lParam);
140 // we don't want Windows to erase background
141 if (message == WM_ERASEBKGND)
143 return TRUE;
146 if (message == WM_SYSCOMMAND)
148 switch (wParam)
150 #ifdef NL_DISABLE_MENU
151 // disable menu (F10, ALT and ALT+SPACE key doesn't freeze or open the menu)
152 case SC_KEYMENU:
153 #endif // NL_DISABLE_MENU
155 // Screensaver Trying To Start?
156 case SC_SCREENSAVE:
158 // Monitor Trying To Enter Powersave?
159 case SC_MONITORPOWER:
161 // Prevent From Happening
162 return 0;
164 default:
165 break;
169 // disable menu (default ALT-F4 behavior is disabled)
170 if (message == WM_CLOSE)
172 if(pDriver && pDriver->ExitFunc)
174 pDriver->ExitFunc();
176 else
178 #ifndef NL_DISABLE_MENU
179 // if we don't disable menu, alt F4 make a direct exit else we discard the message
180 exit(0);
181 #endif // NL_DISABLE_MENU
183 return 0;
186 #ifdef WM_UNICHAR
187 // https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-unichar
188 if (message == WM_UNICHAR)
189 return (wParam == UNICODE_NOCHAR);
190 #endif
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)
201 if(!driver)
202 return false;
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)
221 char buf[80];
222 XGetErrorText(dpy, e->error_code, buf, sizeof(buf));
223 nlwarning("3D: XError: %s", buf);
224 return 1;
227 bool GlWndProc(CDriverGL *driver, XEvent &e)
229 H_AUTO_OGL(GlWndProc)
231 if (!driver)
232 return false;
234 // nlinfo("3D: glop %d %d", e.type, e.xmap.window);
236 // disable menu (default ALT-F4 behavior is disabled)
237 switch(e.type)
239 case DestroyNotify:
241 if(driver && driver->ExitFunc)
243 driver->ExitFunc();
245 else
247 #ifndef NL_DISABLE_MENU
248 // if we don't disable menu, alt F4 make a direct exit else we discard the message
249 exit(0);
250 #endif // NL_DISABLE_MENU
252 break;
254 case MapNotify:
255 driver->_WndActive = true;
256 break;
258 case UnmapNotify:
259 driver->_WndActive = false;
260 break;
262 case Expose:
263 // nlwarning("Expose event");
264 break;
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;
277 long *data = NULL;
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];
287 else
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;
305 break;
307 case FocusIn:
309 driver->_WindowFocus = true;
310 return driver->_EventEmitter.processMessage(e);
313 case FocusOut:
315 driver->_WindowFocus = false;
316 return driver->_EventEmitter.processMessage(e);
319 default:
321 // Process the message by the emitter
322 return driver->_EventEmitter.processMessage(e);
325 return true;
328 #endif // NL_OS_UNIX
330 // ***************************************************************************
331 bool CDriverGL::init (uintptr_t windowIcon, emptyProc exitFunc)
333 H_AUTO_OGL(CDriverGL_init)
335 ExitFunc = exitFunc;
337 createCursors();
339 #ifdef NL_OS_WINDOWS
340 WNDCLASSW wc;
342 if (!_Registered)
344 memset(&wc,0,sizeof(wc));
345 wc.style = CS_HREDRAW | CS_VREDRAW ;//| CS_DBLCLKS;
346 wc.lpfnWndProc = (WNDPROC)WndProc;
347 wc.cbClsExtra = 0;
348 wc.cbWndExtra = 0;
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) )
357 return false;
359 _Registered=1;
362 // Backup monitor color parameters
363 HDC dc = CreateDCA ("DISPLAY", NULL, NULL, NULL);
364 if (dc)
366 _NeedToRestoreGammaRamp = GetDeviceGammaRamp (dc, _GammaRampBackuped) != FALSE;
368 // Release the DC
369 ReleaseDC (NULL, dc);
371 else
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);
394 if (_dpy == NULL)
396 nlerror ("XOpenDisplay failed on '%s'", getenv("DISPLAY"));
398 else
400 nldebug("3D: XOpenDisplay on '%s' OK", getenv("DISPLAY"));
403 _xrandr_version = 0;
405 #ifdef HAVE_XRANDR
406 _OldSizeID = 0;
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;
417 #ifdef XF86VIDMODE
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);
424 #endif
426 _xrender_version = 0;
428 #ifdef HAVE_XRENDER
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:");
442 if (DebugLog)
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);
463 // define Atoms
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);
471 #endif
473 return true;
476 // ***************************************************************************
477 bool CDriverGL::unInit()
479 H_AUTO_OGL(CDriverGL_unInit)
481 if (!_CurrentMode.Windowed)
483 restoreScreenMode();
484 showCursor(true);
486 _CurrentMode.Windowed = true;
489 #ifdef NL_OS_WINDOWS
491 #ifndef USE_OPENGLES
492 // Off-screen rendering ?
493 if (_PBuffer)
495 nwglReleasePbufferDCARB(_PBuffer, _hDC);
496 nwglDestroyPbufferARB(_PBuffer);
497 _PBuffer = NULL;
499 #endif
501 if (_Registered && !UnregisterClassW(L"NLClass", GetModuleHandle(NULL)))
503 nlwarning("Can't unregister NLClass");
505 _Registered = 0;
507 // Restore monitor color parameters
508 if (_NeedToRestoreGammaRamp)
510 HDC dc = CreateDCA("DISPLAY", NULL, NULL, NULL);
511 if (dc)
513 if (!SetDeviceGammaRamp(dc, _GammaRampBackuped))
514 nlwarning("(CDriverGL::release): SetDeviceGammaRamp failed");
516 // Release the DC
517 ReleaseDC(NULL, dc);
519 else
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);
534 if (_dpy)
536 XCloseDisplay(_dpy);
537 _dpy = NULL;
540 #endif // NL_OS_UNIX
542 return true;
545 void CDriverGL::setWindowIcon(const std::vector<NLMISC::CBitmap> &bitmaps)
547 if (_win == EmptyWindow)
548 return;
550 #if defined(NL_OS_WINDOWS)
552 static HICON winIconBig = NULL;
553 static HICON winIconSmall = NULL;
555 if (winIconBig)
557 DestroyIcon(winIconBig);
558 winIconBig = NULL;
561 if (winIconSmall)
563 DestroyIcon(winIconSmall);
564 winIconSmall = NULL;
567 sint smallIndex = -1;
568 uint smallWidth = GetSystemMetrics(SM_CXSMICON);
569 uint smallHeight = GetSystemMetrics(SM_CYSMICON);
571 sint bigIndex = -1;
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)
579 smallIndex = i;
581 if (bigIndex == -1 && bitmaps[i].getWidth() == bigWidth && bitmaps[i].getHeight() == bigHeight)
582 bigIndex = i;
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)
589 smallIndex = i;
591 if (bigIndex == -1 && bitmaps[i].getWidth() >= bigWidth && bitmaps[i].getHeight() >= bigHeight)
592 bigIndex = i;
595 if (smallIndex > -1)
596 convertBitmapToIcon(bitmaps[smallIndex], winIconSmall, smallWidth, smallHeight, 32);
598 if (bigIndex > -1)
599 convertBitmapToIcon(bitmaps[bigIndex], winIconBig, bigWidth, bigHeight, 32);
601 if (winIconBig)
603 SendMessageA(_win, WM_SETICON, 0 /* ICON_SMALL */, (LPARAM)winIconSmall);
604 SendMessageA(_win, WM_SETICON, 1 /* ICON_BIG */, (LPARAM)winIconBig);
606 else
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());
634 else
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)
648 if (!mode.OffScreen)
649 NLMISC::INelContext::getInstance().setWindowedApplication(true);
651 _win = EmptyWindow;
653 _CurrentMode = mode;
655 _WindowVisible = false;
656 _Resizable = resizeable;
657 _DestroyWindow = false;
659 #ifdef NL_OS_WINDOWS
661 // Init pointers
662 #ifndef USE_OPENGLES
663 _PBuffer = NULL;
664 _hRC = NULL;
665 _hDC = NULL;
666 #endif
668 // Driver caps.
669 //=============
670 // Retrieve the WGL extensions before init the driver.
672 // Offscreen mode ?
673 if (_CurrentMode.OffScreen)
675 if (!createWindow(mode)) return false;
677 HWND tmpHWND = _win;
678 int width = mode.Width;
679 int height = mode.Height;
681 #ifdef USE_OPENGLES
682 // TODO: implement for OpenGL ES 1.x
683 #else
684 // resize the window
685 RECT rc;
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 );
690 // Get the
691 HDC tempHDC = GetDC(tmpHWND);
693 _CurrentMode.Depth = uint8(GetDeviceCaps(tempHDC,BITSPIXEL));
695 // ---
696 memset(&_pfd,0,sizeof(_pfd));
697 _pfd.nSize = sizeof(_pfd);
698 _pfd.nVersion = 1;
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;
708 else
710 _pfd.cDepthBits = 24;
711 _pfd.cAlphaBits = 8;
713 _pfd.iLayerType = PFD_MAIN_PLANE;
714 int pf=ChoosePixelFormat(tempHDC,&_pfd);
715 if (!pf)
717 nlwarning ("CDriverGL::setDisplay: ChoosePixelFormat failed");
718 DestroyWindow (tmpHWND);
719 return false;
721 if ( !SetPixelFormat(tempHDC,pf,&_pfd) )
723 nlwarning ("CDriverGL::setDisplay: SetPixelFormat failed");
724 DestroyWindow (tmpHWND);
725 return false;
728 // Create gl context
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);
735 _PBuffer = NULL;
736 _win = EmptyWindow;
737 _hRC = NULL;
738 _hDC = NULL;
739 return false;
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);
749 _PBuffer = NULL;
750 _win = EmptyWindow;
751 _hRC = NULL;
752 _hDC = NULL;
753 return false;
756 // Register WGL functions
757 #ifdef USE_OPENGLES
758 registerEGlExtensions (_Extensions, tempHDC);
759 #else
760 registerWGlExtensions (_Extensions, tempHDC);
761 #endif
763 HDC hdc = wglGetCurrentDC ();
765 if (hdc == NULL)
767 DWORD error = GetLastError ();
768 nlwarning ("CDriverGL::setDisplay: wglGetCurrentDC failed: 0x%x", error);
769 DestroyWindow (tmpHWND);
770 _PBuffer = NULL;
771 _win = EmptyWindow;
772 _hRC = NULL;
773 _hDC = NULL;
774 return false;
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];
781 int niattribs = 0;
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++ )
787 iattributes[a] = 0;
788 fattributes[a] = 0;
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;
795 niattribs++;
797 // We require a minimum of 24-bit depth.
798 iattributes[2*niattribs ] = WGL_DEPTH_BITS_ARB;
799 iattributes[2*niattribs+1] = 24;
800 niattribs++;
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;
805 niattribs++;
806 iattributes[2*niattribs ] = WGL_GREEN_BITS_ARB;
807 iattributes[2*niattribs+1] = 8;
808 niattribs++;
809 iattributes[2*niattribs ] = WGL_BLUE_BITS_ARB;
810 iattributes[2*niattribs+1] = 8;
811 niattribs++;
812 iattributes[2*niattribs ] = WGL_ALPHA_BITS_ARB;
813 iattributes[2*niattribs+1] = 8;
814 niattribs++;
816 // Now obtain a list of pixel formats that meet these minimum
817 // requirements.
818 int pformat[20];
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);
826 return false;
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);
842 _PBuffer = NULL;
843 _win = EmptyWindow;
844 _hRC = NULL;
845 _hDC = NULL;
846 return false;
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);
856 _PBuffer = NULL;
857 _win = EmptyWindow;
858 _hRC = NULL;
859 _hDC = NULL;
860 return false;
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);
869 _PBuffer = NULL;
870 _win = EmptyWindow;
871 _hRC = NULL;
872 _hDC = NULL;
873 return false;
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 );
882 if (_hDC == NULL)
884 DWORD error = GetLastError ();
885 nlwarning ("CDriverGL::setDisplay: wglGetPbufferDCARB failed: 0x%x", error);
886 nwglDestroyPbufferARB( _PBuffer );
888 wglDeleteContext (tempGLRC);
890 DestroyWindow (tmpHWND);
891 _PBuffer = NULL;
892 _win = EmptyWindow;
893 _hRC = NULL;
894 _hDC = NULL;
895 return false;
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 );
901 if (_hRC == NULL)
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);
909 _PBuffer = NULL;
910 _win = EmptyWindow;
911 _hRC = NULL;
912 _hDC = NULL;
913 return false;
916 // Get the depth
917 _CurrentMode.Depth = uint8(GetDeviceCaps (_hDC, BITSPIXEL));
919 // Destroy the temp gl context
920 #ifdef USE_OPENGLES
921 if (!eglDestroyContext(_EglDisplay, _EglContext);)
923 DWORD error = GetLastError ();
924 nlwarning ("CDriverGL::setDisplay: wglDeleteContext failed: 0x%x", error);
926 #else
927 if (!wglDeleteContext (tempGLRC))
929 DWORD error = GetLastError ();
930 nlwarning ("CDriverGL::setDisplay: wglDeleteContext failed: 0x%x", error);
932 #endif
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);
946 #ifdef USE_OPENGLES
947 eglDestroyContext(_EglDisplay, _EglContext);
948 #else
949 wglDeleteContext (_hRC);
950 nwglReleasePbufferDCARB( _PBuffer, _hDC );
951 nwglDestroyPbufferARB( _PBuffer );
952 #endif
954 DestroyWindow (tmpHWND);
955 _PBuffer = NULL;
956 _win = EmptyWindow;
957 _hRC = NULL;
958 _hDC = NULL;
959 return false;
961 #endif
963 else
965 if (wnd == EmptyWindow)
967 if (!createWindow(mode))
968 return false;
970 else
972 _win = wnd;
975 // associate OpenGL driver to window
976 SetWindowLongPtr(_win, GWLP_USERDATA, (LONG_PTR)this);
978 createContext();
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))
997 return false;
999 else
1001 _win = wnd;
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];
1038 if(!format)
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];
1050 if(!_glView)
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];
1062 // adjust size
1063 [_glView setFrame: [containerView() frame]];
1065 // create a opengl context for the view
1066 _ctx = [_glView openGLContext];
1068 if(!_ctx)
1069 nlerror("cannot create context");
1071 // free the pixel format object
1072 [format release];
1074 // let the open gl view handle the input
1075 [[containerView() window] makeFirstResponder:_glView];
1077 // prevents scrambled content in the view before first swap
1078 [_ctx flushBuffer];
1079 [_glView display];
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[] =
1090 GLX_RGBA,
1091 GLX_DOUBLEBUFFER,
1092 GLX_DEPTH_SIZE, 16,
1093 GLX_RED_SIZE, 4,
1094 GLX_GREEN_SIZE, 4,
1095 GLX_BLUE_SIZE, 4,
1096 GLX_ALPHA_SIZE, 4,
1097 GLX_STENCIL_SIZE, 8,
1098 None
1101 static int sAttribList24bpp[] =
1103 GLX_RGBA,
1104 GLX_DOUBLEBUFFER,
1105 GLX_DEPTH_SIZE, 24,
1106 GLX_RED_SIZE, 8,
1107 GLX_GREEN_SIZE, 8,
1108 GLX_BLUE_SIZE, 8,
1109 GLX_ALPHA_SIZE, 8,
1110 GLX_STENCIL_SIZE, 8,
1111 None
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);
1126 if (_ctx == NULL)
1128 nlerror("glXCreateContext() failed");
1131 if (wnd == EmptyWindow)
1133 if (!createWindow(mode))
1134 return false;
1136 else
1138 _win = wnd;
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);
1156 // XEvent event;
1157 // XIfEvent(dpy, &event, WaitForNotify, (char *)this);
1159 #endif // NL_OS_UNIX
1161 // setup OpenGL structures
1162 if (!setupDisplay())
1163 return false;
1165 // setup window size and screen mode
1166 if (!setMode(mode))
1167 return false;
1169 if (show || !_CurrentMode.Windowed)
1170 showWindow(true);
1172 return true;
1175 // --------------------------------------------------
1176 bool CDriverGL::saveScreenMode()
1178 H_AUTO_OGL(CDriverGL_saveScreenMode)
1180 bool res = true;
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);
1193 res = false;
1195 #ifdef HAVE_XRANDR
1197 if (!res && _xrandr_version > 0)
1199 XRRScreenConfiguration *screen_config = XRRGetScreenInfo(_dpy, RootWindow(_dpy, screen));
1201 if (screen_config)
1203 Rotation saved_rotation;
1204 _OldSizeID = XRRConfigCurrentConfiguration(screen_config, &saved_rotation);
1205 nlinfo("3D: current XRandR mode %d", _OldSizeID);
1206 XRRFreeScreenConfigInfo(screen_config);
1208 res = true;
1210 else
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
1232 return res;
1235 // --------------------------------------------------
1236 bool CDriverGL::restoreScreenMode()
1238 H_AUTO_OGL(CDriverGL_restoreScreenMode)
1240 bool res = false;
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
1249 res = true;
1251 #elif defined(NL_OS_UNIX)
1253 int screen = DefaultScreen(_dpy);
1255 #ifdef HAVE_XRANDR
1257 if (!res && _xrandr_version > 0)
1259 Window root = RootWindow(_dpy, screen);
1261 XRRScreenConfiguration *screen_config = XRRGetScreenInfo(_dpy, root);
1263 if (screen_config)
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);
1270 res = true;
1273 XRRFreeScreenConfigInfo(screen_config);
1275 else
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");
1290 // This is UGLY
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
1314 return res;
1317 // ***************************************************************************
1319 #ifdef XF86VIDMODE
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)
1332 if (mode.Windowed)
1334 // if fullscreen, switch back to desktop screen mode
1335 if (!_CurrentMode.Windowed)
1336 restoreScreenMode();
1338 return true;
1341 // save previous screen mode only if switching from windowed to fullscreen
1342 if (_CurrentMode.Windowed)
1343 saveScreenMode();
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)
1352 return true;
1354 #if defined(NL_OS_WINDOWS)
1356 DEVMODE devMode;
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;
1364 if(mode.Depth > 0)
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");
1379 return false;
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)
1388 bool found = false;
1390 #ifdef HAVE_XRANDR
1392 if (!found && _xrandr_version > 0)
1394 int screen = DefaultScreen(_dpy);
1395 Window root = RootWindow(_dpy, screen);
1397 XRRScreenConfiguration *screen_config = XRRGetScreenInfo(_dpy, root);
1399 if (screen_config)
1401 Rotation saved_rotation;
1402 SizeID cur_size = XRRConfigCurrentConfiguration(screen_config, &saved_rotation);
1404 sint nsizes;
1405 XRRScreenSize *sizes = XRRConfigSizes(screen_config, &nsizes);
1406 sint size = -1;
1408 for (sint i = 0; i < nsizes; ++i)
1410 if (sizes[i].width == mode.Width && sizes[i].height == mode.Height)
1412 size = i;
1413 break;
1417 if (size > -1)
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);
1422 found = true;
1424 else
1426 nlwarning("3D: XRRSetScreenConfig failed for mode %d: %dx%d", size, sizes[size].width, sizes[size].height);
1429 else
1431 nlwarning("3D: No corresponding screen mode");
1434 XRRFreeScreenConfigInfo(screen_config);
1436 else
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;
1450 int nmodes;
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);
1464 found = true;
1466 break;
1469 XFree(modes);
1473 #endif // XF86VIDMODE
1475 if (!found)
1476 return false;
1478 #endif // NL_OS_WINDOWS
1480 return true;
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;
1496 if (mode.OffScreen)
1498 dwStyle &= ~WS_VISIBLE;
1499 pos = 0;
1500 hwndParent = NULL;
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);
1509 return false;
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];
1529 if(!cocoa_window)
1531 nlerror("cannot create cocoa window");
1532 return false;
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");
1575 return false;
1578 #elif defined (NL_OS_UNIX)
1580 if (_visual_info == NULL)
1581 return false;
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");
1595 return false;
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);
1601 // set WM hints
1602 XWMHints *wm_hints = XAllocWMHints();
1604 if (wm_hints)
1606 wm_hints->flags = StateHint | InputHint;
1607 wm_hints->initial_state = NormalState;
1608 wm_hints->input = True;
1610 XSetWMHints(_dpy, window, wm_hints);
1611 XFree(wm_hints);
1613 else
1615 nlwarning("3D: Couldn't allocate XWMHints");
1618 // set class hints
1619 XClassHint *class_hints = XAllocClassHint();
1621 if (class_hints)
1623 class_hints->res_name = (char*)"NeL";
1624 class_hints->res_class = (char*)"nel";
1626 XSetClassHint(_dpy, window, class_hints);
1627 XFree(class_hints);
1629 else
1631 nlwarning("3D: Couldn't allocate XClassHint");
1634 #endif // NL_OS_UNIX
1636 _win = window;
1638 _CurrentMode.Width = mode.Width;
1639 _CurrentMode.Height = mode.Height;
1641 // Must destroy this window
1642 _DestroyWindow = true;
1644 setWindowTitle(ucstring("NeL window"));
1646 createCursors();
1648 return true;
1651 // ***************************************************************************
1653 bool CDriverGL::destroyWindow()
1655 H_AUTO_OGL(CDriverGL_destroyWindow)
1657 releaseCursors();
1659 // make sure window icons are deleted
1660 std::vector<NLMISC::CBitmap> bitmaps;
1661 setWindowIcon(bitmaps);
1663 #ifdef USE_OPENGLES
1665 if (_EglDisplay && _EglContext)
1667 eglMakeCurrent(_EglDisplay, _EglSurface, _EglSurface, _EglContext);
1669 if (_DestroyWindow)
1671 eglDestroyContext(_EglDisplay, _EglContext);
1675 #elif defined(NL_OS_WINDOWS)
1677 // Then delete.
1678 // wglMakeCurrent(NULL,NULL);
1680 if (_hDC)
1681 wglMakeCurrent(_hDC, NULL);
1683 if (_hRC)
1685 wglDeleteContext(_hRC);
1686 _hRC = NULL;
1689 if (_win && _hDC)
1691 ReleaseDC(_win, _hDC);
1692 _hDC = NULL;
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);
1702 _ctx = NULL;
1704 #endif
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)
1714 if (_DestroyWindow)
1716 [[containerView() window] release];
1717 [containerView() release];
1718 [_glView release];
1721 _ctx = nil;
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);
1732 XSync(_dpy, True);
1733 XUngrabKeyboard(_dpy, CurrentTime);
1735 #endif
1737 _win = EmptyWindow;
1739 return true;
1742 // ***************************************************************************
1744 CDriverGL::EWindowStyle CDriverGL::getWindowStyle() const
1746 H_AUTO_OGL(CDriverGL_getWindowStyle)
1748 if (!_CurrentMode.Windowed)
1749 return EWSFullscreen;
1751 return EWSWindowed;
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)
1762 return true;
1764 if (getWindowStyle() == windowStyle)
1765 return true;
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)
1793 #ifndef _DEBUG
1794 dwNewStyle |= WS_POPUP;
1795 #endif
1796 isVisible = true;
1799 if (isVisible)
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]];
1855 #endif
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
1874 XEvent xev;
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");
1890 return false;
1893 else
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);
1900 else
1902 // delete state property
1903 XDeleteProperty(_dpy, _win, XA_WM_STATE);
1907 #endif // NL_OS_WINDOWS
1909 _CurrentMode.Windowed = (windowStyle == EWSWindowed);
1911 return true;
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)
1921 return true;
1923 #if defined(NL_OS_WINDOWS)
1924 // save relative cursor
1925 POINT cursorPos;
1926 cursorPos.x = 0;
1927 cursorPos.y = 0;
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;
1934 #endif
1936 if (!setScreenMode(mode))
1937 return false;
1939 // when changing window style, it's possible system change window size too
1940 setWindowStyle(mode.Windowed ? EWSWindowed : EWSFullscreen);
1942 if (!mode.Windowed)
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;
1951 case 24:
1952 case 32: _ColorDepth = ColorDepth32; break;
1955 #if defined(NL_OS_WINDOWS)
1956 // restore relative cursor
1957 if (cursorPosOk)
1959 cursorPos.x = curX / (sint)mode.Width;
1960 cursorPos.y = curY / (sint)mode.Height;
1961 ClientToScreen(_win, &cursorPos);
1962 SetCursorPos(cursorPos.x, cursorPos.y);
1964 #endif
1966 // set color depth for custom cursor
1967 updateCursor(true);
1969 return true;
1972 #ifdef NL_OS_MAC
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)
1983 return 32;
1985 else if(CFStringCompare(pixelEncoding, CFSTR(IO16BitDirectPixels),
1986 kCFCompareCaseInsensitive) == kCFCompareEqualTo)
1987 return 16;
1989 return 0;
1992 #else
1994 long GetDictionaryLong(CFDictionaryRef theDict, const void* key)
1996 long value = 0;
1997 CFNumberRef numRef;
1998 numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key);
1999 if (numRef != NULL)
2000 CFNumberGetValue(numRef, kCFNumberLongType, &value);
2001 return 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)
2009 #endif
2011 #endif // NL_OS_MAC
2013 // --------------------------------------------------
2014 bool CDriverGL::getModes(std::vector<GfxMode> &modes)
2016 H_AUTO_OGL(CDriverGL_getModes)
2018 #ifdef NL_OS_WINDOWS
2019 sint modeIndex = 0;
2020 DEVMODE devMode;
2021 while (EnumDisplaySettings (NULL, modeIndex, &devMode))
2023 // Keep only 16 and 32 bits
2024 if ((devMode.dmBitsPerPel == 16 ) || (devMode.dmBitsPerPel == 32))
2026 // Add this mode
2027 GfxMode mode;
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);
2035 // Mode index
2036 modeIndex++;
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);
2049 return false;
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);
2060 #else
2061 CFArrayRef modeList = CGDisplayAvailableModes(dspy);
2062 #endif
2064 if (modeList == NULL)
2066 nlwarning("Display is invalid");
2067 continue;
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);
2075 #else
2076 CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex(modeList, j);
2077 uint8 bpp = (uint8)GetModeBitsPerPixel(mode);
2078 #endif
2080 if (bpp >= 16)
2082 #ifdef NL_MAC_VERSION_10_6_UP
2083 uint16 w = CGDisplayModeGetWidth(mode);
2084 uint16 h = CGDisplayModeGetHeight(mode);
2085 #else
2086 uint16 w = (uint16)GetModeWidth(mode);
2087 uint16 h = (uint16)GetModeHeight(mode);
2088 #endif
2090 // Add this mode
2091 GfxMode mode;
2092 mode.Width = w;
2093 mode.Height = h;
2094 mode.Depth = bpp;
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.
2099 mode.Frequency = 0;
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);
2108 #endif
2111 #elif defined (NL_OS_UNIX)
2113 if (!_dpy)
2115 nlwarning("3D: Unable to list modes because Display is NULL, did you forget to call init() ?");
2116 return false;
2119 bool found = false;
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));
2127 if (screen_config)
2129 // retrieve the list of resolutions
2130 int nsizes = 0;
2131 XRRScreenSize *sizes = XRRConfigSizes(screen_config, &nsizes);
2133 if (nsizes > 0)
2135 // nldebug("3D: %d available XRandR modes:", nsizes);
2136 for (sint i = 0; i < nsizes; ++i)
2138 // Add this mode
2139 GfxMode mode;
2140 mode.Width = sizes[i].width;
2141 mode.Height = sizes[i].height;
2142 mode.Depth = 32;
2143 mode.Frequency = 0;
2144 modes.push_back(mode);
2145 // nldebug("3D: Mode %d: %dx%d", i, mode.Width, mode.Height);
2148 found = true;
2150 else
2152 nlwarning("3D: No XRandR modes available");
2155 XRRFreeScreenConfigInfo(screen_config);
2157 else
2159 nlwarning("3D: XRRGetScreenInfo failed");
2162 #endif
2164 #ifdef XF86VIDMODE
2165 if (!found && _xvidmode_version > 0)
2167 int nmodes;
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++)
2174 // Add this mode
2175 GfxMode mode;
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);
2182 XFree(ms);
2184 else
2186 nlwarning("3D: XF86VidModeGetAllModeLines failed");
2189 #endif // XF86VIDMODE
2191 if (!found)
2193 // Add current screen mode
2194 GfxMode mode;
2195 mode.Width = DisplayWidth(_dpy, screen);
2196 mode.Height = DisplayHeight(_dpy, screen);
2197 mode.Frequency = 0;
2198 modes.push_back(mode);
2201 #endif
2202 return true;
2205 // --------------------------------------------------
2206 bool CDriverGL::getCurrentScreenMode(GfxMode &mode)
2208 H_AUTO_OGL(CDriverGL_getCurrentScreenMode)
2210 #ifdef NL_OS_WINDOWS
2212 DEVMODE devmode;
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;
2231 mode.Frequency = 0;
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;
2243 // in windowed mode
2244 else
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)
2254 bool found = false;
2255 int screen = DefaultScreen(_dpy);
2257 #ifdef HAVE_XRANDR
2259 if (!found && _xrandr_version > 0)
2261 XRRScreenConfiguration *screen_config = XRRGetScreenInfo(_dpy, RootWindow(_dpy, screen));
2263 if (screen_config)
2265 int nsizes;
2266 XRRScreenSize *sizes = XRRConfigSizes(screen_config, &nsizes);
2267 if (nsizes > 0)
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);
2275 mode.Frequency = 0;
2276 mode.Width = sizes[size].width;
2277 mode.Height = sizes[size].height;
2279 found = true;
2281 nlinfo("3D: Current XRandR mode %d: %dx%d, %dbit", size, mode.Width, mode.Height, mode.Depth);
2283 else
2285 nlwarning("3D: No XRandR modes available");
2288 XRRFreeScreenConfigInfo(screen_config);
2290 else
2292 nlwarning("3D: XRRGetScreenInfo failed");
2296 #endif // HAVE_XRANDR
2298 #ifdef XF86VIDMODE
2300 if (!found && _xvidmode_version > 0)
2302 sint pixelClock;
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);
2315 found = true;
2317 else
2319 nlwarning("3D: XF86VidModeGetModeLine failed, cannot get current video mode");
2323 #endif // XF86VidMode
2325 if (!found)
2327 mode.Windowed = _CurrentMode.Windowed;
2328 mode.OffScreen = _CurrentMode.OffScreen;
2329 mode.Depth = (uint) DefaultDepth(_dpy, screen);
2330 mode.Frequency = 0;
2331 mode.Width = DisplayWidth(_dpy, screen);
2332 mode.Height = DisplayHeight(_dpy, screen);
2334 found = true;
2336 nldebug("Current mode: %dx%d, %d Hz, %dbit", mode.Width, mode.Height, mode.Frequency, mode.Depth);
2339 #endif // NL_OS_UNIX
2341 return true;
2344 // --------------------------------------------------
2345 void CDriverGL::setWindowTitle(const ucstring &title)
2347 H_AUTO_OGL(CDriverGL_setWindowTitle)
2349 if (_win == EmptyWindow)
2350 return;
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
2367 // UTF8 properties
2368 Xutf8SetWMProperties (_dpy, _win, (char*)title.toUtf8().c_str(), (char*)title.toUtf8().c_str(), NULL, 0, NULL, NULL, NULL);
2369 #else
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);
2376 else
2378 nlwarning("3D: Can't convert title to TextProperty");
2380 #endif
2382 #endif // NL_OS_WINDOWS
2385 // ***************************************************************************
2386 void CDriverGL::setWindowPos(sint32 x, sint32 y)
2388 H_AUTO_OGL(CDriverGL_setWindowPos)
2390 _WindowX = x;
2391 _WindowY = y;
2393 if (_win == EmptyWindow || !_CurrentMode.Windowed)
2394 return;
2396 #ifdef NL_OS_WINDOWS
2398 // save relative cursor
2399 POINT cursorPos;
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);
2406 if (cursorPosOk)
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)
2449 return;
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)
2463 if (show)
2465 XMapRaised(_dpy, _win);
2467 // fix window position if windows manager want to impose them
2468 setWindowPos(_WindowX, _WindowY);
2470 else
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()
2489 #ifdef USE_OPENGLES
2490 uint samples = 0;
2492 if (_CurrentMode.AntiAlias > -1)
2494 if (_CurrentMode.AntiAlias == 0)
2496 samples = 4;
2498 else
2500 samples = _CurrentMode.AntiAlias;
2504 EGLint attribList[] =
2506 EGL_RED_SIZE, 8,
2507 EGL_GREEN_SIZE, 8,
2508 EGL_BLUE_SIZE, 8,
2509 EGL_ALPHA_SIZE, 8,
2510 EGL_DEPTH_SIZE, 16,
2511 EGL_STENCIL_SIZE, 8,
2512 // EGL_SAMPLE_BUFFERS, _CurrentMode.AntiAlias > -1 ? 1:0,
2513 // EGL_SAMPLES, samples,
2514 EGL_RENDERABLE_TYPE,
2515 EGL_OPENGL_ES_BIT,
2516 EGL_NONE
2519 // Get Display
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());
2529 return false;
2533 // Initialize EGL
2534 EGLint majorVersion;
2535 EGLint minorVersion;
2537 if (!eglInitialize(_EglDisplay, &majorVersion, &minorVersion))
2539 return EGL_FALSE;
2542 const char *extensions = eglQueryString(_EglDisplay, EGL_EXTENSIONS);
2545 // Get configs
2546 EGLint numConfigs;
2548 if (!eglGetConfigs(_EglDisplay, NULL, 0, &numConfigs))
2550 return false;
2553 // Choose config
2554 EGLConfig config = NULL;
2556 if (!eglChooseConfig(_EglDisplay, attribList, &config, 1, &numConfigs))
2558 return false;
2561 // Create a surface
2562 _EglSurface = eglCreateWindowSurface(_EglDisplay, config, (EGLNativeWindowType)_win, NULL);
2564 if (_EglSurface == EGL_NO_SURFACE)
2566 return false;
2569 // Create a GL context
2570 EGLint contextAttribs[] =
2572 EGL_CONTEXT_CLIENT_VERSION, 1,
2573 EGL_NONE
2576 _EglContext = eglCreateContext(_EglDisplay, config, EGL_NO_CONTEXT, contextAttribs);
2578 if (_EglContext == EGL_NO_CONTEXT)
2580 return false;
2583 // Make the context current
2584 if (!eglMakeCurrent(_EglDisplay, _EglSurface, _EglSurface, _EglContext))
2586 return false;
2588 #elif defined(NL_OS_WINDOWS)
2589 _hDC = GetDC(_win);
2590 _CurrentMode.Depth = uint8(GetDeviceCaps(_hDC,BITSPIXEL));
2592 wglMakeCurrent(_hDC,NULL);
2593 // ---
2594 memset(&_pfd,0,sizeof(_pfd));
2595 _pfd.nSize = sizeof(_pfd);
2596 _pfd.nVersion = 1;
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;
2605 else
2607 _pfd.cDepthBits = 24;
2608 _pfd.cAlphaBits = 8;
2609 _pfd.cStencilBits = 8;
2611 _pfd.iLayerType = PFD_MAIN_PLANE;
2612 int pf=ChoosePixelFormat(_hDC,&_pfd);
2613 if (!pf)
2615 return false;
2618 if ( !SetPixelFormat(_hDC,pf,&_pfd) )
2620 return false;
2622 _hRC=wglCreateContext(_hDC);
2624 wglMakeCurrent(_hDC,_hRC);
2625 #endif
2627 return true;
2630 // --------------------------------------------------
2631 bool CDriverGL::activate()
2633 H_AUTO_OGL(CDriverGL_activate);
2635 if (_win == EmptyWindow)
2636 return false;
2638 #ifdef USE_OPENGLES
2640 EGLContext ctx = eglGetCurrentContext();
2642 if (ctx != _EglContext)
2644 // Make the context current
2645 if (!eglMakeCurrent(_EglDisplay, _EglSurface, _EglSurface, _EglContext))
2647 return false;
2651 #elif defined(NL_OS_WINDOWS)
2653 HGLRC hglrc = wglGetCurrentContext();
2655 if (hglrc != _hRC)
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
2672 return true;
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)))
2695 case IDOK:
2696 return okId;
2697 case IDCANCEL:
2698 return cancelId;
2699 case IDABORT:
2700 return abortId;
2701 case IDRETRY:
2702 return retryId;
2703 case IDIGNORE:
2704 return ignoreId;
2705 case IDYES:
2706 return yesId;
2707 case IDNO:
2708 return noId;
2710 nlstop;
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);
2714 // log only
2715 printf("%s:%s\n", title, message);
2716 nlwarning("%s: %s", title, message);
2717 #endif // NL_OS_WINDOWS
2718 return okId;
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
2730 if (_PBuffer)
2732 nwglQueryPbufferARB( _PBuffer, WGL_PBUFFER_WIDTH_ARB, (int*)&width );
2733 nwglQueryPbufferARB( _PBuffer, WGL_PBUFFER_HEIGHT_ARB, (int*)&height );
2735 #endif
2737 #endif
2739 else
2741 #ifdef NL_OS_MAC
2742 if([containerView() isInFullScreenMode])
2744 width = _backBufferWidth;
2745 height = _backBufferHeight;
2746 return;
2748 #endif
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)
2759 return;
2761 #if defined(NL_OS_WINDOWS)
2763 // resize the window
2764 RECT rc;
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
2774 RECT clientRect;
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;
2805 else
2807 // only change the window size if the driver created the window itself
2808 if(_DestroyWindow)
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)
2824 if (!_Resizable)
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);
2836 XFree(size_hints);
2838 else
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)
2862 x = y = 0;
2864 else
2866 x = _WindowX;
2867 y = _WindowY;
2871 // --------------------------------------------------
2872 bool CDriverGL::isActive()
2874 H_AUTO_OGL(CDriverGL_isActive)
2876 if (_win == EmptyWindow)
2877 return false;
2879 bool res = true;
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
2897 return res;
2900 // ***************************************************************************
2901 bool CDriverGL::setMonitorColorProperties (const CMonitorColorProperties &properties)
2903 H_AUTO_OGL(CDriverGL_setMonitorColorProperties )
2905 #ifdef NL_OS_WINDOWS
2907 // Get a DC
2908 HDC dc = CreateDCA ("DISPLAY", NULL, NULL, NULL);
2909 if (dc)
2911 // The ramp
2912 WORD ramp[256*3];
2914 // For each composant
2915 uint c;
2916 for( c=0; c<3; c++ )
2918 uint i;
2919 for( i=0; i<256; i++ )
2921 // Floating value
2922 float value = (float)i / 256;
2924 // Contrast
2925 value = (float) max (0.0f, (value-0.5f) * (float) pow (3.f, properties.Contrast[c]) + 0.5f );
2927 // Gamma
2928 value = (float) pow (value, (properties.Gamma[c]>0) ? 1 - 3 * properties.Gamma[c] / 4 : 1 - properties.Gamma[c] );
2930 // Luminosity
2931 value = value + properties.Luminosity[c] / 2.f;
2932 ramp[i+(c<<8)] = (WORD)min ((int)65535, max (0, (int)(value * 65535)));
2936 // Set the ramp
2937 bool result = SetDeviceGammaRamp (dc, ramp) != FALSE;
2939 // Release the DC
2940 ReleaseDC (NULL, dc);
2942 // Returns result
2943 return result;
2945 else
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");
2958 #endif
2960 return false;
2963 #ifdef NL_OS_MAC
2964 void CDriverGL::setupApplicationMenu()
2966 NSMenu* menu;
2967 NSMenuItem* menuItem;
2968 NSString* title;
2969 NSString* appName;
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:@""];
2982 // separator
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:@""];
2999 // separator
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];
3021 #endif
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);
3044 CBitmap colorBm;
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);
3054 ++ srcColorPtr;
3055 ++ destColorPtr;
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]);
3085 else
3087 colorHbm = CreateBitmap(iconWidth, iconHeight, 1, 32, &colorBm.getPixels(0)[0]);
3088 maskHbm = CreateBitmap(iconWidth, iconHeight, 1, 32, &colorBm.getPixels(0)[0]);
3091 ICONINFO iconInfo;
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);
3107 return true;
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;
3135 return true;
3138 #endif
3140 #ifdef NL_STATIC
3141 } // NLDRIVERGL/ES
3142 #endif
3144 } // NL3D